1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-19 03:00:25 +02:00

Add test case for the GOOPS `class-redefinition' memory corruption.

This commit is contained in:
Ludovic Courtès 2008-08-20 00:44:20 +02:00
parent dc0f35ca61
commit f4833b3906
2 changed files with 78 additions and 2 deletions

View file

@ -1,3 +1,8 @@
2008-08-19 Ludovic Courtès <ludo@gnu.org>
* tests/goops.test (object update)[changing class, `hell' in
`goops.c' grows as expected]: New tests.
2008-07-06 Ludovic Courtès <ludo@gnu.org> 2008-07-06 Ludovic Courtès <ludo@gnu.org>
* standalone/test-asmobs, standalone/test-bad-identifiers, * standalone/test-asmobs, standalone/test-bad-identifiers,

View file

@ -18,7 +18,8 @@
;;;; Boston, MA 02110-1301 USA ;;;; Boston, MA 02110-1301 USA
(define-module (test-suite test-goops) (define-module (test-suite test-goops)
#:use-module (test-suite lib)) #:use-module (test-suite lib)
#:autoload (srfi srfi-1) (unfold))
(pass-if "GOOPS loads" (pass-if "GOOPS loads"
(false-if-exception (false-if-exception
@ -277,7 +278,77 @@
(y #:accessor y #:init-value 456) (y #:accessor y #:init-value 456)
(z #:accessor z #:init-value 789)) (z #:accessor z #:init-value 789))
(current-module)) (current-module))
(eval '(and (= (y foo) 456) (= (z foo) 789)) (current-module)))) (eval '(and (= (y foo) 456) (= (z foo) 789)) (current-module)))
(pass-if "changing class"
(let* ((c1 (class () (the-slot #:init-keyword #:value)))
(c2 (class () (the-slot #:init-keyword #:value)
(the-other-slot #:init-value 888)))
(o1 (make c1 #:value 777)))
(and (is-a? o1 c1)
(not (is-a? o1 c2))
(equal? (slot-ref o1 'the-slot) 777)
(let ((o2 (change-class o1 c2)))
(and (eq? o1 o2)
(is-a? o2 c2)
(not (is-a? o2 c1))
(equal? (slot-ref o2 'the-slot) 777))))))
(pass-if "`hell' in `goops.c' grows as expected"
;; This snippet yielded a segfault prior to the 2008-08-19 `goops.c'
;; fix (i.e., Guile 1.8.5 and earlier). The root of the problem was
;; that `go_to_hell ()' would not reallocate enough room for the `hell'
;; array, leading to out-of-bounds accesses.
(let* ((parent-class (class ()
#:name '<class-that-will-be-redefined>))
(classes
(unfold (lambda (i) (>= i 20))
(lambda (i)
(make-class (list parent-class)
'((the-slot #:init-value #:value)
(the-other-slot))
#:name (string->symbol
(string-append "<foo-to-redefine-"
(number->string i)
">"))))
(lambda (i)
(+ 1 i))
0))
(objects
(map (lambda (class)
(make class #:value 777))
classes)))
(define-method (change-class (foo parent-class)
(new <class>))
;; Called by `scm_change_object_class ()', via `purgatory ()'.
(if (null? classes)
(next-method)
(let ((class (car classes))
(object (car objects)))
(set! classes (cdr classes))
(set! objects (cdr objects))
;; Redefine the class so that its instances are eventually
;; passed to `scm_change_object_class ()'. This leads to
;; nested `scm_change_object_class ()' calls, which increases
;; the size of HELL and increments N_HELL.
(class-redefinition class
(make-class '() (class-slots class)
#:name (class-name class)))
;; Use `slot-ref' to trigger the `scm_change_object_class ()'
;; and `go_to_hell ()' calls.
(slot-ref object 'the-slot)
(next-method))))
;; Initiate the whole `change-class' chain.
(let* ((class (car classes))
(object (change-class (car objects) class)))
(is-a? object class)))))
(with-test-prefix "object comparison" (with-test-prefix "object comparison"
(pass-if "default method" (pass-if "default method"