David McClain dbm@refined-audiometrics.com writes:
Just curious for other opinions... but wouldn't this (Heartbleed) sort of buffer excess read-back failure have been prevented by utilizing a "safe" language like Lisp or SML?
I used to be an "unsafe" language bigot -- having mastered C/C++ for many years, and actually producing C compilers for a living at one time. I felt there should be no barriers to me as master of my machine, and not the other way around.
Oh, so you are directly (if partially) responsible for the C mess!
The C standards say that:
{ char a[10]; return a[12]; }
is _undefined_.
Why, as a compiler writer, didn't you define it to raise an exception? Yes, the C standard doesn't define exceptions, why, as a compiler writer, didn't you add this obvious extension?
Notice how CLHS aref specifies:
subscripts---a list of valid array indices for the array.
Exceptional Situations: None.
and how:
1.4.4.3 The ``Arguments and Values'' Section of a Dictionary Entry
An English language description of what arguments the operator accepts and what values it returns, including information about defaults for parameters corresponding to omittable arguments (such as optional parameters and keyword parameters). For special operators and macros, their arguments are not evaluated unless it is explicitly stated in their descriptions that they are evaluated.
Except as explicitly specified otherwise, the consequences are undefined if these type restrictions are violated.
Which means that (let ((a (make-array 10))) (aref a 12)) is as undefined in CL as in C!
However, you don't see Lisp implementers allow it, and instead they all signal an error:
[pjb@kuiper :0.0 tmp]$ clall -r '(let ((a (make-array 10))) (aref a 12))'
Armed Bear Common Lisp Invalid array index 12 for #(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL) (should be >= 0 and < 10). Clozure Common Lisp Array index 12 out of bounds for #(0 0 0 0 0 0 0 0 0 0) . CLISP AREF: index 12 for #(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL) is out of range CMU Common Lisp Error in function LISP::%ARRAY-ROW-MAJOR-INDEX: Invalid index 12 in #(0 0 0 0 0 0 0 0 0 0) ECL In function AREF, the index into the object #(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL). takes a value 12 out of the range (INTEGER 0 9). SBCL Value of SB-INT:INDEX in (THE (INTEGER 0 (10)) SB-INT:INDEX) is 12, not a (MOD 10).
And even with safety 0, which should never be used, (but perhaps on a specific function that you've proven needs to 2 cycles faster, for which you can't find a better algorithm, and when you have proven and tested that bounds and other adverse conditions couldn't occur, that is, so many conditions that they never occur in real life), non-toy implementations still check bounds:
[pjb@kuiper :0.0 tmp]$ clall -r '(declaim (optimize (safety 0) (speed 3) (debug 0) (space 3)))' '(let ((a (make-array 10))) (aref a 12))'
Armed Bear Common Lisp --> NIL Armed Bear Common Lisp Invalid array index 12 for #(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL) (should be >= 0 and < 10). CCL /home/pjb/bin/clall: line 284: 16162 Segmentation fault "$implementation" "$@" "${user_args[@]}" > "$error" 2>&1 CLISP --> NIL CLISP AREF: index 12 for #(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL) is out of range CMU Common Lisp --> NIL CMU Common Lisp Error in function LISP::%ARRAY-ROW-MAJOR-INDEX: Invalid index 12 in #(0 0 0 0 0 0 0 0 0 0) ECL --> NIL ECL In function AREF, the index into the object #(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL). takes a value 12 out of the range (INTEGER 0 9). SBCL --> No value. SBCL --> 0
Here is how a lisp programmer implements a C compiler:
cl-user> (ql:quickload :vacietis) ;; … cl-user> (defun read-c-expression-from-string (source) (let ((*readtable* vacietis:c-readtable) (vacietis:*compiler-state* (vacietis:make-compiler-state))) (read-from-string source))) read-c-expression-from-string cl-user> (read-c-expression-from-string "char f(){ char a[10]; return a[12]; }") (vacietis::defun/1 f nil (prog* ((a (vacietis:allocate-memory 10))) (return (vacietis.c:[] a 12)))) cl-user> (eval (read-c-expression-from-string "char f(){ char a[10]; return a[12]; }")) f cl-user> (f)
Debug: Array index 12 out of bounds for #<vector 10, adjustable> . While executing: (:internal swank::invoke-default-debugger), in process repl-thread(871). Type :POP to abort, :R for a list of available restarts. Type :? for other options.
1 > :q ; Evaluation aborted on #<simple-error #x302003010B7D>. cl-user>
A final word: Don't use FFI! Implement the libraries you need in Lisp!