On 19D the following code will cause an error:
* (defun test-string-stream ()
(with-output-to-string (stream)
(dotimes (x 17)
(write-string (make-string (* 1024 1024)) stream)))
(values))
TEST-STRING-STREAM
* (test-string-stream)
; [GC threshold exceeded with 18,887,688 bytes in use. Commencing GC.]
; [GC completed with 13,461,936 bytes retained and 5,425,752 bytes freed.]
; [GC will next occur when at least 25,461,936 bytes are in use.]
; [GC threshold exceeded with 33,388,360 bytes in use. Commencing GC.]
; [GC completed with 33,390,368 bytes retained and -2,008 bytes freed.]
; [GC will next occur when at least 45,390,368 bytes are in use.]
; [GC threshold exceeded with 74,288,928 bytes in use. Commencing GC.]
; [GC completed with 54,362,504 bytes retained and 19,926,424 bytes freed.]
; [GC will next occur when at least 66,362,504 bytes are in use.]
Type-error in KERNEL::OBJECT-NOT-TYPE-ERROR-HANDLER:
134217792 is not of type (UNSIGNED-BYTE 27)
[Condition of type TYPE-ERROR]
Restarts:
0: [ABORT] Return to Top-Level.
Debug (type H for help)
(KERNEL:BIT-BASH-COPY 5
""
64
""
...)[:EXTERNAL]
Source: Error finding source:
Error in function DEBUG::GET-FILE-TOP-LEVEL-FORM: Source file no longer exists:
target:code/bit-bash.lisp.
0]
----------------------------------------------------------------------
Note that the error is signaled starting from 17MB.
The following code gets rid of the bug in the string streams, although
there may be a more serious error somewhere else, as I haven't been
able to track down the call to BIT-BASH-COPY.
(in-package :lisp)
(defun my-string-sout (stream string start end)
(declare (simple-string string) (fixnum start end))
(let* ((current (string-output-stream-index stream))
(length (- end start))
(dst-end (+ length current))
(workspace (string-output-stream-string stream)))
(declare (simple-string workspace)
(fixnum current length))
(unless (< dst-end (length workspace))
(let ((new-length (min (1- array-dimension-limit)
(+ (* current 2) length))))
(unless (<= dst-end new-length)
(error "Can't stretch output string any further."))
(let ((new-workspace (make-string new-length)))
(do ((i 0 (1+ i)))
((= i current))
(declare (fixnum i))
(setf (aref new-workspace i)
(aref workspace i)))
(setf workspace new-workspace
(string-output-stream-string stream) new-workspace))))
(do ((target-index current (1+ target-index))
(source-index start (1+ source-index)))
((or (= target-index dst-end)
(= source-index end)))
(declare (fixnum target-index source-index))
(setf (aref workspace target-index)
(aref string source-index)))
(setf (string-output-stream-index stream) dst-end)))
(defstruct (string-output-stream
(:include string-stream
(out #'string-ouch)
(sout #'my-string-sout)
(misc #'string-out-misc))
(:print-function %print-string-output-stream)
(:constructor %make-string-output-stream ()))
;; The string we throw stuff in.
(string (make-string 40) :type simple-string)
;; Index of the next location to use.
(index 0 :type fixnum))
(defun get-output-stream-string (stream)
"Returns a string of all the characters sent to a stream made by
Make-String-Output-Stream since the last call to this function."
(declare (type string-output-stream stream))
(let* ((length (string-output-stream-index stream))
(result (make-string length))
(source (string-output-stream-string stream)))
(do ((i 0 (1+ i)))
((= i length))
(declare (fixnum i))
(setf (aref result i)
(aref source i)))
(setf (string-output-stream-index stream) 0)
result))
--
walter pelissero
http://www.pelissero.de