diff --git a/src/gc.c b/src/gc.c index 30983d1b4de9dd3bbd8d589c30f8fd395de9bde3..e3fd8dd3bcdda940b4cfd2095aa600191e2b8cb1 100644 --- a/src/gc.c +++ b/src/gc.c @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: gc.c,v 1.301 2007/12/28 13:38:15 nilsson Exp $ +|| $Id: gc.c,v 1.302 2008/03/29 16:20:15 mast Exp $ */ #include "global.h" @@ -3376,7 +3376,7 @@ size_t do_gc(void *ignored, int explicit_call) gc_check_all_programs(); gc_check_all_objects(); #if defined (PIKE_DEBUG) || defined (DO_PIKE_CLEANUP) - debug_gc_check_all_types(); + gc_check_all_types(); #endif } END_ACCEPT_UNFINISHED_TYPE_FIELDS; diff --git a/src/global.h b/src/global.h index b3a430ef99084d6856bd353befd209334c02136b..8c08d3bfb943f25103a45258614e57e64284b402 100644 --- a/src/global.h +++ b/src/global.h @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: global.h,v 1.110 2007/06/18 09:21:24 mast Exp $ +|| $Id: global.h,v 1.111 2008/03/29 16:20:16 mast Exp $ */ #ifndef GLOBAL_H @@ -435,6 +435,12 @@ typedef struct p_wchar_p #define NDEBUG #endif +#if defined (PIKE_DEBUG) || defined (DO_PIKE_CLEANUP) +#define DO_IF_DEBUG_OR_CLEANUP(X) X +#else +#define DO_IF_DEBUG_OR_CLEANUP(X) +#endif + #ifdef INTERNAL_PROFILING #define DO_IF_INTERNAL_PROFILING(X) X #else diff --git a/src/module.c b/src/module.c index 82a330fc5c2f75cc9a1dac77f68bd237e288e7d0..616114646c4c94b904d042fbaf0f19511e955fd1 100644 --- a/src/module.c +++ b/src/module.c @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: module.c,v 1.49 2008/02/15 17:37:04 grubba Exp $ +|| $Id: module.c,v 1.50 2008/03/29 16:20:16 mast Exp $ */ #include "global.h" @@ -191,7 +191,8 @@ static void exit_builtin_modules(void) type_type_string, void_type_string, zero_type_string, any_type_string, \ weak_type_string, -#define REPORT_LINKED_LIST_LEAKS(TYPE, START, STATICS, T_TYPE, NAME) do { \ +#define REPORT_LINKED_LIST_LEAKS(TYPE, START, STATICS, T_TYPE, NAME, \ + PRINT_EXTRA) do { \ struct TYPE *x; \ for (x = START; x; x = x->next) { \ struct marker *m = find_marker (x); \ @@ -213,37 +214,64 @@ static void exit_builtin_modules(void) fputs ("Leak(s) found at exit:\n", stderr); \ leak_found = 1; \ } \ - fprintf (stderr, NAME " got %d unaccounted references: ", \ - x->refs - (m->refs + is_static)); \ - print_short_svalue (stderr, (union anything *) &x, T_TYPE); \ + fprintf (stderr, NAME " at %p got %d unaccounted references: ", \ + x, x->refs - (m->refs + is_static)); \ + safe_print_short_svalue (stderr, (union anything *) &x, T_TYPE); \ fputc ('\n', stderr); \ - DO_IF_DEBUG(if (T_TYPE == T_PROGRAM) { \ - struct program *p = (struct program *)x; \ - if (p->parent) { \ - fprintf(stderr, " Parent is: %p\n", \ - p->parent); \ - dump_program_tables(p->parent, 6); \ - } \ - fprintf(stderr, " Symbol tables:\n"); \ - dump_program_tables(p, 4); \ - }); \ - DO_IF_DMALLOC (debug_malloc_dump_references (x, 2, 1, 0)); \ + {PRINT_EXTRA;} \ + DO_IF_DMALLOC ( \ + debug_malloc_dump_references (x, 2, 1, 0); \ + fputc ('\n', stderr); \ + ); \ } \ } \ } \ } while (0) - REPORT_LINKED_LIST_LEAKS (array, first_array, STATIC_ARRAYS, T_ARRAY, "Array"); - REPORT_LINKED_LIST_LEAKS (multiset, first_multiset, NOTHING, T_MULTISET, "Multiset"); - REPORT_LINKED_LIST_LEAKS (mapping, first_mapping, NOTHING, T_MAPPING, "Mapping"); - REPORT_LINKED_LIST_LEAKS (program, first_program, NOTHING, T_PROGRAM, "Program"); - REPORT_LINKED_LIST_LEAKS (object, first_object, NOTHING, T_OBJECT, "Object"); - report_all_type_leaks(); + REPORT_LINKED_LIST_LEAKS (array, first_array, STATIC_ARRAYS, T_ARRAY, "Array", {}); + REPORT_LINKED_LIST_LEAKS (multiset, first_multiset, NOTHING, T_MULTISET, "Multiset", {}); + REPORT_LINKED_LIST_LEAKS (mapping, first_mapping, NOTHING, T_MAPPING, "Mapping", {}); + REPORT_LINKED_LIST_LEAKS ( + program, first_program, NOTHING, T_PROGRAM, "Program", + { + /* This kind of info is rarely useful - the output from + * print_short_svalue is usually enough to identify the program, and + * the dmalloc ref dump shows where it has been used. + DO_IF_DEBUG( + struct program *p = (struct program *)x; + if (p->parent) { + fprintf(stderr, " Parent is: %p\n", + p->parent); + dump_program_tables(p->parent, 6); + } + fprintf(stderr, " Symbol tables:\n"); + dump_program_tables(p, 4); + ); + */ + } + ); + REPORT_LINKED_LIST_LEAKS ( + object, first_object, NOTHING, T_OBJECT, "Object", { + DO_IF_DEBUG ( + if (!x->prog) { + struct program *p = id_to_program (x->program_id); + if (p) { + fputs ("Destructed object - program was: ", stderr); + safe_print_short_svalue (stderr, + (union anything *) &p, T_PROGRAM); + fputc ('\n', stderr); + } + else + fprintf (stderr, "Destructed object - " + "program gone too, its id was %d\n", x->program_id); + } + ); + }); { size_t index; for (index = 0; index < pike_type_hash_size; index++) { - REPORT_LINKED_LIST_LEAKS(pike_type, pike_type_hash[index], STATIC_TYPES, PIKE_T_TYPE, "Type"); + REPORT_LINKED_LIST_LEAKS(pike_type, pike_type_hash[index], STATIC_TYPES, PIKE_T_TYPE, "Type", {}); } } diff --git a/src/pike_types.c b/src/pike_types.c index 39303c501b77bdcaf3672cfeb3407c3618f0beaf..16be2c671f03eca7eebc7ee579e0bcf7ef328219 100644 --- a/src/pike_types.c +++ b/src/pike_types.c @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: pike_types.c,v 1.317 2008/03/27 12:31:11 grubba Exp $ +|| $Id: pike_types.c,v 1.318 2008/03/29 16:20:16 mast Exp $ */ #include "global.h" @@ -2417,34 +2417,6 @@ void debug_gc_check_all_types (void) } } -/* Leak reporting similar to the exit_with_cleanup code in - * exit_builtin_modules. */ - -void report_all_type_leaks (void) -{ - unsigned INT32 index; - if (!gc_keep_markers) - Pike_fatal ("Should only be called in final cleanup.\n"); - for (index = 0; index < pike_type_hash_size; index++) { - struct pike_type *t; - for (t = pike_type_hash[index]; t; t = t->next) { - struct marker *m = find_marker (t); - /* We aren't hooked in to the gc mark pass so we don't have - * markers for types with only external references. */ - INT32 m_refs = m ? m->refs : 0; - if (t->refs != m_refs) { - fprintf (stderr, "Type at %p got %d unaccounted refs: ", - t, t->refs - m_refs); - simple_describe_type (t); - fputc ('\n', stderr); -#ifdef DEBUG_MALLOC - debug_malloc_dump_references (t, 2, 1, 0); -#endif - } - } - } -} - void free_all_leaked_types (void) { unsigned INT32 index; @@ -2454,21 +2426,24 @@ void free_all_leaked_types (void) struct pike_type *t; for (t = pike_type_hash[index]; t; t = t->next) { struct marker *m = find_marker (t); - INT32 m_refs = m ? m->refs : 0; - INT32 refs = t->refs; - if (refs > m_refs) { + if (m) { + INT32 refs = t->refs; + if (refs > m->refs) { #ifdef PIKE_DEBUG - if (m) m->flags |= GC_CLEANUP_FREED; + m->flags |= GC_CLEANUP_FREED; #endif /* PIKE_DEBUG */ - do { - free_type (t); - refs--; - } while (refs > m_refs); - /* t is invalid here, as is its next pointer. - * Start over from the top of this hash entry. - */ - index--; - break; + do { + free_type (t); + refs--; + } while (refs > m->refs); + if (!refs) { + /* t is invalid here, as is its next pointer. + * Start over from the top of this hash entry. + */ + index--; + break; + } + } } } } @@ -7713,8 +7688,12 @@ void cleanup_pike_type_table(void) #endif /* DO_PIKE_CLEANUP */ } -#if 0 -#ifdef PIKE_DEBUG +#if defined (PIKE_DEBUG) || defined (DO_PIKE_CLEANUP) + +/* This is only enough gc stuff to detect leaking pike_type structs + * and to locate references to them. More is needed if types are + * extended to contain pointers to other memory objects or if they + * might contain cycles. */ void gc_mark_type_as_referenced(struct pike_type *t) { @@ -7748,78 +7727,17 @@ void gc_mark_type_as_referenced(struct pike_type *t) } } -unsigned gc_touch_all_types(void) +static void gc_check_type (struct pike_type *t) { - size_t e; - unsigned n = 0; - if (!pike_type_hash) return 0; - for(e=0;e<pike_type_hash_size;e++) - { - struct pike_type *t; - for(t = pike_type_hash[e]; t; t=t->next) debug_gc_touch(t), n++; - } - return n; -} + debug_malloc_touch (t); -void gc_mark_all_types(void) -{ - size_t e; - if(!pike_type_hash) return; - for(e=0;e<pike_type_hash_size;e++) - { - struct pike_type *t; - for(t=pike_type_hash[e]; t; t=t->next) { - if (gc_is_referenced(t)) { - gc_mark_type_as_referenced(t); - } - } - } -} - -size_t gc_free_all_unreferenced_types(void) -{ - size_t unreferenced = 0; - size_t e; - for (e = 0; e < pike_type_hash_size; e++) { - struct pike_type *t; - loop: - for (t = pike_type_hash[e]; t; t = t->next) { - struct marker *m = find_marker(t); - if (!m) continue; - if ((m->flags & GC_GOT_EXTRA_REF) == GC_GOT_EXTRA_REF) { - if (gc_do_free(t)) { - free_type(t); - unreferenced++; - /* The hash table may have been modified! */ - goto loop; - } - } - } - } - for (e = 0; e < pike_type_hash_size; e++) { - struct pike_type *t; - for (t = pike_type_hash[e]; t; t = t->next) { - struct marker *m = find_marker(t); - if (!m) continue; - if ((m->flags & GC_GOT_EXTRA_REF) == GC_GOT_EXTRA_REF) { - fprintf(stderr, "There's still an extra ref to "); - simple_describe_type(t); - fprintf(stderr, "\n"); - } - } - } - return unreferenced; -} - -void real_gc_cycle_check_type(struct pike_type *t, int weak) -{ - GC_CYCLE_ENTER(t, PIKE_T_TYPE, weak) { + GC_ENTER (t, PIKE_T_TYPE) { switch(t->type) { case PIKE_T_SCOPE: case T_ASSIGN: case PIKE_T_NAME: case PIKE_T_ATTRIBUTE: - if (t->cdr) gc_cycle_check_type(t->cdr, 0); + if (t->cdr) debug_gc_check (t->cdr, " as cdr in a type"); break; case PIKE_T_FUNCTION: case T_MANY: @@ -7828,34 +7746,28 @@ void real_gc_cycle_check_type(struct pike_type *t, int weak) case PIKE_T_MAPPING: case T_OR: case T_AND: - if (t->cdr) gc_cycle_check_type(t->cdr, 0); - /* FALL_THOUGH */ + if (t->cdr) debug_gc_check (t->cdr, " as cdr in a type"); + /* FALL_THOUGH */ case PIKE_T_ARRAY: case PIKE_T_MULTISET: case T_NOT: case PIKE_T_TYPE: case PIKE_T_PROGRAM: - if (t->car) gc_cycle_check_type(t->car, 0); + if (t->car) debug_gc_check (t->car, " as car in a type"); break; } - } GC_CYCLE_LEAVE; + } GC_LEAVE; } -void gc_cycle_check_all_types(void) +void gc_check_all_types (void) { -#if 0 size_t e; - if(!pike_type_hash) return; + if (!pike_type_hash) return; for(e=0;e<pike_type_hash_size;e++) { struct pike_type *t; - for(t=pike_type_hash[e]; t; t=t->next) { - real_gc_cycle_check_type(t, 0); - gc_cycle_run_queue(); - } + for(t = pike_type_hash[e]; t; t=t->next) gc_check_type (t); } -#endif } -#endif /* PIKE_DEBUG */ -#endif /* 0 */ +#endif /* PIKE_DEBUG || DO_PIKE_CLEANUP */ diff --git a/src/pike_types.h b/src/pike_types.h index 4e058122c0e4997279301ab772d63cfb7527b2ac..0051a356901ce47074e5cf48f62f704d87c917d5 100644 --- a/src/pike_types.h +++ b/src/pike_types.h @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: pike_types.h,v 1.110 2007/11/11 13:49:01 nilsson Exp $ +|| $Id: pike_types.h,v 1.111 2008/03/29 16:20:17 mast Exp $ */ #ifndef PIKE_TYPES_H @@ -94,15 +94,20 @@ extern struct pike_type *type_stack[PIKE_TYPE_STACK_SIZE]; extern struct pike_type **pike_type_mark_stack[PIKE_TYPE_STACK_SIZE/4]; #ifdef DEBUG_MALLOC -#define free_type(T) debug_free_type((struct pike_type *)debug_malloc_pass_named(T, "free_type")) #define check_type_string(T) debug_check_type_string((struct pike_type *)debug_malloc_pass_named(T, "check_type_string")) -#else /* !DEBUG_MALLOC */ -#define free_type debug_free_type -#ifdef PIKE_DEBUG +#elif defined (PIKE_DEBUG) #define check_type_string debug_check_type_string #endif /* PIKE_DEBUG */ -#endif /* DEBUG_MALLOC */ +#define free_type(T) do { \ + struct pike_type *t_ = (T); \ + debug_malloc_touch_named (t_, "free_type"); \ + DO_IF_DEBUG ( \ + DO_IF_PIKE_CLEANUP ( \ + if (gc_external_refs_zapped) \ + gc_check_zapped (t_, PIKE_T_TYPE, __FILE__, __LINE__))); \ + debug_free_type (t_); \ + } while (0) extern int max_correct_args; PMOD_EXPORT extern struct pike_type *string0_type_string; @@ -217,7 +222,6 @@ void simple_describe_type(struct pike_type *s); void my_describe_type(struct pike_type *type); struct pike_string *describe_type(struct pike_type *type); void debug_gc_check_all_types (void); -void report_all_type_leaks (void); void free_all_leaked_types (void); TYPE_T compile_type_to_runtime_type(struct pike_type *s); struct pike_type *or_pike_types(struct pike_type *a, @@ -266,6 +270,8 @@ struct pike_type *object_type_to_program_type(struct pike_type *obj_t); PMOD_EXPORT char *get_name_of_type(TYPE_T t); void cleanup_pike_types(void); void cleanup_pike_type_table(void); +void gc_mark_type_as_referenced(struct pike_type *t); +void gc_check_all_types (void); int type_may_overload(struct pike_type *type, int lfun); void yyexplain_nonmatching_types(struct pike_type *type_a, struct pike_type *type_b, @@ -273,7 +279,6 @@ void yyexplain_nonmatching_types(struct pike_type *type_a, struct pike_type *debug_make_pike_type(const char *t); struct pike_string *type_to_string(struct pike_type *t); int pike_type_allow_premature_toss(struct pike_type *type); -void real_gc_cycle_check_type(struct pike_type *t, int weak); void register_attribute_handler(struct pike_string *attr, struct svalue *handler); /* Prototypes end here */ @@ -375,13 +380,6 @@ void register_attribute_handler(struct pike_string *attr, #define push_finished_type_backwards debug_push_finished_type_backwards #endif -#if 0 -#define gc_cycle_check_type(T, WEAK) \ - gc_cycle_enqueue((gc_cycle_check_cb *)real_gc_cycle_check_type, (T), (WEAK)) -#else -#define gc_cycle_check_type(T, WEAK) -#endif /* 0 */ - #ifndef PIKE_DEBUG #define check_type_string(X) #endif diff --git a/src/program.c b/src/program.c index fdf862b108ab6e8eeeefbb6b80abfee0e3f69ba0..2d60e078a03f03ce98374dcad8df8be5d72003f1 100644 --- a/src/program.c +++ b/src/program.c @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: program.c,v 1.655 2008/03/26 15:07:11 grubba Exp $ +|| $Id: program.c,v 1.656 2008/03/29 16:20:18 mast Exp $ */ #include "global.h" @@ -8008,10 +8008,10 @@ void gc_mark_program_as_referenced(struct program *p) if(p->parent) gc_mark_program_as_referenced(p->parent); - for(e=0;e<p->num_constants;e++) + for(e = p->num_constants - 1; e >= 0; e--) gc_mark_svalues(& p->constants[e].sval, 1); - for(e=0;e<p->num_inherits;e++) + for(e = p->num_inherits - 1; e >= 0; e--) { if(p->inherits[e].parent) gc_mark_object_as_referenced(p->inherits[e].parent); @@ -8020,6 +8020,11 @@ void gc_mark_program_as_referenced(struct program *p) gc_mark_program_as_referenced(p->inherits[e].prog); } +#if defined (PIKE_DEBUG) || defined (DO_PIKE_CLEANUP) + for (e = p->num_identifiers - 1; e >= 0; e--) + gc_mark_type_as_referenced (p->identifiers[e].type); +#endif + } GC_LEAVE; } @@ -8030,10 +8035,10 @@ void real_gc_cycle_check_program(struct program *p, int weak) if (!(p->flags & PROGRAM_AVOID_CHECK)) { - for(e=0;e<p->num_constants;e++) + for(e = p->num_constants - 1; e >= 0; e--) gc_cycle_check_svalues(& p->constants[e].sval, 1); - for(e=0;e<p->num_inherits;e++) + for(e = p->num_inherits - 1; e >= 0; e--) { if(p->inherits[e].parent) gc_cycle_check_object(p->inherits[e].parent, 0); @@ -8042,11 +8047,6 @@ void real_gc_cycle_check_program(struct program *p, int weak) gc_cycle_check_program(p->inherits[e].prog, 0); } -#ifdef DEBUG_MALLOC - for (e = 0; e < p->num_identifiers; e++) - gc_cycle_check_type(p->identifiers[e].type, 0); -#endif - /* Strong ref follows. It must be last. */ if(p->parent) gc_cycle_check_program(p->parent, 0); @@ -8072,11 +8072,11 @@ static void gc_check_program(struct program *p) if(p->parent) debug_gc_check (p->parent, " as parent program of a program"); - for(e=0;e<p->num_constants;e++) { + for(e = p->num_constants - 1; e >= 0; e--) { debug_gc_check_svalues (&p->constants[e].sval, 1, " as program constant"); } - for(e=0;e<p->num_inherits;e++) + for(e = p->num_inherits - 1; e >= 0; e--) { if(p->inherits[e].parent) { @@ -8096,19 +8096,18 @@ static void gc_check_program(struct program *p) #if defined (PIKE_DEBUG) || defined (DO_PIKE_CLEANUP) if (gc_keep_markers || Pike_in_gc == GC_PASS_LOCATE) { - int e; - for(e=0;e<(int)p->num_strings;e++) + for(e = p->num_strings - 1; e >= 0; e--) debug_gc_check (p->strings[e], " in the string storage of a program"); - - for(e=0;e<(int)p->num_identifiers;e++) - { + for(e = p->num_identifiers - 1; e >= 0; e--) debug_gc_check (p->identifiers[e].name, " as identifier name in a program"); - debug_gc_check (p->identifiers[e].type, - " as identifier type in a program"); - } } + + for(e = p->num_identifiers - 1; e >= 0; e--) + debug_gc_check (p->identifiers[e].type, + " as identifier type in a program"); #endif + } GC_LEAVE; } diff --git a/src/svalue.c b/src/svalue.c index b02b87df005bbb98d4334c1535cf714fa608ed0e..1f5d7a78b4276522c88753259a5c5513c17b1335 100644 --- a/src/svalue.c +++ b/src/svalue.c @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: svalue.c,v 1.237 2008/03/29 02:43:42 mast Exp $ +|| $Id: svalue.c,v 1.238 2008/03/29 16:20:19 mast Exp $ */ #include "global.h" @@ -2079,10 +2079,10 @@ PMOD_EXPORT void real_gc_mark_external_svalues(const struct svalue *s, ptrdiff_t #define DO_CHECK_FUNC_SVALUE(U, T, ZAP, GC_DO) \ if (s->subtype == FUNCTION_BUILTIN) { \ - DO_IF_DEBUG( \ - if (d_flag && !gc_check(s->u.efun)) { \ - gc_check(s->u.efun->name); \ - gc_check(s->u.efun->type); \ + DO_IF_DEBUG_OR_CLEANUP ( \ + if (!gc_check (s->u.efun)) { \ + DO_IF_DEBUG (if (d_flag) gc_check (s->u.efun->name)); \ + gc_check (s->u.efun->type); \ } \ ) \ break; \ @@ -2236,12 +2236,10 @@ void gc_check_weak_short_svalue(const union anything *u, TYPE_T type) #define DO_MARK_FUNC_SVALUE(U, T, ZAP, GC_DO) \ if (s->subtype == FUNCTION_BUILTIN) { \ - DO_IF_DEBUG( \ - if (d_flag) { \ - gc_mark(s->u.efun->name); \ - gc_mark(s->u.efun->type); \ - } \ - ) \ + DO_IF_DEBUG (if (d_flag) gc_mark (s->u.efun->name)); \ + DO_IF_DEBUG_OR_CLEANUP ( \ + gc_mark_enqueue ((queue_call) gc_mark_type_as_referenced, \ + s->u.efun->type)); \ break; \ } \ /* Fall through to T_OBJECT. */