From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 20489 invoked by alias); 13 May 2011 23:47:57 -0000 Mailing-List: contact zsh-workers-help@zsh.org; run by ezmlm Precedence: bulk X-No-Archive: yes List-Id: Zsh Workers List List-Post: List-Help: X-Seq: 29267 Received: (qmail 5341 invoked from network); 13 May 2011 23:47:50 -0000 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on f.primenet.com.au X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received-SPF: pass (ns1.primenet.com.au: SPF record at ntlworld.com designates 81.103.221.58 as permitted sender) Date: Sat, 14 May 2011 00:26:38 +0100 From: Peter Stephenson To: Subject: Re: Completion crash owing to bad allocation Message-ID: <20110514002638.25f25f45@pws-pc.ntlworld.com> In-Reply-To: <20110511150909.6fd6dda0@pwslap01u.europe.root.pri> References: <87sjsl2wqg.fsf@ft.bewatermyfriend.org> <20110511150909.6fd6dda0@pwslap01u.europe.root.pri> X-Mailer: Claws Mail 3.7.9 (GTK+ 2.22.0; x86_64-redhat-linux-gnu) Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable X-Cloudmark-Analysis: v=1.1 cv=JvdXmxIgLJv2/GthKqHpGJEEHukvLcvELVXUanXFreg= c=1 sm=0 a=1Cdr1P9wS_4A:10 a=uObrxnre4hsA:10 a=IkcTkHD0fZMA:10 a=4UtWO5riAAAA:8 a=NLZqzBF-AAAA:8 a=HRP0B9Wf3zddeVWcCcgA:9 a=Rq3ZVG2Qg7j0BL_UX1cA:7 a=QEXdDO2ut3YA:10 a=Shd8Sdw-9eQA:10 a=_dQi-Dcv4p4A:10 a=XwZdMCqxHJePR0cr:21 a=1NnG5EH5AVR69_EH:21 a=HpAAvcLHHh0Zw7uRqdWCyQ==:117 On Wed, 11 May 2011 15:09:09 +0100 Peter Stephenson 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=C3=A9nouement in the next episode. Index: configure.ac =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 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]) =20 +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 =3D 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 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 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; =20 static Heap fheap; =20 +#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 =3D (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. */ =20 /**/ @@ -137,6 +188,15 @@ new_heaps(void) fheap =3D heaps =3D NULL; unqueue_signals(); =20 +#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 =3D znewlinklist(); + zpushnode(heaps_saved, h); +#endif return h; } =20 @@ -152,6 +212,12 @@ old_heaps(Heap old) for (h =3D heaps; h; h =3D n) { n =3D 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 =3D 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 =3D heaps_saved ? getlinknode(heaps_saved) : NULL; + if (old !=3D myold) + { + fprintf(stderr, "HEAP DEBUG: invalid old heap " HEAPID_FMT + ", expecting " HEAPID_FMT ".\n", old->heap_id, + myold->heap_id); + } + } +#endif fheap =3D NULL; unqueue_signals(); } @@ -174,6 +255,12 @@ switch_heaps(Heap new) queue_signals(); h =3D heaps; =20 +#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 =3D new; fheap =3D NULL; unqueue_signals(); @@ -202,6 +289,15 @@ pushheap(void) hs->next =3D h->sp; h->sp =3D hs; hs->used =3D h->used; +#ifdef ZSH_HEAP_DEBUG + hs->heap_id =3D h->heap_id; + h->heap_id =3D 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 =3D h; hl =3D 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 =3D 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 =3D 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 =3D 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 =3D hs->heap_id; +#endif if (!fheap && h->used < ARENA_SIZEOF(h)) fheap =3D h; zfree(hs, sizeof(*hs)); @@ -393,6 +513,13 @@ zhalloc(size_t size) h->used =3D n; ret =3D arena(h) + n - size; unqueue_signals(); +#ifdef ZSH_HEAP_DEBUG + last_heap_id =3D 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 =3D size; h->next =3D NULL; h->sp =3D NULL; +#ifdef ZSH_HEAP_DEBUG + h->heap_id =3D new_heap_id(); + if (heap_debug_verbosity & HDV_CREATE) { + fprintf(stderr, "HEAP DEBUG: create new heap " HEAPID_FMT ".\n", + h->heap_id); + } +#endif =20 if (hp) hp->next =3D h; @@ -432,6 +566,13 @@ zhalloc(size_t size) fheap =3D h; =20 unqueue_signals(); +#ifdef ZSH_HEAP_DEBUG + last_heap_id =3D 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 =3D=3D arena(h)) { +#ifdef ZSH_HEAP_DEBUG + Heapid heap_id =3D 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 =3D h; } h->used =3D new; +#ifdef ZSH_HEAP_DEBUG + h->heap_id =3D heap_id; +#endif unqueue_signals(); return arena(h); } @@ -576,6 +723,53 @@ hrealloc(char *p, size_t old, size_t new } } =20 +#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 =3D=3D HEAPID_PERMANENT) + return 0; + + queue_signals(); + for (h =3D heaps; h; h =3D h->next) { + if (h->heap_id =3D=3D heap_id) + return 0; + for (hs =3D heaps->sp; hs; hs =3D hs->next) { + if (hs->heap_id =3D=3D heap_id) + return 0; + } + } + + if (heaps_saved) { + for (node =3D firstnode(heaps_saved); node; incnode(node)) { + for (h =3D (Heap)getdata(node); h; h =3D h->next) { + if (h->heap_id =3D=3D heap_id) + return 0; + for (hs =3D heaps->sp; hs; hs =3D hs->next) { + if (hs->heap_id =3D=3D heap_id) + return 0; + } + } + } + } + + return 1; +} +#endif + /* allocate memory from the current memory pool and clear it */ =20 /**/ Index: Src/zsh.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 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 * *********************/ =20 +#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 =3D 0x01, + /* Report when we pop a heap */ + HDV_POP =3D 0x02, + /* Report when we create a new heap from which to allocate */ + HDV_CREATE =3D 0x04, + /* Report every time we free a complete heap */ + HDV_FREE =3D 0x08, + /* Report when we temporarily install a new set of heaps */ + HDV_NEW =3D 0x10, + /* Report when we restore an old set of heaps */ + HDV_OLD =3D 0x20, + /* Report when we temporarily switch heaps */ + HDV_SWITCH =3D 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 =3D 0x7f should be sufficie= nt. + */ + HDV_ALLOC =3D 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 */ =20 struct heapstack { struct heapstack *next; /* next one in list for this heap */ size_t used; +#ifdef ZSH_HEAP_DEBUG + Heapid heap_id; +#endif }; =20 /* 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 */ =20 +#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=20 #if defined(PAD_64_BIT) && !defined(__GNUC__) Index: Src/Zle/comp.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 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 }; =20 =20 Index: Src/Zle/compcore.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 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 =3D=3D 1 || (nmatches > 1 && !diffmatches)) { /* Only one match. */ Cmgroup m =3D amatches; +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(m->heap_id)) { + HEAP_ERROR(m->heap_id); + } +#endif =20 while (!m->mcount) m =3D m->next; @@ -509,6 +514,11 @@ after_complete(UNUSED(Hookdef dummy), in int ret; =20 cdat.matches =3D amatches; +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(cdat.matches->heap_id)) { + HEAP_ERROR(cdat.matches->heap_id); + } +#endif cdat.num =3D nmatches; cdat.nmesg =3D nmessages; cdat.cur =3D NULL; @@ -987,6 +997,11 @@ makecomplist(char *s, int incmd, int lst diffmatches =3D odm; validlist =3D 1; amatches =3D lastmatches; +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(amatches->heap_id)) { + HEAP_ERROR(amatches->heap_id); + } +#endif lmatches =3D lastlmatches; if (pmatches) { freematches(pmatches, 1); @@ -2959,6 +2974,11 @@ begcmgroup(char *n, int flags) Cmgroup p =3D amatches; =20 while (p) { +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(p->heap_id)) { + HEAP_ERROR(p->heap_id); + } +#endif if (p->name && flags =3D=3D (p->flags & (CGF_NOSORT|CGF_UNIQALL|CGF_UNIQCON)) && !strcmp(n, p->name)) { @@ -2975,6 +2995,9 @@ begcmgroup(char *n, int flags) } } mgroup =3D (Cmgroup) zhalloc(sizeof(struct cmgroup)); +#ifdef ZSH_HEAP_DEBUG + mgroup->heap_id =3D last_heap_id; +#endif mgroup->name =3D dupstring(n); mgroup->lcount =3D mgroup->llcount =3D mgroup->mcount =3D mgroup->ecou= nt =3D=20 mgroup->ccount =3D 0; @@ -3295,6 +3318,11 @@ permmatches(int last) fi =3D 1; } while (g) { +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(g->heap_id)) { + HEAP_ERROR(g->heap_id); + } +#endif if (fi !=3D ofi || !g->perm || g->new) { if (fi) /* We have no matches, try ignoring fignore. */ @@ -3323,6 +3351,9 @@ permmatches(int last) diffmatches =3D 1; =20 n =3D (Cmgroup) zshcalloc(sizeof(struct cmgroup)); +#ifdef ZSH_HEAP_DEBUG + n->heap_id =3D HEAPID_PERMANENT; +#endif =20 if (g->perm) { g->perm->next =3D NULL; Index: Src/Zle/compctl.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 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 =3D odm; validlist =3D 1; amatches =3D lastmatches; +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(amatches->heap_id)) { + HEAP_ERROR(amatches->heap_id); + } +#endif lmatches =3D lastlmatches; if (pmatches) { freematches(pmatches, 1); Index: Src/Zle/complist.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 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 =3D g->ylist; =20 +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(g->heap_id)) { + HEAP_ERROR(g->heap_id); + } +#endif if ((e =3D g->expls)) { int l; =20 @@ -1952,6 +1957,11 @@ complistmatches(UNUSED(Hookdef dummy), C Cmgroup oamatches =3D amatches; =20 amatches =3D dat->matches; +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(amatches->heap_id)) { + HEAP_ERROR(amatches->heap_id); + } +#endif =20 noselect =3D 0; =20 @@ -2640,6 +2650,11 @@ domenuselect(Hookdef dummy, Chdata dat) s->mlbeg =3D mlbeg; memcpy(&(s->info), &minfo, sizeof(struct menuinfo)); s->amatches =3D amatches; +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(amatches->heap_id)) { + HEAP_ERROR(amatches->heap_id); + } +#endif s->pmatches =3D pmatches; s->lastmatches =3D lastmatches; s->lastlmatches =3D lastlmatches; @@ -2835,6 +2850,11 @@ domenuselect(Hookdef dummy, Chdata dat) if (lastmatches) freematches(lastmatches, 0); amatches =3D u->amatches; +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(amatches->heap_id)) { + HEAP_ERROR(amatches->heap_id); + } +#endif pmatches =3D u->pmatches; lastmatches =3D u->lastmatches; lastlmatches =3D u->lastlmatches; Index: Src/Zle/compresult.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 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)) =20 for (minfo.group =3D amatches; minfo.group && !(minfo.group)->mcount; - minfo.group =3D (minfo.group)->next); + minfo.group =3D (minfo.group)->next) { +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(minfo.group->heap_id)) { + HEAP_ERROR(minfo.group->heap_id); + } +#endif + } + =20 mc =3D (minfo.group)->matches; =20 @@ -1172,6 +1179,11 @@ do_single(Cmatch m) struct chdata dat; =20 dat.matches =3D amatches; +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(dat.matches->heap_id)) { + HEAP_ERROR(dat.matches->heap_id); + } +#endif dat.num =3D nmatches; dat.cur =3D m; =20 @@ -1210,8 +1222,14 @@ do_menucmp(int lst) do { if (!*++(minfo.cur)) { do { - if (!(minfo.group =3D (minfo.group)->next)) + if (!(minfo.group =3D (minfo.group)->next)) { minfo.group =3D 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 =3D minfo.group->matches; } @@ -1291,12 +1309,18 @@ accept_last(void) Cmgroup g; Cmatch *m; =20 - for (g =3D amatches, m =3D NULL; g && (!m || !*m); g =3D g->next) + for (g =3D amatches, m =3D NULL; g && (!m || !*m); g =3D g->next) { +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(g->heap_id)) { + HEAP_ERROR(g->heap_id); + } +#endif for (m =3D g->matches; *m; m++) if (!hasbrpsfx(*m, minfo.prebr, minfo.postbr)) { showinglist =3D -2; break; } + } } } menuacc++; @@ -1381,7 +1405,13 @@ do_ambig_menu(void) insgnum =3D comp_mod(insgnum, lastpermgnum); for (minfo.group =3D amatches; minfo.group && (minfo.group)->num !=3D insgnum + 1; - minfo.group =3D (minfo.group)->next); + minfo.group =3D (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 =3D NULL; minfo.asked =3D 0; @@ -1393,8 +1423,14 @@ do_ambig_menu(void) insmnum =3D comp_mod(insmnum, lastpermmnum); for (minfo.group =3D amatches; minfo.group && (minfo.group)->mcount <=3D insmnum; - minfo.group =3D (minfo.group)->next) + minfo.group =3D (minfo.group)->next) { insmnum -=3D (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 =3D NULL; minfo.asked =3D 0; @@ -1483,6 +1519,11 @@ calclist(int showall) int nl =3D 0, l, glong =3D 1, gshort =3D zterm_columns, ndisp =3D 0, totl= =3D 0; int hasf =3D 0; =20 +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(g->heap_id)) { + HEAP_ERROR(g->heap_id); + } +#endif g->flags |=3D CGF_PACKED | CGF_ROWS; =20 if (!onlyexpl && pp) { @@ -1624,6 +1665,11 @@ calclist(int showall) for (g =3D amatches; g; g =3D g->next) { glines =3D 0; =20 +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(g->heap_id)) { + HEAP_ERROR(g->heap_id); + } +#endif zfree(g->widths, 0); g->widths =3D NULL; =20 @@ -1858,6 +1904,11 @@ calclist(int showall) else for (g =3D amatches; g; g =3D g->next) { +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(g->heap_id)) { + HEAP_ERROR(g->heap_id); + } +#endif zfree(g->widths, 0); g->widths =3D NULL; } @@ -1945,6 +1996,11 @@ printlist(int over, CLPrintFunc printm,=20 for (g =3D amatches; g; g =3D g->next) { char **pp =3D g->ylist; =20 +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(g->heap_id)) { + HEAP_ERROR(g->heap_id); + } +#endif if ((e =3D g->expls)) { int l; =20 @@ -2144,7 +2200,13 @@ bld_all_str(Cmatch all) =20 buf[0] =3D '\0'; =20 - for (g =3D amatches; g && !g->mcount; g =3D g->next); + for (g =3D amatches; g && !g->mcount; g =3D g->next) { +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(g->heap_id)) { + HEAP_ERROR(g->heap_id); + } +#endif + } =20 mp =3D g->matches; while (1) { @@ -2262,6 +2324,11 @@ list_matches(UNUSED(Hookdef dummy), UNUS #endif =20 dat.matches =3D amatches; +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(dat.matches->heap_id)) { + HEAP_ERROR(dat.matches->heap_id); + } +#endif dat.num =3D nmatches; dat.cur =3D NULL; ret =3D runhookdef(COMPLISTMATCHESHOOK, (void *) &dat); --=20 Peter Stephenson Web page now at http://homepage.ntlworld.com/p.w.stephenson/