swank-cmucl.lisp contains code which makes cmucl break w.r.t. the ansi cl standard; in that it makes READ-SEQUENCE insist on filling its target buffer. The hyperspec says, in 21.2 under READ-SEQUENCE:
If the end of file for stream is reached before copying all elements of the subsequence, then the extra elements near the end of sequence are not updated.
swank-cmucl installs its own READ-INTO-SIMPLE-STRING which calls SYSTEM:READ-N-BYTES with the EOF-ERRORP argument true. In addition to being wrong, it does not solve the problem I believe it is trying to solve. At the end of this mail is a patch to remove the buggy version of READ-INTO-SIMPLE-STRING. If this is trying to protect against truncated reads, I believe the solution is to run a loop (possibly with a timeout) until the needed bytes have been read from the socket. If I am mistaken, then the assertion that is already there should suffice, making SYSTEM:READ-N-BYTES throw an error gives us nothing extra. Something like the followint patch would make swank.lisp more robust against slow networks:
Index: swank.lisp =================================================================== RCS file: /project/slime/cvsroot/slime/swank.lisp,v retrieving revision 1.137 diff -u -r1.137 swank.lisp --- swank.lisp 5 Mar 2004 22:51:12 -0000 1.137 +++ swank.lisp 8 Mar 2004 17:44:53 -0000 @@ -572,7 +572,12 @@ (ash (next-byte) 8) (next-byte))) (string (make-string length)) - (pos (read-sequence string stream))) + (pos 0)) + ;; Keep reading in case the connection is slow + (loop for iteration = 1 then (1+ iteration) + do (incf pos (read-sequence string stream :start pos)) + until (or (= pos length) (< 10 iterations )) ;;until length or appx. 1 second + do (sleep 0.1)) ;; at least with cmucl this is multi-proc. friendly (assert (= pos length) () "Short read: length=~D pos=~D" length pos) (let ((form (read-form string)))
Here is the patch to remove the bad code from swank-cmucl.lisp:
Index: swank-cmucl.lisp =================================================================== RCS file: /project/slime/cvsroot/slime/swank-cmucl.lisp,v retrieving revision 1.78 diff -u -r1.78 swank-cmucl.lisp --- swank-cmucl.lisp 7 Mar 2004 16:41:11 -0000 1.78 +++ swank-cmucl.lisp 8 Mar 2004 17:46:15 -0000 @@ -4,39 +4,6 @@
(in-package :swank)
-(in-package :lisp) - -;; Fix for read-sequence in 18e -#+cmu18e -(progn - (let ((s (find-symbol (string :*enable-package-locked-errors*) :lisp))) - (when s - (setf (symbol-value s) nil))) - - (defun read-into-simple-string (s stream start end) - (declare (type simple-string s)) - (declare (type stream stream)) - (declare (type index start end)) - (unless (subtypep (stream-element-type stream) 'character) - (error 'type-error - :datum (read-char stream nil #\Null) - :expected-type (stream-element-type stream) - :format-control "Trying to read characters from a binary stream.")) - ;; Let's go as low level as it seems reasonable. - (let* ((numbytes (- end start)) - (bytes-read (system:read-n-bytes stream s start numbytes t))) - (if (< bytes-read numbytes) - (+ start bytes-read) - end))) - - (let ((s (find-symbol (string :*enable-package-locked-errors*) :lisp))) - (when s - (setf (symbol-value s) t))) - - ) - -(in-package :swank) - ;;;; TCP server.
"Håkon Alstadheim" haalst@online.no writes:
swank-cmucl.lisp contains code which makes cmucl break w.r.t. the ansi cl standard; in that it makes READ-SEQUENCE insist on filling its target buffer. The hyperspec says, in 21.2 under READ-SEQUENCE:
You're right. I replaced READ-INTO-SIMPLE-STRING with the version from the CMUCL December snapshot, which calls read-n-bytes in a loop. Thank you for the report.
Helmut.