1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-20 11:40:18 +02:00

fix segfault in goops if class fields are redefined

* libguile/goops.c (map, filter_cpl, remove_duplicate_slots): Use
  scm_is_pair instead of !scm_is_null, given that we use accessor
  macros.
  (check_cpl, build_slots_list): Check that descendents of <class> can't
  redefine slots of <class>.

* test-suite/tests/goops.test ("defining classes"): Add a test.

Patch originally by Stefan Israelsson Tampe.
This commit is contained in:
Andy Wingo 2011-10-21 00:22:44 +02:00
parent aa9c198588
commit 13d807b7d3
2 changed files with 70 additions and 12 deletions

View file

@ -373,7 +373,7 @@ map (SCM (*proc) (SCM), SCM ls)
SCM res = scm_cons (proc (SCM_CAR (ls)), SCM_EOL); SCM res = scm_cons (proc (SCM_CAR (ls)), SCM_EOL);
SCM h = res; SCM h = res;
ls = SCM_CDR (ls); ls = SCM_CDR (ls);
while (!scm_is_null (ls)) while (scm_is_pair (ls))
{ {
SCM_SETCDR (h, scm_cons (proc (SCM_CAR (ls)), SCM_EOL)); SCM_SETCDR (h, scm_cons (proc (SCM_CAR (ls)), SCM_EOL));
h = SCM_CDR (h); h = SCM_CDR (h);
@ -387,7 +387,7 @@ static SCM
filter_cpl (SCM ls) filter_cpl (SCM ls)
{ {
SCM res = SCM_EOL; SCM res = SCM_EOL;
while (!scm_is_null (ls)) while (scm_is_pair (ls))
{ {
SCM el = SCM_CAR (ls); SCM el = SCM_CAR (ls);
if (scm_is_false (scm_c_memq (el, res))) if (scm_is_false (scm_c_memq (el, res)))
@ -422,7 +422,7 @@ remove_duplicate_slots (SCM l, SCM res, SCM slots_already_seen)
{ {
SCM tmp; SCM tmp;
if (scm_is_null (l)) if (!scm_is_pair (l))
return res; return res;
tmp = SCM_CAAR (l); tmp = SCM_CAAR (l);
@ -437,15 +437,63 @@ remove_duplicate_slots (SCM l, SCM res, SCM slots_already_seen)
return remove_duplicate_slots (SCM_CDR (l), res, slots_already_seen); return remove_duplicate_slots (SCM_CDR (l), res, slots_already_seen);
} }
static void
check_cpl (SCM slots, SCM bslots)
{
for (; scm_is_pair (bslots); bslots = SCM_CDR (bslots))
if (scm_is_true (scm_assq (SCM_CAAR (bslots), slots)))
scm_misc_error ("init-object", "a predefined <class> inherited "
"field cannot be redefined", SCM_EOL);
}
static SCM
build_class_class_slots (void);
static SCM static SCM
build_slots_list (SCM dslots, SCM cpl) build_slots_list (SCM dslots, SCM cpl)
{ {
register SCM res = dslots; SCM bslots, class_slots;
int classp;
SCM res = dslots;
for (cpl = SCM_CDR (cpl); !scm_is_null (cpl); cpl = SCM_CDR (cpl)) class_slots = SCM_EOL;
res = scm_append (scm_list_2 (SCM_SLOT (SCM_CAR (cpl), classp = scm_is_true (scm_memq (scm_class_class, cpl));
scm_si_direct_slots),
res)); if (classp)
{
bslots = build_class_class_slots ();
check_cpl (res, bslots);
}
else
bslots = SCM_EOL;
if (scm_is_pair (cpl))
{
for (cpl = SCM_CDR (cpl); scm_is_pair (cpl); cpl = SCM_CDR (cpl))
{
SCM new_slots = SCM_SLOT (SCM_CAR (cpl),
scm_si_direct_slots);
if (classp)
{
if (!scm_is_eq (SCM_CAR (cpl), scm_class_class))
check_cpl (new_slots, bslots);
else
{
/* Move class slots to the head of the list. */
class_slots = new_slots;
continue;
}
}
res = scm_append (scm_list_2 (new_slots, res));
}
}
else
scm_misc_error ("%compute-slots", "malformed cpl argument in "
"build_slots_list", SCM_EOL);
/* make sure to add the <class> slots to the head of the list */
if (classp)
res = scm_append (scm_list_2 (class_slots, res));
/* res contains a list of slots. Remove slots which appears more than once */ /* res contains a list of slots. Remove slots which appears more than once */
return remove_duplicate_slots (scm_reverse (res), SCM_EOL, SCM_EOL); return remove_duplicate_slots (scm_reverse (res), SCM_EOL, SCM_EOL);
@ -457,6 +505,9 @@ maplist (SCM ls)
SCM orig = ls; SCM orig = ls;
while (!scm_is_null (ls)) while (!scm_is_null (ls))
{ {
if (!scm_is_pair (ls))
scm_misc_error ("%compute-slots", "malformed ls argument in "
"maplist", SCM_EOL);
if (!scm_is_pair (SCM_CAR (ls))) if (!scm_is_pair (SCM_CAR (ls)))
SCM_SETCAR (ls, scm_cons (SCM_CAR (ls), SCM_EOL)); SCM_SETCAR (ls, scm_cons (SCM_CAR (ls), SCM_EOL));
ls = SCM_CDR (ls); ls = SCM_CDR (ls);
@ -882,7 +933,7 @@ SCM_SYMBOL (sym_nfields, "nfields");
static SCM static SCM
build_class_class_slots () build_class_class_slots (void)
{ {
/* has to be kept in sync with SCM_VTABLE_BASE_LAYOUT and /* has to be kept in sync with SCM_VTABLE_BASE_LAYOUT and
SCM_CLASS_CLASS_LAYOUT */ SCM_CLASS_CLASS_LAYOUT */

View file

@ -206,8 +206,15 @@
(x #:accessor x #:init-value 123) (x #:accessor x #:init-value 123)
(z #:accessor z #:init-value 789)) (z #:accessor z #:init-value 789))
(current-module)) (current-module))
(eval '(equal? (x (make <qux>)) 123) (current-module))))) (eval '(equal? (x (make <qux>)) 123) (current-module)))
(pass-if-exception "cannot redefine fields of <class>"
'(misc-error . "cannot be redefined")
(eval '(begin
(define-class <test-class> (<class>)
name)
(make <test-class>))
(current-module)))))
(with-test-prefix "defining generics" (with-test-prefix "defining generics"