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

Reply via email to