diff --git a/src/gc.c b/src/gc.c
index 7d1482d47cb0d2d934194e59c5b7ce1803813a58..3c957a51aafe54208aa70b45817fab5afe5d2795 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -30,7 +30,7 @@ struct callback *gc_evaluator_callback=0;
 
 #include "block_alloc.h"
 
-RCSID("$Id: gc.c,v 1.127 2000/08/27 15:21:50 mast Exp $");
+RCSID("$Id: gc.c,v 1.128 2000/09/03 23:09:38 mast Exp $");
 
 /* Run garbage collect approximately every time
  * 20 percent of all arrays, objects and programs is
@@ -62,7 +62,7 @@ RCSID("$Id: gc.c,v 1.127 2000/08/27 15:21:50 mast Exp $");
  * o  Strong references are used in special cases like parent object
  *    references. There can never be a cycle consisting only of strong
  *    references. (This means the gc will never destruct a parent
- *    object before all childs has been destructed.)
+ *    object before all children have been destructed.)
  *
  * The gc tries to detect and warn about cases where there are live
  * objects with no well defined order between them. There are cases
@@ -70,11 +70,11 @@ RCSID("$Id: gc.c,v 1.127 2000/08/27 15:21:50 mast Exp $");
  *
  * Things that aren't live objects but are referenced from them are
  * still intact during this destruct pass, so it's entirely possible
- * to save these things by adding external references to them.
- * However, it's not possible for live objects to save themselves or
- * other live objects; all live objects that didn't have external
- * references at the start of the gc pass will be destructed
- * regardless of added references.
+ * to save them by adding external references to them. However, it's
+ * not possible for live objects to save themselves or other live
+ * objects; all live objects that didn't have external references at
+ * the start of the gc pass will be destructed regardless of added
+ * references.
  *
  * Things that have only weak external references at the start of the
  * gc pass will be freed. That's done before the live object destruct
@@ -225,10 +225,22 @@ static void gc_cycle_pop(void *a);
   (X)->frame = 0;
 #endif
 
+#ifdef PIKE_DEBUG
+#undef get_marker
+#define get_marker debug_get_marker
+#undef find_marker
+#define find_marker debug_find_marker
+#endif
+
 PTR_HASH_ALLOC(marker,MARKER_CHUNK_SIZE)
 
 #ifdef PIKE_DEBUG
 
+#undef get_marker
+#define get_marker(X) ((struct marker *) debug_malloc_pass(debug_get_marker(X)))
+#undef find_marker
+#define find_marker(X) ((struct marker *) debug_malloc_pass(debug_find_marker(X)))
+
 int gc_in_cycle_check = 0;
 static unsigned weak_freed, checked, marked, cycle_checked, live_ref;
 static unsigned max_gc_frames, num_gc_frames = 0;
@@ -273,6 +285,8 @@ TYPE_T attempt_to_identify(void *something)
   for(m=first_mapping;m;m=m->next)
     if(m==(struct mapping *)something)
       return T_MAPPING;
+    else if (m->data == (struct mapping_data *) something)
+      return T_MAPPING_DATA;
 
   for(mu=first_multiset;mu;mu=mu->next)
     if(mu==(struct multiset *)something)
@@ -589,7 +603,7 @@ void debug_gc_check_weak_short_svalue(union anything *u, TYPE_T type, TYPE_T t,
   found_in=0;
 }
 
-int debug_gc_check(void *x, TYPE_T t, void *data)
+int debug_low_gc_check(void *x, TYPE_T t, void *data)
 {
   int ret;
   found_in=data;
@@ -673,7 +687,7 @@ void low_describe_something(void *a,
 	fprintf(stderr,"%*s**There is no parent (any longer?)\n",indent,"");
       }
       break;
-      
+
     case T_PROGRAM:
     {
       char *tmp;
@@ -847,52 +861,65 @@ void debug_gc_touch(void *a)
 {
   struct marker *m;
   if (!a) fatal("Got null pointer.\n");
-
   m = find_marker(a);
-  if (Pike_in_gc == GC_PASS_PRETOUCH) {
-    if (m) gc_fatal(a, 0, "Object touched twice.\n");
-    get_marker(a)->flags |= GC_TOUCHED;
-  }
-  else if (Pike_in_gc == GC_PASS_POSTTOUCH) {
-    if (!*(INT32 *) a)
-      gc_fatal(a, 1, "Found a thing without refs.\n");
-    if (m) {
-      if (!(m->flags & GC_TOUCHED))
-	gc_fatal(a, 2, "An existing but untouched marker found "
-		 "for object in linked lists.\n");
-      else if (m->flags & GC_LIVE_RECURSE ||
-	       (m->frame && m->frame->frameflags & (GC_WEAK_REF|GC_STRONG_REF)))
-	gc_fatal(a, 2, "Thing still got flag from recurse list.\n");
-      else if (m->flags & GC_MARKED)
-	return;
-      else if (!(m->flags & GC_NOT_REFERENCED) || m->flags & GC_XREFERENCED)
-	gc_fatal(a, 3, "A thing with external references "
-		 "got missed by mark pass.\n");
-      else if (!(m->flags & GC_CYCLE_CHECKED))
-	gc_fatal(a, 2, "A thing was missed by "
-		 "both mark and cycle check pass.\n");
-      else if (!(m->flags & GC_IS_REFERENCED))
-	gc_fatal(a, 2, "An unreferenced thing "
-		 "got missed by gc_is_referenced().\n");
-      else if (!(m->flags & GC_DO_FREE))
-	gc_fatal(a, 2, "An unreferenced thing "
-		 "got missed by gc_do_free().\n");
-      else if (m->flags & GC_GOT_EXTRA_REF)
-	gc_fatal(a, 2, "A thing still got an extra ref.\n");
-      else if (!(m->flags & GC_LIVE)) {
-	if (m->weak_refs > 0)
-	  gc_fatal(a, 3, "A thing to garb is still around. "
-		   "It's probably one with only external weak refs.\n");
-	else if (m->weak_refs < 0)
-	  gc_fatal(a, 3, "A thing which had only weak references is "
-		   "still around after gc.\n");
-	else
-	  gc_fatal(a, 3, "A thing to garb is still around.\n");
+
+  switch (Pike_in_gc) {
+    case GC_PASS_PRETOUCH:
+      if (m && !(m->flags & GC_PRETOUCHED))
+	gc_fatal(a, 1, "Thing got an existing but untouched marker.\n");
+      get_marker(a)->flags |= GC_PRETOUCHED;
+      break;
+
+    case GC_PASS_MIDDLETOUCH:
+      if (!m)
+	gc_fatal(a, 1, "Found a thing without marker.\n");
+      else if (!(m->flags & GC_PRETOUCHED))
+	gc_fatal(a, 1, "Thing got an existing but untouched marker.\n");
+      m->flags |= GC_MIDDLETOUCHED;
+      break;
+
+    case GC_PASS_POSTTOUCH:
+      if (!*(INT32 *) a)
+	gc_fatal(a, 1, "Found a thing without refs.\n");
+      if (m) {
+	if (!(m->flags & (GC_PRETOUCHED|GC_MIDDLETOUCHED)))
+	  gc_fatal(a, 2, "An existing but untouched marker found "
+		   "for object in linked lists.\n");
+	else if (m->flags & GC_LIVE_RECURSE ||
+		 (m->frame && m->frame->frameflags & (GC_WEAK_REF|GC_STRONG_REF)))
+	  gc_fatal(a, 2, "Thing still got flag from recurse list.\n");
+	else if (m->flags & GC_MARKED)
+	  return;
+	else if (!(m->flags & GC_NOT_REFERENCED) || m->flags & GC_XREFERENCED)
+	  gc_fatal(a, 3, "A thing with external references "
+		   "got missed by mark pass.\n");
+	else if (!(m->flags & GC_CYCLE_CHECKED))
+	  gc_fatal(a, 2, "A thing was missed by "
+		   "both mark and cycle check pass.\n");
+	else if (!(m->flags & GC_IS_REFERENCED))
+	  gc_fatal(a, 2, "An unreferenced thing "
+		   "got missed by gc_is_referenced().\n");
+	else if (!(m->flags & GC_DO_FREE))
+	  gc_fatal(a, 2, "An unreferenced thing "
+		   "got missed by gc_do_free().\n");
+	else if (m->flags & GC_GOT_EXTRA_REF)
+	  gc_fatal(a, 2, "A thing still got an extra ref.\n");
+	else if (!(m->flags & GC_LIVE)) {
+	  if (m->weak_refs > 0)
+	    gc_fatal(a, 3, "A thing to garb is still around. "
+		     "It's probably one with only external weak refs.\n");
+	  else if (m->weak_refs < 0)
+	    gc_fatal(a, 3, "A thing which had only weak references is "
+		     "still around after gc.\n");
+	  else
+	    gc_fatal(a, 3, "A thing to garb is still around.\n");
+	}
       }
-    }
+      break;
+
+    default:
+      fatal("debug_gc_touch() used in invalid gc pass.\n");
   }
-  else
-    fatal("debug_gc_touch() used in invalid gc pass.\n");
 }
 
 static INLINE struct marker *gc_check_debug(void *a, int weak)
@@ -1090,7 +1117,7 @@ int debug_gc_is_referenced(void *a)
 
   if (gc_debug) {
     m = find_marker(a);
-    if ((!m || !(m->flags & GC_TOUCHED)) &&
+    if ((!m || !(m->flags & GC_PRETOUCHED)) &&
 	!safe_debug_findstring((struct pike_string *) a))
       gc_fatal(a, 0, "Doing gc_is_referenced() on invalid object.\n");
     if (!m) m = get_marker(a);
@@ -1164,8 +1191,7 @@ int gc_do_weak_free(void *a)
 
 #ifdef PIKE_DEBUG
   if (!a) fatal("Got null pointer.\n");
-  if (Pike_in_gc != GC_PASS_MARK && Pike_in_gc != GC_PASS_CYCLE &&
-      Pike_in_gc != GC_PASS_ZAP_WEAK)
+  if (Pike_in_gc != GC_PASS_MARK && Pike_in_gc != GC_PASS_ZAP_WEAK)
     fatal("gc_do_weak_free() called in invalid gc pass.\n");
   if (gc_debug) {
     if (!(m = find_marker(a)))
@@ -1183,6 +1209,9 @@ int gc_do_weak_free(void *a)
   if (Pike_in_gc != GC_PASS_ZAP_WEAK) {
     if (m->weak_refs < 0) {
       gc_ext_weak_refs--;
+#ifdef PIKE_DEBUG
+      m->flags |= GC_WEAK_FREED;
+#endif
       return 1;
     }
   }
@@ -1195,6 +1224,9 @@ int gc_do_weak_free(void *a)
 #endif
       m->weak_refs--;
       gc_ext_weak_refs--;
+#ifdef PIKE_DEBUG
+      m->flags |= GC_WEAK_FREED;
+#endif
       return 1;
     }
   return 0;
@@ -1421,7 +1453,7 @@ int gc_cycle_push(void *x, struct marker *m, int weak)
   if (m->data != x) fatal("Got wrong marker.\n");
   if (Pike_in_gc != GC_PASS_CYCLE)
     fatal("GC cycle push attempted in invalid pass.\n");
-  if (gc_debug && !(m->flags & GC_TOUCHED))
+  if (gc_debug && !(m->flags & GC_PRETOUCHED))
     gc_fatal(x, 0, "gc_cycle_push() called for untouched thing.\n");
   if ((!(m->flags & GC_NOT_REFERENCED) || m->flags & GC_MARKED) &&
       *(INT32 *) x)
@@ -1812,7 +1844,7 @@ int gc_do_free(void *a)
     if (!(m->flags & GC_NOT_REFERENCED) || m->flags & GC_MARKED)
       gc_fatal(a, 0, "gc_do_free() called for referenced thing.\n");
     if (gc_debug &&
-	(m->flags & (GC_TOUCHED|GC_MARKED|GC_IS_REFERENCED)) == GC_TOUCHED)
+	(m->flags & (GC_PRETOUCHED|GC_MARKED|GC_IS_REFERENCED)) == GC_PRETOUCHED)
       gc_fatal(a, 0, "gc_do_free() called without prior call to "
 	       "gc_mark() or gc_is_referenced().\n");
   }
@@ -1884,6 +1916,7 @@ int do_gc(void)
 #ifdef PIKE_DEBUG
   gc_debug = d_flag;
 #endif
+  gc_debug = 1;
 
   destruct_objects_to_destruct();
 
@@ -1929,6 +1962,7 @@ int do_gc(void)
     n += gc_touch_all_mappings();
     n += gc_touch_all_programs();
     n += gc_touch_all_objects();
+    gc_touch_all_strings();
     if (n != (unsigned) num_objects)
       fatal("Object count wrong before gc; expected %d, got %d.\n", num_objects, n);
     GC_VERBOSE_DO(fprintf(stderr, "| pretouch: %u things\n", n));
@@ -1984,8 +2018,7 @@ int do_gc(void)
   run_queue(&gc_mark_queue);
   gc_mark_all_objects();
   run_queue(&gc_mark_queue);
-/*   if(gc_debug) */
-/*     gc_mark_all_strings(); */
+  if(gc_debug) gc_mark_all_strings();
 
   GC_VERBOSE_DO(fprintf(stderr,
 			"| mark: %u markers referenced,\n"
@@ -2015,6 +2048,38 @@ int do_gc(void)
     fatal("Recurse list not empty or inconsistent after cycle check pass.\n");
 #endif
 
+#ifdef PIKE_DEBUG
+  if (gc_debug) {
+    unsigned n;
+    size_t i;
+    struct marker *m;
+    Pike_in_gc=GC_PASS_MIDDLETOUCH;
+    n = gc_touch_all_arrays();
+    n += gc_touch_all_multisets();
+    n += gc_touch_all_mappings();
+    n += gc_touch_all_programs();
+    n += gc_touch_all_objects();
+    gc_touch_all_strings();
+    if (n != (unsigned) num_objects)
+      fatal("Object count wrong in gc; expected %d, got %d.\n", num_objects, n);
+    get_marker(rec_list.data)->flags |= GC_MIDDLETOUCHED;
+#ifdef DEBUG_MALLOC
+    PTR_HASH_LOOP(marker, i, m)
+      if (!(m->flags & (GC_MIDDLETOUCHED|GC_WEAK_FREED)) &&
+	  dmalloc_is_invalid_memory_block(m->data)) {
+	fprintf(stderr, "Found a stray marker after middletouch pass: ");
+	describe_marker(m);
+	fprintf(stderr, "Describing marker location(s):\n");
+	debug_malloc_dump_references(m, 2, 1, 0);
+	fprintf(stderr, "Describing thing for marker:\n");
+	describe(m->data);
+	fatal("Fatal in garbage collector.\n");
+      }
+#endif
+    GC_VERBOSE_DO(fprintf(stderr, "| middletouch\n"));
+  }
+#endif
+
   GC_VERBOSE_DO(fprintf(stderr,
 			"| cycle: %u internal things visited, %u cycle ids used,\n"
 			"|        %u weak references freed, %d things really freed,\n"
@@ -2133,6 +2198,7 @@ int do_gc(void)
     n += gc_touch_all_mappings();
     n += gc_touch_all_programs();
     n += gc_touch_all_objects();
+    // gc_touch_all_strings();
     if (n != (unsigned) num_objects)
       fatal("Object count wrong after gc; expected %d, got %d.\n", num_objects, n);
     GC_VERBOSE_DO(fprintf(stderr, "| posttouch: %u things\n", n));
diff --git a/src/gc.h b/src/gc.h
index c9f91028e97e62c86cd717eafa95ac0d19201306..e16bc238ba485744a2c9982be4a77517e79134fd 100644
--- a/src/gc.h
+++ b/src/gc.h
@@ -1,5 +1,5 @@
 /*
- * $Id: gc.h,v 1.63 2000/08/22 17:21:26 grubba Exp $
+ * $Id: gc.h,v 1.64 2000/09/03 23:09:38 mast Exp $
  */
 #ifndef GC_H
 #define GC_H
@@ -90,16 +90,30 @@ struct marker
 #define GC_FREE_VISITED		0x0080
 
 #ifdef PIKE_DEBUG
-#define GC_TOUCHED		0x0100
-#define GC_IS_REFERENCED	0x0200
-#define GC_XREFERENCED		0x0400
-#define GC_DO_FREE		0x0800
-#define GC_GOT_EXTRA_REF	0x1000
+#define GC_PRETOUCHED		0x0100
+#define GC_MIDDLETOUCHED	0x0200
+#define GC_IS_REFERENCED	0x0400
+#define GC_XREFERENCED		0x0800
+#define GC_DO_FREE		0x1000
+#define GC_GOT_EXTRA_REF	0x2000
+#define GC_WEAK_FREED		0x4000
+#endif
+
+#ifdef PIKE_DEBUG
+#define get_marker debug_get_marker
+#define find_marker debug_find_marker
 #endif
 
 #include "block_alloc_h.h"
 PTR_HASH_ALLOC(marker,MARKER_CHUNK_SIZE)
 
+#ifdef PIKE_DEBUG
+#undef get_marker
+#define get_marker(X) ((struct marker *) debug_malloc_pass(debug_get_marker(X)))
+#undef find_marker
+#define find_marker(X) ((struct marker *) debug_malloc_pass(debug_find_marker(X)))
+#endif
+
 extern size_t gc_ext_weak_refs;
 
 typedef void gc_cycle_check_cb (void *data, int weak);
@@ -123,7 +137,7 @@ void debug_gc_check_svalues(struct svalue *s, ptrdiff_t num, TYPE_T t, void *dat
 void debug_gc_check_weak_svalues(struct svalue *s, ptrdiff_t num, TYPE_T t, void *data);
 void debug_gc_check_short_svalue(union anything *u, TYPE_T type, TYPE_T t, void *data);
 void debug_gc_check_weak_short_svalue(union anything *u, TYPE_T type, TYPE_T t, void *data);
-int debug_gc_check(void *x, TYPE_T t, void *data);
+int debug_low_gc_check(void *x, TYPE_T t, void *data);
 void low_describe_something(void *a,
 			    int t,
 			    int indent,
@@ -157,8 +171,18 @@ void cleanup_gc(void);
 #define gc_fatal \
   fprintf(stderr, "%s:%d: GC fatal:\n", __FILE__, __LINE__), debug_gc_fatal
 
-#define gc_check(VP) real_gc_check(debug_malloc_pass(VP))
-#define gc_check_weak(VP) real_gc_check_weak(debug_malloc_pass(VP))
+#if defined (PIKE_DEBUG) && defined (DEBUG_MALLOC)
+#define DMALLOC_TOUCH_MARKER(X, EXPR) (get_marker(X), (EXPR))
+#else
+#define DMALLOC_TOUCH_MARKER(X, EXPR) (EXPR)
+#endif
+
+#define gc_check(VP) \
+  DMALLOC_TOUCH_MARKER(VP, real_gc_check(debug_malloc_pass(VP)))
+#define gc_check_weak(VP) \
+  DMALLOC_TOUCH_MARKER(VP, real_gc_check_weak(debug_malloc_pass(VP)))
+#define debug_gc_check(X, T, DATA) \
+  DMALLOC_TOUCH_MARKER(X, debug_low_gc_check(debug_malloc_pass(X), (T), (DATA)))
 
 #define gc_recurse_svalues(S,N)						\
   (Pike_in_gc == GC_PASS_MARK ?						\
@@ -174,7 +198,7 @@ void cleanup_gc(void);
    gc_mark_weak_short_svalue((U), (T)) : gc_cycle_check_weak_short_svalue((U), (T)))
 
 #define GC_RECURSE_THING(V, T)						\
-  (Pike_in_gc == GC_PASS_MARK ?						\
+  (DMALLOC_TOUCH_MARKER(V, Pike_in_gc == GC_PASS_MARK) ?		\
    PIKE_CONCAT3(gc_mark_, T, _as_referenced)(V) :			\
    PIKE_CONCAT(gc_cycle_check_, T)(V, 0))
 #define gc_recurse_array(V) GC_RECURSE_THING((V), array)
@@ -193,13 +217,16 @@ void cleanup_gc(void);
 #endif
 
 #ifdef PIKE_DEBUG
-#define gc_is_referenced(X) debug_gc_is_referenced(debug_malloc_pass(X))
+#define gc_is_referenced(X) \
+  DMALLOC_TOUCH_MARKER(X, debug_gc_is_referenced(debug_malloc_pass(X)))
 #else
 #define gc_is_referenced(X) !(get_marker(X)->flags & GC_NOT_REFERENCED)
 #endif
 
-#define gc_external_mark2(X,Y,Z) gc_external_mark3( debug_malloc_pass(X),(Y),(Z))
-#define gc_external_mark(X) gc_external_mark2( (X),"externally", 0)
+#define gc_external_mark2(X,Y,Z) \
+  DMALLOC_TOUCH_MARKER(X, gc_external_mark3( debug_malloc_pass(X),(Y),(Z)))
+#define gc_external_mark(X) \
+  DMALLOC_TOUCH_MARKER(X, gc_external_mark2( (X),"externally", 0))
 
 #define add_gc_callback(X,Y,Z) \
   dmalloc_touch(struct callback *,debug_add_gc_callback((X),(Y),(Z)))
@@ -214,6 +241,7 @@ void cleanup_gc(void);
 #define GC_PASS_CHECK		100
 #define GC_PASS_MARK		200
 #define GC_PASS_CYCLE		250
+#define GC_PASS_MIDDLETOUCH	260
 #define GC_PASS_ZAP_WEAK	270
 #define GC_PASS_FREE		300
 #define GC_PASS_KILL		400