From 6d30f5d60a3fe5b4774c46237a2575b5bfe5cf65 Mon Sep 17 00:00:00 2001 From: Martin Stjernholm <mast@lysator.liu.se> Date: Tue, 11 Jul 2000 05:45:10 +0200 Subject: [PATCH] Fixed bug in gc where things which got only weak refs externally but non-weak internal cyclic refs didn't get gc'd. Rev: src/array.c:1.77 Rev: src/gc.c:1.105 Rev: src/gc.h:1.54 Rev: src/mapping.c:1.92 Rev: src/multiset.c:1.24 Rev: src/object.c:1.135 Rev: src/program.c:1.249 Rev: src/queue.c:1.5 Rev: src/queue.h:1.4 Rev: src/svalue.c:1.83 Rev: src/testsuite.in:1.312 --- src/array.c | 15 ++++++++- src/gc.c | 80 ++++++++++++++++++++++++++++++++++++++++++------ src/gc.h | 11 ++++--- src/mapping.c | 18 +++++++++-- src/multiset.c | 5 ++- src/object.c | 16 +++++++++- src/program.c | 17 ++++++++-- src/queue.c | 12 ++++++++ src/queue.h | 1 + src/svalue.c | 69 +++++++++++++++++++++++++---------------- src/testsuite.in | 48 ++++++++++++++++++++++++++++- 11 files changed, 243 insertions(+), 49 deletions(-) diff --git a/src/array.c b/src/array.c index e2aadaab90..f62b346c21 100644 --- a/src/array.c +++ b/src/array.c @@ -23,7 +23,7 @@ #include "stuff.h" #include "bignum.h" -RCSID("$Id: array.c,v 1.76 2000/07/07 01:26:39 hubbe Exp $"); +RCSID("$Id: array.c,v 1.77 2000/07/11 03:45:09 mast Exp $"); struct array empty_array= { @@ -1957,6 +1957,19 @@ void gc_free_all_unreferenced_arrays(void) { struct array *a,*next; + if (gc_ext_weak_refs) { + /* Have to go through all marked things if we got external weak + * references to otherwise unreferenced things, so the mark + * functions can free those references. */ + gc_mark_array_pos = empty_array.next; + while (gc_mark_array_pos != gc_internal_array && gc_ext_weak_refs) { + struct array *a = gc_mark_array_pos; + gc_mark_array_pos = a->next; + gc_mark_array_as_referenced(a); + } + discard_queue(&gc_mark_queue); + } + for (a = gc_internal_array; a != &empty_array; a = next) { #ifdef PIKE_DEBUG diff --git a/src/gc.c b/src/gc.c index 4168d9ffcd..93926548c9 100644 --- a/src/gc.c +++ b/src/gc.c @@ -29,7 +29,7 @@ struct callback *gc_evaluator_callback=0; #include "block_alloc.h" -RCSID("$Id: gc.c,v 1.104 2000/07/07 15:33:29 mast Exp $"); +RCSID("$Id: gc.c,v 1.105 2000/07/11 03:45:09 mast Exp $"); /* Run garbage collect approximately every time * 20 percent of all arrays, objects and programs is @@ -102,6 +102,7 @@ static struct marker rec_list = {0, 0, 0}; struct marker *gc_rec_last = &rec_list; static struct marker *kill_list = 0; static unsigned last_cycle; +size_t gc_ext_weak_refs; /* rec_list is a linked list of the markers currently being recursed * through in the cycle check pass. gc_rec_last points at the @@ -770,8 +771,13 @@ void debug_gc_touch(void *a) else if (m->weak_refs == -1) gc_fatal(a, 3, "A thing which had only weak references is " "still around after gc.\n"); - else if (!(m->flags & GC_LIVE)) - gc_fatal(a, 3, "A thing to garb is still around.\n"); + else if (!(m->flags & GC_LIVE)) { + if (m->weak_refs > 0) + gc_fatal(a, 3, "A thing to garb is still around. " + "It's probably one with only external weak refs.\n"); + else + gc_fatal(a, 3, "A thing to garb is still around.\n"); + } } } else @@ -847,6 +853,7 @@ INT32 real_gc_check_weak(void *a) #endif m->weak_refs++; + gc_ext_weak_refs++; if (m->weak_refs >= *(INT32 *) a) m->weak_refs = -1; @@ -1022,7 +1029,8 @@ int gc_do_weak_free(void *a) struct marker *m; if (!a) fatal("Got null pointer.\n"); - if (Pike_in_gc != GC_PASS_MARK && Pike_in_gc != GC_PASS_CYCLE) + if (Pike_in_gc != GC_PASS_MARK && Pike_in_gc != GC_PASS_CYCLE && + !(Pike_in_gc == GC_PASS_FREE && gc_ext_weak_refs)) fatal("gc_do_weak_free() called in invalid gc pass.\n"); if (gc_debug) { if (!(m = find_marker(a))) @@ -1034,7 +1042,22 @@ int gc_do_weak_free(void *a) if (m->weak_refs > m->refs) gc_fatal(a, 0, "More weak references than internal references.\n"); - return m->weak_refs == -1; + if (Pike_in_gc != GC_PASS_FREE) { + if (m->weak_refs == -1) { + gc_ext_weak_refs--; + return 1; + } + } + else + if (!(m->flags & GC_MARKED)) { + if (m->weak_refs <= 0) + gc_fatal(a, 0, "Too many weak refs cleared to thing with external " + "weak refs.\n"); + m->weak_refs--; + gc_ext_weak_refs--; + return 1; + } + return 0; } #endif /* PIKE_DEBUG */ @@ -1045,16 +1068,42 @@ int gc_mark(void *a) #ifdef PIKE_DEBUG if (!a) fatal("Got null pointer.\n"); - if (Pike_in_gc != GC_PASS_MARK) + if (Pike_in_gc != GC_PASS_MARK && + !(Pike_in_gc == GC_PASS_FREE && gc_ext_weak_refs)) fatal("gc mark attempted in invalid pass.\n"); if (!*(INT32 *) a) gc_fatal(a, 0, "Marked a thing without refs.\n"); + if (m->weak_refs == -1) + gc_fatal(a, 0, "Marking thing scheduled for weak free.\n"); + if (Pike_in_gc == GC_PASS_FREE && !(m->flags & GC_MARKED)) + gc_fatal(a, 0, "gc_mark() called for thing in free pass " + "that wasn't marked before.\n"); #endif - if(m->flags & GC_MARKED) - { + if (Pike_in_gc == GC_PASS_FREE) + /* Things are visited in the free pass through the mark functions + * to free refs to internal things that only got weak external + * references. That happens only when a thing also have internal + * cyclic non-weak refs. */ + if (m->flags & GC_FREE_VISITED) + return 0; + else { + m->flags |= GC_FREE_VISITED; + return 1; + } + + else if (m->flags & GC_MARKED) { +#ifdef PIKE_DEBUG + if (m->weak_refs != 0) + gc_fatal(a, 0, "weak_refs changed in marker already visited by gc_mark().\n"); +#endif return 0; - }else{ + } + else { + if (m->weak_refs) { + gc_ext_weak_refs -= m->weak_refs; + m->weak_refs = 0; + } m->flags = (m->flags & ~GC_NOT_REFERENCED) | GC_MARKED; DO_IF_DEBUG(marked++); return 1; @@ -1212,6 +1261,15 @@ int gc_cycle_push(void *x, struct marker *m, int weak) if (weak < 0) gc_rec_last->flags |= GC_FOLLOWED_STRONG; #endif + if (weak > 0) { +#ifdef PIKE_DEBUG + if (m->weak_refs <= 0) + gc_fatal(x, 0, "Followed weak ref to thing that should have none left.\n"); + m->weak_refs--; +#endif + gc_ext_weak_refs--; + } + if (m->flags & GC_IN_REC_LIST) { /* A cyclic reference is found. */ #ifdef PIKE_DEBUG if (m == &rec_list || gc_rec_last == &rec_list) @@ -1670,6 +1728,7 @@ int do_gc(void) #endif Pike_in_gc=GC_PASS_CHECK; + gc_ext_weak_refs = 0; /* First we count internal references */ gc_check_all_arrays(); gc_check_all_multisets(); @@ -1835,6 +1894,9 @@ int do_gc(void) } if (gc_extra_refs) fatal("Lost track of %d extra refs to things in gc.\n", gc_extra_refs); + if (gc_ext_weak_refs) + fatal("Still got %u external weak references to internal things in gc.\n", + gc_ext_weak_refs); #endif Pike_in_gc=0; diff --git a/src/gc.h b/src/gc.h index 2cf31512f8..146b2ceddb 100644 --- a/src/gc.h +++ b/src/gc.h @@ -1,5 +1,5 @@ /* - * $Id: gc.h,v 1.53 2000/07/04 00:43:57 mast Exp $ + * $Id: gc.h,v 1.54 2000/07/11 03:45:10 mast Exp $ */ #ifndef GC_H #define GC_H @@ -93,6 +93,7 @@ struct marker #define GC_WEAK_REF 0x0400 #define GC_STRONG_REF 0x0800 #define GC_GOT_DEAD_REF 0x1000 +#define GC_FREE_VISITED 0x2000 /* Debug mode flags. */ #define GC_TOUCHED 0x010000 @@ -106,6 +107,7 @@ struct marker PTR_HASH_ALLOC(marker,MARKER_CHUNK_SIZE) extern struct marker *gc_rec_last; +extern size_t gc_ext_weak_refs; /* Prototypes begin here */ struct callback *debug_add_gc_callback(callback_func call, @@ -187,12 +189,11 @@ void f__gc_status(INT32 args); #define gc_is_referenced(X) debug_gc_is_referenced(debug_malloc_pass(X)) #else #define gc_is_referenced(X) !(get_marker(X)->flags & GC_NOT_REFERENCED) -#define gc_do_weak_free(X) (get_marker(X)->weak_refs == -1) +#define gc_do_weak_free(X) (Pike_in_gc != GC_PASS_FREE ? \ + get_marker(X)->weak_refs == -1 : \ + !(get_marker(X)->flags & GC_MARKED)) #endif -#define gc_do_weak_free_svalue(S) \ - ((S)->type <= MAX_COMPLEX && gc_do_weak_free((S)->u.refs)) - #define gc_external_mark2(X,Y,Z) gc_external_mark3( debug_malloc_pass(X),(Y),(Z)) #define gc_external_mark(X) gc_external_mark2( (X),"externally", 0) diff --git a/src/mapping.c b/src/mapping.c index b43d44273d..93b6bd3d19 100644 --- a/src/mapping.c +++ b/src/mapping.c @@ -5,7 +5,7 @@ \*/ /**/ #include "global.h" -RCSID("$Id: mapping.c,v 1.91 2000/07/06 23:25:26 mast Exp $"); +RCSID("$Id: mapping.c,v 1.92 2000/07/11 03:45:10 mast Exp $"); #include "main.h" #include "object.h" #include "mapping.h" @@ -846,7 +846,8 @@ void check_mapping_for_destruct(struct mapping *m) fatal("Zero refs in mapping->data\n"); if(d_flag>1) check_mapping(m); debug_malloc_touch(m); - if (Pike_in_gc > GC_PASS_PREPARE && Pike_in_gc != GC_PASS_MARK) + if (Pike_in_gc > GC_PASS_PREPARE && Pike_in_gc < GC_PASS_FREE && + Pike_in_gc != GC_PASS_MARK) fatal("check_mapping_for_destruct called in wrong pass inside gc.\n"); #endif @@ -2060,6 +2061,19 @@ void gc_free_all_unreferenced_mappings(void) struct mapping *m,*next; struct mapping_data *md; + if (gc_ext_weak_refs) { + /* Have to go through all marked things if we got external weak + * references to otherwise unreferenced things, so the mark + * functions can free those references. */ + gc_mark_mapping_pos = first_mapping; + while (gc_mark_mapping_pos != gc_internal_mapping && gc_ext_weak_refs) { + struct mapping *m = gc_mark_mapping_pos; + gc_mark_mapping_pos = m->next; + gc_mark_mapping_as_referenced(m); + } + discard_queue(&gc_mark_queue); + } + for(m=gc_internal_mapping;m;m=next) { if(gc_do_free(m)) diff --git a/src/multiset.c b/src/multiset.c index 98bc4392a9..8340d086ad 100644 --- a/src/multiset.c +++ b/src/multiset.c @@ -16,7 +16,7 @@ #include "gc.h" #include "security.h" -RCSID("$Id: multiset.c,v 1.23 2000/07/06 23:25:26 mast Exp $"); +RCSID("$Id: multiset.c,v 1.24 2000/07/11 03:45:10 mast Exp $"); struct multiset *first_multiset; @@ -369,6 +369,9 @@ void gc_free_all_unreferenced_multisets(void) { struct multiset *l,*next; + /* No gc_ext_weak_refs stuff here; it's been taken care of by + * gc_free_all_unreferenced_arrays(). */ + for(l=gc_internal_multiset;l;l=next) { if(gc_do_free(l)) diff --git a/src/object.c b/src/object.c index e3e66866fe..13b58c32cc 100644 --- a/src/object.c +++ b/src/object.c @@ -5,7 +5,7 @@ \*/ /**/ #include "global.h" -RCSID("$Id: object.c,v 1.134 2000/07/10 21:05:25 mast Exp $"); +RCSID("$Id: object.c,v 1.135 2000/07/11 03:45:10 mast Exp $"); #include "object.h" #include "dynamic_buffer.h" #include "interpret.h" @@ -1477,6 +1477,20 @@ void gc_free_all_unreferenced_objects(void) { struct object *o,*next; + if (gc_ext_weak_refs) { + /* Have to go through all marked things if we got external weak + * references to otherwise unreferenced things, so the mark + * functions can free those references. */ + gc_mark_object_pos = first_object; + while (gc_mark_object_pos != gc_internal_object && gc_ext_weak_refs) { + struct object *o = gc_mark_object_pos; + gc_mark_object_pos = o->next; + if (o->refs) + gc_mark_object_as_referenced(o); + } + discard_queue(&gc_mark_queue); + } + for(o=gc_internal_object; o; o=next) { if(gc_do_free(o)) diff --git a/src/program.c b/src/program.c index 3c2f8787c2..037b4d7c21 100644 --- a/src/program.c +++ b/src/program.c @@ -5,7 +5,7 @@ \*/ /**/ #include "global.h" -RCSID("$Id: program.c,v 1.248 2000/07/10 18:21:32 grubba Exp $"); +RCSID("$Id: program.c,v 1.249 2000/07/11 03:45:10 mast Exp $"); #include "program.h" #include "object.h" #include "dynamic_buffer.h" @@ -3728,6 +3728,19 @@ void gc_free_all_unreferenced_programs(void) { struct program *p,*next; + if (gc_ext_weak_refs) { + /* Have to go through all marked things if we got external weak + * references to otherwise unreferenced things, so the mark + * functions can free those references. */ + gc_mark_program_pos = first_program; + while (gc_mark_program_pos != gc_internal_program && gc_ext_weak_refs) { + struct program *p = gc_mark_program_pos; + gc_mark_program_pos = p->next; + gc_mark_program_as_referenced(p); + } + discard_queue(&gc_mark_queue); + } + for(p=gc_internal_program;p;p=next) { debug_malloc_touch(p); @@ -3765,7 +3778,7 @@ void gc_free_all_unreferenced_programs(void) for (p = first_program; p != gc_internal_program; p = p->next) { int e,tmp=0; if (!p) - fatal("gc_internal_program is bogus.\n"); + fatal("gc_internal_program was bogus.\n"); for(e=0;e<p->num_constants;e++) { if(p->constants[e].sval.type == T_PROGRAM && p->constants[e].sval.u.program == p) diff --git a/src/queue.c b/src/queue.c index dbfb1f2632..41e62d27dc 100644 --- a/src/queue.c +++ b/src/queue.c @@ -42,6 +42,18 @@ void run_queue(struct pike_queue *q) q->last=0; } +void discard_queue(struct pike_queue *q) +{ + struct queue_block *b = q->first; + while (b) + { + struct queue_block *next = b->next; + free((char *) b); + b = next; + } + q->first = q->last = 0; +} + void enqueue(struct pike_queue *q, queue_call call, void *data) { struct queue_block *b; diff --git a/src/queue.h b/src/queue.h index fb0bfc4ce5..7d60308e38 100644 --- a/src/queue.h +++ b/src/queue.h @@ -12,6 +12,7 @@ typedef void (*queue_call)(void *data); struct queue_entry; struct queue_block; void run_queue(struct pike_queue *q); +void discard_queue(struct pike_queue *q); void enqueue(struct pike_queue *q, queue_call call, void *data); void run_lifo_queue(struct pike_queue *q); void enqueue_lifo(struct pike_queue *q, queue_call call, void *data); diff --git a/src/svalue.c b/src/svalue.c index 5a1852951e..fc7757d9fa 100644 --- a/src/svalue.c +++ b/src/svalue.c @@ -24,7 +24,7 @@ #include "queue.h" #include "bignum.h" -RCSID("$Id: svalue.c,v 1.82 2000/07/06 22:07:41 grubba Exp $"); +RCSID("$Id: svalue.c,v 1.83 2000/07/11 03:45:10 mast Exp $"); struct svalue dest_ob_zero = { T_INT, 0 }; @@ -1392,7 +1392,7 @@ void gc_check_weak_short_svalue(union anything *u, TYPE_T type) u->refs = 0; \ } while (0) -#define GC_RECURSE_SWITCH(U,T,ZAP,FREE_WEAK,GC_DO,PRE,DO_FUNC,DO_STR) \ +#define GC_RECURSE_SWITCH(U,T,ZAP,FREE_WEAK,GC_DO,PRE,DO_FUNC,DO_OBJ,DO_STR) \ switch (T) { \ case T_FUNCTION: \ PRE DO_FUNC(U, T, ZAP, GC_DO) \ @@ -1403,7 +1403,7 @@ void gc_check_weak_short_svalue(union anything *u, TYPE_T type) freed = 1; \ break; \ } \ - FREE_WEAK(U, T, ZAP) GC_DO(U, object); \ + FREE_WEAK(U, T, ZAP) DO_OBJ(U, object); \ break; \ case T_STRING: \ DO_STR(U); break; \ @@ -1417,6 +1417,22 @@ void gc_check_weak_short_svalue(union anything *u, TYPE_T type) PRE FREE_WEAK(U, T, ZAP) GC_DO(U, mapping); break; \ } +#define DONT_FREE_WEAK(U, T, ZAP) + +#define FREE_WEAK(U, T, ZAP) \ + if (gc_do_weak_free(U.refs)) { \ + ZAP(); \ + freed = 1; \ + break; \ + } + +#define GC_DO_MARK(U, TN) \ + enqueue(&gc_mark_queue, \ + (queue_call) PIKE_CONCAT3(gc_mark_, TN, _as_referenced), \ + U.TN) + +#define GC_DO_NO_WEAK_MARK(U, TN) do {} while (0) + #define DO_MARK_FUNC_SVALUE(U, T, ZAP, GC_DO) \ if (s->subtype == FUNCTION_BUILTIN) { \ DO_IF_DEBUG( \ @@ -1429,23 +1445,14 @@ void gc_check_weak_short_svalue(union anything *u, TYPE_T type) } \ /* Fall through to T_OBJECT. */ +#define DO_MARK_OBJ_WEAK(U, TN) \ + if (U.object->prog && \ + (U.object->prog->flags & PROGRAM_NO_WEAK_FREE)) \ + GC_DO_MARK(U, TN) + #define DO_MARK_STRING(U) \ DO_IF_DEBUG(if (U.refs && d_flag) gc_mark(U.string)) -#define GC_DO_MARK(U, TN) \ - enqueue(&gc_mark_queue, \ - (queue_call) PIKE_CONCAT3(gc_mark_, TN, _as_referenced), \ - U.TN) - -#define DONT_FREE_WEAK(U, T, ZAP) - -#define FREE_WEAK(U, T, ZAP) \ - if (gc_do_weak_free(U.refs)) { \ - ZAP(); \ - freed = 1; \ - break; \ - } - TYPE_FIELD real_gc_mark_svalues(struct svalue *s, size_t num) { TYPE_FIELD t = 0; @@ -1456,7 +1463,8 @@ TYPE_FIELD real_gc_mark_svalues(struct svalue *s, size_t num) dmalloc_touch_svalue(s); GC_RECURSE_SWITCH((s->u), (s->type), ZAP_SVALUE, DONT_FREE_WEAK, GC_DO_MARK, {}, - DO_MARK_FUNC_SVALUE, DO_MARK_STRING); + DO_MARK_FUNC_SVALUE, GC_DO_MARK, + DO_MARK_STRING); t |= 1 << s->type; } return freed ? t : 0; @@ -1471,8 +1479,9 @@ TYPE_FIELD gc_mark_weak_svalues(struct svalue *s, size_t num) { dmalloc_touch_svalue(s); GC_RECURSE_SWITCH((s->u), (s->type), ZAP_SVALUE, FREE_WEAK, - GC_DO_MARK, {}, - DO_MARK_FUNC_SVALUE, DO_MARK_STRING); + GC_DO_NO_WEAK_MARK, {}, + DO_MARK_FUNC_SVALUE, DO_MARK_OBJ_WEAK, + DO_MARK_STRING); t |= 1 << s->type; } return freed ? t : 0; @@ -1484,7 +1493,8 @@ int real_gc_mark_short_svalue(union anything *u, TYPE_T type) debug_malloc_touch(u); GC_RECURSE_SWITCH((*u), type, ZAP_SHORT_SVALUE, DONT_FREE_WEAK, GC_DO_MARK, {if (!u->refs) return 0;}, - DO_FUNC_SHORT_SVALUE, DO_MARK_STRING); + DO_FUNC_SHORT_SVALUE, GC_DO_MARK, + DO_MARK_STRING); return freed; } @@ -1493,8 +1503,9 @@ int gc_mark_weak_short_svalue(union anything *u, TYPE_T type) int freed = 0; debug_malloc_touch(u); GC_RECURSE_SWITCH((*u), type, ZAP_SHORT_SVALUE, FREE_WEAK, - GC_DO_MARK, {if (!u->refs) return 0;}, - DO_FUNC_SHORT_SVALUE, DO_MARK_STRING); + GC_DO_NO_WEAK_MARK, {if (!u->refs) return 0;}, + DO_FUNC_SHORT_SVALUE, DO_MARK_OBJ_WEAK, + DO_MARK_STRING); return freed; } @@ -1517,7 +1528,8 @@ TYPE_FIELD real_gc_cycle_check_svalues(struct svalue *s, size_t num) dmalloc_touch_svalue(s); GC_RECURSE_SWITCH((s->u), (s->type), ZAP_SVALUE, DONT_FREE_WEAK, GC_DO_CYCLE_CHECK, {}, - DO_CYCLE_CHECK_FUNC_SVALUE, DO_CYCLE_CHECK_STRING); + DO_CYCLE_CHECK_FUNC_SVALUE, GC_DO_CYCLE_CHECK, + DO_CYCLE_CHECK_STRING); t |= 1 << s->type; } return freed ? t : 0; @@ -1533,7 +1545,8 @@ TYPE_FIELD gc_cycle_check_weak_svalues(struct svalue *s, size_t num) dmalloc_touch_svalue(s); GC_RECURSE_SWITCH((s->u), (s->type), ZAP_SVALUE, FREE_WEAK, GC_DO_CYCLE_CHECK_WEAK, {}, - DO_CYCLE_CHECK_FUNC_SVALUE, DO_CYCLE_CHECK_STRING); + DO_CYCLE_CHECK_FUNC_SVALUE, GC_DO_CYCLE_CHECK_WEAK, + DO_CYCLE_CHECK_STRING); t |= 1 << s->type; } return freed ? t : 0; @@ -1545,7 +1558,8 @@ int real_gc_cycle_check_short_svalue(union anything *u, TYPE_T type) debug_malloc_touch(u); GC_RECURSE_SWITCH((*u), type, ZAP_SHORT_SVALUE, DONT_FREE_WEAK, GC_DO_CYCLE_CHECK, {if (!u->refs) return 0;}, - DO_FUNC_SHORT_SVALUE, DO_CYCLE_CHECK_STRING); + DO_FUNC_SHORT_SVALUE, GC_DO_CYCLE_CHECK, + DO_CYCLE_CHECK_STRING); return freed; } @@ -1555,7 +1569,8 @@ int gc_cycle_check_weak_short_svalue(union anything *u, TYPE_T type) debug_malloc_touch(u); GC_RECURSE_SWITCH((*u), type, ZAP_SHORT_SVALUE, FREE_WEAK, GC_DO_CYCLE_CHECK_WEAK, {if (!u->refs) return 0;}, - DO_FUNC_SHORT_SVALUE, DO_CYCLE_CHECK_STRING); + DO_FUNC_SHORT_SVALUE, GC_DO_CYCLE_CHECK_WEAK, + DO_CYCLE_CHECK_STRING); return freed; } diff --git a/src/testsuite.in b/src/testsuite.in index f658b77d2e..125b2f07c0 100644 --- a/src/testsuite.in +++ b/src/testsuite.in @@ -1,4 +1,4 @@ -test_true([["$Id: testsuite.in,v 1.311 2000/07/10 17:28:28 grubba Exp $"]]); +test_true([["$Id: testsuite.in,v 1.312 2000/07/11 03:45:10 mast Exp $"]]); cond([[all_constants()->_verify_internals]], [[ @@ -1886,6 +1886,52 @@ ifefun(gc, gc(); }]]); + test_any([[{ + array a = ({0}), b = ({a, set_weak_flag (({a}), 1)}); + array x = set_weak_flag (({a}), 1); + a[0] = b; + a = b = 0; + gc(); + return !x[0]; + }]], 1); + test_any([[{ + mapping a = ([]), b = ([a:set_weak_flag (([a:a]), 1)]); + mapping x = set_weak_flag (([a:2]), 1); + a[b] = b; + a = b = 0; + gc(); + return !sizeof (x); + }]], 1); + test_any([[{ + multiset a = (<>), b = (<a, set_weak_flag ((<a>), 1)>); + multiset x = set_weak_flag ((<a>), 1); + a[b] = 1; + a = b = 0; + gc(); + return !sizeof (x); + }]], 1); + test_any([[{ + class Foo { + Foo f = this_object(); + multiset(Foo) g = set_weak_flag((<this_object()>), 1); + }; + multiset(Foo) x = set_weak_flag ((<Foo()>), 1); + gc(); + return !sizeof (x); + }]], 1); + test_any([[{ + class Foo { + Foo f = this_object(); + multiset(Foo) g = set_weak_flag((<this_object()>), 1); + void destroy() {add_constant("beltbent_oblivion", 1);} + }; + multiset(Foo) x = set_weak_flag ((<Foo()>), 1); + gc(); + int res = all_constants()->beltbent_oblivion; + add_constant("beltbent_oblivion"); + return res; + }]], 1); + test_do([[{ int got_error = 0; array(string) destruct_order; -- GitLab