From 83aa03ce40b1147b5e64f20edb1b97ceabfe9f0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20H=C3=BCbinette=20=28Hubbe=29?= <hubbe@hubbe.net> Date: Tue, 3 Mar 1998 14:30:29 -0800 Subject: [PATCH] DEBUG_MALLOC now usable, only minor leaks in compiler left as far as I know Rev: src/array.c:1.24 Rev: src/dmalloc.h:1.2 Rev: src/error.h:1.8 Rev: src/language.yacc:1.52 Rev: src/las.c:1.41 Rev: src/las.h:1.10 Rev: src/lex.c:1.37 Rev: src/main.c:1.29 Rev: src/modules/Gmp/mpz_glue.c:1.25 Rev: src/modules/Image/colortable.c:1.30 Rev: src/modules/Image/encodings/pnm.c:1.6 Rev: src/object.c:1.31 Rev: src/object.h:1.13 Rev: src/pike_memory.c:1.7 Rev: src/pike_types.c:1.29 Rev: src/stralloc.c:1.20 Rev: src/svalue.h:1.11 Rev: src/testsuite.in:1.64 --- src/array.c | 5 +-- src/dmalloc.h | 8 ++++ src/error.h | 4 +- src/language.yacc | 5 +-- src/las.c | 35 ++++++++++++++-- src/las.h | 11 +++++- src/lex.c | 6 +-- src/main.c | 66 ++++++++++++++++++++++++++++++- src/modules/Gmp/mpz_glue.c | 11 +++++- src/modules/Image/colortable.c | 38 ++++++++++++++---- src/modules/Image/encodings/pnm.c | 10 +++-- src/object.c | 23 ++++++++++- src/object.h | 6 ++- src/pike_memory.c | 50 +++++++++++++++++++---- src/pike_types.c | 4 +- src/stralloc.c | 59 ++++++++++++++++++++++++++- src/svalue.h | 2 +- src/testsuite.in | 22 +++++------ 18 files changed, 307 insertions(+), 58 deletions(-) diff --git a/src/array.c b/src/array.c index 5475965fb3..993fb3b4d1 100644 --- a/src/array.c +++ b/src/array.c @@ -1139,10 +1139,7 @@ node *make_node_from_array(struct array *a) if(e == a->size) { return mkefuncallnode("allocate", - mknode(F_ARG_LIST, - mkintnode(a->size), - mkstrnode(make_shared_string("mixed")) - )); + mkintnode(a->size)); } } if(check_that_array_is_constant(a)) diff --git a/src/dmalloc.h b/src/dmalloc.h index 91ccb74dac..55d8147def 100644 --- a/src/dmalloc.h +++ b/src/dmalloc.h @@ -19,6 +19,8 @@ extern void *debug_realloc(void *, size_t, const char *, int); extern void debug_free(void *, const char *, int); extern char *debug_strdup(const char *, const char *, int); void *debug_malloc_update_location(void *,const char *, int); +void *debug_malloc_track(void *m, size_t s, const char *fn, int line); +void debug_malloc_untrack(void *p, const char *fn, int line); #define malloc(x) debug_malloc((x), __FILE__, __LINE__) #define calloc(x, y) debug_calloc((x), (y), __FILE__, __LINE__) #define realloc(x, y) debug_realloc((x), (y), __FILE__, __LINE__) @@ -28,7 +30,13 @@ void *debug_malloc_update_location(void *,const char *, int); #define debug_malloc_touch(X) debug_malloc_update_location((X),__FILE__,__LINE__) #define debug_malloc_pass(X) debug_malloc_update_location((X),__FILE__,__LINE__) #define xalloc(X) ((char *)debug_malloc_touch(debug_xalloc(X))) +#define dmalloc_track(X) debug_malloc_track((X), 0 ,__FILE__,__LINE__) +#define dmalloc_untrack(X) debug_malloc_untrack((X),__FILE__,__LINE__) +void dmalloc_dump_track(void *p); #else +#define dmalloc_dump_track(X) +#define dmalloc_track(X) +#define dmalloc_untrack(X) #define xalloc debug_xalloc #define dbm_main main #define DO_IF_DMALLOC(X) diff --git a/src/error.h b/src/error.h index e28b84cbfa..0f722b6c32 100644 --- a/src/error.h +++ b/src/error.h @@ -50,6 +50,7 @@ extern struct svalue throw_value; #define SET_ONERROR(X,Y,Z) \ do{ \ + if(!recoveries) break; \ X.func=(error_call)(Y); \ X.arg=(void *)(Z); \ X.previous=recoveries->onerror; \ @@ -58,11 +59,12 @@ extern struct svalue throw_value; #ifdef DEBUG #define UNSET_ONERROR(X) do {\ + if(!recoveries) break; \ if(recoveries->onerror != &(X)) fatal("UNSET_ONERROR out of sync.\n"); \ recoveries->onerror=(X).previous; \ } while(0) #else -#define UNSET_ONERROR(X) recoveries->onerror=X.previous +#define UNSET_ONERROR(X) recoveries && (recoveries->onerror=X.previous) #endif /* Prototypes begin here */ diff --git a/src/language.yacc b/src/language.yacc index 62d9eda0c8..282e350d27 100644 --- a/src/language.yacc +++ b/src/language.yacc @@ -157,7 +157,7 @@ /* This is the grammar definition of Pike. */ #include "global.h" -RCSID("$Id: language.yacc,v 1.51 1998/03/03 11:24:31 hubbe Exp $"); +RCSID("$Id: language.yacc,v 1.52 1998/03/03 22:30:20 hubbe Exp $"); #ifdef HAVE_MEMORY_H #include <memory.h> #endif @@ -371,8 +371,7 @@ optional_rename_inherit: ':' F_IDENTIFIER { $$=$2; } program_ref: string_constant { - reference_shared_string($1); - push_string($1); + ref_push_string($1); push_string($1); reference_shared_string(current_file); push_string(current_file); diff --git a/src/las.c b/src/las.c index 0e121ab9c2..8eb0a4355b 100644 --- a/src/las.c +++ b/src/las.c @@ -4,7 +4,7 @@ ||| See the files COPYING and DISCLAIMER for more information. \*/ #include "global.h" -RCSID("$Id: las.c,v 1.40 1998/03/03 11:24:32 hubbe Exp $"); +RCSID("$Id: las.c,v 1.41 1998/03/03 22:30:21 hubbe Exp $"); #include "language.h" #include "interpret.h" @@ -44,6 +44,7 @@ extern char *get_type_name(int); int car_is_node(node *n) { + check_node(n); switch(n->token) { case F_IDENTIFIER: @@ -58,6 +59,7 @@ int car_is_node(node *n) int cdr_is_node(node *n) { + check_node(n); switch(n->token) { case F_IDENTIFIER: @@ -75,6 +77,7 @@ INT32 count_args(node *n) { int a,b; if(!n) return 0; + check_node(n); switch(n->token) { case F_VAL_LVAL: @@ -174,8 +177,10 @@ void free_all_nodes(void) else #endif { + check_node(tmp); /* Free the node and be happy */ /* Make sure we don't free any nodes twice */ + dmalloc_dump_track(tmp); if(car_is_node(tmp)) CAR(tmp)=0; if(cdr_is_node(tmp)) CDR(tmp)=0; debug_malloc_touch(tmp->type); @@ -203,9 +208,10 @@ void free_all_nodes(void) } } -void free_node(node *n) +void debug_free_node(node *n) { if(!n) return; + check_node(n); switch(n->token) { case USHRT_MAX: @@ -222,6 +228,7 @@ void free_node(node *n) } n->token=USHRT_MAX; if(n->type) free_string(n->type); + dmalloc_untrack(n); CAR(n)=free_nodes; free_nodes=n; } @@ -251,10 +258,11 @@ static node *mkemptynode(void) res->node_info=0; res->tree_info=0; res->parent=0; + dmalloc_track(res); return res; } -node *mknode(short token,node *a,node *b) +node *debug_mknode(short token,node *a,node *b) { node *res; res = mkemptynode(); @@ -323,6 +331,7 @@ node *mknode(short token,node *a,node *b) verify_shared_strings_tables(); #endif + check_node(res); return res; } @@ -337,6 +346,7 @@ node *mkstrnode(struct pike_string *str) res->u.sval.subtype = 0; #endif copy_shared_string(res->u.sval.u.string, str); + check_node(res); return res; } @@ -352,6 +362,7 @@ node *mkintnode(int nr) res->u.sval.type = T_INT; res->u.sval.subtype = NUMBER_NUMBER; res->u.sval.u.integer = nr; + check_node(res); return res; } @@ -365,6 +376,7 @@ node *mkfloatnode(FLOAT_TYPE foo) res->u.sval.subtype = 0; #endif res->u.sval.u.float_number = foo; + check_node(res); return res; } @@ -385,6 +397,7 @@ node *mkefuncallnode(char *function, node *args) } n=mkapplynode(mksvaluenode(sp-1), args); pop_stack(); + check_node(n); return n; } @@ -407,6 +420,7 @@ node *mklocalnode(int var) CDR(res)=0; #endif res->u.number = var; + check_node(res); return res; } @@ -430,6 +444,7 @@ node *mkidentifiernode(int i) CDR(res)=0; #endif res->u.number = i; + check_node(res); return res; } @@ -451,16 +466,19 @@ node *mkcastnode(struct pike_string *type,node *n) CDR(res)=0; #endif n->parent=res; + check_node(res); return res; } void resolv_constant(node *n) { struct identifier *i; + check_node(n); if(!n) { push_int(0); }else{ + check_node(n); switch(n->token) { case F_CONSTANT: @@ -498,6 +516,7 @@ node *debug_index_node(node *n, struct pike_string * id) { node *ret; JMP_BUF tmp; + check_node(n); if(SETJMP(tmp)) { ONERROR tmp; @@ -1178,6 +1197,8 @@ void fix_type_field(node *n) { struct pike_string *type_a,*type_b; + check_node(n); + if(n->type) return; /* assume it is correct */ switch(n->token) @@ -1211,6 +1232,7 @@ void fix_type_field(node *n) if(!check_indexing(type_a, type_b, n)) my_yyerror("Indexing on illegal type."); n->type=index_type(type_a,n); + check_node(n); break; case F_ARROW: @@ -1219,6 +1241,7 @@ void fix_type_field(node *n) if(!check_indexing(type_a, type_b, n)) my_yyerror("Indexing on illegal type."); n->type=index_type(type_a,n); + check_node(n); break; case F_APPLY: @@ -1257,6 +1280,7 @@ void fix_type_field(node *n) my_yyerror("Bad argument %d to %s.", max_correct_args+1, name); } + check_node(n); copy_shared_string(n->type, mixed_type_string); } free_string(s); @@ -1356,11 +1380,13 @@ void fix_type_field(node *n) default: copy_shared_string(n->type,mixed_type_string); } + check_node(n); } static void zapp_try_optimize(node *n) { if(!n) return; + check_node(n); n->node_info &=~ OPT_TRY_OPTIMIZE; n->tree_info &=~ OPT_TRY_OPTIMIZE; if(car_is_node(n)) zapp_try_optimize(CAR(n)); @@ -1371,6 +1397,7 @@ static void optimize(node *n) { node *tmp1, *tmp2, *tmp3; INT32 save_line = current_line; + check_node(n); do { if(car_is_node(n) && !(CAR(n)->node_info & OPT_OPTIMIZED)) @@ -1434,6 +1461,8 @@ static void optimize(node *n) } #endif + check_node(n); + switch(n->token) { case F_APPLY: diff --git a/src/las.h b/src/las.h index 82dcbb64a7..bc0f693e5c 100644 --- a/src/las.h +++ b/src/las.h @@ -80,8 +80,8 @@ int cdr_is_node(node *n); INT32 count_args(node *n); struct node_chunk; void free_all_nodes(void); -void free_node(node *n); -node *mknode(short token,node *a,node *b); +void debug_free_node(node *n); +node *debug_mknode(short token,node *a,node *b); node *mkstrnode(struct pike_string *str); node *mkintnode(int nr); node *mkfloatnode(FLOAT_TYPE foo); @@ -142,9 +142,16 @@ INT32 get_opt_info(void); extern dynamic_buffer areas[NUM_AREAS]; #ifdef DEBUG_MALLOC +#define check_node(N) do { if((N)->token == F_CONSTANT) check_svalue(&(N)->u.sval); debug_malloc_touch((N)->type); }while(0) + #define index_node(X,Y) ((node *)debug_malloc_touch(debug_index_node((node *)debug_malloc_touch(X),(struct pike_string *)debug_malloc_touch(Y)))) +#define free_node(N) do { node *n_=(N); check_node(n_); debug_free_node(n_); } while(0) +#define mknode(T,X,Y) ((node *)debug_malloc_touch(debug_mknode(T,(node *)debug_malloc_touch( (X)), (node *)debug_malloc_touch((Y))))) #else +#define check_node(N) #define index_node debug_index_node +#define free_node debug_free_node +#define mknode debug_mknode #endif #endif diff --git a/src/lex.c b/src/lex.c index 855a2b52e4..f6fdf21f61 100644 --- a/src/lex.c +++ b/src/lex.c @@ -4,7 +4,7 @@ ||| See the files COPYING and DISCLAIMER for more information. \*/ #include "global.h" -RCSID("$Id: lex.c,v 1.36 1998/03/03 14:30:35 grubba Exp $"); +RCSID("$Id: lex.c,v 1.37 1998/03/03 22:30:22 hubbe Exp $"); #include "language.h" #include "array.h" #include "lex.h" @@ -1281,9 +1281,7 @@ static int do_lex2(int literal, YYSTYPE *yylval) #endif { int c; -#ifdef MALLOC_DEBUG - check_sfltable(); -#endif + while(1) { switch(c=GETC()) diff --git a/src/main.c b/src/main.c index 3e5a2e925f..00d2609ec9 100644 --- a/src/main.c +++ b/src/main.c @@ -4,7 +4,7 @@ ||| See the files COPYING and DISCLAIMER for more information. \*/ #include "global.h" -RCSID("$Id: main.c,v 1.28 1998/03/03 11:24:33 hubbe Exp $"); +RCSID("$Id: main.c,v 1.29 1998/03/03 22:30:23 hubbe Exp $"); #include "backend.h" #include "module.h" #include "object.h" @@ -300,6 +300,70 @@ void low_exit_main(void) do_gc(); cleanup_callbacks(); + +#if defined(DEBUG) && defined(DEBUG_MALLOC) + if(verbose_debug_exit) + { + INT32 num,size,recount=0; + fprintf(stderr,"Exited normally, counting bytes.\n"); + + count_memory_in_arrays(&num, &size); + if(num) + { + recount++; + fprintf(stderr,"Arrays left: %d (%d bytes) (zapped)\n",num,size); + } + + zap_all_arrays(); + + count_memory_in_mappings(&num, &size); + if(num) + { + recount++; + fprintf(stderr,"Mappings left: %d (%d bytes) (zapped)\n",num,size); + } + + zap_all_mappings(); + + count_memory_in_multisets(&num, &size); + if(num) + fprintf(stderr,"Multisets left: %d (%d bytes)\n",num,size); + + + if(recount) + { + fprintf(stderr,"Garbage collecting..\n"); + do_gc(); + + count_memory_in_arrays(&num, &size); + fprintf(stderr,"Arrays left: %d (%d bytes)\n",num,size); + count_memory_in_mappings(&num, &size); + fprintf(stderr,"Mappings left: %d (%d bytes)\n",num,size); + count_memory_in_multisets(&num, &size); + fprintf(stderr,"Multisets left: %d (%d bytes)\n",num,size); + } + + + count_memory_in_programs(&num, &size); + if(num) + fprintf(stderr,"Programs left: %d (%d bytes)\n",num,size); + + { + struct program *p; + for(p=first_program;p;p=p->next) + { + describe_something(p, T_PROGRAM); + } + } + + + count_memory_in_objects(&num, &size); + if(num) + fprintf(stderr,"Objects left: %d (%d bytes)\n",num,size); + + cleanup_shared_string_table(); + } +#endif zap_all_arrays(); zap_all_mappings(); diff --git a/src/modules/Gmp/mpz_glue.c b/src/modules/Gmp/mpz_glue.c index 56916f4e7f..56934d55f9 100644 --- a/src/modules/Gmp/mpz_glue.c +++ b/src/modules/Gmp/mpz_glue.c @@ -4,7 +4,7 @@ ||| See the files COPYING and DISCLAIMER for more information. \*/ #include "global.h" -RCSID("$Id: mpz_glue.c,v 1.24 1997/10/29 11:20:41 hubbe Exp $"); +RCSID("$Id: mpz_glue.c,v 1.25 1998/03/03 22:30:27 hubbe Exp $"); #include "gmp_machine.h" #if !defined(HAVE_LIBGMP) @@ -298,7 +298,13 @@ static void mpzmod_cast(INT32 args) } /* Converts an svalue, located on the stack, to an mpz object */ -static MP_INT *get_mpz(struct svalue *s, int throw_error) +#if defined(__GNUC__) && defined(DEBUG_MALLOC) +#define get_mpz(X,Y) ({ check_svalue(X); debug_get_mpz((X), (Y)); }) +#else +#define get_mpz(X,Y) debug_get_mpz((X), (Y) +#endif + +static MP_INT *debug_get_mpz(struct svalue *s, int throw_error) { #define ERROR(x) if (throw_error) error(x) struct object *o; @@ -315,6 +321,7 @@ static MP_INT *get_mpz(struct svalue *s, int throw_error) case T_ARRAY: #endif o=clone_object(mpzmod_program,0); + debug_malloc_touch(o); get_new_mpz(OBTOMPZ(o), s); free_svalue(s); s->u.object=o; diff --git a/src/modules/Image/colortable.c b/src/modules/Image/colortable.c index c58ab665a8..86759d59cc 100644 --- a/src/modules/Image/colortable.c +++ b/src/modules/Image/colortable.c @@ -1,11 +1,11 @@ #include <config.h> -/* $Id: colortable.c,v 1.29 1998/03/03 11:24:42 hubbe Exp $ */ +/* $Id: colortable.c,v 1.30 1998/03/03 22:30:28 hubbe Exp $ */ /* **! module Image **! note -**! $Id: colortable.c,v 1.29 1998/03/03 11:24:42 hubbe Exp $ +**! $Id: colortable.c,v 1.30 1998/03/03 22:30:28 hubbe Exp $ **! class colortable **! **! This object keeps colortable information, @@ -21,7 +21,7 @@ #undef COLORTABLE_REDUCE_DEBUG #include "global.h" -RCSID("$Id: colortable.c,v 1.29 1998/03/03 11:24:42 hubbe Exp $"); +RCSID("$Id: colortable.c,v 1.30 1998/03/03 22:30:28 hubbe Exp $"); #include <sys/types.h> #include <sys/stat.h> @@ -45,6 +45,8 @@ RCSID("$Id: colortable.c,v 1.29 1998/03/03 11:24:42 hubbe Exp $"); #include "image.h" #include "colortable.h" +#include "dmalloc.h" + struct program *image_colortable_program; extern struct program *image_program; @@ -708,6 +710,8 @@ rerun_rehash: hash=malloc(sizeof(struct color_hash_entry)*hashsize); if (!hash) { + debug_malloc_touch(hash); + debug_malloc_touch(oldhash); free(oldhash); error("out of memory\n"); } @@ -718,7 +722,13 @@ rerun_rehash: if (oldhash[j].pixels) { mark=insert_in_hash(oldhash[j].color,hash,hashsize); - if (!mark) goto rerun_rehash; + if (!mark) + { + debug_malloc_touch(hash); + debug_malloc_touch(oldhash); + free(hash); + goto rerun_rehash; + } mark->pixels=oldhash[j].pixels; } @@ -729,6 +739,8 @@ rerun_rehash: i--; s++; } + + debug_malloc_touch(hash); if (i) /* restart, but with mask */ { @@ -762,7 +774,12 @@ rerun_mask: if (oldhash[j].pixels) { mark=insert_in_hash_mask(oldhash[j].color,hash,hashsize,rgb_mask); - if (!mark) goto rerun_mask; /* increase mask level inst of hash */ + if (!mark) + { + debug_malloc_touch(oldhash); + debug_malloc_touch(hash); + goto rerun_mask; /* increase mask level inst of hash */ + } mark->pixels+=oldhash[j].pixels-1; } @@ -771,7 +788,11 @@ rerun_mask: while (i) { if (!insert_in_hash_mask(*s,hash,hashsize,rgb_mask)) - goto rerun_mask; /* increase mask */ + { + debug_malloc_touch(hash); + debug_malloc_touch(oldhash); + goto rerun_mask; /* increase mask */ + } i--; s++; @@ -780,6 +801,8 @@ rerun_mask: /* convert to flat */ + debug_malloc_touch(hash); + i=hashsize; j=0; while (i--) @@ -810,6 +833,7 @@ rerun_mask: if (((int)j)!=flat.numentries) abort(); + debug_malloc_touch(hash); free(hash); return flat; @@ -2897,8 +2921,6 @@ static INLINE void _build_cubicle(struct neo_colortable *nct, #include "colortable_lookup.h" -#include "dmalloc.h" - #undef NCTLU_DESTINATION #undef NCTLU_CACHE_HIT_WRITE #undef NCTLU_DITHER_GOT diff --git a/src/modules/Image/encodings/pnm.c b/src/modules/Image/encodings/pnm.c index cd81715847..844f39ca8c 100644 --- a/src/modules/Image/encodings/pnm.c +++ b/src/modules/Image/encodings/pnm.c @@ -1,9 +1,9 @@ -/* $Id: pnm.c,v 1.5 1997/11/29 21:33:36 grubba Exp $ */ +/* $Id: pnm.c,v 1.6 1998/03/03 22:30:29 hubbe Exp $ */ /* **! module Image **! note -**! $Id: pnm.c,v 1.5 1997/11/29 21:33:36 grubba Exp $ +**! $Id: pnm.c,v 1.6 1998/03/03 22:30:29 hubbe Exp $ **! submodule PNM **! **! This submodule keeps the PNM encode/decode capabilities @@ -49,7 +49,7 @@ #include "stralloc.h" #include "global.h" -RCSID("$Id: pnm.c,v 1.5 1997/11/29 21:33:36 grubba Exp $"); +RCSID("$Id: pnm.c,v 1.6 1998/03/03 22:30:29 hubbe Exp $"); #include "pike_macros.h" #include "object.h" #include "constants.h" @@ -305,6 +305,7 @@ struct program *image_pnm_module_program=NULL; void init_image_pnm(void) { + struct pike_string *s; start_new_program(); add_function("encode",img_pnm_encode_binary, @@ -319,7 +320,8 @@ void init_image_pnm(void) image_pnm_module_program=end_program(); push_object(clone_object(image_pnm_module_program,0)); - add_constant(make_shared_string("PNM"),sp-1,0); + add_constant(s=make_shared_string("PNM"),sp-1,0); + free_sstring(s); pop_stack(); } diff --git a/src/object.c b/src/object.c index 6972f02d6d..6c50c7b60a 100644 --- a/src/object.c +++ b/src/object.c @@ -4,7 +4,7 @@ ||| See the files COPYING and DISCLAIMER for more information. \*/ #include "global.h" -RCSID("$Id: object.c,v 1.30 1998/03/03 11:24:36 hubbe Exp $"); +RCSID("$Id: object.c,v 1.31 1998/03/03 22:30:23 hubbe Exp $"); #include "object.h" #include "dynamic_buffer.h" #include "interpret.h" @@ -33,7 +33,7 @@ void setup_fake_object(void) fake_object.refs=0xffffff; } -struct object *low_clone(struct program *p) +struct object *debug_low_clone(struct program *p) { int e; struct object *o; @@ -65,6 +65,8 @@ struct object *low_clone(struct program *p) frame.current_object->refs++; + debug_malloc_touch(o); + /* clear globals and call C initializers */ for(e=p->num_inherits-1; e>=0; e--) { @@ -95,6 +97,8 @@ struct object *low_clone(struct program *p) } } + debug_malloc_touch(o); + if(frame.context.prog->init) frame.context.prog->init(o); @@ -104,6 +108,7 @@ struct object *low_clone(struct program *p) free_object(frame.current_object); fp = frame.parent_frame; + debug_malloc_touch(o); return o; } @@ -115,10 +120,19 @@ static void init_object(struct object *o, int args) pop_stack(); } +void do_free_object(struct object *o) +{ + free_object(o); +} + struct object *debug_clone_object(struct program *p, int args) { + ONERROR tmp; struct object *o=low_clone(p); + SET_ONERROR(tmp, do_free_object, o); + debug_malloc_touch(o); init_object(o,args); + UNSET_ONERROR(tmp); return o; } @@ -156,6 +170,7 @@ struct object *get_master(void) pop_stack(); inside = 0; + debug_malloc_touch(master_object); return master_object; } @@ -164,6 +179,7 @@ struct object *master(void) struct object *o; o=get_master(); if(!o) fatal("Couldn't load master object.\n"); + debug_malloc_touch(o); return o; } @@ -173,6 +189,8 @@ void destruct(struct object *o) struct frame frame; struct program *p; + debug_malloc_touch(o); + #ifdef DEBUG if(d_flag > 20) do_debug(); #endif @@ -293,6 +311,7 @@ void destruct_objects_to_destruct(void) void really_free_object(struct object *o) { + debug_malloc_touch(o); if(o->prog && (o->prog->flags & PROG_DESTRUCT_IMMEDIATE)) { o->refs++; diff --git a/src/object.h b/src/object.h index 4be84f95ff..ef487a27e1 100644 --- a/src/object.h +++ b/src/object.h @@ -38,7 +38,7 @@ extern struct program *master_program; /* Prototypes begin here */ void setup_fake_object(void); -struct object *low_clone(struct program *p); +struct object *debug_low_clone(struct program *p); struct object *debug_clone_object(struct program *p, int args); struct object *get_master(void); struct object *master(void); @@ -75,9 +75,11 @@ void gc_free_all_unreferenced_objects(void); void count_memory_in_objects(INT32 *num_, INT32 *size_); /* Prototypes end here */ -#ifdef MALLOC_DEBUG +#ifdef DEBUG_MALLOC +#define low_clone(X) ((struct object *)debug_malloc_touch(debug_low_clone((X)))) #define clone_object(X,Y) ((struct object *)debug_malloc_touch(debug_clone_object((X),(Y)))) #else +#define low_clone debug_low_clone #define clone_object debug_clone_object #endif diff --git a/src/pike_memory.c b/src/pike_memory.c index e050786cb1..24704b5b5a 100644 --- a/src/pike_memory.c +++ b/src/pike_memory.c @@ -698,20 +698,25 @@ static int remove_memhdr(void *p) return 0; } +void *debug_malloc_track(void *m, size_t s, const char *fn, int line) +{ + mt_lock(&debug_malloc_mutex); + + if(m) make_memhdr(m, s, location_number(fn,line)); + + mt_unlock(&debug_malloc_mutex); + return m; +} + void *debug_malloc(size_t s, const char *fn, int line) { void *m; - mt_lock(&debug_malloc_mutex); - m=malloc(s); - if(m) - make_memhdr(m, s, location_number(fn,line)); - + debug_malloc_track(m,s,fn,line); if(verbose_debug_malloc) fprintf(stderr, "malloc(%d) => %p (%s:%d)\n", s, m, fn, line); - mt_unlock(&debug_malloc_mutex); return m; } @@ -747,14 +752,20 @@ void *debug_realloc(void *p, size_t s, const char *fn, int line) return m; } -void debug_free(void *p, const char *fn, int line) + +void debug_malloc_untrack(void *p, const char *fn, int line) { mt_lock(&debug_malloc_mutex); remove_memhdr(p); + mt_unlock(&debug_malloc_mutex); +} + +void debug_free(void *p, const char *fn, int line) +{ + debug_malloc_untrack(p,fn,line); free(p); if(verbose_debug_malloc) fprintf(stderr, "free(%p) (%s:%d)\n", p, fn,line); - mt_unlock(&debug_malloc_mutex); } char *debug_strdup(const char *s, const char *fn, int line) @@ -787,6 +798,29 @@ void dump_memhdr_locations(struct memhdr *from, } } +void dmalloc_dump_track(void *p) +{ + struct memhdr *m; + mt_lock(&debug_malloc_mutex); + if((m=find_memhdr(p))) + { + struct memloc *l; + fprintf(stderr, "LEAK: (%p) %d bytes\n",m->data, m->size); + for(l=m->locations;l;l=l->next) + { + struct fileloc *f=find_file_location(l->locnum); + fprintf(stderr," *** %s:%d (%d times) %s\n", + f->file, + f->line, + l->times, + find_location(&no_leak_memlocs, l->locnum) ? "" : " *"); + } + } + + mt_unlock(&debug_malloc_mutex); + +} + void cleanup_memhdrs(void) { unsigned long h; diff --git a/src/pike_types.c b/src/pike_types.c index df03aa77ca..599bb136b2 100644 --- a/src/pike_types.c +++ b/src/pike_types.c @@ -4,7 +4,7 @@ ||| See the files COPYING and DISCLAIMER for more information. \*/ #include "global.h" -RCSID("$Id: pike_types.c,v 1.28 1998/03/03 14:37:15 grubba Exp $"); +RCSID("$Id: pike_types.c,v 1.29 1998/03/03 22:30:25 hubbe Exp $"); #include <ctype.h> #include "svalue.h" #include "pike_types.h" @@ -969,6 +969,8 @@ static struct pike_string *low_index_type(char *t, node *n) push_finished_type(b); push_finished_type(a); push_type(T_OR); + free_string(a); + free_string(b); return pop_unfinished_type(); } diff --git a/src/stralloc.c b/src/stralloc.c index a61e649df7..3e425fd6ad 100644 --- a/src/stralloc.c +++ b/src/stralloc.c @@ -12,6 +12,8 @@ #include "error.h" #include "gc.h" +#include <ctype.h> + #define BEGIN_HASH_SIZE 997 #define MAX_AVG_LINK_LENGTH 3 @@ -369,13 +371,50 @@ struct pike_string *debug_findstring(const struct pike_string *foo) return tmp; } +void debug_dump_pike_string(struct pike_string *s, INT32 max) +{ + INT32 e; + fprintf(stderr,"0x%p: %ld refs, len=%ld, hval=%lux (%lx)\n", + s, + (long)s->refs, + (long)s->len, + (unsigned long)s->hval, + (unsigned long)StrHash(s->str, s->len)); + fprintf(stderr," \""); + for(e=0;e<s->len && max>0;e++) + { + int c=EXTRACT_UCHAR(s->str+e); + switch(c) + { + case '\t': fprintf(stderr,"\\t"); max-=2; break; + case '\n': fprintf(stderr,"\\n"); max-=2; break; + case '\r': fprintf(stderr,"\\r"); max-=2; break; + case '\b': fprintf(stderr,"\\b"); max-=2; break; + + default: + if(is8bitalnum(c) || c==' ' || isgraph(c)) + { + putc(c,stderr); + max--; + }else{ + fprintf(stderr,"\\%03o",c); + max-=4; + } + } + } + if(!max) + fprintf(stderr,"...\n"); + else + fprintf(stderr,"\"\n"); +} + void dump_stralloc_strings(void) { unsigned INT32 e; struct pike_string *p; for(e=0;e<htable_size;e++) for(p=base_table[e];p;p=p->next) - printf("%ld refs \"%s\"\n",(long)p->refs,p->str); + debug_dump_pike_string(p, 70); } #endif @@ -583,6 +622,22 @@ void cleanup_shared_string_table(void) { unsigned INT32 e; struct pike_string *s,*next; + +#if defined(DEBUG) && defined(DEBUG_MALLOC) + if(verbose_debug_exit) + { + INT32 num,size; + count_memory_in_strings(&num,&size); + if(num) + { + fprintf(stderr,"Strings left: %d (%d bytes) (zapped)\n",num,size); + dump_stralloc_strings(); + } + } +#endif + + if(!base_table) return; + for(e=0;e<htable_size;e++) { for(s=base_table[e];s;s=next) @@ -597,6 +652,8 @@ void cleanup_shared_string_table(void) base_table[e]=0; } free((char *)base_table); + base_table=0; + num_strings=0; } void count_memory_in_strings(INT32 *num, INT32 *size) diff --git a/src/svalue.h b/src/svalue.h index e198ff8377..88298bdf68 100644 --- a/src/svalue.h +++ b/src/svalue.h @@ -171,7 +171,7 @@ do{ \ #ifdef DEBUG #define check_type(T) if(T > MAX_TYPE && T!=T_LVALUE && T!=T_SHORT_LVALUE && T!=T_VOID && T!=T_DELETED) fatal("Type error\n") -#define check_refs(S) if((S)->type < MAX_REF_TYPE && (!(S)->u.refs || (S)->u.refs[0] < 0)) fatal("Svalue to object without references.\n") +#define check_refs(S) do { if((S)->type < MAX_REF_TYPE) { debug_malloc_touch((S)->u.refs); if(!(S)->u.refs || (S)->u.refs[0] < 0) fatal("Svalue to object without references.\n"); } }while(0) #define check_refs2(S,T) if((T) < MAX_REF_TYPE && (S)->refs && (S)->refs[0] <= 0) fatal("Svalue to object without references.\n") #else diff --git a/src/testsuite.in b/src/testsuite.in index df2a935b0e..650ea06e5b 100644 --- a/src/testsuite.in +++ b/src/testsuite.in @@ -1,4 +1,4 @@ -test_true([["$Id: testsuite.in,v 1.63 1998/02/11 00:56:34 grubba Exp $"]]) +test_true([["$Id: testsuite.in,v 1.64 1998/03/03 22:30:27 hubbe Exp $"]]) test_eq(1e1,10.0) test_eq(1E1,10.0) test_eq(1e+1,10.0) @@ -31,17 +31,17 @@ class c1 { inherit p1; inherit p2; }; return c1()->foo();]],2); test_any([[class foo { int x=random(100); int `<(object o) { return x < o->x; } }; object *o=Array.map(allocate(100),foo); sort(o); for(int e=1;e<100;e++) if(o[e-1]->x > o[e]->x) return e; return -1;]],-1) -test_compile_error([[void foo() { return destruct(this_object()); }]]) +test_compile_error([[void foo0() { return destruct(this_object()); }]]) test_any([[class foo { constant x=17; }; class bar { inherit foo; constant x=18; }; return bar()->x;]],18) test_program([[inline string foo(string s){ while(s[0] == ' ' || s[0] == '\t') s = s[1..]; return(s); } string a() { return foo(" bar"); }]]) test_true([[lambda(function f) {return 1;}(object_program(this_object()));]]) test_eq([[class { int `()(){ return 4711; } }()(); ]],4711) teste_eval_error(mixed foo=({}); sort(@foo); ) -test_compile_error([[int foo() { return 1} ; constant foo=(["foo":foo]); return foo->foo();]]) +test_compile_error([[int foo2() { return 1} ; constant foo2=(["foo2":foo2]); return foo2->foo2();]]) test_compile_error([[class T{void p(object e,object f){lambda::create(f);}}]]) -test_eval_error(mixed *foo=({}); return mkmapping(foo,({1})); ) +test_eval_error(mixed *foo3=({}); return mkmapping(foo3,({1})); ) test_true(time()) -test_compile_error([[mapping (string:array(string:string)) foo=([]); ]]) +test_compile_error([[mapping (string:array(string:string)) foo4=([]); ]]) test_compile_error([[int a() { switch(random(2)) { case 3: if(random(2)) { case 0: return 1; } else { case 1: return 2; } } }]]) test_true(encode_value(0)) @@ -77,7 +77,7 @@ test_any([[float p=2.0; return p--;]],2.0); test_any([[float p=2.0; p--; return p;]],1.0); test_any([[float p=2.0; return --p;]],1.0); -test_compile_error(int foo() { LJjjjjJJJ ; }) +test_compile_error(int foo5() { LJjjjjJJJ ; }) test_true(clone(class { constant i=1; })->i) test_true(clone(class { constant i=0; mixed `->(string s) { if(s=="i") return 1; }})->i) test_true(clone(class { constant i=1; mixed `->(string s) { return 0; }})["i"]) @@ -104,7 +104,7 @@ test_program(inherit test;) test_program(inherit test; int a() { return foo; } ) test_define_program(test,[[class TEST { int a() { return 1; } }]]) test_program(inherit test; inherit TEST; ) -test_compile_error(class { object(Stdio.File) foo; object(Regexp) bar=foo; }) +test_compile_error(class { object(Stdio.File) foo6; object(Regexp) bar=foo6; }) test_do(class { object foo; object(Regexp) bar=foo; }) test_do(class { object(Stdio.File) foo; object bar=foo; }) test_any(if(int i=1) return i; return 0;,1) @@ -126,7 +126,7 @@ test_any([[int e; return e--;]],0) test_any([[int e; return --e;]],-1) test_any([[int e; if(e--) return 0; return e;]],-1) -test_compile_error_low(master()->add_precompiled_program(\"/test\",compile_string(\"int foo() { return 17; }\",\"62\"))) +test_compile_error_low(master()->add_precompiled_program(\"/test\",compile_string(\"int foo7() { return 17; }\",\"62\"))) test_any([[function f=random_seed; int t; foreach(allocate(1),t) f(t); return 1;]],1) test_compile([[while(0)if(0)continue;else;]]) @@ -432,15 +432,15 @@ test_false(clone(class { int foo() { return 1; }})->bar) test_eq(clone(clone(class { program foo=class { int i=20; }; })->foo)->i,20) // type checks -test_compile_error([[} int foo() { return]]); -test_compile_error([[} void foo() { return 1]]); +test_compile_error([[} int foo9() { return]]); +test_compile_error([[} void foo10() { return 1]]); // Not yet cataloged test_any(int i=10; { int i; } return i, 10) test_program(void foo(int a ,int b); function(int,int:void) a() { return foo; }) test_program(void foo(int a, int ... b); function(int,int ...:void) a() { return foo; }) test_program(void foo(); function(:void) a() { return foo; }) -test_compile_error([[} void foo(); function(:string) a() { return foo;]]) +test_compile_error([[} void foo11(); function(:string) a() { return foo11;]]) test_do(lambda(){return;}()) test_equal( ({ lambda() { return 3; } , lambda() { return 7; }, lambda() { return 9; } })(), ({ 3,7,9 })) -- GitLab