+ alloc.c: Kill hand-made memory allocation code, that is definitely buggy. Replace with simple wrapper around malloc, at least this works, and it's easier to debug anyways. + alloc.c: Don't allow alloc() and aresize() to fail. Their return value was only checked in two place (both in conjunction with str_save). Upon malloc/realloc failure we call internal_errorf() which pops throws and error and pops back to the last good state. Index: pdksh-5.2.14/alloc.c =================================================================== --- pdksh-5.2.14.orig/alloc.c 2008-04-15 20:46:56.000000000 +0200 +++ pdksh-5.2.14/alloc.c 2008-04-15 20:50:18.000000000 +0200 @@ -1,3 +1,5 @@ +#ifndef DEBIAN + /* * area-based allocation built on malloc/free */ @@ -110,6 +112,13 @@ Block *block; struct {int _;} junk; /* alignment */ double djunk; /* alignment */ +#ifdef DEBIAN /* patch from RedHat */ +#ifdef __ia64__ + /* IA64 requires 16 byte alignment for some objects, so make + * this the minimum allocation size */ + char ajunk[16]; +#endif +#endif }; struct Block { @@ -282,7 +291,9 @@ * working (as it assumes size < ICELLS means it is not * a `large object'). */ - if (oldcells > ICELLS && cells > ICELLS) { + if (oldcells > ICELLS && cells > ICELLS + && ((dp-2)->block->last == dp+oldcells) /* don't destroy blocks which have grown! */ + ) { Block *bp = (dp-2)->block; Block *nbp; /* Saved in case realloc fails.. */ @@ -332,7 +343,7 @@ * (need to check that cells < ICELLS so we don't make an * object a `large' - that would mess everything up). */ - if (dp && cells > oldcells && cells <= ICELLS) { + if (dp && cells > oldcells) { Cell *fp, *fpp; Block *bp = (dp-2)->block; int need = cells - oldcells - NOBJECT_FIELDS; @@ -363,7 +374,7 @@ * it to malloc...) * Note: this also handles cells == oldcells (a no-op). */ - if (dp && cells <= oldcells && oldcells <= ICELLS) { + if (dp && cells <= oldcells) { int split; split = oldcells - cells; @@ -411,7 +422,9 @@ /* If this is a large object, just free it up... */ /* Release object... */ - if ((dp-1)->size > ICELLS) { + if ((dp-1)->size > ICELLS + && (bp->last == dp + (dp-1)->size) /* don't free non-free blocks which have grown! */ + ) { ablockfree(bp, ap); ACHECK(ap); return; @@ -774,3 +787,127 @@ # endif /* TEST_ALLOC */ #endif /* MEM_DEBUG */ + +#else /* DEBIAN */ /* patch from OpenBSD */ + +/* $OpenBSD: alloc.c,v 1.6 2003/08/05 20:52:27 millert Exp $ */ +/* + * Copyright (c) 2002 Marc Espie. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD + * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * area-based allocation built on malloc/free + */ + +#include "sh.h" + +struct link { + struct link *prev; + struct link *next; +}; + +Area * +ainit(Area *ap) +{ + ap->freelist = NULL; + return ap; +} + +void +afreeall(Area *ap) +{ + struct link *l, *l2; + + for (l = ap->freelist; l != NULL; l = l2) { + l2 = l->next; + free(l); + } + ap->freelist = NULL; +} + +#define L2P(l) ( (void *)(((char *)(l)) + sizeof(struct link)) ) +#define P2L(p) ( (struct link *)(((char *)(p)) - sizeof(struct link)) ) + +void * +alloc(size_t size, Area *ap) +{ + struct link *l; + + l = malloc(size + sizeof(struct link)); + if (l == NULL) + internal_errorf(1, "unable to allocate memory"); + l->next = ap->freelist; + l->prev = NULL; + if (ap->freelist) + ap->freelist->prev = l; + ap->freelist = l; + + return L2P(l); +} + +void * +aresize(void *ptr, size_t size, Area *ap) +{ + struct link *l, *l2, *lprev, *lnext; + + if (ptr == NULL) + return alloc(size, ap); + + l = P2L(ptr); + lprev = l->prev; + lnext = l->next; + + l2 = realloc(l, size+sizeof(struct link)); + if (l2 == NULL) + internal_errorf(1, "unable to allocate memory"); + if (lprev) + lprev->next = l2; + else + ap->freelist = l2; + if (lnext) + lnext->prev = l2; + + return L2P(l2); +} + +void +afree(void *ptr, Area *ap) +{ + struct link *l; + + if (!ptr) + return; + + l = P2L(ptr); + + if (l->prev) + l->prev->next = l->next; + else + ap->freelist = l->next; + if (l->next) + l->next->prev = l->prev; + + free(l); +} +#endif /* DEBIAN */