ADMB Documentation  Fournier-pthread.1088
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines
mem.cpp
Go to the documentation of this file.
00001 /*
00002  * $Id: mem.cpp 422 2012-04-12 23:02:36Z johnoel $
00003  *
00004  * Author: Walter Bright
00005  *
00006  * This in an early version of Walter Bright's MEM package originally
00007  * published in the March-April 1990 edition of Micro Cornucopia magazine.
00008  * The MEM package was freely distributed with the Zortech compiler.
00009  * Bright contributed an updated version of the MEM package to the
00010  * Public Domain. It can be downladed from http://snippets.snippets.org/
00011  */
00012 #include <stdio.h>
00013 #include  <stdlib.h>
00014 #ifndef EXIT_FAILURE
00015   #define EXIT_FAILURE 1
00016 #endif
00017 
00018 //#if defined(__NDPX__) || defined (__GNUDOS__) || defined(DOS386) || defined(__MSVC32__)
00019   #define NEAR
00020 //#else
00021 //  #define NEAR near
00022 //#endif
00023 
00024 #if defined (__WAT32__)
00025   #include <io.h>
00026 #endif
00027 
00028 //#else
00029   //extern void *malloc();
00030   //extern void *calloc();
00031   //extern void *realloc();
00032 //#endif
00033 
00034 #ifndef SAFE_MEM_H
00035   #include  "safe_mem.h"
00036 #endif
00037 
00038 #ifndef assert
00039   #include  <assert.h>
00040 #endif
00041 
00042 #if defined(__MSVC32__)
00043   #include  <dos.h>
00044 #endif
00045 
00046 #ifndef VAX11C
00047   #ifdef BSDUNIX
00048     #include <adstrings.h>
00049   #else
00050     #include <string.h>
00051   #endif
00052 #else
00053   extern char *strcpy(),*memcpy();
00054   extern int strlen();
00055 #endif  /* VAX11C */
00056 
00057 int mem_inited = 0;    /* != 0 if initialized      */
00058 
00059 static int mem_behavior = MEM_ABORTMSG;
00060 static int (*fp)(void) = NULL;  /* out-of-memory handler  */
00061 static int mem_count;    /* # of allocs that haven't been free'd  */
00062 static int mem_scount;    /* # of sallocs that haven't been free'd */
00063 
00064 /* Determine where to send error messages  */
00065 #if defined (MSDOS)
00066   #define ferr  stdout  /* stderr can't be redirected with MS-DOS  */
00067 #else
00068   #define ferr  stderr
00069 #endif
00070 
00071 /*******************************/
00072 
00073 void mem_setexception(
00074   #if __ZTC__ && __cplusplus
00075     enum MEM_E
00076   #else
00077     int
00078   #endif
00079   flag,
00080   int (*handler_fp)(void))
00081 {
00082     mem_behavior = flag;
00083     fp = (mem_behavior == MEM_CALLFP) ? handler_fp : 0;
00084 #if MEM_DEBUG
00085     assert(0 <= flag && flag <= MEM_RETRY);
00086 #endif
00087 }
00088 
00089 /*************************
00090  * This is called when we're out of memory.
00091  * Returns:
00092  *  1:  try again to allocate the memory
00093  *  0:  give up and return NULL
00094  */
00095 
00096 static int NEAR mem_exception()
00097 {
00098     int behavior;
00099 
00100     behavior = mem_behavior;
00101     while (1)
00102     {
00103       switch (behavior)
00104       {
00105       case MEM_ABORTMSG:
00106       #if defined (MSDOS) || defined (__OS2__)
00107     /* Avoid linking in buffered I/O */
00108         {  
00109           static char msg[] = "Fatal error: out of memory\r\n";
00110           write(1,msg,sizeof(msg) - 1);
00111         }
00112       #else
00113         fputs("Fatal error: out of memory\n",ferr);
00114       #endif
00115     /* FALL-THROUGH */
00116       case MEM_ABORT:
00117         exit(EXIT_FAILURE);
00118     /* NOTREACHED */
00119       case MEM_CALLFP:
00120         assert(fp);
00121         behavior = (*fp)();
00122         break;
00123       case MEM_RETNULL:
00124         return 0;
00125       case MEM_RETRY:
00126         return 1;
00127       default:
00128         assert(0);
00129       }
00130     }
00131 }
00132 
00133 /****************************/
00134 
00135 #if MEM_DEBUG
00136 
00137 #undef mem_strdup
00138 
00139 char *mem_strdup(const char *s)
00140 {
00141   return mem_strdup_debug(s,__FILE__,__LINE__);
00142 }
00143 
00144 char *mem_strdup_debug(const char* s,char* file,int line)
00145 {
00146   char *p;
00147 
00148   p = s
00149       ? (char *) mem_malloc_debug((unsigned) strlen(s) + 1,file,line)
00150       : NULL;
00151   return p ? strcpy(p,s) : p;
00152 }
00153 
00154 #else // !MEM_DEBUG
00155 char *mem_strdup(const char *s)
00156 {
00157   char *p;
00158   p = s ? (char *) mem_malloc((unsigned) strlen(s) + 1) : NULL;
00159   return p ? strcpy(p,s) : p;
00160 }
00161 
00162 #endif /* MEM_DEBUG */
00163 
00164 #ifdef MEM_DEBUG
00165 
00166 static long mem_maxalloc;  /* max # of bytes allocated    */
00167 static long mem_numalloc;  /* current # of bytes allocated    */
00168 
00169 #define BEFOREVAL  0x12345678  /* value to detect underrun  */
00170 #define AFTERVAL  0x87654321  /* value to detect overrun  */
00171 
00172 #if SUN || SUN386
00173   static long afterval = AFTERVAL;  /* so we can do &afterval  */
00174 #endif
00175 
00176 /* The following should be selected to give maximum probability that  */
00177 /* pointers loaded with these values will cause an obvious crash. On  */
00178 /* Unix machines, a large value will cause a segment fault.    */
00179 /* MALLOCVAL is the value to set malloc'd data to.      */
00180 
00181 #if MSDOS || __OS2__
00182   #define BADVAL    0xFF
00183   #define MALLOCVAL  0xEE
00184 #else
00185   #define BADVAL    0x7A
00186   #define MALLOCVAL  0xEE
00187 #endif
00188 
00189 /* Disable mapping macros  */
00190 #undef  mem_malloc
00191 #undef  mem_calloc
00192 #undef  mem_realloc
00193 #undef  mem_free
00194 
00195 /* Create a list of all alloc'ed pointers, retaining info about where  */
00196 /* each alloc came from. This is a real memory and speed hog, but who  */
00197 /* cares when you've got obscure pointer bugs.        */
00198 
00199 #if __BORLANDC__ >= 0x300
00200 struct mh
00201 { struct mem_debug *Mnext;  /* next in list      */
00202   struct mem_debug *Mprev;  /* previous value in list  */
00203   char *Mfile;    /* filename of where allocated    */
00204   int Mline;    /* line number of where allocated  */
00205   unsigned Mnbytes;  /* size of the allocation    */
00206   long Mbeforeval;  /* detect underrun of data    */
00207 };
00208 
00209 static struct mem_debug
00210 {
00211   struct mh m;
00212   char data[1];    /* the data actually allocated    */
00213 } mem_alloclist =
00214 {
00215   {
00216     (struct mem_debug *) NULL,
00217     (struct mem_debug *) NULL,
00218     "noname",
00219     11111,
00220     0,
00221     BEFOREVAL
00222   },
00223   AFTERVAL
00224 };
00225 
00226 #else
00227 static struct mem_debug
00228 {
00229   struct mh
00230   { struct mem_debug *Mnext;  /* next in list      */
00231     struct mem_debug *Mprev;  /* previous value in list  */
00232     char *Mfile;    /* filename of where allocated    */
00233     int Mline;    /* line number of where allocated  */
00234     unsigned Mnbytes;  /* size of the allocation    */
00235     long Mbeforeval;  /* detect underrun of data    */
00236   } m;
00237   char data[1];    /* the data actually allocated    */
00238 } mem_alloclist =
00239 {
00240   {
00241     (struct mem_debug *) NULL,
00242     (struct mem_debug *) NULL,
00243     "noname",
00244     11111,
00245     0,
00246     BEFOREVAL
00247   },
00248   AFTERVAL
00249 };
00250 #endif
00251 
00252 /* Convert from a void *to a mem_debug struct.  */
00253 #define mem_ptrtodl(p)  ((struct mem_debug *) ((char *)p - sizeof(struct mh)))
00254 
00255 /* Convert from a mem_debug struct to a mem_ptr.  */
00256 #define mem_dltoptr(dl)  ((void *) &((dl)->data[0]))
00257 
00258 #define next    m.Mnext
00259 #define prev    m.Mprev
00260 #define file    m.Mfile
00261 #define line    m.Mline
00262 #define nbytes    m.Mnbytes
00263 #define beforeval  m.Mbeforeval
00264 
00265 /*****************************
00266  * Set new value of file,line
00267  */
00268 
00269 void mem_setnewfileline(void* ptr, char* fil, int lin)
00270 {
00271     struct mem_debug *dl;
00272 
00273     dl = mem_ptrtodl(ptr);
00274     dl->file = fil;
00275     dl->line = lin;
00276 }
00277 
00278 /****************************
00279  * Print out struct mem_debug.
00280  */
00281 
00282 static void NEAR mem_printdl(struct mem_debug *dl)
00283 {
00284   fprintf(ferr,"alloc'd from file '%s' line %d nbytes %d ptr x%lx\n",
00285     dl->file,dl->line,dl->nbytes,(long)mem_dltoptr(dl));
00286 }
00287 
00288 /****************************
00289  * Print out file and line number.
00290  */
00291 
00292 static void NEAR mem_fillin(char *fil, int lin)
00293 {
00294   fprintf(ferr,"File '%s' line %d\n",fil,lin);
00295   fflush(ferr);
00296 }
00297 
00298 /****************************
00299  * If MEM_DEBUG is not on for some modules, these routines will get
00300  * called.
00301  */
00302 
00303 void *mem_calloc(unsigned u)
00304 {
00305   return mem_calloc_debug(u,__FILE__,__LINE__);
00306 }
00307 
00308 void *mem_malloc(unsigned u)
00309 {
00310   return mem_malloc_debug(u,__FILE__,__LINE__);
00311 }
00312 
00313 void *mem_realloc(void* p, unsigned u)
00314 {
00315   return mem_realloc_debug(p,u,__FILE__,__LINE__);
00316 }
00317 
00318 void mem_free(void *p)
00319 {
00320   mem_free_debug(p,__FILE__,__LINE__);
00321 }    
00322 
00323 
00324 /**************************/
00325 
00326 void mem_freefp(void* p)
00327 {
00328   mem_free(p);
00329 }
00330 
00331 /***********************
00332  * Debug versions of mem_calloc(), mem_free() and mem_realloc().
00333  */
00334 
00335 void *mem_malloc_debug(unsigned n, char *fil, int lin)
00336 {   void *p;
00337 
00338     p = mem_calloc_debug(n,fil,lin);
00339     if (p)
00340   memset(p,MALLOCVAL,n);
00341     return p;
00342 }
00343 
00344 void *mem_calloc_debug(unsigned n, char *fil, int lin)
00345 {
00346   struct mem_debug *dl;
00347 
00348     do
00349   dl = (struct mem_debug *)
00350       calloc(sizeof(*dl) + n + sizeof(AFTERVAL) - 1,1);
00351     while (dl == NULL && mem_exception());
00352     if (dl == NULL)
00353     {
00354 #if 0
00355   printf("Insufficient memory for alloc of %d at ",n);
00356   mem_fillin(fil,lin);
00357   printf("Max allocated was: %ld\n",mem_maxalloc);
00358 #endif
00359   return NULL;
00360     }
00361     dl->file = fil;
00362     dl->line = lin;
00363     dl->nbytes = n;
00364     dl->beforeval = BEFOREVAL;
00365 #if SUN || SUN386 /* bus error if we store a long at an odd address */
00366     memcpy(&(dl->data[n]),&afterval,sizeof(AFTERVAL));
00367 #else
00368     *(long *) &(dl->data[n]) = AFTERVAL;
00369 #endif
00370 
00371     /* Add dl to start of allocation list  */
00372     dl->next = mem_alloclist.next;
00373     dl->prev = &mem_alloclist;
00374     mem_alloclist.next = dl;
00375     if (dl->next != NULL)
00376   dl->next->prev = dl;
00377 
00378     mem_count++;
00379     mem_numalloc += n;
00380     if (mem_numalloc > mem_maxalloc)
00381   mem_maxalloc = mem_numalloc;
00382     return mem_dltoptr(dl);
00383 }
00384 
00385 void mem_free_debug(void* ptr, char* fil, int lin)
00386 {
00387   struct mem_debug *dl;
00388 
00389   if (ptr == NULL)
00390     return;
00391   if (mem_count <= 0)
00392   {  fprintf(ferr,"More frees than allocs at ");
00393     goto err;
00394   }
00395   dl = mem_ptrtodl(ptr);
00396   if (dl->beforeval != BEFOREVAL)
00397   {
00398     fprintf(ferr,"Pointer x%lx underrun\n",(long)ptr);
00399     goto err2;
00400   }
00401 #if SUN || SUN386 /* Bus error if we read a long from an odd address  */
00402   if (memcmp(&dl->data[dl->nbytes],&afterval,sizeof(AFTERVAL)) != 0)
00403 #else
00404   if (*(long *) &dl->data[dl->nbytes] != AFTERVAL)
00405 #endif
00406   {
00407     fprintf(ferr,"Pointer x%lx overrun\n",(long)ptr);
00408     goto err2;
00409   }
00410   mem_numalloc -= dl->nbytes;
00411   if (mem_numalloc < 0)
00412   {  fprintf(ferr,"error: mem_numalloc = %ld, dl->nbytes = %d\n",
00413       mem_numalloc,dl->nbytes);
00414     goto err2;
00415   }
00416 
00417   /* Remove dl from linked list  */
00418   if (dl->prev)
00419     dl->prev->next = dl->next;
00420   if (dl->next)
00421     dl->next->prev = dl->prev;
00422 
00423   /* Stomp on the freed storage to help detect references  */
00424   /* after the storage was freed.        */
00425   memset((void *) dl,BADVAL,sizeof(*dl) + dl->nbytes);
00426   mem_count--;
00427 
00428   /* Some compilers can detect errors in the heap.  */
00429 #if DLC
00430   {  int i;
00431     i = free(dl);
00432     assert(i == 0);
00433   }
00434 #else
00435   free((void *) dl);
00436 #endif
00437   return;
00438 
00439 err2:
00440   mem_printdl(dl);
00441 err:
00442   fprintf(ferr,"free'd from ");
00443   mem_fillin(fil,lin);
00444   assert(0);
00445   /* NOTREACHED */
00446 }
00447 
00448 /*******************
00449  * Debug version of mem_realloc().
00450  */
00451 
00452 void *mem_realloc_debug(void *oldp, unsigned n, char *fil, int lin)
00453 {   void *p;
00454     struct mem_debug *dl;
00455 
00456     if (n == 0)
00457     {  mem_free_debug(oldp,fil,lin);
00458   p = NULL;
00459     }
00460     else if (oldp == NULL)
00461   p = mem_malloc_debug(n,fil,lin);
00462     else
00463     {
00464   p = mem_malloc_debug(n,fil,lin);
00465   if (p != NULL)
00466   {
00467       dl = mem_ptrtodl(oldp);
00468       if (dl->nbytes < n)
00469     n = dl->nbytes;
00470       memcpy(p,oldp,n);
00471       mem_free_debug(oldp,fil,lin);
00472   }
00473     }
00474     return p;
00475 }
00476 
00477 /***************************/
00478 
00479 void mem_check()
00480 {   register struct mem_debug *dl;
00481 
00482     for (dl = mem_alloclist.next; dl != NULL; dl = dl->next)
00483   mem_checkptr(mem_dltoptr(dl));
00484 }
00485 
00486 /***************************/
00487 
00488 void mem_checkptr(register void *p)
00489 {   register struct mem_debug *dl;
00490 
00491     for (dl = mem_alloclist.next; dl != NULL; dl = dl->next)
00492     {
00493   if (p >= (void *) &(dl->data[0]) &&
00494       p < (void *)((char *)dl + sizeof(struct mem_debug)-1 + dl->nbytes))
00495       goto L1;
00496     }
00497     assert(0);
00498 
00499 L1:
00500     dl = mem_ptrtodl(p);
00501     if (dl->beforeval != BEFOREVAL)
00502     {
00503       fprintf(ferr,"Pointer x%lx underrun\n",(long)p);
00504       goto err2;
00505     }
00506 #if SUN || SUN386 /* Bus error if we read a long from an odd address  */
00507     if (memcmp(&dl->data[dl->nbytes],&afterval,sizeof(AFTERVAL)) != 0)
00508 #else
00509     if (*(long *) &dl->data[dl->nbytes] != AFTERVAL)
00510 #endif
00511     {
00512       fprintf(ferr,"Pointer x%lx overrun\n",(long)p);
00513       goto err2;
00514     }
00515     return;
00516 
00517 err2:
00518     mem_printdl(dl);
00519     assert(0);
00520 }
00521 
00522 #else
00523 
00524 /***************************/
00525 
00526 void *mem_malloc(unsigned numbytes)
00527 {  void *p;
00528 
00529   if (numbytes == 0)
00530     return NULL;
00531   while (1)
00532   {
00533     p = malloc(numbytes);
00534     if (p == NULL)
00535     {  if (mem_exception())
00536         continue;
00537     }
00538     else
00539       mem_count++;
00540     break;
00541   }
00542   /*printf("malloc(%d) = x%lx\n",numbytes,p);*/
00543   return p;
00544 }
00545 
00546 /***************************/
00547 
00548 void *mem_calloc(unsigned numbytes)
00549 {  void *p;
00550 
00551   if (numbytes == 0)
00552     return NULL;
00553   while (1)
00554   {
00555     p = calloc(numbytes,1);
00556     if (p == NULL)
00557     {  if (mem_exception())
00558         continue;
00559     }
00560     else
00561       mem_count++;
00562     break;
00563   }
00564   /*printf("calloc(%d) = x%lx\n",numbytes,p);*/
00565   return p;
00566 }
00567 
00568 /***************************/
00569 
00570 void *mem_realloc(void* oldmem_ptr, unsigned newnumbytes)
00571 {   void *p;
00572 
00573     if (oldmem_ptr == NULL)
00574   p = mem_malloc(newnumbytes);
00575     else if (newnumbytes == 0)
00576     {  mem_free(oldmem_ptr);
00577   p = NULL;
00578     }
00579     else
00580     {
00581   do
00582       p = realloc(oldmem_ptr,newnumbytes);
00583   while (p == NULL && mem_exception());
00584     }
00585     /*printf("realloc(x%lx,%d) = x%lx\n",oldmem_ptr,newnumbytes,p);*/
00586     return p;
00587 }
00588 
00589 /***************************/
00590 
00591 void mem_free(void* ptr)
00592 {
00593     /*printf("free(x%lx)\n",ptr);*/
00594     if (ptr != NULL)
00595     {  assert(mem_count != 0);
00596   mem_count--;
00597 #if DLC
00598   {  int i;
00599 
00600     i = free(ptr);
00601     assert(i == 0);
00602   }
00603 #else
00604   free(ptr);
00605 #endif
00606     }
00607 }
00608 
00609 #if __ZTC__
00610 
00611 /* Minimum size of a free block  */
00612 #define MINBLKSIZE  (sizeof(size_t) + sizeof(void *))
00613 /* Boundary that allocations are aligned on  */
00614 #define ALIGNSIZE  (sizeof(size_t))
00615 
00616 /*****************************/
00617 
00618 void *mem_scalloc(size_t numbytes)
00619 {   size_t *p;
00620 
00621     if (numbytes == 0)
00622   return NULL;
00623     if (numbytes < MINBLKSIZE)
00624   numbytes = MINBLKSIZE;
00625     else
00626   numbytes = (numbytes + (ALIGNSIZE - 1)) & ~(ALIGNSIZE - 1);
00627     p = (size_t *) mem_calloc(numbytes - sizeof(size_t));
00628     if (p)
00629     {
00630   p--;
00631   *p = 0;
00632   mem_count--;
00633   mem_scount++;
00634     }
00635     return p;
00636 }
00637 
00638 /*****************************/
00639 
00640 void mem_sfree(void *ptr, size_t numbytes)
00641 {
00642     if (ptr != NULL)
00643     {  assert(mem_scount > 0);
00644   mem_scount--;
00645   if (numbytes < MINBLKSIZE)
00646       numbytes = MINBLKSIZE;
00647   else
00648       numbytes = (numbytes + (ALIGNSIZE - 1)) & ~(ALIGNSIZE - 1);
00649   *((size_t *)ptr)++ = numbytes;  /* store size of free block  */
00650   free(ptr);
00651     }
00652 }
00653 
00654 #endif /* __ZTC__ */
00655 
00656 #endif
00657 
00658 /***************************/
00659 
00660 void mem_init()
00661 {
00662   if (mem_inited == 0)
00663   {  mem_count = 0;
00664 #if MEM_DEBUG
00665     mem_numalloc = 0;
00666     mem_maxalloc = 0;
00667     mem_alloclist.next = NULL;
00668 #endif
00669 #if __ZTC__
00670     /* Necessary if mem_sfree() calls free() before any  */
00671     /* calls to malloc().          */
00672     free(malloc(1));  /* initialize storage allocator  */
00673 #endif
00674     mem_inited++;
00675   }
00676 }
00677 
00678 /***************************/
00679 
00680 void mem_term()
00681 {
00682 
00683   if (mem_inited)
00684   {
00685 #if MEM_DEBUG
00686     register struct mem_debug *dl;
00687 
00688     for (dl = mem_alloclist.next; dl; dl = dl->next)
00689     {  fprintf(ferr,"Unfreed pointer: ");
00690       mem_printdl(dl);
00691     }
00692 #if 0
00693     fprintf(ferr,"Max amount ever allocated == %ld bytes\n",
00694       mem_maxalloc);
00695 #endif
00696 #else
00697     if (mem_count)
00698       fprintf(ferr,"%d unfreed items\n",mem_count);
00699     if (mem_scount)
00700       fprintf(ferr,"%d unfreed s items\n",mem_scount);
00701 #endif /* MEM_DEBUG */
00702     assert(mem_count == 0 && mem_scount == 0);
00703     mem_inited = 0;
00704   }
00705 }
00706 
00707 #undef next
00708 #undef prev
00709 #undef file
00710 #undef line
00711 #undef nbytes
00712 #undef beforeval
00713