|
Testing how array-creation routines interact with continuations, and crashing when the user does something that "is an error".
Bradley Lucier
(08 Mar 2023 21:19 UTC)
|
|
Re: Testing how array-creation routines interact with continuations, and crashing when the user does something that "is an error". Marc Nieper-Wißkirchen (09 Mar 2023 08:33 UTC)
|
|
Re: Testing how array-creation routines interact with continuations, and crashing when the user does something that "is an error".
Bradley Lucier
(09 Mar 2023 18:30 UTC)
|
|
New tests for procedures when reinvoking continuations; fix crashes.
Bradley Lucier
(09 Mar 2023 22:02 UTC)
|
I think it is perfectly fine that the library crashes the system when
one selects an "unsafe" mode of the implementation.
After all, this is what is expected: By selecting an "unsafe" mode, I
ask for maximal efficiency at the expense of comprehensive tests
against programming errors.
Am Mi., 8. März 2023 um 22:19 Uhr schrieb Bradley Lucier <xxxxxx@purdue.edu>:
>
> There are currently no tests in the test suite for how
>
> array-{copy|append|stack|decurry|block}[!]*
>
> interact with continuations, and I'd like to fix that, especially for
> independent implementations of this SRFI.
>
> I started with (pp is pretty-print to the system output port):
>
> > (import (srfi 231))
> > (let* ((cont #f)
> (call-cont #t)
> (domain (make-interval '#(2 2)))
> (A_ (lambda (i j)
> (call-with-current-continuation
> (lambda (c)
> (if (= i j 0)
> (set! cont c))
> 1))))
> (A (make-array domain A_))
> (array-list '()))
> (set! array-list (cons (array-copy A) array-list))
> (pp 'printing)
> (for-each (lambda (A) (pp (array->list* A))) array-list)
> (if call-cont
> (begin
> (set! call-cont #f)
> (cont 4)))
> (pp (apply eq? array-list)))
> printing
> ((1 1) (1 1))
> printing
> ((4 1) (1 1))
> ((1 1) (1 1))
> #f
>
> which works as expected.
>
> Replacing array-copy with array-copy! in this test causes the library to
> crash when compiled in Gambit with safety checks removed:
>
> > (let* ((cont #f)
> (call-cont #t)
> (domain (make-interval '#(2 2)))
> (A_ (lambda (i j)
> (call-with-current-continuation
> (lambda (c)
> (if (= i j 0)
> (set! cont c))
> 1))))
> (A (make-array domain A_))
> (array-list '()))
> (set! array-list (cons (array-copy! A) array-list))
> (pp 'printing)
> (for-each (lambda (A) (pp (array->list* A))) array-list)
> (if call-cont
> (begin
> (set! call-cont #f)
> (cont 4)))
> (pp (apply eq? array-list)))
> printing
> ((1 1) (1 1))
> printing
> Segmentation fault (core dumped)
>
> I didn't expect this, I just expected that the first and second elements
> of array-list would be eq?. Running the library interpreted shows the
> problem:
>
> > (load "generic-arrays.scm")
> "/home/lucier/lang/scheme/srfi-231/srfi-231-temp/generic-arrays.scm"
> > (let* ((cont #f)
> (call-cont #t)
> (domain (make-interval '#(2 2)))
> (A_ (lambda (i j)
> (call-with-current-continuation
> (lambda (c)
> (if (= i j 0)
> (set! cont c))
> 1))))
> (A (make-array domain A_))
> (array-list '()))
> (set! array-list (cons (array-copy! A) array-list))
> (pp 'printing)
> (for-each (lambda (A) (pp (array->list* A))) array-list)
> (if call-cont
> (begin
> (set! call-cont #f)
> (cont 4)))
> (pp (apply eq? array-list)))
> printing
> ((1 1) (1 1))
> *** ERROR IN #<procedure #2>, "generic-arrays.scm"@2534.42 -- (Argument
> 2, k) Out of range
> (vector-set! #(4 1 1 1) 5 1)
> 1>
>
> Here is the code:
>
> ;; No checks needed, storage-class-setter is
> vector-set!
> (let ((body (%%array-body destination)))
> (%%interval-for-each
> (case (%%interval-dimension domain)
> ((0) (let ((index initial-offset))
> (lambda ()
> (vector-set! body index (getter))
> (set! index (fx+ index 1)))))
> ;; not necessary
> ((1) (let ((index initial-offset))
> (lambda (i)
> (vector-set! body index
> (getter i))
> (set! index (fx+ index 1)))))
> ((2) (let ((index initial-offset))
> (lambda (i j)
> (vector-set! body index
> (getter i j)) ;; <<<<<< problem
> (set! index (fx+ index 1)))))
> ((3) (let ((index initial-offset))
> (lambda (i j k)
> (vector-set! body index
> (getter i j k))
> (set! index (fx+ index 1)))))
> ((4) (let ((index initial-offset))
> (lambda (i j k l)
> (vector-set! body index
> (getter i j k l))
> (set! index (fx+ index 1)))))
> (else (let ((index initial-offset))
> (lambda multi-index
> (vector-set! body index (apply
> getter multi-index))
> (set! index (fx+ index 1))))))
> domain))
>
> So I was using mutated state (the value of index) in a (perhaps vain)
> attempt to speed things up, but this causes index to walk off the end of
> the specialized array result's body the second time the continuation is
> invoked.
>
> The specifications says "Don't do that!", don't invoke the continuation
> of the argument array's getter more than once when calling array-copy!.
>
> On the other hand, I didn't expect the library to crash the system.
>
> Is this OK behavior, to crash when the user does something that "is an
> error", or would it be better to try to catch all such instances while
> possibly slowing down the general case?
>
> Brad