diff --git a/src/array.h b/src/array.h
index ba67be304f55ef1709988793ccd5c6c1d39fe829..95d54b1b9ec80048a9397595d7a432f48df3002c 100644
--- a/src/array.h
+++ b/src/array.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: array.h,v 1.58 2004/03/17 15:27:26 grubba Exp $
+|| $Id: array.h,v 1.59 2004/04/18 02:16:05 mast Exp $
 */
 
 #ifndef ARRAY_H
@@ -68,7 +68,16 @@ extern struct array *gc_internal_array;
 #define PIKE_ARRAY_OP_SUB PIKE_MINTERM(PIKE_ARRAY_OP_TAKE_A,PIKE_ARRAY_OP_SKIP_A ,PIKE_ARRAY_OP_SKIP_B)
 
 
-#define free_array(V) do{ struct array *v_=(V); debug_malloc_touch(v_); if(!sub_ref(v_)) really_free_array(v_); }while(0)
+#define free_array(V) do{						\
+    struct array *v_=(V);						\
+    debug_malloc_touch(v_);						\
+    DO_IF_PIKE_CLEANUP (						\
+      if (gc_external_refs_zapped)					\
+	gc_check_zapped (v_, PIKE_T_ARRAY, __FILE__, __LINE__);		\
+    );									\
+    if(!sub_ref(v_))							\
+      really_free_array(v_);						\
+  }while(0)
 
 #define allocate_array(X) low_allocate_array((X),0)
 #define allocate_array_no_init(X,Y) low_allocate_array((X),(Y))
diff --git a/src/dmalloc.h b/src/dmalloc.h
index 0149c073f8741a52ba720d79fbf80aece4a4db07..ae0260296fe26bd0a949a880568d3e53b13b7c9e 100644
--- a/src/dmalloc.h
+++ b/src/dmalloc.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: dmalloc.h,v 1.49 2004/04/03 18:24:24 mast Exp $
+|| $Id: dmalloc.h,v 1.50 2004/04/18 02:16:05 mast Exp $
 */
 
 #ifndef DMALLOC_H
@@ -35,6 +35,8 @@ extern size_t dmalloc_tracelogptr;
 
 #if defined (PIKE_DEBUG) && defined (DO_PIKE_CLEANUP)
 extern int verbose_debug_exit;
+extern int gc_external_refs_zapped;
+void gc_check_zapped (void *a, TYPE_T type, const char *file, int line);
 #endif
 
 #ifdef DO_PIKE_CLEANUP
diff --git a/src/gc.c b/src/gc.c
index 6f92fe31696d7292950e68f26c71447a21103f56..6daa608ae7364c2e324302dfa867e1693927e820 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.252 2004/04/17 23:35:53 mast Exp $
+|| $Id: gc.c,v 1.253 2004/04/18 02:16:05 mast Exp $
 */
 
 #include "global.h"
@@ -33,7 +33,7 @@ struct callback *gc_evaluator_callback=0;
 
 #include "block_alloc.h"
 
-RCSID("$Id: gc.c,v 1.252 2004/04/17 23:35:53 mast Exp $");
+RCSID("$Id: gc.c,v 1.253 2004/04/18 02:16:05 mast Exp $");
 
 int gc_enabled = 1;
 
@@ -321,10 +321,11 @@ int attempt_to_identify(void *something, void **inblock)
   if(safe_debug_findstring((struct pike_string *)something))
     return T_STRING;
 
-  for (i = 0; i < pike_type_hash_size; i++)
-    for (t = pike_type_hash[i]; t; t = t->next)
-      if (t == (struct pike_type *) something)
-	return T_TYPE;
+  if (pike_type_hash)
+    for (i = 0; i < pike_type_hash_size; i++)
+      for (t = pike_type_hash[i]; t; t = t->next)
+	if (t == (struct pike_type *) something)
+	  return T_TYPE;
 
   for (c = first_callable; c; c = c->next)
     if (c == (struct callable *) something)
@@ -1528,7 +1529,22 @@ static void cleanup_markers (void)
 {
 #ifdef DO_PIKE_CLEANUP
   size_t e=0;
-  struct marker *h;
+
+  if (gc_keep_markers) {
+    /* Carry over any GC_CLEANUP_FREED flags but reinitialize them
+     * otherwise. */
+    for(e=0;e<marker_hash_table_size;e++) {
+      struct marker *m;
+      for (m = marker_hash_table[e]; m; m = m->next) {
+	m->flags &= GC_CLEANUP_FREED;
+	m->refs = m->weak_refs = m->xrefs = 0;
+	m->saved_refs = -1;
+	m->frame = 0;
+      }
+    }
+    return;
+  }
+
   for(e=0;e<marker_hash_table_size;e++)
     while(marker_hash_table[e])
       remove_marker(marker_hash_table[e]->data);
@@ -1536,7 +1552,6 @@ static void cleanup_markers (void)
   exit_marker_hash();
 }
 
-
 static void init_gc(void)
 {
 #ifdef PIKE_DEBUG
@@ -1544,16 +1559,16 @@ static void init_gc(void)
     /* The marker hash table is left around after a previous gc if
      * gc_keep_markers is set. */
     if (marker_hash_table) cleanup_markers();
+    if (!marker_hash_table)
 #endif
-
-    low_init_marker_hash(num_objects);
+      low_init_marker_hash(num_objects);
     get_marker(rec_list.data);	/* Used to simplify fencepost conditions. */
 #ifdef PIKE_DEBUG
   }
 #endif
 }
 
-static void exit_gc(void)
+void exit_gc(void)
 {
   if (gc_evaluator_callback) {
     remove_callback(gc_evaluator_callback);
@@ -1764,6 +1779,16 @@ int gc_mark_external (void *a, const char *place)
   return 0;
 }
 
+#ifdef DO_PIKE_CLEANUP
+void gc_check_zapped (void *a, TYPE_T type, const char *file, int line)
+{
+  struct marker *m = find_marker (a);
+  if (m && (m->flags & GC_CLEANUP_FREED))
+    fprintf (stderr, "Free of leaked %s %p from %s:%d, %d refs remaining\n",
+	     get_name_of_type (type), a, file, line, *(INT32 *)a - 1);
+}
+#endif
+
 void debug_really_free_gc_frame(struct gc_frame *l)
 {
   if (l->frameflags & GC_LINK_FREED)
diff --git a/src/gc.h b/src/gc.h
index f773cf9a8290114c855d72915479ced6f261e629..3c3307e66750c4a8b415f821027d52be9f4a13ab 100644
--- a/src/gc.h
+++ b/src/gc.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: gc.h,v 1.111 2004/03/19 02:23:26 mast Exp $
+|| $Id: gc.h,v 1.112 2004/04/18 02:16:05 mast Exp $
 */
 
 #ifndef GC_H
@@ -87,7 +87,6 @@ extern int gc_destruct_everything;
 
 #if defined (PIKE_DEBUG) && defined (DO_PIKE_CLEANUP)
 extern int gc_keep_markers;
-extern int gc_external_refs_zapped;
 #else
 #define gc_keep_markers 0
 #endif
@@ -242,6 +241,9 @@ struct marker
 /* The thing has been visited by gc_checked_as_weak(). */
 #define GC_WATCHED		0x01000000
 /* The thing has been set under watch by gc_watch(). */
+#define GC_CLEANUP_FREED	0x02000000
+/* The thing was freed by the cleanup code under the assumption that
+ * references were lost. */
 #endif
 
 #ifdef PIKE_DEBUG
@@ -290,6 +292,7 @@ void gc_watch(void *a);
 void debug_gc_touch(void *a);
 PMOD_EXPORT int real_gc_check(void *a);
 int real_gc_check_weak(void *a);
+void exit_gc(void);
 void locate_references(void *a);
 void debug_gc_add_extra_ref(void *a);
 void debug_gc_free_extra_ref(void *a);
diff --git a/src/main.c b/src/main.c
index e152cf19b92f511782251e1b4e8f8ed8b7959bdb..1b5549bf7951cbb9f4175ee531d38ce651ce956c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -2,11 +2,11 @@
 || 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: main.c,v 1.199 2004/04/06 15:37:55 nilsson Exp $
+|| $Id: main.c,v 1.200 2004/04/18 02:16:05 mast Exp $
 */
 
 #include "global.h"
-RCSID("$Id: main.c,v 1.199 2004/04/06 15:37:55 nilsson Exp $");
+RCSID("$Id: main.c,v 1.200 2004/04/18 02:16:05 mast Exp $");
 #include "fdlib.h"
 #include "backend.h"
 #include "module.h"
@@ -1066,8 +1066,10 @@ void low_exit_main(void)
 	  for (i = 0; i < (ptrdiff_t) NELEM (statics); i++)		\
 	    if (x == statics[i])					\
 	      is_static = 1;						\
-	  while (x->refs > m->refs + is_static)				\
+	  while (x->refs > m->refs + is_static) {			\
+	    m->flags |= GC_CLEANUP_FREED;				\
 	    PIKE_CONCAT(free_, TYPE) (x);				\
+	  }								\
 	}								\
       }									\
     } while (0)
@@ -1084,9 +1086,11 @@ void low_exit_main(void)
      * above we should try to handle it gracefully. */
     gc_external_refs_zapped = 1;
 
-    gc_keep_markers = 0;
     do_gc (NULL, 1);
 
+    gc_keep_markers = 0;
+    exit_gc();
+
 #ifdef DEBUG_MALLOC
     {
       INT32 num, size;
diff --git a/src/mapping.h b/src/mapping.h
index c71565e5405cb4138e70ddd2ac878395752a9e98..21009355045e3e2be3be75b6c30247deb5a27dab 100644
--- a/src/mapping.h
+++ b/src/mapping.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: mapping.h,v 1.53 2004/03/22 19:35:44 mast Exp $
+|| $Id: mapping.h,v 1.54 2004/04/18 02:16:06 mast Exp $
 */
 
 #ifndef MAPPING_H
@@ -82,7 +82,16 @@ extern struct mapping *gc_internal_mapping;
   for(((k = MD_KEYPAIRS((m)->data, (m)->data->hashsize)), e=0) DO_IF_DMALLOC( ?0:(debug_malloc_touch(m),debug_malloc_touch((m)->data)) ) ; e<(m)->data->size; e++,k++)
 #endif /* PIKE_MAPPING_KEYPAIR_LOOP */
 
-#define free_mapping(M) do{ struct mapping *m_=(M); debug_malloc_touch(m_); if(!sub_ref(m_)) really_free_mapping(m_); }while(0)
+#define free_mapping(M) do{						\
+    struct mapping *m_=(M);						\
+    debug_malloc_touch(m_);						\
+    DO_IF_PIKE_CLEANUP (						\
+      if (gc_external_refs_zapped)					\
+	gc_check_zapped (m_, PIKE_T_MAPPING, __FILE__, __LINE__);	\
+    );									\
+    if(!sub_ref(m_))							\
+      really_free_mapping(m_);						\
+  }while(0)
 
 #define free_mapping_data(M) do{ \
  struct mapping_data *md_=(M); \
diff --git a/src/multiset.h b/src/multiset.h
index b7c8206834378acbaed8edb9fae94f9d2f4b4378..561f4e5a1b21b594be767abade68e3cf271df150 100644
--- a/src/multiset.h
+++ b/src/multiset.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: multiset.h,v 1.33 2004/04/06 15:37:55 nilsson Exp $
+|| $Id: multiset.h,v 1.34 2004/04/18 02:16:06 mast Exp $
 */
 
 #ifndef MULTISET_H
@@ -224,6 +224,10 @@ PMOD_PROTO void really_free_multiset (struct multiset *l);
 #define free_multiset(L) do {						\
     struct multiset *_ms_ = (L);					\
     debug_malloc_touch (_ms_);						\
+    DO_IF_PIKE_CLEANUP (						\
+      if (gc_external_refs_zapped)					\
+	gc_check_zapped (_ms_, PIKE_T_MULTISET, __FILE__, __LINE__);	\
+    );									\
     if (!sub_ref (_ms_)) really_free_multiset (_ms_);			\
   } while (0)
 
diff --git a/src/object.h b/src/object.h
index e6f97a67f1a3f2b6aec64a00e03c3725dd5b3a07..d9817071077d194cc6b1ed03f00b8739143b6615 100644
--- a/src/object.h
+++ b/src/object.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: object.h,v 1.81 2004/03/15 22:47:15 mast Exp $
+|| $Id: object.h,v 1.82 2004/04/18 02:16:06 mast Exp $
 */
 
 #ifndef OBJECT_H
@@ -38,7 +38,17 @@ extern struct program *magic_set_index_program;
 extern struct program *magic_indices_program;
 extern struct program *magic_values_program;
 
-#define free_object(O) do{ struct object *o_=(O); debug_malloc_touch(o_); debug_malloc_touch(o_->storage); if(!sub_ref(o_)) schedule_really_free_object(o_); }while(0)
+#define free_object(O) do{						\
+    struct object *o_=(O);						\
+    debug_malloc_touch(o_);						\
+    debug_malloc_touch(o_->storage);					\
+    DO_IF_PIKE_CLEANUP (						\
+      if (gc_external_refs_zapped)					\
+	gc_check_zapped (o_, PIKE_T_OBJECT, __FILE__, __LINE__);	\
+    );									\
+    if(!sub_ref(o_))							\
+      schedule_really_free_object(o_);					\
+  }while(0)
 
 #ifdef DEBUG_MALLOC
 #define PIKE_OBJ_STORAGE(O) ((char *)debug_malloc_pass( (O)->storage ))
diff --git a/src/program.c b/src/program.c
index 618fb671da8cdcf48304ae3755a65729209b2565..e5967e378abac6c766dfd62dab5694fc4d9cf365 100644
--- a/src/program.c
+++ b/src/program.c
@@ -2,11 +2,11 @@
 || 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.562 2004/04/17 15:18:52 marcus Exp $
+|| $Id: program.c,v 1.563 2004/04/18 02:16:06 mast Exp $
 */
 
 #include "global.h"
-RCSID("$Id: program.c,v 1.562 2004/04/17 15:18:52 marcus Exp $");
+RCSID("$Id: program.c,v 1.563 2004/04/18 02:16:06 mast Exp $");
 #include "program.h"
 #include "object.h"
 #include "dynamic_buffer.h"
@@ -2340,6 +2340,7 @@ static void exit_program_struct(struct program *p)
 #ifdef PIKE_DEBUG
   if (p->refs) {
 #ifdef DEBUG_MALLOC
+    fprintf (stderr, "Program to be freed still got %d references:\n", p->refs);
     describe_something(p, T_PROGRAM, 0,2,0, NULL);
 #endif
     Pike_fatal("Program to be freed still got %d references.\n", p->refs);
diff --git a/src/program.h b/src/program.h
index 12cdc0f965800072f88c4ab40dd2e6db25f3aa40..fbc0e413afbfb7c4b86a3d2c436563eeab829266 100644
--- a/src/program.h
+++ b/src/program.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: program.h,v 1.201 2004/03/16 12:46:51 grubba Exp $
+|| $Id: program.h,v 1.202 2004/04/18 02:16:06 mast Exp $
 */
 
 #ifndef PROGRAM_H
@@ -564,7 +564,16 @@ static inline int CHECK_IDREF_RANGE (int x, const struct program *p)
 #define FIND_LFUN(P,N) ( dmalloc_touch(struct program *,(P))->flags & PROGRAM_FIXED?((P)->lfuns[(N)]):low_find_lfun((P), (N)) )
 #define QUICK_FIND_LFUN(P,N) (dmalloc_touch(struct program *,(P))->lfuns[N])
 
-#define free_program(p) do{ struct program *_=(p); debug_malloc_touch(_); if(!sub_ref(_)) really_free_program(_); }while(0)
+#define free_program(p) do{						\
+    struct program *_=(p);						\
+    debug_malloc_touch(_);						\
+    DO_IF_PIKE_CLEANUP (						\
+      if (gc_external_refs_zapped)					\
+	gc_check_zapped (_, PIKE_T_PROGRAM, __FILE__, __LINE__);	\
+    );									\
+    if(!sub_ref(_))							\
+      really_free_program(_);						\
+  }while(0)
 
 BLOCK_ALLOC_FILL_PAGES(program, n/a)