home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Programming / C / SASC6571.LZX / extras / memlib / mwcontrol.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-12-24  |  10.9 KB  |  429 lines

  1. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
  2. * |_o_o|\\ Copyright (c) 1989 The Software Distillery.                    *
  3. * |. o.| ||          All Rights Reserved                                  *
  4. * | .  | ||          Written by Doug Walker                               *
  5. * | o  | ||          The Software Distillery                              *
  6. * |  . |//           235 Trillingham Lane                                 *
  7. * ======             Cary, NC 27513                                       *
  8. *                    BBS:(919)-471-6436                                   *
  9. \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  10.  
  11. /* This file contains the routines that must be linked in to every pgm   */
  12. /* that wants to use MemLib - MWInit, MWTerm, MWCheck, MWHold, MWPurge   */
  13.  
  14. #include "mempriv.h"
  15. #include <exec/execbase.h>
  16.  
  17. struct MWGlobal mwg;
  18.  
  19. /* Autoinit routine.  This is called by the startup code before main(). */
  20. /* The 240 is the priority of this init routine.  Don't mess with it.   */
  21. int _STI_240_MWInit(void)
  22. {
  23.    MWInit(NULL, __MWFlags, __MWLogName);
  24.    return 0;
  25. }
  26.  
  27. static void MWClose(void);
  28.  
  29. /* Initialization routine - should be called once before any memory */
  30. /* is allocated                                                     */
  31.  
  32. void MWInit(BPTR dbfh, LONG flags, char *dbnm)
  33. {
  34.  
  35.    /* Close any existing log that we opened */
  36.    if(mwg.flags & MWF_ACTIVE) MWClose();
  37.  
  38.    if(dbfh) mwg.dbfh = dbfh;
  39.    else if(dbnm) mwg.dbnm = dbnm;  /* Deferred logname */
  40.    else if(!(flags & MWF_NOLOG)) mwg.dbfh = Output();
  41.  
  42.    if(!(mwg.flags & MWF_ACTIVE))
  43.    {
  44.       mwg.lim[MWT_CHIP] = mwg.lim[MWT_FAST] = 0x7fffffff;
  45.  
  46.       mwg.task = FindTask(0L);
  47.    }
  48.  
  49.    mwg.flags = flags|MWF_ACTIVE;
  50. }
  51.  
  52. /* Termination routine.  Called by the cleanup code after exit(). */
  53. /* The 240 is the priority of this cleanup routine; don't mess with it. */
  54.  
  55. void _STD_240_MWTerm(void)
  56. {
  57.    struct MWAlc *mwa;
  58.    int msgdone = 0;
  59.  
  60.    if(!mwg.flags & MWF_ACTIVE) 
  61.       return;
  62.  
  63.    MWCheck();
  64.  
  65.    /* no need to trash the mem we may be about to free for good */
  66.    mwg.flags |= MWF_NOFTRASH;
  67.    mwg.flags &= ~MWF_CHECK;
  68.  
  69.    if(!(mwg.flags & MWF_NOFREE))
  70.    {
  71.       for(mwa=mwg.first; mwa; mwa=mwa->next)
  72.       {
  73.          if(!(mwg.first->flags & (MWI_MALLOC|MWI_VEC)))
  74.          {
  75.             if(!msgdone)
  76.             {
  77.                MWPrintf("\7\nMemWatch ERROR: The following "
  78.                         "allocations were not freed:\n");
  79.                msgdone = 1;
  80.             }
  81.             MWPrintAlc(mwg.first);
  82.          }
  83.       }
  84.       while(mwg.first)
  85.          MWFreeMem(mwg.first->memory, mwg.first->size, MWI_ANY, "MWTERM", 0);
  86.    }
  87.  
  88.    MWPurge();  /* Really free all mem on the 'free' chain */
  89.  
  90.    MWClose();
  91.  
  92.    memset((char *)&mwg, 0, sizeof(struct MWGlobal));
  93. }
  94.  
  95. /* For compatibility with previous versions */
  96. void MWTerm(void)
  97. {
  98.    _STD_240_MWTerm();
  99. }
  100.  
  101. #define V37 ((*(struct ExecBase **)4)->LibNode.lib_Version >= 36) 
  102.  
  103. static void MWClose(void)
  104. {
  105.    char tmp[2];
  106.  
  107.    if(mwg.dbnm && mwg.dbfh)
  108.    {
  109.       if(!V37)  // If V37, they will be using /AUTO/CLOSE/WAIT
  110.       {
  111.          MWPrintf("Hit RETURN to continue: ");
  112.          Read(mwg.dbfh, tmp, 1);
  113.       }
  114.       Close(mwg.dbfh);
  115.    }
  116.    mwg.dbfh = NULL;
  117. }
  118.  
  119. void MWLimit(LONG chiplim, LONG fastlim)
  120. {
  121.    mwg.lim[MWT_CHIP] = chiplim;
  122.    mwg.lim[MWT_FAST] = fastlim;
  123. }
  124.  
  125. int MWCheckA(struct MWAlc *mwa)
  126. {
  127.    int header, trailer;
  128.    char trash[2*MW_TRAILLEN+1];
  129.    int i, j;
  130.    char *mem;
  131.    static const char hexchars[] = "0123456789ABCDEF";
  132.  
  133.    if(mwa->internal & MWI_REPORTED) 
  134.       return 0;
  135.  
  136.    if(header=memcmp((char *)&mwa->header, MWHEADSTR, MW_HEADLEN))
  137.       MWPrintf("\7\nMemWatch ERROR: Header trashed\n");
  138.  
  139.    if(trailer=memcmp(mwa->memory+mwa->size, MWTRAILSTR, MW_TRAILLEN))
  140.    {
  141.       mem = mwa->memory + mwa->size;
  142.       for(i=j=0; i<MW_TRAILLEN; i++)
  143.       {
  144.          trash[j++] = hexchars[(mem[i]&0xf0)>>4];
  145.          trash[j++] = hexchars[mem[i]&0xf];
  146.       }
  147.       trash[j] = 0;
  148.       MWPrintf("\7\nMemWatch ERROR: Trailer trashed, data 0x%s\n", trash);
  149.    }
  150.  
  151.    if(header || trailer)
  152.    {
  153.       mwa->internal |= MWI_REPORTED;
  154.       MWPrintAlc(mwa);
  155.       return(1);
  156.    }
  157.  
  158.    return(0);
  159. }
  160.  
  161. /* Validity check routine - checks all known allocations for overwrites */
  162. /* Called from every alloc and free routine, plus when specifically     */
  163. /* invoked                                                              */
  164.  
  165. void MWCheck(void)
  166. {
  167.    struct MWAlc *mwa;
  168.    char *tmpchar;
  169.    int error, tmpint;
  170.  
  171.    error = 0;
  172.    for(mwa=mwg.first; mwa; mwa=mwa->next)
  173.    {
  174.       if( (mwa->internal & MWI_REPMASK) == MWI_REPORTED) continue;
  175.  
  176.       error = MWCheckA(mwa);
  177.    }
  178.  
  179.    for(mwa=mwg.freed; mwa; mwa=mwa->next)
  180.    {
  181.       if( (mwa->internal & MWI_REPMASK) == MWI_REPORTED) continue;
  182.  
  183.       for(tmpint=0, tmpchar=mwa->memory; 
  184.           tmpint<mwa->size; 
  185.           tmpint++, tmpchar++)
  186.       {
  187.          if(*tmpchar != MWFTRASH)
  188.          {
  189.             mwa->internal |= MWI_REPORTED;
  190.             error = 1;
  191.             MWPrintf("\7\nMemWatch ERROR: Freed memory modified\n");
  192.             MWPrintAlc(mwa);
  193.             break;
  194.          }
  195.       }
  196.    }
  197.  
  198.    if(error) MWHold();
  199. }
  200.  
  201. void MWHold(void)
  202. {
  203.    struct MWAlc *mwa;
  204.  
  205.    mwg.flags &= ~MWF_ERROR;
  206.  
  207.    /* We're attempting to go on, make all the sentinels correct */
  208.    for(mwa=mwg.first; mwa; mwa=mwa->next)
  209.    {
  210.       mwa->internal &= ~MWI_REPMASK;
  211.       memcpy(mwa->header, MWHEADSTR, MW_HEADLEN);
  212.       memcpy((mwa->memory + mwa->size), MWTRAILSTR, MW_TRAILLEN);
  213.    }
  214.  
  215.    for(mwa=mwg.freed; mwa; mwa=mwa->next)
  216.    {
  217.       mwa->internal &= ~MWI_REPMASK;
  218.       memset(mwa->memory, MWFTRASH, mwa->size);
  219.    }
  220. }
  221.  
  222. /* MWPurge really frees all memory placed on the 'freed' chain by */
  223. /* FreeMem() or free()                                            */
  224.  
  225. void MWPurge(void)
  226. {
  227.    struct MWAlc *cur, *next;
  228.  
  229.    for(cur=mwg.freed; cur; cur=next)
  230.    {
  231.       next = cur->next;
  232.       FreeMem(cur, cur->size + sizeof(struct MWAlc));
  233.    }
  234.    mwg.freed = NULL;
  235. }
  236.  
  237. void MWPrintf(char *ctl, ...)
  238. {
  239.    static char buffer[256];
  240.    va_list args;
  241.  
  242.    va_start(args, ctl);
  243.  
  244.    /* Note: The weird string constant is actually CODE that will */
  245.    /* be called by RawDoFmt.                                     */
  246.    RawDoFmt(ctl, args, (void (*))"\x16\xc0\x4e\x75", buffer);
  247.  
  248.    va_end(args);
  249.  
  250. /* If you don't have Commodore's debug.lib, KPutStr will come up undefined. */
  251. /* Edit mempriv.h and change the #define for USEDEBUGLIB to 0 in this case. */
  252. #if USEDEBUGLIB
  253.    if(mwg.flags & MWF_SERIAL) KPutStr(buffer);
  254.    else
  255. #endif
  256.    {
  257.       if(!mwg.dbfh && mwg.dbnm) mwg.dbfh = Open(mwg.dbnm, MODE_NEWFILE);
  258.       if(mwg.dbfh) Write(mwg.dbfh, buffer, strlen(buffer));
  259.    }
  260. }
  261.  
  262. void *MWAllocMem(long size, long flags, long internal, char *file, long line)
  263. {
  264.    struct MWAlc *hd;
  265.    char *tmpchar;
  266.    int memtype;
  267.  
  268.    if(!(mwg.flags & MWF_ACTIVE)) return(NULL);
  269.  
  270.    /* Force warning for malloc'd memory not freed if requested */
  271.    if(mwg.flags & MWF_MALLOCWRN) internal &= ~MWI_MALLOC;
  272.  
  273.    if(mwg.flags & MWF_CHECK) MWCheck();
  274.  
  275.    if(size <= 0)
  276.    {
  277.       MWPrintf("\7\nMemWatch ERROR: Bad %s() length %ld from line %ld file \"%s\"\n",
  278.          ALCFAMILY(internal), size, line, file);
  279.       return(NULL);
  280.    }
  281.  
  282.    memtype = (flags & MEMF_CHIP ? MWT_CHIP : MWT_FAST);
  283.    if(mwg.sum[memtype] + size > mwg.lim[memtype])
  284.    {
  285.       /* Over the limit, fail it */
  286.       MWPrintf("MemWatch: %s memory allocation exceeds MWLimit amount\n",
  287.          memtype == MWT_CHIP ? "CHIP" : "FAST");
  288.       return(NULL);
  289.    }
  290.  
  291.    while(!(tmpchar = (char *)AllocMem(sizeof(struct MWAlc)+size, flags)))
  292.    {
  293.       if(mwg.freed) MWPurge();
  294.       else return(NULL);
  295.    }
  296.    
  297.    hd = (struct MWAlc *)tmpchar;
  298.    hd->size = size;
  299.    hd->flags = flags;
  300.    hd->internal = internal;
  301.    hd->file = file;
  302.    hd->line = line;
  303.    hd->ffile = NULL;
  304.    hd->fline = 0;
  305.    memcpy(hd->header, MWHEADSTR, MW_HEADLEN);
  306.    memcpy(hd->memory+size, MWTRAILSTR, MW_TRAILLEN);
  307.  
  308.    if(!(flags & MEMF_CLEAR) && !(mwg.flags & MWF_NOATRASH))
  309.       memset(hd->memory, MWATRASH, size);   /* Trash the memory */
  310.  
  311.    hd->next = mwg.first;
  312.    mwg.first = hd;
  313.  
  314.    if((mwg.sum[memtype] += size) > mwg.max[memtype]) 
  315.       mwg.max[memtype] = mwg.sum[memtype];
  316.    ++(mwg.num[memtype]);
  317.  
  318.    return((char *)hd->memory);
  319. }
  320.  
  321. void MWFreeMem(void *mem, long size, long internal, 
  322.                char *file, long line)
  323. {
  324.    struct MWAlc *mwa, *prev;
  325.    int memtype;
  326.    int error = 0;
  327.  
  328.    if(!(mwg.flags & MWF_ACTIVE)) return;
  329.    if(mwg.flags & MWF_CHECK) MWCheck();
  330.  
  331.    for(prev = NULL, mwa = mwg.first; 
  332.        mwa && mwa->memory != mem; 
  333.        prev = mwa, mwa = mwa->next);
  334.  
  335.    if(!mwa)
  336.    {
  337.       for(mwa=mwg.freed; mwa && mwa->memory != mem; mwa=mwa->next);
  338.       if(mwa)
  339.       {
  340.          MWPrintf("\7\nMemWatch ERROR: Memory freed twice line %ld file \"%s\"\n",
  341.             line, file);
  342.          MWPrintAlc(mwa);
  343.       }
  344.       MWPrintf("\7\nMemWatch ERROR: %s() called on invalid memory\n"\
  345.                   "addr 0x%08lx length %ld line %ld file \"%s\"\n",
  346.             FREFAMILY(internal), mem, size, line, file);
  347.       error = 1;
  348.    }
  349.    else if(!(internal & (MWI_MALLOC|MWI_VEC)) && mwa->size != size)
  350.    {
  351.       MWPrintf("\7\nMemWatch ERROR: Incorrect %s() length %ld line %ld file \"%s\"\n", 
  352.          FREFAMILY(internal), size, line, file);
  353.       MWPrintAlc(mwa);
  354.       error = 2;
  355.    }
  356.    else if(internal != MWI_ANY && (internal & mwa->internal) != internal)
  357.    {
  358.       MWPrintf("\7\nMemWatch ERROR: %s() mem freed with %s(), line %ld file \"%s\"\n",
  359.          ALCFAMILY(mwa->internal), FREFAMILY(internal), line, file);
  360.       MWPrintAlc(mwa);
  361.    }
  362.    else if(MWCheckA(mwa))
  363.      error = 2;
  364.  
  365.    if(error)
  366.    {
  367.       MWHold();
  368.       if(error == 1) return;
  369.    }
  370.  
  371.    memtype = (mwa->flags & MEMF_CHIP ? MWT_CHIP : MWT_FAST);
  372.    mwg.sum[memtype] -= mwa->size;
  373.    --mwg.num[memtype];
  374.  
  375.    if(prev) prev->next = mwa->next;
  376.    else     mwg.first = mwa->next;
  377.  
  378.    if(!(mwg.flags & MWF_NOFTRASH))
  379.       memset(mwa->memory, MWFTRASH, mwa->size);  /* Trash it */
  380.  
  381.    if(mwg.flags & MWF_NOFKEEP)
  382.      FreeMem((char *)mwa, mwa->size + sizeof(struct MWAlc));
  383.    else
  384.    {
  385.       mwa->next = mwg.freed;
  386.       mwg.freed = mwa;
  387.       mwa->ffile = file;
  388.       mwa->fline = line;
  389.    }
  390. }
  391.  
  392. void *MWrealloc(void *mem, long size, char *file, long line)
  393. {
  394.    void *new;
  395.    struct MWAlc *mwa;
  396.  
  397.    if(!(new = MWAllocMem(size, 0, MWI_MALLOC, file, line)))
  398.       return(NULL);
  399.  
  400.    if(mem)
  401.    {
  402.       for(mwa = mwg.first; 
  403.           mwa && mwa->memory != mem; 
  404.           mwa = mwa->next);
  405.  
  406.       if(mwa == NULL)
  407.       {
  408.          MWPrintf("\7\nMemWatch ERROR: bad memory passed to realloc\n");
  409.          MWPrintf("\7\nPointer is 0x%08lx, called from line %ld file \"%s\"\n",
  410.             line, file);
  411.       }
  412.       else if(!(mwa->internal & MWI_MALLOC))
  413.       {
  414.          MWPrintf("\7nMemwatch ERROR: %s() memory passed to realloc()\n",
  415.             ALCFAMILY(mwa->internal));
  416.          MWPrintf("Passed from line %ld file \"%s\"\n", line, file);
  417.          MWPrintAlc(mwa);
  418.       }
  419.       else if(mwa->size < size)
  420.          size = mwa->size;
  421.  
  422.       memcpy(new, mem, size);
  423.  
  424.       if(mwa) MWFreeMem(mem, -1, MWI_MALLOC, file, line);
  425.    }
  426.  
  427.    return(new);
  428. }
  429.