diff --git a/src/array.c b/src/array.c
index 5475965fb349edba969a9dc5f8b1efc4992e2cc8..993fb3b4d133beb4f54347a40cd4c9164a0e1f95 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 91ccb74dac28a933612ad83dfdbfa5f349cdf05c..55d8147def693e605eed079a2c3905f29a51a137 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 e28b84cbfa515429058df22c30aa46cd46fde005..0f722b6c32cdea4c89eb15cfc2253b1260fa8c65 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 62d9eda0c8b9564c7271f206ac56a8b87d332ede..282e350d271b1c87ead8e392b2737988e5f04954 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 0e121ab9c24ddbc52a9156ed502d16b69e71f3c0..8eb0a4355b624353db818e428aaacb4548c66b60 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 82dcbb64a7790fb4aacafab9dec122e519e62614..bc0f693e5caca1af31981230224c16664fea48fb 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 855a2b52e446d99ed8b353670d7cb04ffd686eed..f6fdf21f61a42e01e06f1aae665daf673ac16de8 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 3e5a2e925f20af908be55a1b1389d9b1d7c4af31..00d2609ec9a55b3d313958c48e5e9b623046620b 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 56916f4e7f0380530954e4640457407c671f3aaa..56934d55f90340fbc89efa5649c1fc3c0592b86c 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 c58ab665a893006072347544537e3ca43b70b703..86759d59cc07b8eb5f09931baf572efd3c64b643 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 cd8171584746991243f5e9057ee824c1ebb5e81a..844f39ca8cff7fc8aba143f36e85d627e93a5fc3 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 6972f02d6d0536a5689593beb84019f39a450471..6c50c7b60a33821f07f5bd37e72e804b9ec032bf 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 4be84f95ff49720db0d651296eac0ed65225d8a5..ef487a27e1496e801977cd0f0b4f902718bfdf74 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 e050786cb17dd45674744a08a936ed2e001f7964..24704b5b5a5843fb7de65dad521d7dc3d4766499 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 df03aa77ca6d3178ac8a58ea859dd39c79156c4a..599bb136b2ad954319b51d3bc12a66014aaef71d 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 a61e649df7d48d4e84d49d6e58533d33e786fc43..3e425fd6ad4315dc4d08dc757c2c2aade1f1d730 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 e198ff8377757f0780018cc071934cfb38ddb85b..88298bdf68efea7ca6471a001cfb4219f68f842c 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 df2a935b0e6699d9c4b77a7b196818d5f27cfb0c..650ea06e5b203ae25ebf36aaf136be2ba2597ce2 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 }))