Common Lisp类型注释会导致不正确的行为吗?

时间:2015-07-01 20:06:40

标签: types common-lisp declare

我知道如果安全设置很低,Common Lisp可以使用类型注释作为优化辅助工具而不会被检查。例如,此程序运行并打印数字和字符串,没有任何类型错误。 (当安全> = 1时,我只在SBCL中出现类型错误)

(declaim (optimize
           (speed 3)
           (safety 0)))

(defun f (x)
  (declare (type fixnum x))
  x)

(format t "1 ~A~%" (f 17))
(format t "2 ~A~%" (f "asd"))

我现在想知道如果安全性设置为零并且不遵守类型注释,是否可以创建一个令人讨厌的程序。比如从一种类型转换为另一种类型(如C类型转换)和其他类型的未定义行为。

到目前为止,我还没有找到一个能够做到这一点的例子。我尝试了使用类型化数组的此示例的变体,但没有一个导致类型转换行为。

(declaim (optimize
           (speed 3)
           (safety 0)
           ))

(defun f ()
    (let ((arr (make-array '(5)
      :element-type 'fixnum
      :initial-contents (list 1 2 3 4 5))))
      (declare (type (vector fixnum 5) arr))
      (setf (aref arr 0) "hello")
      (aref arr 0)))

(format t "a1 ~A~%" (f))

在CLISP中,此程序打印" hello",而不对int进行类型转换,在SBCL中,程序以SIMPLE-TYPE-ERROR错误中止。

有没有办法创建一个Common Lisp程序,如果我不尊重我的类型声明,会导致恶魔从我的鼻子中冒出来?

3 个答案:

答案 0 :(得分:4)

Common Lisp标准说有类型声明。它并没有真正说出他们做了什么或者实现对他们做了什么。

用途:

  • 生成特定于类型的代码
  • 运行时和/或编译时类型检查。这主要是由CMUCL,SBCL和SCL完成的。

假设我们有操作:

(+ i 100)

默认情况下,它是一个通用+,可以处理所有数字类型。

如果我们告诉ifixnum那么

  • +操作可以是特定于fixnum的

如果另外将返回类型声明为fixnum

  • 它可能不会溢出到bignum

如果我们另外告诉编译器我们想要低safety,那么编译器将不会生成运行时类型检查。

编译器提供的功能未标准化。它甚至可以完全忽略类型声明。

如果你有一个支持类型特定代码的编译器(并且有许多这样的编译器),安全性很低,并且在运行时提供了错误类型的对象,那么它可能会产生不良后果。包括因堆内存损坏而崩溃Lisp。

因此,最好只在非常小的代码区域使用低安全性,而不是在整个文件或系统上使用。使用locally声明有助于。

SBCL(也是SCL和CMUCL)很特殊,因为它还将类型声明视为类型检查的断言。

答案 1 :(得分:2)

不确定恶魔,但是你可以获得段错误,就像我15年前用CMUCL做的那样和类似的代码:

(declaim (optimize (speed 3) (safety 0)))
(defun f (v)
  (declare (type (vector double-float) v))
  (loop for x in v sum x))
(f #(1 2 3))

请注意,我承诺我只会将(vector double-float)传递给f,然后我用simple-vector给它fixnum

答案 2 :(得分:2)

以下是sbcl中的safety 0的几个示例:

CL-USER> (proclaim '(optimize (safety 0)))
; No value

Out of Bounds Read

CL-USER> (loop for i from 0 to 20 
              do (print (aref #(0) i)))

0 
0 
#(0) 
(I) 
I 
NIL 
(AREF #(0) I) 
NIL 
(PRINT (AREF #(0) I)) 
NIL 
#<unknown immediate object, lowtag=#b1001, widetag=#x59 {D59}> 
#<SB-KERNEL:LAYOUT for SB-KERNEL:LEXENV {10005F3C33}> 
NIL 
NIL 
NIL 
NIL 
NIL 
NIL 
NIL 
NIL 
NIL 
NIL

未定义的类型转换

CL-USER> (defun f (x y)
           (declare (fixnum x y))
           (+ x y))
F
CL-USER> (f t ())
537919538

在SBCL中,如果您闻到鼻子恶魔,您可以重新启动图像并输入(sb-ext:restrict-compiler-policy 'safety 3)(也可能再次使用'debug),然后再加载有问题的代码。运气不错会让你得到一个很好的条件,而不是未定义的行为。