Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Completion crash owing to bad allocation



On Wed, 11 May 2011 15:09:09 +0100
Peter Stephenson <Peter.Stephenson@xxxxxxx> wrote:
> One way to tackle this would be to add a stack corresponding to the
> current heap stack, with each level having a unique (up to 32-bit
> integer wrap) ID that tells you if that heap variant is valid.  Then
> when memory is allocated for use by a Cmgroup it stores the ID
> corresponding to the currently pushed heap at the top of the stack
> (with a special ID to be used if it was permanently allocated).  Every
> time amatches is examined the code could report an error if a heap ID
> stored somewhere along the list doesn't correspond to one somewhere on
> the current heap debug stack.  (Unfortunately examining amatches at the
> point of a popheap() won't work --- the code is lax about marking
> amatches as invalid, it just expects you not to access it in that case,
> which is part of the problem.)

Hmm...

So I added the following code, which seems to working in that it's
performing the checks and not usually reporting errors, and turned it
on, and ... dénouement in the next episode.

Index: configure.ac
===================================================================
RCS file: /cvsroot/zsh/zsh/configure.ac,v
retrieving revision 1.135
diff -p -u -r1.135 configure.ac
--- configure.ac	18 Apr 2011 20:36:31 -0000	1.135
+++ configure.ac	13 May 2011 23:18:30 -0000
@@ -105,6 +105,18 @@ AC_HELP_STRING([--enable-zsh-secure-free
   AC_DEFINE(ZSH_SECURE_FREE)
 fi])
 
+dnl Do you want to debug zsh heap allocation?
+dnl Does not depend on zsh-mem.
+ifdef([zsh-heap-debug],[undefine([zsh-heap-debug])])dnl
+AH_TEMPLATE([ZSH_HEAP_DEBUG],
+[Define to 1 if you want to turn on error checking for heap allocation.])
+AC_ARG_ENABLE(zsh-heap-debug,
+AC_HELP_STRING([--enable-zsh-heap-debug],
+[turn on error checking for heap allocation]),
+[if test x$enableval = xyes; then
+  AC_DEFINE(ZSH_HEAP_DEBUG)
+fi])
+
 dnl Do you want debugging information on internal hash tables.
 dnl This turns on the `hashinfo' builtin command.
 ifdef([zsh-hash-debug],[undefine([zsh-hash-debug])])dnl
Index: Src/mem.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/mem.c,v
retrieving revision 1.18
diff -p -u -r1.18 mem.c
--- Src/mem.c	7 May 2011 19:32:57 -0000	1.18
+++ Src/mem.c	13 May 2011 23:18:31 -0000
@@ -123,6 +123,57 @@ static Heap heaps;
 
 static Heap fheap;
 
+#ifdef ZSH_HEAP_DEBUG
+/*
+ * The heap ID we'll allocate next.
+ *
+ * We'll avoid using 0 as that means zero-initialised memory
+ * containing a heap ID is (correctly) marked as invalid.
+ */
+static Heapid next_heap_id = (Heapid)1;
+
+/*
+ * The ID of the heap from which we last allocated heap memory.
+ * In theory, since we carefully avoid allocating heap memory during
+ * interrupts, after any call to zhalloc() or wrappers this should
+ * be the ID of the heap containing the memory just returned.
+ */
+/**/
+mod_export Heapid last_heap_id;
+
+/*
+ * Stack of heaps saved by new_heaps().
+ * Assumes old_heaps() will come along and restore it later
+ * (outputs an error if old_heaps() is called out of sequence).
+ */
+LinkList heaps_saved;
+
+/*
+ * Debugging verbosity.  This must be set from a debugger.
+ * An 'or' of bits from the enum heap_debug_verbosity.
+ */
+volatile int heap_debug_verbosity;
+
+/*
+ * Generate a heap identifier that's unique up to unsigned integer wrap.
+ *
+ * For the purposes of debugging we won't bother trying to make a
+ * heap_id globally unique, which would require checking all existing
+ * heaps every time we create an ID and still wouldn't do what we
+ * ideally want, which is to make sure the IDs of valid heaps are
+ * different from the IDs of no-longer-valid heaps.  Given that,
+ * we'll just assume that if we haven't tracked the problem when the
+ * ID wraps we're out of luck.  We could change the type to a long long
+ * if we wanted more room
+ */
+
+static Heapid
+new_heap_id(void)
+{
+    return next_heap_id++;
+}
+#endif
+
 /* Use new heaps from now on. This returns the old heap-list. */
 
 /**/
@@ -137,6 +188,15 @@ new_heaps(void)
     fheap = heaps = NULL;
     unqueue_signals();
 
+#ifdef ZSH_HEAP_DEBUG
+    if (heap_debug_verbosity & HDV_NEW) {
+	fprintf(stderr, "HEAP DEBUG: heap " HEAPID_FMT
+		" saved, new heaps created.\n", h->heap_id);
+    }
+    if (!heaps_saved)
+	heaps_saved = znewlinklist();
+    zpushnode(heaps_saved, h);
+#endif
     return h;
 }
 
@@ -152,6 +212,12 @@ old_heaps(Heap old)
     for (h = heaps; h; h = n) {
 	n = h->next;
 	DPUTS(h->sp, "BUG: old_heaps() with pushed heaps");
+#ifdef ZSH_HEAP_DEBUG
+	if (heap_debug_verbosity & HDV_FREE) {
+	    fprintf(stderr, "HEAP DEBUG: heap " HEAPID_FMT
+		    "freed in old_heaps().\n", h->heap_id);
+	}
+#endif
 #ifdef USE_MMAP
 	munmap((void *) h, h->size);
 #else
@@ -159,6 +225,21 @@ old_heaps(Heap old)
 #endif
     }
     heaps = old;
+#ifdef ZSH_HEAP_DEBUG
+    if (heap_debug_verbosity & HDV_OLD) {
+	fprintf(stderr, "HEAP DEBUG: heap " HEAPID_FMT
+		"restored.\n", heaps->heap_id);
+    }
+    {
+	Heap myold = heaps_saved ? getlinknode(heaps_saved) : NULL;
+	if (old != myold)
+	{
+	    fprintf(stderr, "HEAP DEBUG: invalid old heap " HEAPID_FMT
+		    ", expecting " HEAPID_FMT ".\n", old->heap_id,
+		    myold->heap_id);
+	}
+    }
+#endif
     fheap = NULL;
     unqueue_signals();
 }
@@ -174,6 +255,12 @@ switch_heaps(Heap new)
     queue_signals();
     h = heaps;
 
+#ifdef ZSH_HEAP_DEBUG
+    if (heap_debug_verbosity & HDV_SWITCH) {
+	fprintf(stderr, "HEAP DEBUG: heap temporarily switched from "
+		HEAPID_FMT " to " HEAPID_FMT ".\n", h->heap_id, new->heap_id);
+    }
+#endif
     heaps = new;
     fheap = NULL;
     unqueue_signals();
@@ -202,6 +289,15 @@ pushheap(void)
 	hs->next = h->sp;
 	h->sp = hs;
 	hs->used = h->used;
+#ifdef ZSH_HEAP_DEBUG
+	hs->heap_id = h->heap_id;
+	h->heap_id = new_heap_id();
+	if (heap_debug_verbosity & HDV_PUSH) {
+	    fprintf(stderr, "HEAP DEBUG: heap " HEAPID_FMT " pushed, new id is "
+		    HEAPID_FMT ".\n",
+		    hs->heap_id, h->heap_id);
+	}
+#endif
     }
     unqueue_signals();
 }
@@ -251,6 +347,22 @@ freeheap(void)
 	    if (!fheap && h->used < ARENA_SIZEOF(h))
 		fheap = h;
 	    hl = h;
+#ifdef ZSH_HEAP_DEBUG
+	    /*
+	     * As the free makes the heap invalid, give it a new
+	     * identifier.  We're not popping it, so don't use
+	     * the one in the heap stack.
+	     */
+	    {
+		Heapid new_id = new_heap_id();
+		if (heap_debug_verbosity & HDV_FREE) {
+		    fprintf(stderr, "HEAP DEBUG: heap " HEAPID_FMT
+			    " freed, new id is " HEAPID_FMT ".\n",
+			    h->heap_id, new_id);
+		}
+		h->heap_id = new_id;
+	    }
+#endif
 	} else {
 #ifdef USE_MMAP
 	    munmap((void *) h, h->size);
@@ -291,6 +403,14 @@ popheap(void)
 	    memset(arena(h) + hs->used, 0xff, h->used - hs->used);
 #endif
 	    h->used = hs->used;
+#ifdef ZSH_HEAP_DEBUG
+	    if (heap_debug_verbosity & HDV_POP) {
+		fprintf(stderr, "HEAP DEBUG: heap " HEAPID_FMT
+			" popped, old heap was " HEAPID_FMT ".\n",
+			h->heap_id, hs->heap_id);
+	    }
+	    h->heap_id = hs->heap_id;
+#endif
 	    if (!fheap && h->used < ARENA_SIZEOF(h))
 		fheap = h;
 	    zfree(hs, sizeof(*hs));
@@ -393,6 +513,13 @@ zhalloc(size_t size)
 	    h->used = n;
 	    ret = arena(h) + n - size;
 	    unqueue_signals();
+#ifdef ZSH_HEAP_DEBUG
+	    last_heap_id = h->heap_id;
+	    if (heap_debug_verbosity & HDV_ALLOC) {
+		fprintf(stderr, "HEAP DEBUG: allocated memory from heap "
+			HEAPID_FMT ".\n", h->heap_id);
+	    }
+#endif
 	    return ret;
 	}
     }
@@ -424,6 +551,13 @@ zhalloc(size_t size)
 	h->used = size;
 	h->next = NULL;
 	h->sp = NULL;
+#ifdef ZSH_HEAP_DEBUG
+	h->heap_id = new_heap_id();
+	if (heap_debug_verbosity & HDV_CREATE) {
+	    fprintf(stderr, "HEAP DEBUG: create new heap " HEAPID_FMT ".\n",
+		    h->heap_id);
+	}
+#endif
 
 	if (hp)
 	    hp->next = h;
@@ -432,6 +566,13 @@ zhalloc(size_t size)
 	fheap = h;
 
 	unqueue_signals();
+#ifdef ZSH_HEAP_DEBUG
+	last_heap_id = h->heap_id;
+	if (heap_debug_verbosity & HDV_ALLOC) {
+	    fprintf(stderr, "HEAP DEBUG: allocated memory from heap "
+		    HEAPID_FMT ".\n", h->heap_id);
+	}
+#endif
 	return arena(h);
     }
 }
@@ -495,6 +636,9 @@ hrealloc(char *p, size_t old, size_t new
      * don't use the heap for anything else.)
      */
     if (p == arena(h)) {
+#ifdef ZSH_HEAP_DEBUG
+	Heapid heap_id = h->heap_id;
+#endif
 	/*
 	 * Zero new seems to be a special case saying we've finished
 	 * with the specially reallocated memory, see scanner() in glob.c.
@@ -554,6 +698,9 @@ hrealloc(char *p, size_t old, size_t new
 		heaps = h;
 	}
 	h->used = new;
+#ifdef ZSH_HEAP_DEBUG
+	h->heap_id = heap_id;
+#endif
 	unqueue_signals();
 	return arena(h);
     }
@@ -576,6 +723,53 @@ hrealloc(char *p, size_t old, size_t new
     }
 }
 
+#ifdef ZSH_HEAP_DEBUG
+/*
+ * Check if heap_id is the identifier of a currently valid heap,
+ * including any heap buried on the stack, or of permanent memory.
+ * Return 0 if so, else 1.
+ *
+ * This gets confused by use of switch_heaps().  That's because so do I.
+ */
+
+/**/
+mod_export int
+memory_validate(Heapid heap_id)
+{
+    Heap h;
+    Heapstack hs;
+    LinkNode node;
+
+    if (heap_id == HEAPID_PERMANENT)
+	return 0;
+
+    queue_signals();
+    for (h = heaps; h; h = h->next) {
+	if (h->heap_id == heap_id)
+	    return 0;
+	for (hs = heaps->sp; hs; hs = hs->next) {
+	    if (hs->heap_id == heap_id)
+		return 0;
+	}
+    }
+
+    if (heaps_saved) {
+	for (node = firstnode(heaps_saved); node; incnode(node)) {
+	    for (h = (Heap)getdata(node); h; h = h->next) {
+		if (h->heap_id == heap_id)
+		    return 0;
+		for (hs = heaps->sp; hs; hs = hs->next) {
+		    if (hs->heap_id == heap_id)
+			return 0;
+		}
+	    }
+	}
+    }
+
+    return 1;
+}
+#endif
+
 /* allocate memory from the current memory pool and clear it */
 
 /**/
Index: Src/zsh.h
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/zsh.h,v
retrieving revision 1.174
diff -p -u -r1.174 zsh.h
--- Src/zsh.h	19 Jan 2011 12:42:53 -0000	1.174
+++ Src/zsh.h	13 May 2011 23:18:31 -0000
@@ -2327,11 +2327,67 @@ enum {
  * Memory management *
  *********************/
 
+#ifdef ZSH_HEAP_DEBUG
+/*
+ * A Heapid is a type for identifying, uniquely up to the point where
+ * the count of new identifiers wraps. all heaps that are or
+ * (importantly) have been valid.  Each valid heap is given an
+ * identifier, and every time we push a heap we save the old identifier
+ * and give the heap a new identifier so that when the heap is popped
+ * or freed we can spot anything using invalid memory from the popped
+ * heap.
+ *
+ * We could make this unsigned long long if we wanted a big range.
+ */
+typedef unsigned int Heapid;
+
+/* printf format specifier corresponding to Heapid */
+#define HEAPID_FMT	"%x"
+
+/* Marker that memory is permanently allocated */
+#define HEAPID_PERMANENT (UINT_MAX)
+
+/*
+ * Heap debug verbosity.
+ * Bits to be 'or'ed into the variable also called heap_debug_verbosity.
+ */
+enum heap_debug_verbosity {
+    /* Report when we push a heap */
+    HDV_PUSH = 0x01,
+    /* Report when we pop a heap */
+    HDV_POP = 0x02,
+    /* Report when we create a new heap from which to allocate */
+    HDV_CREATE = 0x04,
+    /* Report every time we free a complete heap */
+    HDV_FREE = 0x08,
+    /* Report when we temporarily install a new set of heaps */
+    HDV_NEW = 0x10,
+    /* Report when we restore an old set of heaps */
+    HDV_OLD = 0x20,
+    /* Report when we temporarily switch heaps */
+    HDV_SWITCH = 0x40,
+    /*
+     * Report every time we allocate memory from the heap.
+     * This is very verbose, and arguably not very useful: we
+     * would expect to allocate memory from a heap we create.
+     * For much debugging heap_debug_verbosity = 0x7f should be sufficient.
+     */
+    HDV_ALLOC = 0x80
+};
+
+#define HEAP_ERROR(heap_id)			\
+    fprintf(stderr, "%s:%d: HEAP DEBUG: invalid heap: " HEAPID_FMT ".\n", \
+	    __FILE__, __LINE__, heap_id)
+#endif
+
 /* heappush saves the current heap state using this structure */
 
 struct heapstack {
     struct heapstack *next;	/* next one in list for this heap */
     size_t used;
+#ifdef ZSH_HEAP_DEBUG
+    Heapid heap_id;
+#endif
 };
 
 /* A zsh heap. */
@@ -2342,6 +2398,10 @@ struct heap {
     size_t used;		/* bytes used from the heap                  */
     struct heapstack *sp;	/* used by pushheap() to save the value used */
 
+#ifdef ZSH_HEAP_DEBUG
+    unsigned int heap_id;
+#endif
+
 /* Uncomment the following if the struct needs padding to 64-bit size. */
 /* Make sure sizeof(heap) is a multiple of 8 
 #if defined(PAD_64_BIT) && !defined(__GNUC__)
Index: Src/Zle/comp.h
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/comp.h,v
retrieving revision 1.20
diff -p -u -r1.20 comp.h
--- Src/Zle/comp.h	9 May 2011 09:49:09 -0000	1.20
+++ Src/Zle/comp.h	13 May 2011 23:18:31 -0000
@@ -76,6 +76,9 @@ struct cmgroup {
     int totl;			/* total length */
     int shortest;		/* length of shortest match */
     Cmgroup perm;		/* perm. alloced version of this group */
+#ifdef ZSH_HEAP_DEBUG
+    Heapid heap_id;
+#endif
 };
 
 
Index: Src/Zle/compcore.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/compcore.c,v
retrieving revision 1.105
diff -p -u -r1.105 compcore.c
--- Src/Zle/compcore.c	18 Feb 2011 22:08:46 -0000	1.105
+++ Src/Zle/compcore.c	13 May 2011 23:18:31 -0000
@@ -405,6 +405,11 @@ do_completion(UNUSED(Hookdef dummy), Com
 	} else if (nmatches == 1 || (nmatches > 1 && !diffmatches)) {
 	    /* Only one match. */
 	    Cmgroup m = amatches;
+#ifdef ZSH_HEAP_DEBUG
+	    if (memory_validate(m->heap_id)) {
+		HEAP_ERROR(m->heap_id);
+	    }
+#endif
 
 	    while (!m->mcount)
 		m = m->next;
@@ -509,6 +514,11 @@ after_complete(UNUSED(Hookdef dummy), in
 	int ret;
 
 	cdat.matches = amatches;
+#ifdef ZSH_HEAP_DEBUG
+	if (memory_validate(cdat.matches->heap_id)) {
+	    HEAP_ERROR(cdat.matches->heap_id);
+	}
+#endif
 	cdat.num = nmatches;
 	cdat.nmesg = nmessages;
 	cdat.cur = NULL;
@@ -987,6 +997,11 @@ makecomplist(char *s, int incmd, int lst
 	    diffmatches = odm;
 	    validlist = 1;
 	    amatches = lastmatches;
+#ifdef ZSH_HEAP_DEBUG
+	    if (memory_validate(amatches->heap_id)) {
+		HEAP_ERROR(amatches->heap_id);
+	    }
+#endif
 	    lmatches = lastlmatches;
 	    if (pmatches) {
 		freematches(pmatches, 1);
@@ -2959,6 +2974,11 @@ begcmgroup(char *n, int flags)
 	Cmgroup p = amatches;
 
 	while (p) {
+#ifdef ZSH_HEAP_DEBUG
+	    if (memory_validate(p->heap_id)) {
+		HEAP_ERROR(p->heap_id);
+	    }
+#endif
 	    if (p->name &&
 		flags == (p->flags & (CGF_NOSORT|CGF_UNIQALL|CGF_UNIQCON)) &&
 		!strcmp(n, p->name)) {
@@ -2975,6 +2995,9 @@ begcmgroup(char *n, int flags)
 	}
     }
     mgroup = (Cmgroup) zhalloc(sizeof(struct cmgroup));
+#ifdef ZSH_HEAP_DEBUG
+    mgroup->heap_id = last_heap_id;
+#endif
     mgroup->name = dupstring(n);
     mgroup->lcount = mgroup->llcount = mgroup->mcount = mgroup->ecount = 
 	mgroup->ccount = 0;
@@ -3295,6 +3318,11 @@ permmatches(int last)
 	fi = 1;
     }
     while (g) {
+#ifdef ZSH_HEAP_DEBUG
+	if (memory_validate(g->heap_id)) {
+	    HEAP_ERROR(g->heap_id);
+	}
+#endif
 	if (fi != ofi || !g->perm || g->new) {
 	    if (fi)
 		/* We have no matches, try ignoring fignore. */
@@ -3323,6 +3351,9 @@ permmatches(int last)
 		diffmatches = 1;
 
 	    n = (Cmgroup) zshcalloc(sizeof(struct cmgroup));
+#ifdef ZSH_HEAP_DEBUG
+	    n->heap_id = HEAPID_PERMANENT;
+#endif
 
 	    if (g->perm) {
 		g->perm->next = NULL;
Index: Src/Zle/compctl.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/compctl.c,v
retrieving revision 1.40
diff -p -u -r1.40 compctl.c
--- Src/Zle/compctl.c	14 Dec 2010 10:35:39 -0000	1.40
+++ Src/Zle/compctl.c	13 May 2011 23:18:31 -0000
@@ -1838,6 +1838,11 @@ ccmakehookfn(UNUSED(Hookdef dummy), stru
 	    diffmatches = odm;
 	    validlist = 1;
 	    amatches = lastmatches;
+#ifdef ZSH_HEAP_DEBUG
+	    if (memory_validate(amatches->heap_id)) {
+		HEAP_ERROR(amatches->heap_id);
+	    }
+#endif
 	    lmatches = lastlmatches;
 	    if (pmatches) {
 		freematches(pmatches, 1);
Index: Src/Zle/complist.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/complist.c,v
retrieving revision 1.125
diff -p -u -r1.125 complist.c
--- Src/Zle/complist.c	9 May 2011 09:49:09 -0000	1.125
+++ Src/Zle/complist.c	13 May 2011 23:18:32 -0000
@@ -1363,6 +1363,11 @@ compprintlist(int showall)
     while (g) {
 	char **pp = g->ylist;
 
+#ifdef ZSH_HEAP_DEBUG
+	if (memory_validate(g->heap_id)) {
+	    HEAP_ERROR(g->heap_id);
+	}
+#endif
 	if ((e = g->expls)) {
 	    int l;
 
@@ -1952,6 +1957,11 @@ complistmatches(UNUSED(Hookdef dummy), C
     Cmgroup oamatches = amatches;
 
     amatches = dat->matches;
+#ifdef ZSH_HEAP_DEBUG
+    if (memory_validate(amatches->heap_id)) {
+	HEAP_ERROR(amatches->heap_id);
+    }
+#endif
 
     noselect = 0;
 
@@ -2640,6 +2650,11 @@ domenuselect(Hookdef dummy, Chdata dat)
 	    s->mlbeg = mlbeg;
 	    memcpy(&(s->info), &minfo, sizeof(struct menuinfo));
 	    s->amatches = amatches;
+#ifdef ZSH_HEAP_DEBUG
+	    if (memory_validate(amatches->heap_id)) {
+		HEAP_ERROR(amatches->heap_id);
+	    }
+#endif
 	    s->pmatches = pmatches;
 	    s->lastmatches = lastmatches;
 	    s->lastlmatches = lastlmatches;
@@ -2835,6 +2850,11 @@ domenuselect(Hookdef dummy, Chdata dat)
 		if (lastmatches)
 		    freematches(lastmatches, 0);
 		amatches = u->amatches;
+#ifdef ZSH_HEAP_DEBUG
+		if (memory_validate(amatches->heap_id)) {
+		    HEAP_ERROR(amatches->heap_id);
+		}
+#endif
 		pmatches = u->pmatches;
 		lastmatches = u->lastmatches;
 		lastlmatches = u->lastlmatches;
Index: Src/Zle/compresult.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/compresult.c,v
retrieving revision 1.81
diff -p -u -r1.81 compresult.c
--- Src/Zle/compresult.c	9 May 2011 09:49:09 -0000	1.81
+++ Src/Zle/compresult.c	13 May 2011 23:18:32 -0000
@@ -906,7 +906,14 @@ do_allmatches(UNUSED(int end))
 
     for (minfo.group = amatches;
 	 minfo.group && !(minfo.group)->mcount;
-	 minfo.group = (minfo.group)->next);
+	 minfo.group = (minfo.group)->next) {
+#ifdef ZSH_HEAP_DEBUG
+	if (memory_validate(minfo.group->heap_id)) {
+	    HEAP_ERROR(minfo.group->heap_id);
+	}
+#endif
+    }
+
 
     mc = (minfo.group)->matches;
 
@@ -1172,6 +1179,11 @@ do_single(Cmatch m)
 	struct chdata dat;
 
 	dat.matches = amatches;
+#ifdef ZSH_HEAP_DEBUG
+	if (memory_validate(dat.matches->heap_id)) {
+	    HEAP_ERROR(dat.matches->heap_id);
+	}
+#endif
 	dat.num = nmatches;
 	dat.cur = m;
 
@@ -1210,8 +1222,14 @@ do_menucmp(int lst)
     do {
 	if (!*++(minfo.cur)) {
 	    do {
-		if (!(minfo.group = (minfo.group)->next))
+		if (!(minfo.group = (minfo.group)->next)) {
 		    minfo.group = amatches;
+#ifdef ZSH_HEAP_DEBUG
+		    if (memory_validate(minfo.group->heap_id)) {
+			HEAP_ERROR(minfo.group->heap_id);
+		    }
+#endif
+		}
 	    } while (!(minfo.group)->mcount);
 	    minfo.cur = minfo.group->matches;
 	}
@@ -1291,12 +1309,18 @@ accept_last(void)
 	    Cmgroup g;
 	    Cmatch *m;
 
-	    for (g = amatches, m = NULL; g && (!m || !*m); g = g->next)
+	    for (g = amatches, m = NULL; g && (!m || !*m); g = g->next) {
+#ifdef ZSH_HEAP_DEBUG
+		if (memory_validate(g->heap_id)) {
+		    HEAP_ERROR(g->heap_id);
+		}
+#endif
 		for (m = g->matches; *m; m++)
 		    if (!hasbrpsfx(*m, minfo.prebr, minfo.postbr)) {
 			showinglist = -2;
 			break;
 		    }
+	    }
 	}
     }
     menuacc++;
@@ -1381,7 +1405,13 @@ do_ambig_menu(void)
 	insgnum = comp_mod(insgnum, lastpermgnum);
 	for (minfo.group = amatches;
 	     minfo.group && (minfo.group)->num != insgnum + 1;
-	     minfo.group = (minfo.group)->next);
+	     minfo.group = (minfo.group)->next) {
+#ifdef ZSH_HEAP_DEBUG
+	    if (memory_validate(minfo.group->heap_id)) {
+		HEAP_ERROR(minfo.group->heap_id);
+	    }
+#endif
+	}
 	if (!minfo.group || !(minfo.group)->mcount) {
 	    minfo.cur = NULL;
 	    minfo.asked = 0;
@@ -1393,8 +1423,14 @@ do_ambig_menu(void)
 	insmnum = comp_mod(insmnum, lastpermmnum);
 	for (minfo.group = amatches;
 	     minfo.group && (minfo.group)->mcount <= insmnum;
-	     minfo.group = (minfo.group)->next)
+	     minfo.group = (minfo.group)->next) {
 	    insmnum -= (minfo.group)->mcount;
+#ifdef ZSH_HEAP_DEBUG
+	    if (memory_validate(minfo.group->heap_id)) {
+		HEAP_ERROR(minfo.group->heap_id);
+	    }
+#endif
+	}
 	if (!minfo.group) {
 	    minfo.cur = NULL;
 	    minfo.asked = 0;
@@ -1483,6 +1519,11 @@ calclist(int showall)
 	int nl = 0, l, glong = 1, gshort = zterm_columns, ndisp = 0, totl = 0;
         int hasf = 0;
 
+#ifdef ZSH_HEAP_DEBUG
+	if (memory_validate(g->heap_id)) {
+	    HEAP_ERROR(g->heap_id);
+	}
+#endif
 	g->flags |= CGF_PACKED | CGF_ROWS;
 
 	if (!onlyexpl && pp) {
@@ -1624,6 +1665,11 @@ calclist(int showall)
 	for (g = amatches; g; g = g->next) {
 	    glines = 0;
 
+#ifdef ZSH_HEAP_DEBUG
+	    if (memory_validate(g->heap_id)) {
+		HEAP_ERROR(g->heap_id);
+	    }
+#endif
 	    zfree(g->widths, 0);
 	    g->widths = NULL;
 
@@ -1858,6 +1904,11 @@ calclist(int showall)
     else
 	for (g = amatches; g; g = g->next)
 	{
+#ifdef ZSH_HEAP_DEBUG
+	    if (memory_validate(g->heap_id)) {
+		HEAP_ERROR(g->heap_id);
+	    }
+#endif
 	    zfree(g->widths, 0);
 	    g->widths = NULL;
 	}
@@ -1945,6 +1996,11 @@ printlist(int over, CLPrintFunc printm, 
     for (g = amatches; g; g = g->next) {
 	char **pp = g->ylist;
 
+#ifdef ZSH_HEAP_DEBUG
+	if (memory_validate(g->heap_id)) {
+	    HEAP_ERROR(g->heap_id);
+	}
+#endif
 	if ((e = g->expls)) {
 	    int l;
 
@@ -2144,7 +2200,13 @@ bld_all_str(Cmatch all)
 
     buf[0] = '\0';
 
-    for (g = amatches; g && !g->mcount; g = g->next);
+    for (g = amatches; g && !g->mcount; g = g->next) {
+#ifdef ZSH_HEAP_DEBUG
+	if (memory_validate(g->heap_id)) {
+	    HEAP_ERROR(g->heap_id);
+	}
+#endif
+    }
 
     mp = g->matches;
     while (1) {
@@ -2262,6 +2324,11 @@ list_matches(UNUSED(Hookdef dummy), UNUS
 #endif
 
     dat.matches = amatches;
+#ifdef ZSH_HEAP_DEBUG
+    if (memory_validate(dat.matches->heap_id)) {
+	HEAP_ERROR(dat.matches->heap_id);
+    }
+#endif
     dat.num = nmatches;
     dat.cur = NULL;
     ret = runhookdef(COMPLISTMATCHESHOOK, (void *) &dat);

-- 
Peter Stephenson <p.w.stephenson@xxxxxxxxxxxx>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/



Messages sorted by: Reverse Date, Date, Thread, Author