Realloc hängt sicch auf



  • Ich habe mir selber eine realloc Funktion gechrieben aber die hängt sich auf. Der Code von malloc und free funktioniert sonst aber gut.
    Könnnt ihr mir helfen?

    #include <string.h>
    
    /* Memory pool struct */
    struct __mp__  
    { 
      struct __mp__ *next;	/* singly linked list */
      unsigned long len;  		/* length of following block */
    };
    
    /* Memory Pool Head */
    void *__mpool__;    
    
    void __init_mempool (void *pool, unsigned long size)
    {
    	__mpool__ = pool;
    	((struct __mp__ *) pool)->next = 0;
    	((struct __mp__ *) pool)->len = size - sizeof(struct __mp__);
    }
    
    void *__malloc (unsigned long size)
    {
    	struct __mp__ *q;  /* ptr to free block */
    	struct __mp__ *p;  /* q->next */
    	unsigned long k;       /* space remaining in the allocated block */
    
    	/*  Make sure that block is word aligned                                    */
    	size = (unsigned long)((size + 1) & ~1L);
    
    	/*  Initialization:  Q is the pointer to the next available block.          */
      	q = (struct __mp__ *) &__mpool__;
    
    	/*  End-Of-List:  P points to the next block.  If that block DNE (P==NULL),
     		we are at the end of the list.
       	*/
    	while (1)
     	{
      		p = q->next;
        	if (!p)  
    			return 0; /* FAILURE */
    
    		/*  Found Space:  If block is large enough, reserve if.  Otherwise, copy P
     			to Q and try the next free block.
        	*/
       		if (p->len >= size)
    	    	break;
        	q = p;
    	}
    
    	/*  Reserve P:  Use at least part of the P block to satisfy the allocation
     		request.  At this time, the following pointers are setup:
     		P points to the block from which we allocate Q->next points to P
       	*/
    	k = p->len - size;            /* calc. remaining bytes in block */
      	if (k < (sizeof(struct __mp__) * 4))
        {         
    		/* rem. bytes too small for new block */
        	q->next = p->next;
        	return &p[1];                 /* SUCCESS */
    	}
    
    	/*  Split P Block:  If P is larger than we need, we split P into two blocks:
     		the leftover space and the allocated space.  That means, we need to 
     		create a header in the allocated space.
       	*/
    	k -= sizeof(struct __mp__);
    	p->len = k;
    	q = (struct __mp__ *) (((char *) (&p[1])) + k);
      	q->len = size;
      	return &q[1];           /* SUCCESS */
    }
    
    void __free (void *memp)  
    {
    	struct __mp__ *q;                  /* ptr to free block */
    	struct __mp__ *p;                  /* q->next */
    
    	/*  If the user tried to free NULL, get out now.  Otherwise, get the address
     		of the header of the memp block (P0).  Then, try to locate Q and P such
     		that Q < P0 < P.
       	*/
      	if (!memp)
        	return;
    	/* get address of header */
    	memp = &((struct __mp__ *) memp)[-1];              
    
    	/*  Initialize.  Q = Location of first available block. */
      	q = __mpool__;
      	if (!q)
        {
        	__mpool__ =((struct __mp__ *) memp);
        	return;
    	}
    
    	/*  Advance P. Hop through the list until we find a free block that is
     		located in memory AFTER the block we're trying to free.
       	*/
      	while (1)
        {
        	p = q->next;
        	if (!p || ((void*)p > (void*)memp))
    	    	break;
        	q = p;
      	}
    
    	/*  Check upper bound. If P0 and P are contiguous, merge block P into
     		block P0.
    	*/
    	if (p && ((((char *)((struct __mp__ *) memp)) + 
    		((struct __mp__ *) memp)->len + sizeof (struct __mp__)) == (char *) p))
     	{
        	((struct __mp__ *) memp)->len += p->len + sizeof (struct __mp__);
        	((struct __mp__ *) memp)->next = p->next;
    	}
      	else
    		((struct __mp__ *) memp)->next = p;
    
    	/*  Check lower bound. If Q and P0 are contiguous, merge P0 into Q.  */
      	if ((((char *)q) + q->len + sizeof (struct __mp__)) == (char *)((struct __mp__ *) memp))
        {
        	q->len += ((struct __mp__ *) memp)->len + sizeof (struct __mp__);
        	q->next = ((struct __mp__ *) memp)->next;
      	}
      	else
        	q->next = ((struct __mp__ *) memp);
    }
    
    void *__realloc (void *p_old, unsigned long new_len)
    {
        struct __mp__ *mp;
        unsigned long old_len;
        void *p_new;
    
        if (p_old == 0)
            return __malloc (new_len);
    
        mp = &((struct __mp__ *)p_old)[-1];
        old_len = mp->len;
    
        p_new = __malloc (new_len);
        if (p_new == 0)
            return 0;
    
        if (new_len >= old_len)
            memcpy (p_new, p_old, old_len);
        else
            memcpy (p_new, p_old, new_len);
    
        __free (p_old);
    
        return p_new;
    }
    
    ///////////////////////////////////////////////////////////////////////////
    
    #include <stdio.h>
    
    char mypool[1000];
    
    void main (void)
    {
        char *p;
        int s;
    
        __init_mempool (mypool, sizeof(mypool));
    
        p = __malloc (100);
        for (s=0; s<100; s++)
            p[s] = (char)s;
    
        p = __realloc (p, 5);  /* Hier stürzt er ab */
        for (s=0; s<5; s++)
            printf ("%d\n", p[s]);
    
    }
    


  • Benutze nen Debugger wie gdb. Ich habe selten so nen unleserlichen Code gesehen bzw. wo man als Nicht-Ersteller so Probleme hat, da reinzufinden.



  • Ich habe deinen Code bei mir kompiliert und er läuft sauber bei mir durch.
    Ob er auch das tut, was er soll, weiß ich nicht.
    Ich befürchte mal, du musst bei dir mit nen Debugger ran.

    Gruß mcr



  • Der Code sieht eher so aus, als wäre er von jemanden einfach nur kopiert worden (da die Library-Hersteller ihren Code häufig so "verschönern"), insbesondere wegen den 2 Unterstrichen, da diese reserviert sind.



  • Hallo, ich habe den Code unter Windows compiliert und er läuft auch. Auf meinen C167 will es nicht??? OK. Dann muß ich irgendwie weiter sehen. Danke dass ihr euch das angesehen habt.



  • hi,
    ich dachte, das wär' was für meine sammlung, aber deine __malloc/__free funzen nicht richtig (haben ein speicherleck eingebaut). das wird wohl der grund sein, warum dein 'realloc' auch nicht will, obwohl es (oberflächlich betrachtet) richtig aussieht.
    🙂



  • dein Code ist grauenhaft, hab mir nur ein wenig durchgelsen und mir ist folgendes aufgefallen:

    1. tests wie if(ptr == 0) finde ich schlecht, denn NULL muss nicht zwangsläufig 0 entsprechen. if(ptr == NULL) ist besser. Dasselbe gilt für return NULL statt return 0... eine häßliche Angewohnheit, die ich sehr oft sehe.

    2. du benutzt __realloc falsch, wenn __realloc NULL zurückliefert, dann verlierst du einen Zeiger und du merkst es nicht.

    char *p, *tmp;
    ...
    tmp = __realloc(p, 5);
    
    if(tmp == NULL)
    {
        fprintf(stder, "....");
        __free(p);
        return 1;
    }
    
    p = tmp;
    for (s=0; s<5; s++)
        printf ("%d\n", p[s]);
    

    wir sind leider keine debugger, ich denke, mit einem debugger wirst du schlauer werden als mit uns 😉



  • @supertux: du beanstandest den testcode. der wurm steckt aber in den allocator funktionen selber. entweder ein problem mit der linked list oder irgendwas alignment-spezifisches. jedenfalls wird der speicher bei wiederholtem __malloc/__free immer kleiner.
    @bernd: ich stückele dir nachher mal (vielleicht) 'nen code zusammen von einem heap, der bei mir immer gut funzte.
    🙂



  • wie versprochen...
    der code sieht zwar auch grausam aus, aber der tut's 😉

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    /*---------------------------------------------------------------------------------
      MEMORY MANAGEMENT:
      Header Files: stdlib.h
                    heap.h
      Functions   : calloc
                    free
                    malloc
                    realloc
                    _heapcrash_
      Defines     : LIBDEF_FAR_HEAP_DATA  (0 (default) or 1)
                    LIBDEF_HEAPSIZE       (default 2000)
      Data Segment: HEAP_SEGMENT          far if LIBDEF_FAR_HEAP_DATA is 1
      Code Segment: DEFAULT
      ---------------------------------------------------------------------------------*/
    
    #define LIBDEF_HEAPSIZE 1000  /* Adjust to your requirements, nofBytes = LIBDEF_HEAPSIZE,                                 must be multipe of 4!  */
    
    /*****************************************************
          heap.h - ANSI-C library: heap definition
     ----------------------------------------------------
       Copyright (c) HIWARE AG, Basel, Switzerland
                   All rights reserved
                      Do not modify!
     *****************************************************/
    
    #define  ERR_HEAP_ALLOC  1  /* free-list distroyed; found while allocating */
    #define  ERR_HEAP_FREE   2  /* freeing already freed or distroyed block   */
    #define  ERR_HEAP_RANGE  3  /* freeing block outside of pool               */
    #define  ERR_HEAP_REALL  4  /* free list crashed; found while reallocating */
    
    unsigned char _heap_[LIBDEF_HEAPSIZE];
    
    void _heapcrash_(void *where, int cause)
    {
        printf ("HEAP CRASHED!!!!!!!!!!!");
    }
    
    /*****************************************************
         alloc.c - ANSI-C library: memory management
     ----------------------------------------------------
       Copyright (c) HIWARE AG, Basel, Switzerland
                   All rights reserved
                      Do not modify!
     *****************************************************/
    
    typedef struct _header *HeaderPtr;
    
    #define DIS_OPT_0 1
    
    #ifndef DIS_OPT_0
      #define DIS_OPT_0 0 /* use char/0/1 by default */
    #endif
    
    #ifndef DIS_OPT_1
      #define DIS_OPT_1 0
    #endif
    
    #ifndef DIS_OPT_2
      #define DIS_OPT_2 0
    #endif
    
    #ifndef DIS_OPT_3
      #define DIS_OPT_3 0
    #endif
    
    typedef struct _header {
    #if DIS_OPT_0
      unsigned int inuse;
    #else
      unsigned char inuse;
    #endif
      HeaderPtr next;
      size_t    size;
    } header;
    
    static HeaderPtr heap_end  = NULL; /* pointer */
    static HeaderPtr free_ptr  = NULL; /* pointer to free list */
    #if DIS_OPT_1
    static char HeapInitialized; /* initialized to zero */
    #endif
    
    #if DIS_OPT_0
    #define FREE 0x7067
    #define USED 0x5047
    #else
    #define FREE 0
    #define USED 1
    #endif
    
    /*****************************************************/
    void *Xmalloc (size_t nbytes) {
      size_t nunits;
      HeaderPtr p, pl;
    
      if (nbytes == 0) {
        return NULL;
      }
    #if DIS_OPT_1
      if (!HeapInitialized) { /* first call to malloc, init heap first block */
        _heap_[0] = LIBDEF_HEAPSIZE; /* the free block has the size of the heap */
        HeapInitialized = 1;
      }
    #endif
      nunits = ( ( nbytes + sizeof(header) -1 ) / sizeof(header) ) + 1;
    #if DIS_OPT_1
      if ( (heap_end == NULL) && (free_ptr == NULL) ) {
    #else
      if (heap_end == NULL) {
    #endif
        /* setup heap */
        free_ptr        = (header *) &_heap_[0];
    #if DIS_OPT_1
        free_ptr->size  = _heap_[0] / sizeof(header);
    #else
        free_ptr->size  = LIBDEF_HEAPSIZE / sizeof(header);
    #endif
        free_ptr->next  = NULL;
        free_ptr->inuse = FREE;
        heap_end        = free_ptr + free_ptr->size - 1;
      }
      if (free_ptr == NULL) {
        return (NULL);     /* free list is empty; no more memory */
      } else {
        pl = NULL;
        p  = free_ptr;
        while (p != NULL) {
          if (p->size >= nunits) {
            if (p->size > nunits) {
              /* block is bigger, so break it */
              p[nunits].next  = p->next;           /* link to next free block */
              p[nunits].size  = p->size - nunits;  /* size of new free block  */
              p[nunits].inuse = FREE;
              p->size = nunits;                    /* new size of block       */
              p->next = p + nunits;                /* ptr to next free block  */
            }
            if (pl == NULL) {
              /* we use the first block */
              free_ptr = p->next;
            } else {
              pl->next = p->next;
            }
            if (p->inuse != FREE) {
              _heapcrash_(p, ERR_HEAP_ALLOC);
            }
            p->next  = NULL;
            p->inuse = USED;
            return (++p);
          }
          pl = p;
          p  = p->next;    /* next block */
        }
      }
      return (NULL);    /* All free blocks are to small */
    } /* end malloc */
    
    /*****************************************************/
    
    void Xfree(void *ap)
    {
      HeaderPtr p, pNext, pPrev, pEnd, pPrevEnd;
    
      if (ap == NULL) {
        return;
      }
      p = (HeaderPtr)ap; 
      --p;
      if ( (p < (HeaderPtr) &_heap_[0]) || (p > heap_end) ) {
        _heapcrash_(p, ERR_HEAP_RANGE);
        return;
      }
      if (p->inuse != USED) {
        _heapcrash_(p, ERR_HEAP_FREE);
      }
    
      p->inuse = FREE;
      p->next  = NULL;
    
      if ( free_ptr == NULL) {
        /* freelist is empty */
        free_ptr = p;
        return;
      }
    
      pNext = free_ptr;
      pPrev = NULL;
      while(pNext != NULL && pNext < p) {
        pPrev = pNext;
        pNext = pNext->next;
      } /* end while */
    
      pEnd = p + p->size;
    #if DIS_OPT_2
      if (pNext == pEnd && pNext != NULL) {
    #else
      if (pNext == pEnd /* && pNext != NULL : pNext cannot be NULL because it is equal to pEnd */) {
    #endif
      /* concatenate p and pNext */
        p->size += pNext->size;
        p->next  = pNext->next;
      } else if (pNext == p){
    #if DIS_OPT_2
        if (p->size > pNext->size) {
          pNext->size = p->size;
        }
    #else /* 'pNext == p' implies that 'p->size == pNext->size' */
        _heapcrash_(p, ERR_HEAP_FREE); /* block to be released was already in free list */
    #endif
      } else if (pEnd > pNext && pNext != NULL) {
    #if DIS_OPT_2
        p->size = pNext - p;
        p->next = pNext;
    #else
        _heapcrash_(p, ERR_HEAP_FREE); /* block to be released was completely contained in element in free list */
    #endif
      } else {
        p->next = pNext;
      }
      if (pPrev == NULL){
      /* p must be the first free block in the list */
        free_ptr = p;
        return;
      }
      pPrevEnd = pPrev + pPrev->size;
      if (p == pPrevEnd) {
      /* concatenate pPrev and p */
        pPrev->size += p->size;
        pPrev->next  = p->next;
        return;
      }
      if (pPrevEnd > p) {
    #if DIS_OPT_2
        if (pPrev->next < pEnd) {
          pPrev->next = p->next;
          pPrev->size = p - pPrev + p->size;
        }
    #else
        _heapcrash_(p, ERR_HEAP_FREE); /* start of block to be released was contained in element in free list */
    #endif
        return;
      }
      pPrev->next = p;
    } /* end free */
    
    /*****************************************************/
    
    void *Xcalloc (size_t n, size_t size)
    {
      void          *save;
    
      size = n*size;
      save = Xmalloc(size);
      if (save != NULL) {
    #if DIS_OPT_3
        unsigned char *LIBDEF_HEAP_DPTRQ rv;
        rv = save;
        while(size--) {
          *rv++ = 0;
        }
    #else
        (void)memset(save, 0, size);
    #endif
      }
      return (save);
    } /* end calloc */
    
    /*****************************************************/
    
    void *Xrealloc (void *ptr, size_t size)
    {
      size_t  nunits;
      HeaderPtr p, p1, p2;
      void     *rv;
    
      if (ptr == NULL) {
        return ( Xmalloc(size) );
      }
      if (size == 0) {
        Xfree(ptr);
        return (NULL);
      } else {
        /* calculate size of new block in allocation units */
        nunits = ( ( size + sizeof(header) -1 ) / sizeof(header) ) + 1;
    
        p = (HeaderPtr)ptr;
        --p;    /* get pointer to internal struct */
    
        if ( (p < (HeaderPtr) &_heap_[0]) || (p > heap_end) ) {
          _heapcrash_(p, ERR_HEAP_RANGE);
          return (NULL);
        }
    
        if (p->size == nunits) {
          return (ptr);    /* if new blocksizze == old; do nothing */
        }
        if (p->size > nunits) { /* if new block will be smaller, so break it */
          p[nunits].size  = p->size - nunits;    /* create new block */
          p[nunits].next  = NULL;
          p[nunits].inuse = USED;             /* mark it used */
    
          p->size = nunits;            /* resize old block */
    
          Xfree( p + nunits + 1);        /* free the new unused block */
    
          return (ptr);
        }
    
        if ( (p + p->size) < heap_end ) {
          /* this is not the last block in pool */
          p1 = p + p->size;        /* p1 = pointer to next block */
          if (p1->inuse == FREE) {
            /* the fallowing block is free !! */
            size = p1->size + p->size;  /* calculate size of cat-blocks */ 
    
            if  (size > nunits) { 
              /* the superblock will be to big, so break it */ 
    
              p2 = p + nunits;    /* p2 = pointer to new unused block */
    
              p2->next  = p1->next;        /* break block and link them */
              p2->size  = size - nunits;    /* together in the free list */
              p1->size -= p2->size;
              p2->inuse = FREE;
              p1->next  = p2;
    
              size = nunits;
            }
    
            if (size == nunits) {
              /* unlink the next block from the free list and concatenate */
              if (free_ptr == p1) {
                /* it's the first pointer in free list */
                free_ptr = p1->next;    /* unlink the block */
    
                p->size += p1->size;    /* adjust size */
                return (++p);
              }
    
              p2 = free_ptr;
              while (p2->next != NULL) {
                /* search the block */
                if (p2->next == p1) {
                  /* we found it */
                  p2->next = p1->next;    /* unlink the block */
    
                  p->size += p1->size;    /* adjust size */
                  return (++p);
                }
                p2 = p2->next;
              }
              _heapcrash_(p1, ERR_HEAP_REALL);
            }
          }
        }
    
        /* There was no way to adjust the block size in place.
           The only chance left is to allocate a new block.
          */
        rv =  Xmalloc(size);
        if (rv != NULL) {
          (void)memcpy(rv, ptr, size);
          Xfree(ptr);
        }
      }
      return (rv);
    } /* end realloc */
    
    //////////////////////////////////////////////////////
    
    // testing...
    int main ()
    {
    	for (;;)
    	{
    	   int a = 1+rand()%(LIBDEF_HEAPSIZE/2);
               int b = 1+rand()%(LIBDEF_HEAPSIZE/2);
               char *p = Xmalloc (a);
    	   char *q = Xmalloc (b);
    
               printf ("heapsize:%d %p(%d) %p(%d) sum==%d", LIBDEF_HEAPSIZE, p,a, q,b, a+b);
               if (p == 0 || q == 0)
                  printf (" -->FAIL");
    	   printf ("\n");
    
               Xfree (p);
    	   Xfree (q);
    	}
    }
    

    🙂



  • Online Debugger schrieb:

    @supertux: du beanstandest den testcode. der wurm steckt aber in den allocator funktionen selber. entweder ein problem mit der linked list oder irgendwas alignment-spezifisches. jedenfalls wird der speicher bei wiederholtem __malloc/__free immer kleiner.

    ich hab nur gesagt, dass ich mir *ein wenig* durchgelesen habe. Wo der Fehler liegt, weiß ich nicht, dazu hab ich mir den Code zu ungenau angeguckt.



  • supertux schrieb:

    Online Debugger schrieb:

    @supertux: du beanstandest den testcode. der wurm steckt aber in den allocator funktionen selber. entweder ein problem mit der linked list oder irgendwas alignment-spezifisches. jedenfalls wird der speicher bei wiederholtem __malloc/__free immer kleiner.

    ich hab nur gesagt, dass ich mir *ein wenig* durchgelesen habe. Wo der Fehler liegt, weiß ich nicht, dazu hab ich mir den Code zu ungenau angeguckt.

    is ja gut 😉 du musst dich nicht entschuldigen. ich weiss ja, dass für dich ein falscher realloc-aufruf ein rotes tuch ist.
    ich hab' den code des OP auch nicht auf herz und nieren debuggt, finde ihn aber recht interessant, weil er ziemlich schlank zu sein scheint. ich nehme an, er hat ihn aus einer 'libc' für embedded systeme, aber irgendwo hat er einen bug eingebaut.
    @Bernd: wo hast du den code her?


Anmelden zum Antworten