home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 2 / crawlyvol2.bin / program / c / memdebug / memdebug.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-08  |  53.2 KB  |  2,127 lines

  1. /********************************************************************************/
  2. /* REMARK: set tab width to 4 spaces for best format                            */
  3. /********************************************************************************/
  4. /********************************************************************************/
  5. /*                                                                                 */
  6. /* Copyright (C) 1992                                                            */
  7. /* Centre de Recherche Public Henri Tudor (CRP-HT)                                */
  8. /* 6, rue Coudenhove-Kalergi                                                    */
  9. /* L1359 Luxembourg-Kirchberg                                                    */
  10. /*                                                                                 */
  11. /* Authors : Schmit Rene                                                         */
  12. /*                                                                                 */
  13. /* This software may be copied, distributed, ported and modified in source or    */
  14. /* object format as long as :                                                    */
  15. /*                                                                                 */
  16. /*     1) No distribution for commercial purposes is made.                            */
  17. /*     2) No third-party copyrights (such as runtime licenses) are involved        */
  18. /*     3) This copyright notice is not removed or changed.                            */
  19. /*                                                                                 */
  20. /* No responsibility is assumed for any damages that may result                 */
  21. /* from any defect in this software.                                            */
  22. /*                                                                                 */
  23. /********************************************************************************/
  24.  
  25. /* 
  26.     CURRENT IMPLEMENTATION LIMITS AND WISH-LIST:
  27.         * Restrictions with VAX C, as DECs pre-processor is not ANSI-compliant
  28.         
  29.  
  30.  
  31.         * MEMDEBUG++
  32.         
  33.         * Machine/OS-specific stuff
  34.                 DOS:    far pointers
  35.                         block size limits
  36.                 Mac:    Mac-specific routines
  37.                             NewPtr
  38.                             NewHandle
  39.                             ...
  40.                             
  41.         * check_ValidPointer(): pass it a pointer, returns FALSE if not
  42.                 inside a user_allocated block (would be cool, eh)
  43.                 
  44.         * External option setting
  45.         
  46.         * register_Pointer(): no error message when pointer is freed
  47.             (useful for memory allocated by non-MEMDEBUGed library)
  48.             
  49.         * Use own random function, so rand() is not disturbed
  50.         
  51.         * Change tree library to more general version
  52.         
  53.         ? variable sized watchdog
  54.         
  55.         ? Print-out of pointer value (== address)
  56.         
  57. */
  58.  
  59.  
  60. /*
  61.     Modifications:
  62.     
  63.     6/14/1993:
  64.     
  65.         * Check memdebug disabling on memory error (in check_XXX() functions)
  66.             -->    Added!
  67.                 
  68.         * #include <stdlib.h> twice in memdebug.h file 
  69.             -->    was already done before
  70.  
  71.         *limit # of chars to be printed out as string
  72.             -->    limited to D_MaxRawDataStringLength
  73.  
  74.         * open_XXXFile() -> transform to a single function!!!
  75.             -->    one global function open_File() replaces two old functions
  76.             
  77.     6/30/1993:
  78.     
  79.         * Add off-by-one watchdog option
  80.             -->    Added!
  81.         
  82.         * add two underscores to check_XXX() functions
  83.             -->    Added!
  84.  
  85.     7/1/1993:
  86.     
  87.         * Check for realloc() with special parameters passed
  88.             -> NULL pointer : call malloc
  89.             -> 0-size        : call free
  90.  
  91.         * Raw data printing
  92.             -> only up to first \0
  93.             
  94.     7/8/1993:
  95.         
  96.         * Correction in detab_String: was moving one character too much
  97.         
  98.     8/19/1993:
  99.         
  100.         * changed memcheck to memdebug
  101.         
  102.         * Added segmentation pragma for macintosh
  103.         
  104.         * fflush() after printout of general statistics
  105.         
  106.         * set error file to line buffering
  107.         
  108.     10/4/93:
  109.     
  110.         * added C++ C linkage specification to memdebug.h
  111.         
  112.         * added new and delete overloaded operator to memdebug.h
  113.         
  114.     10/5/93:
  115.         
  116.         * overloaded operators new and delete moved to file memdebug.cp
  117.         
  118.         * changed memdebug.h file to reflect C++ modifications
  119.         
  120.     10/6/93
  121.  
  122.         * added macro VarInfo for use with new and delete, as we can't get this info
  123.             automatically like with malloc() et al.
  124.             
  125.     1/26/94
  126.     
  127.         * bug in init: compared result of atexit() to NULL, now to 0
  128.         
  129.     1/27/94
  130.     
  131.         * bug in set & check sentinel functions: memory alignment error on access
  132.             to end sentinel
  133.             
  134.             applied patch provided by Wilfred Mollenvanger and John Borst
  135.             
  136.         * added #include's for Sun
  137.  
  138.         * in memdebug.h: changed macro definitions of malloc() et al. for VAX compilers
  139.              
  140.             applied patch provided by David M. Stone
  141.  
  142.     2/1/94
  143.         
  144.         * Replaced function name max() by find_MaxValue(), as some compilers define
  145.             a macro called max
  146.             
  147.     2/11/94
  148.         
  149.         * added definition for RAND_MAX for SUNs
  150.         
  151.         * malloc(0)/calloc(0,0) may be a potential portability problem.
  152.             Added test in __check_malloc() and __check_calloc(),
  153.             call them with size 1 instead
  154.             
  155.         * in memdebug.h :define __MSDOS__ when _MSDOS defined
  156.         
  157.     2/15/94
  158.         
  159.         * added a cast to long in memory alignment patch (cf 1/27/94) to support
  160.              boundary checks on machines with 2 byte integers
  161.     
  162.     2/16/94
  163.     
  164.         * changed portability strategy for size_t type: using now unsigned long for
  165.             all internal size-related data
  166.             
  167.         * added Col80 symbol: if defined, MEMDEBUG will TRY to limit line length to
  168.             80 characters
  169.             
  170.     3/3/94
  171.         
  172.         * Close output files upon termination, if != from standard streams
  173. */
  174.  
  175. #ifdef macintosh
  176. #pragma segment memdebug
  177. #endif
  178.  
  179. #ifndef MEMDEBUG
  180. #define MEMDEBUG
  181. #endif
  182.  
  183. #include <limits.h>
  184. #include <ctype.h>
  185. #include <stdio.h>
  186. #include <stdlib.h>
  187. #include <string.h>
  188.  
  189. #ifdef sun
  190. #define        atexit    on_exit
  191. #include    <memory.h>      /* for memset proto */
  192. #ifndef RAND_MAX
  193. #define RAND_MAX INT_MAX
  194. #endif
  195. #endif
  196.  
  197. #include "memdebug.h"
  198.  
  199. /*
  200. #define Col80
  201. */
  202.  
  203. #ifdef Col80
  204. #define D_RawDataMaxSize            14
  205. #define print_80ColLineFeed(FILE)    fprintf(FILE,"\n    ")
  206. #else
  207. #define print_80ColLineFeed(FILE)    
  208. #endif
  209.  
  210. /**************************************************************************/
  211. /**************************** Utility Include *****************************/
  212. /**************************************************************************/
  213.  
  214. #include "memfree.h"
  215. #include "memalpha.h"
  216.  
  217. /**************************************************************************/
  218.  
  219. /*
  220.     We have to undefine our allocation and free macros, as well as the memdebug functions
  221.         because we use or define 'The Right Stuff' in this file.
  222. */
  223.  
  224. #undef malloc
  225. #undef calloc
  226. #undef realloc
  227. #undef free
  228.  
  229. #undef generate_MemdebugError
  230. #undef print_MemdebugStatistics
  231. #undef set_MemdebugOptions
  232. #undef check_MemdebugError
  233.  
  234.  
  235. #define D_InternalMallocError            1
  236. #define D_InternalFreeError                2
  237. #define D_InternalOutOfMemoryError        3
  238. #define D_ExitNotInstallable            4
  239. #define D_CouldNotOpenStatisticsFile    5
  240. #define D_CouldNotOpenErrorFile            6
  241.  
  242. #define D_MaxRawDataStringLength        80
  243.  
  244. /*
  245. Here come some old macros used for VERY primitive memory checking. They were used
  246. to check whether memdebug itself is more or less memory error free.
  247.  
  248. int g_malloc    = 0;
  249. int g_free        = 0;
  250.  
  251. #define malloc(a)    (fprintf(stdout,"malloc %lu\n",    g_malloc++),    malloc(a)        )
  252. #define free(a)        (fprintf(stdout,"free %lu %p\n",g_free++,a),    free(a),    a=0    )
  253. */
  254.  
  255.  
  256. #define wrap_Pointer(p)                p = (void *) (((long *) (p)) + 1)
  257. #define unwrap_Pointer(p)            p = (void *) (((long *) (p)) - 1)
  258.  
  259. /**************************************************************************/
  260. /**************************** File global data ****************************/
  261. /**************************************************************************/
  262.  
  263. static    FILE          * g_StatisticsFile;                /* output text files                            */
  264. static    FILE          * g_ErrorFile;
  265.  
  266. static    t_OptionRecord    g_OptionRecord;                    /* record containing options given with set_memdebugOptions */
  267.  
  268. static    unsigned long    g_CurrentNumber;                /* number of currently allocated blocks(using malloc() & calloc() )    */
  269. static    unsigned long    g_TotalNumber;
  270. static    unsigned long    g_MaxNumber;
  271.  
  272. static    unsigned long    g_MallocCalls;                    /* number of calls to given routine                */
  273. static    unsigned long    g_CallocCalls;
  274. static    unsigned long    g_ReallocCalls;
  275. static    unsigned long    g_FreeCalls;
  276.  
  277. static    unsigned long    g_CurrentSize;                    /* currently allocated amount of memory            */
  278. static    unsigned long    g_TotalSize;                    /* memory allocated since program start            */
  279. static    unsigned long    g_MaxSize;                        /* max. memory allocated since program start    */
  280.  
  281. static    unsigned long    g_UnsuccessfulMallocs;            /* contain number of unsuccessful calls to given routine    */
  282. static    unsigned long    g_UnsuccessfulCallocs;
  283. static    unsigned long    g_UnsuccessfulReallocs;
  284.  
  285. static    unsigned long    g_IllegalReallocs;                /* number of reallocs of illegal pointers            */
  286. static    unsigned long    g_IllegalFrees;                    /* number of frees of unallocated pointers            */
  287. static    unsigned long    g_SpuriousFrees;                /* number of free(NULL) calls                        */
  288. static    unsigned long    g_NonPortableMalloc;            /* number of non-portable mallocs                     */
  289. static    unsigned long    g_NonPortableCalloc;            /* number of non-portable callocs                    */
  290. static    unsigned long    g_NonPortableRealloc;            /* number of non-portable reallocs (malloc/free)    */
  291. static    unsigned long    g_CorruptedBlock;                /* number of corrupted blocks (bound check failed)    */
  292.  
  293. static    unsigned int    g_WatchdogSize;                    /* size needed by watchdog's head and tail    */
  294.  
  295. static    t_CallSequenceLink      *    g_CallSequenceList;        /* sequence list descriptors                    */
  296. static     t_CallSequenceLink      *    g_CallSequenceListEnd;
  297.  
  298. static    t_biState    g_StatisticsPrinted;                /* statistics are printed at least once            */
  299. static    t_biState    g_memdebugDeactivated;                /* package deactivated if REAL memory problems    */
  300.  
  301. /*************************************************************************/
  302. /*********************** Local function prototypes ***********************/
  303. /*************************************************************************/
  304.  
  305. static void detab_String      (    char * p_String);
  306.  
  307. static void    init               (    void);
  308.  
  309. static unsigned long find_MaxValue      (    unsigned    long    p1,
  310.                                         unsigned    long    p2
  311.                                       );
  312.                   
  313. static void set_Watchdog      (    t_BlockDescriptor      * p_BlockDescriptor     );
  314.  
  315. static void check_Watchdog       ( t_BlockDescriptor      * p_BlockDescriptor,
  316.                                  char                  * p_NameString        );
  317.  
  318.  
  319. static void open_File          (    FILE ** p_FileDescriptor,
  320.                                 char  * p_FileName,
  321.                                 int        p_ErrorCode
  322.                               );
  323.  
  324. static void insert_BlockDes_into_SeqList  (    t_BlockDescriptor      *    p_BlockDescriptor,
  325.                                             t_CallKind                p_CallKind,
  326.                                             unsigned long            p_Size,
  327.                                             char                  *    p_SizeExpression,
  328.                                             char                  * p_FileName,
  329.                                             long                    p_LineNumber
  330.                                           );
  331.                                                           
  332. static void print_CallSequenceList              (    void);
  333. static void remove_CallSequence_from_List      (    t_CallSequenceLink      *    p_Link );
  334. static void delete_CallSequenceList              (    void);
  335.         
  336. static void print_NotFreeList      (void);
  337.                                 
  338. static void print_RawData            (    void              * p_Data,
  339.                                     unsigned long         p_DataLength);
  340.                                     
  341. static void        account_alloc      (    void          * p_Pointer,
  342.                                     unsigned long    p_Size,
  343.                                     t_CallKind        p_CallKind,
  344.                                     char          *    p_SizeExpression,
  345.                                     char          * p_FileName,
  346.                                     long            p_LineNumber
  347.                                   );
  348.         
  349. static void      * account_realloc      ( void          * p_Pointer,
  350.                                     unsigned long    p_Size,
  351.                                     char          *    p_NameString,
  352.                                     char          *    p_SizeExpression,
  353.                                     char          * p_FileName,
  354.                                     long            p_LineNumber
  355.                                   );
  356.                                     
  357. static t_ObjectState account_free (    void      * p_Pointer,
  358.                                     char      *    p_NameString,
  359.                                     char      * p_FileName,
  360.                                     long        p_LineNumber
  361.                                   );
  362.         
  363. static void    print_Location          (    FILE      * p_TargetFile,
  364.                                     char      * p_FileName,
  365.                                     long        p_LineNumber
  366.                                   );
  367.  
  368. static void    print_GeneralStatistics(void);
  369.  
  370. static void print_FinalStatistics      (void);
  371. static void check_MallocFreeBalance      (void);
  372. static void cleanup_Data              (void);
  373.  
  374. static void print_AlphaList              (void);
  375.  
  376. /**************************************************************************/
  377. /**************************** Local functions *****************************/
  378. /**************************************************************************/
  379.  
  380. int    compare_BlockPointers    (    t_BlockDescriptor      *    p_Block1,
  381.                                 t_BlockDescriptor      *    p_Block2)
  382.  
  383. /*
  384.     DESCRIPTION:
  385.         Compares the numerical value (== adress) of two pointers
  386.         
  387.     CLASS:
  388.         Application specific
  389.         
  390.     ALGORITHM USED:
  391.         Simple substraction. Casts used to prevent warnings or other problems...
  392.  
  393.     WARNING:
  394.         This routine is a potential portability problem, so beware when porting!
  395.         
  396.     REMARK:    
  397.         Used to store and retrieve the pointer in the trees
  398.  
  399. */
  400.  
  401. {
  402. long l_difference;
  403.     l_difference = ((unsigned long) (p_Block1->f_Pointer)) - ((unsigned long) (p_Block2->f_Pointer));
  404.     if (l_difference == 0)
  405.         return 0;
  406.     else
  407.         if (l_difference > 0)
  408.             return 1;
  409.         else
  410.             return -1;
  411. }
  412.  
  413. /**************************************************************************/
  414.  
  415. int    compare_Identifiers        (    t_BlockDescriptor      *    p_Block1,
  416.                                 t_BlockDescriptor      *    p_Block2)
  417.                                 
  418. /*
  419.     DESCRIPTION:
  420.         Compares the identifiers denoting two blocks
  421.         
  422.     CLASS:
  423.         Application specific
  424.         
  425.     ALGORITHM USED:
  426.         Trivial. Function is kind of a short notation
  427. */
  428.  
  429. {
  430.     return( strcmp(p_Block1->f_Identifier,p_Block2->f_Identifier));
  431. }
  432.  
  433. /**************************************************************************/
  434.  
  435. static void detab_String(char * p_String)
  436.  
  437. /*
  438.     DESCRIPTION:
  439.         delete all horizontal tabs in a string
  440.         
  441.     CLASS:
  442.         String Manipulation
  443.         
  444.     ALGORITHM USED:
  445.         Look for tabs.
  446.         Move trailing sub_string forward by one character (replacing the tab)
  447.  
  448.     REMARK:
  449.         Uses strchr() function from string.h to find tabs
  450.         Uses memmove to move substring.
  451.         
  452. */
  453.  
  454. {
  455. char * l_TabPosition;
  456.  
  457.     while ((l_TabPosition = strchr(p_String,'\t')) != NULL)
  458.         memmove(l_TabPosition,l_TabPosition+1,strlen(l_TabPosition));
  459. }
  460.  
  461.  
  462. /**************************************************************************/
  463.  
  464. void treat_InternalError    (    int    p_ErrorCode    )
  465.  
  466. /*
  467.     DESCRIPTION:
  468.         memdebug's error treatment routine.
  469.         
  470.     CLASS:
  471.         Application specific
  472.         
  473.     ALGORITHM USED:
  474.         Prints a final error message to the error file, cleans up all data and sets a global
  475.             variable that deactivates all calls to memdebug routines.
  476.             
  477.     REMARK:        
  478.         This routine deactivates also all further calls to itself.
  479.         
  480.         The first two errors are used by the tree routines.
  481.             During normal operation, these errors should never occur, however.
  482.     
  483. */
  484.  
  485. {
  486.     if (g_memdebugDeactivated)    /* once is enough    */
  487.         return;
  488.         
  489.     switch (p_ErrorCode)
  490.     {
  491.         case D_InternalMallocError          :    fprintf(g_ErrorFile,"memdebug deactivated. Malloc returned same pointer twice.\n");
  492.                                             break;
  493.                     
  494.         case D_InternalFreeError          :    fprintf(g_ErrorFile,"memdebug deactivated. Internal free error.\n");
  495.                                             break;
  496.                     
  497.         case D_InternalOutOfMemoryError      :    fprintf(g_ErrorFile,"memdebug deactivated. Internal out of memory.\n");
  498.                                             break;
  499.  
  500.         case D_ExitNotInstallable          :    fprintf(g_ErrorFile,"memdebug deactivated. Could not install exit function.\n");
  501.                                             break;
  502.                                             
  503.         case D_CouldNotOpenStatisticsFile :    fprintf(g_ErrorFile,"memdebug deactivated. Could not open statistics file.\n");
  504.                                             break;
  505.                                             
  506.         case D_CouldNotOpenErrorFile      :    fprintf(g_ErrorFile,"memdebug deactivated. Could not open error file.\n");
  507.                                             break;
  508.                                             
  509.     }
  510.             
  511.     print_FinalStatistics();
  512.     cleanup_Data();
  513.     
  514.     g_memdebugDeactivated = c_Yes;
  515. }
  516.  
  517. /**************************************************************************/
  518.  
  519. static void close_Files (void)
  520.  
  521. /*
  522.     DESCRIPTION:
  523.         Closes all output files
  524.         
  525.     CLASS:
  526.         Application specific
  527.         
  528.     ALGORITHM USED:
  529.         Checks if output streams are stdout or stderr and closes them if not so
  530.         
  531. */
  532.  
  533. {
  534.     if (g_StatisticsFile != stdout)
  535.         fclose(g_StatisticsFile);
  536.  
  537.     if (g_ErrorFile != stderr)
  538.         fclose(g_ErrorFile);
  539. }
  540.  
  541. /**************************************************************************/
  542.  
  543. static void exit_memdebug (void)
  544.  
  545. /*
  546.     DESCRIPTION:
  547.         Calls routines to print out final statistics and to make data clean-up
  548.         
  549.     CLASS:
  550.         Application specific
  551.         
  552.     ALGORITHM USED:
  553.         Trivial.
  554.         
  555.     REMARK:        
  556.         This routine is installed as exit function during program initialisation. It
  557.             uses one exit() slot!
  558. */
  559.  
  560. {
  561.     print_FinalStatistics    ();
  562.     check_MallocFreeBalance    ();
  563.     cleanup_Data            ();
  564.     close_Files                ();
  565. }
  566.  
  567. /**************************************************************************/
  568.  
  569. static void init (void)
  570.  
  571. /*
  572.     DESCRIPTION:
  573.         Initialises all program globals.
  574.         
  575.     CLASS:
  576.         Application specific
  577.         
  578.     ALGORITHM USED:
  579.         Set all variables to program default value (0, stdout, stderr....)
  580.         Call initialisation routines for the two trees
  581.         Install exit routine
  582.         
  583.         This routine is called for each user function call, but executes only once.
  584.             s_AlreadyCalled is used as a flag at the first call
  585. */
  586.  
  587. {
  588. static t_biState s_AlreadyCalled = c_No;
  589.  
  590.     if (s_AlreadyCalled)
  591.         return;
  592.  
  593.     s_AlreadyCalled = c_Yes;
  594.  
  595.     g_CurrentNumber            = 0;
  596.     g_TotalNumber            = 0;
  597.     g_MaxNumber                = 0;
  598.  
  599.     g_MallocCalls            = 0;
  600.     g_CallocCalls            = 0;
  601.     g_ReallocCalls            = 0;
  602.     g_FreeCalls                = 0;
  603.  
  604.     g_CurrentSize            = 0;
  605.     g_TotalSize                = 0;
  606.     g_MaxSize                = 0;
  607.             
  608.     g_UnsuccessfulMallocs    = 0;
  609.     g_IllegalReallocs        = 0;
  610.     g_IllegalFrees            = 0;
  611.     g_SpuriousFrees            = 0;
  612.     g_NonPortableMalloc        = 0;
  613.     g_NonPortableCalloc        = 0;
  614.     g_NonPortableRealloc    = 0;
  615.     g_CorruptedBlock        = 0;
  616.     
  617.     g_StatisticsFile        = stdout;
  618.     g_ErrorFile                = stderr;
  619.     
  620.     g_StatisticsPrinted        = c_No;
  621.     g_memdebugDeactivated    = c_No;
  622.     
  623.     g_OptionRecord.f_GeneralStatistics        = c_Yes,
  624.     g_OptionRecord.f_AlphaList                = c_Yes;
  625.     g_OptionRecord.f_NotFreeList            = c_Yes;
  626.     g_OptionRecord.f_CallSequenceList        = c_No;
  627.  
  628.     g_OptionRecord.f_PrintContents            = c_Yes;
  629.     g_OptionRecord.f_DestroyContents        = c_Yes;
  630.     
  631.     g_OptionRecord.f_SpuriousFreeList        = c_Yes;
  632.  
  633.     g_OptionRecord.f_GenerateErrorCount        = 0;
  634.     g_OptionRecord.f_MaximalMemoryAvailable    = LONG_MAX;
  635.     
  636.     g_OptionRecord.f_StatisticsFileName     = "stdout";
  637.     g_OptionRecord.f_ErrorFileName            = "stderr";
  638.  
  639.     g_WatchdogSize            = 2 * sizeof (long);
  640.  
  641.     g_CallSequenceList        = NULL;
  642.     g_CallSequenceListEnd    = NULL;
  643.         
  644.     create_NotFreeBlockTree    ();
  645.     create_AlphaBlockTree    ();
  646.     
  647.     if (atexit(exit_memdebug) != 0) 
  648.         treat_InternalError(D_ExitNotInstallable);
  649. }
  650.  
  651. /**************************************************************************/
  652.  
  653. static void insert_BlockDes_into_SeqList  (    t_BlockDescriptor      *    p_BlockDescriptor,
  654.                                             t_CallKind                p_CallKind,
  655.                                             unsigned long            p_Size,
  656.                                             char                  *    p_SizeExpression,
  657.                                             char                  * p_FileName,
  658.                                             long                    p_LineNumber
  659.                                           )
  660. /*
  661.     DESCRIPTION:
  662.         Add a block descriptor to the seuence cal list
  663.         
  664.     CLASS:
  665.         Application specific
  666.         
  667.     ALGORITHM USED:
  668.         Create and fill the new block descriptor
  669.         If list empty, new block is entire list, else append it at end of existing list.
  670.         
  671.         The backlink in the list is updated according to the memory function called.
  672.         
  673.         For more informstion, see documentation (TOOL-PM-1, page 8 and 9)
  674.  
  675.     REMARK:        
  676.         An error might occur during memory allocation for the new link
  677.         
  678. */
  679.  
  680. {
  681. t_CallSequenceLink      *    l_NewSequenceLink;
  682.         
  683.     l_NewSequenceLink = (t_CallSequenceLink *) malloc(sizeof(t_CallSequenceLink));
  684.     
  685.     if (l_NewSequenceLink == NULL)
  686.     {
  687.         treat_InternalError(D_InternalOutOfMemoryError);
  688.         return;
  689.     }
  690.     
  691.     l_NewSequenceLink->f_Next                 = NULL;
  692.     l_NewSequenceLink->f_Previous             = g_CallSequenceListEnd;
  693.     l_NewSequenceLink->f_BlockDescriptor    = p_BlockDescriptor;
  694.     l_NewSequenceLink->f_CallKind            = p_CallKind;
  695.     
  696.     l_NewSequenceLink->f_SizeExpression        = p_SizeExpression;
  697.     l_NewSequenceLink->f_Size                = p_Size;
  698.     l_NewSequenceLink->f_FileName            = p_FileName;
  699.     l_NewSequenceLink->f_LineNumber            = p_LineNumber;
  700.  
  701.     if (g_CallSequenceList == NULL)
  702.         g_CallSequenceList = l_NewSequenceLink;
  703.     else
  704.         g_CallSequenceListEnd->f_Next = l_NewSequenceLink;
  705.     
  706.     g_CallSequenceListEnd = l_NewSequenceLink;
  707.     
  708.     switch    (p_CallKind)
  709.     {
  710.         case    c_Malloc      :    
  711.         case    c_Calloc      :    l_NewSequenceLink->f_MallocLink    = NULL;
  712.                                 p_BlockDescriptor->f_BackLink    = l_NewSequenceLink;
  713.                                 break;
  714.                                 
  715.         case    c_Realloc      :    l_NewSequenceLink->f_MallocLink    = p_BlockDescriptor->f_BackLink;
  716.                                 p_BlockDescriptor->f_BackLink    = l_NewSequenceLink;
  717.                                 break;
  718.                                 
  719.         case    c_Free          :    l_NewSequenceLink->f_MallocLink    = p_BlockDescriptor->f_BackLink;
  720.                                 p_BlockDescriptor->f_BackLink    = NULL;
  721.                                 break;
  722.     }
  723. }
  724.  
  725. /**************************************************************************/
  726.  
  727. static void print_CallSequenceList        (void)
  728.  
  729. /*
  730.     DESCRIPTION:
  731.         Prints the sequence list of memory function calls
  732.     CLASS:
  733.         Application specific
  734.         
  735.     ALGORITHM USED:
  736.         Print a header
  737.         Iterate through list, printing the following information
  738.             * Source File name
  739.             * Source line number
  740.             * Memory function name (malloc, calloc, realloc, free)
  741.             * pointer identifier    (if known)
  742.             * block size in bytes    
  743.             * size expression        
  744. */
  745.  
  746. {
  747. t_CallSequenceLink      *    l_Link;
  748.     fprintf(g_StatisticsFile,"*************************************\n");
  749.     fprintf(g_StatisticsFile,"** Malloc/Free Call Sequence List  **\n");
  750.     fprintf(g_StatisticsFile,"*************************************\n");
  751. /*                                123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890*/
  752.     fprintf(g_StatisticsFile,  "                                   Call   Identifier                              Size  Size Expression\n");
  753.  
  754.     l_Link = g_CallSequenceList;
  755.     while (l_Link)
  756.     {
  757.         fprintf(g_StatisticsFile,"File %-15s; Line %-5lu # ",l_Link->f_FileName,l_Link->f_LineNumber);
  758.  
  759.         switch (l_Link->f_CallKind)
  760.         {
  761.             case c_Malloc      :    fprintf(g_StatisticsFile,"Malloc  ");
  762.                                 break;
  763.                                 
  764.             case c_Calloc      : fprintf(g_StatisticsFile,"Calloc  ");
  765.                                 break;
  766.                                 
  767.             case c_Realloc      : fprintf(g_StatisticsFile,"Realloc ");
  768.                                 break;
  769.                                 
  770.             case c_Free          : fprintf(g_StatisticsFile,"Free    ");
  771.                                 break;
  772.                                 
  773.         }
  774.         
  775.         if (l_Link->f_BlockDescriptor->f_Identifier)
  776.             fprintf(g_StatisticsFile,"%-35.35s : ",l_Link->f_BlockDescriptor->f_Identifier);
  777.         else
  778.             fprintf(g_StatisticsFile,"??????                              : ");    /* 21 spaces! */
  779.  
  780.         fprintf(g_StatisticsFile,"%6lu  %s",l_Link->f_Size,l_Link->f_SizeExpression);
  781.  
  782.         fprintf(g_StatisticsFile,"\n");
  783.         l_Link = l_Link->f_Next;
  784.     }
  785.  
  786.     fprintf(g_StatisticsFile,  "\n");
  787. }
  788.  
  789. /**************************************************************************/
  790.  
  791. static void remove_CallSequence_from_List    (t_CallSequenceLink      *    p_Link)
  792.  
  793. /*
  794.     DESCRIPTION:
  795.         Removes a sequence descriptor from the call sequence list.
  796.         
  797.     CLASS:
  798.         List manipulation
  799.         
  800.     ALGORITHM USED:
  801.         Standard list ooperation. Deallocates memory of block when done.
  802.  
  803. */
  804.  
  805. {
  806.      if (p_Link->f_Previous    != NULL)
  807.         p_Link->f_Previous->f_Next     = p_Link->f_Next;
  808.     else
  809.         g_CallSequenceList            = p_Link->f_Next;
  810.         
  811.      if (p_Link->f_Next        != NULL)
  812.         p_Link->f_Next->f_Previous    = p_Link->f_Previous;
  813.     else
  814.         g_CallSequenceListEnd         = p_Link->f_Previous;
  815.     
  816.     free(p_Link);
  817. }
  818.  
  819. /**************************************************************************/
  820.  
  821. static void delete_CallSequenceList    (void)
  822.  
  823. /*
  824.     DESCRIPTION:
  825.         Frees the whole call sequnece list
  826.     
  827.     CLASS:
  828.         List manipulation
  829.         
  830.     ALGORITHM USED:
  831.         Standard list operation. Deallocates all memory used by list.
  832. */
  833.  
  834. {
  835. t_CallSequenceLink      *    l_Link;
  836. t_CallSequenceLink      *    l_NextLink;
  837.     l_Link = g_CallSequenceList;
  838.     while (l_Link)
  839.     {
  840.         l_NextLink = l_Link->f_Next;
  841.         free(l_Link);
  842.         l_Link = l_NextLink;
  843.     }
  844. }
  845.  
  846. /**************************************************************************/
  847.  
  848. static void open_File      (    FILE ** p_FileDescriptor,
  849.                             char  * p_FileName,
  850.                             int        p_ErrorCode
  851.                           )
  852.  
  853. /*
  854.     DESCRIPTION:
  855.         Opens a file
  856.         
  857.     CLASS:
  858.         Application specific
  859.         
  860.     ALGORITHM USED:
  861.         Close old  file (allows for multiple such files, resetable with set_memdebugOptions)
  862.         Open new file.
  863.         
  864.         stdout and stderr are treated separately (never opened or closed, file descriptor simply copied)        
  865.         
  866.     REMARK:
  867.         Should the open not be successful, stderr is reused for a final message...
  868. */
  869.  
  870. {
  871. int l_success;
  872.     
  873.     if (* p_FileDescriptor != stdout)
  874.         l_success = fclose(* p_FileDescriptor);
  875.     l_success++;
  876.         
  877.     if (!strcmp(p_FileName,"stdout"))
  878.         * p_FileDescriptor = stdout;
  879.     else
  880.         if (!strcmp(p_FileName,"stderr"))
  881.             g_ErrorFile = stderr;
  882.         else
  883.             * p_FileDescriptor = fopen(p_FileName,"w");
  884.     
  885.     if (* p_FileDescriptor == NULL)
  886.     {
  887.         g_ErrorFile = stderr;
  888.         treat_InternalError (p_ErrorCode);
  889.         * p_FileDescriptor = stdout;
  890.     }
  891. }
  892.  
  893. /**************************************************************************/
  894.  
  895. static void set_Watchdog  (    t_BlockDescriptor      * p_BlockDescriptor )
  896.  
  897. /*
  898.     DESCRIPTION:
  899.         Set a blocks sentinels
  900.         
  901.     CLASS:
  902.         Application specific
  903.         
  904.     ALGORITHM USED:
  905.         Create a long random number
  906.         store this value at:
  907.             start of block
  908.             end of block
  909.             block-descriptor
  910.  
  911.     REMARK:
  912.         The end sentinel value is written byte by byte to avoid memory alignment problems
  913.         
  914. */
  915.  
  916. {
  917. long            l_RandomNumber;
  918. long          * l_Pointer;
  919. unsigned long    l_Size;
  920.  
  921.     l_RandomNumber    = rand() * RAND_MAX + rand();
  922.     l_Pointer        = (long *) p_BlockDescriptor->f_Pointer;
  923.     l_Size            = p_BlockDescriptor->f_BackLink->f_Size;
  924.     
  925.     *((l_Pointer ) - 1)                     = l_RandomNumber;
  926.     *((char *) (l_Pointer ) + l_Size    )   = (unsigned char) ((l_RandomNumber >> (3*8)) & 255);
  927.     *((char *) (l_Pointer ) + l_Size + 1)   = (unsigned char) ((l_RandomNumber >> (2*8)) & 255);
  928.     *((char *) (l_Pointer ) + l_Size + 2)   = (unsigned char) ((l_RandomNumber >> (1*8)) & 255);
  929.     *((char *) (l_Pointer ) + l_Size + 3)   = (unsigned char) ((l_RandomNumber >> (  0)) & 255);
  930.  
  931. #if 0 
  932.     *((long*) ((char *) (l_Pointer ) + l_Size))    = l_RandomNumber;
  933. #endif
  934.     
  935.     p_BlockDescriptor->f_WatchdogValue        = l_RandomNumber;
  936. }
  937.  
  938. /**************************************************************************/
  939.  
  940. static void check_Watchdog     (     t_BlockDescriptor * p_BlockDescriptor,
  941.                                  char              * p_NameString        )
  942.  
  943. /*
  944.     DESCRIPTION:
  945.         Tests via sentinels if block has not been corrupted
  946.         
  947.     CLASS:
  948.         Application specific
  949.         
  950.     ALGORITHM USED:
  951.         Retrieve value at begin and end of block, as well as from block_descriptor
  952.         If the start or end value have changed, print out an error message
  953.         
  954.     REMARK:
  955.         The end sentinel value is read byte by byte to avoid memory alignment problems
  956.         
  957. */
  958.  
  959. {
  960. long             l_WatchdogHead;
  961. long             l_WatchdogTail;
  962. long             l_WatchdogValue;
  963.  
  964. long          * l_Pointer;
  965. unsigned long    l_Size;
  966.  
  967.     l_Pointer        = (long *) p_BlockDescriptor->f_Pointer;
  968.     l_Size            = p_BlockDescriptor->f_BackLink->f_Size;
  969.  
  970.     l_WatchdogHead      = *((l_Pointer) - 1);
  971.     l_WatchdogTail    = ((long)*((unsigned char *) (l_Pointer) + l_Size    ) << (3*8)) +
  972.                         ((long)*((unsigned char *) (l_Pointer) + l_Size + 1) << (2*8)) +
  973.                         ((long)*((unsigned char *) (l_Pointer) + l_Size + 2) << (1*8)) +
  974.                         ((long)*((unsigned char *) (l_Pointer) + l_Size + 3) << (  0));
  975.  
  976. #if 0
  977.     l_WatchdogTail    = *((long*) ((char *) (l_Pointer ) + l_Size));
  978. #endif
  979.  
  980.     l_WatchdogValue = p_BlockDescriptor->f_WatchdogValue;
  981.     
  982.     if    (l_WatchdogHead    != l_WatchdogValue)
  983.     {
  984.         g_CorruptedBlock++;
  985.         fprintf(g_ErrorFile,"Memory block corrupted at start: %s\n", p_NameString);
  986.     }
  987.                         
  988.     if    (l_WatchdogTail    != l_WatchdogValue)
  989.     {
  990.         g_CorruptedBlock++;
  991.         fprintf(g_ErrorFile,"Memory block corrupted at end  : %s\n", p_NameString);
  992.     }
  993. }
  994.  
  995. /**************************************************************************/
  996.  
  997. static    unsigned long    find_MaxValue      ( unsigned    long    p1,
  998.                                             unsigned    long    p2)
  999.  
  1000. /*
  1001.     DESCRIPTION:
  1002.         Returns the largest of two input values
  1003.         
  1004.     CLASS:
  1005.         Application specific
  1006.         
  1007.     ALGORITHM USED:
  1008.         Trivial
  1009.         
  1010.     REMARK:        
  1011.         If performance were important, we would (and could) use a macro...
  1012. */
  1013.  
  1014. {
  1015.     return ( (p1 > p2) ? p1 : p2);
  1016. }
  1017.  
  1018. /**************************************************************************/
  1019.  
  1020. static void print_Location      (    FILE      * p_TargetFile,
  1021.                                 char      * p_FileName,
  1022.                                 long        p_LineNumber
  1023.                               )
  1024.  
  1025. /*
  1026.     DESCRIPTION:
  1027.         Print file name and line number to target file
  1028.         
  1029.     CLASS:
  1030.         Application specific
  1031.         
  1032.     ALGORITHM USED:
  1033.         Trivial. Used for simplification.
  1034. */
  1035.  
  1036. {
  1037.     fprintf(p_TargetFile,"File %-15s; Line %-5lu # ",p_FileName,p_LineNumber);
  1038. }
  1039.  
  1040. /**************************************************************************/
  1041.  
  1042. void print_AlphaBlock    (t_BlockDescriptor     *    p_data)
  1043.  
  1044. /*
  1045.     DESCRIPTION:
  1046.         Prints the content of an alphabetical block descriptor
  1047.         
  1048.     CLASS:
  1049.         Application specific
  1050.         
  1051.     ALGORITHM USED:
  1052.         Prints to the statistics file (on one line)
  1053.             * The pointer identifier
  1054.             * The number of times this identifier was used
  1055.             * The total number of bytes allocated for this identifier
  1056.             * The average size of this block
  1057.     
  1058.     REMARK:
  1059.         Called by the alphabetic tree iteration function
  1060. */
  1061.  
  1062. {
  1063.     fprintf(g_StatisticsFile,  "%-35.35s: ",p_data->f_Identifier);
  1064.  
  1065.     fprintf(g_StatisticsFile,  "%6lu ",p_data->f_TimesUsed);
  1066.     fprintf(g_StatisticsFile,  "%6lu ",p_data->f_TotalAllocated);
  1067.     fprintf(g_StatisticsFile,  "%8.2f",(float)p_data->f_TotalAllocated / (float)p_data->f_TimesUsed);
  1068.  
  1069.     fprintf(g_StatisticsFile,  "\n");
  1070. }
  1071.  
  1072. /**************************************************************************/
  1073.  
  1074. static void print_AlphaList    (void)
  1075.  
  1076. /*
  1077.     DESCRIPTION:
  1078.         Print an alphabetically odered list of all blocks
  1079.         
  1080.     CLASS:
  1081.         Application specific
  1082.         
  1083.     ALGORITHM USED:
  1084.         Print a header
  1085.         Call the alphabetic tree iteration function 
  1086. */
  1087.  
  1088. {
  1089.     fprintf(g_StatisticsFile,"***************************************\n");
  1090.     fprintf(g_StatisticsFile,"** Alphabetic pointer variable list  **\n");
  1091.     fprintf(g_StatisticsFile,"***************************************\n");
  1092. /*                                123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890*/
  1093.     fprintf(g_StatisticsFile,  "Identifier                           Blocks   Size   Average Size\n");
  1094.     
  1095.     print_AlphaBlockTree();
  1096.  
  1097.     fprintf(g_StatisticsFile,  "\n");
  1098. }
  1099.  
  1100. /**************************************************************************/
  1101.  
  1102. static void print_RawData      (    void          * p_Data,
  1103.                                 unsigned long    p_DataLength)
  1104.  
  1105. /*
  1106.     DESCRIPTION:
  1107.         Prints out all printable characters up to \0 in a raw data block
  1108.  
  1109.     CLASS:
  1110.         Printing
  1111.     
  1112.     ALGORITHM USED:
  1113.         For all bytes in the data block
  1114.             Check whether byte is a printable ASCII character
  1115.                 YES:     print it
  1116.                 NO:        print a '.' instead
  1117.  
  1118. */
  1119. {
  1120. int        l_i;
  1121. char    l_Character;
  1122.  
  1123. #ifdef Col80
  1124.     if (p_DataLength > D_RawDataMaxSize)
  1125.         p_DataLength = D_RawDataMaxSize;
  1126. #endif
  1127.     for (l_i = 0; l_i < p_DataLength; l_i++)
  1128.     {
  1129.         if (l_i > D_MaxRawDataStringLength)
  1130.             break;
  1131.         l_Character = *((char *)p_Data + l_i);
  1132.         if (l_Character == '\0')
  1133.             break;
  1134.         if (isprint(l_Character))
  1135.             fprintf(g_StatisticsFile,"%1c",l_Character);
  1136.         else
  1137.             fprintf(g_StatisticsFile,".");
  1138.     }
  1139. }
  1140.  
  1141. /**************************************************************************/
  1142.  
  1143. void print_NotFreeBlock    (t_BlockDescriptor     *    p_data)
  1144.  
  1145. /*
  1146.     DESCRIPTION:
  1147.         Print the content of a not free block to the statistics file
  1148.         
  1149.     CLASS:
  1150.         Application specific
  1151.         
  1152.     ALGORITHM USED:
  1153.         Print to the statistics file (one per line)
  1154.             * the source file name &
  1155.             * the source line number of the allocation site of the block
  1156.             * the size
  1157.             * the size expression
  1158.             * the memory content as a string, terminated at the end by an \0
  1159.             
  1160.     REMARK:        
  1161.         Used by the notFree tree iteration function
  1162.  
  1163. */
  1164.  
  1165. {
  1166.     fprintf(g_StatisticsFile,    "File %-15s; Line %-5lu # ",
  1167.                                 p_data->f_BackLink->f_FileName,
  1168.                                 p_data->f_BackLink->f_LineNumber);
  1169.  
  1170.     fprintf(g_StatisticsFile,    "%6lu  %-20s",
  1171.                                 p_data->f_BackLink->f_Size,
  1172.                                 p_data->f_BackLink->f_SizeExpression);
  1173.  
  1174.     if (g_OptionRecord.f_PrintContents)
  1175.         print_RawData(p_data->f_Pointer,p_data->f_BackLink->f_Size);
  1176.     
  1177.     fprintf(g_StatisticsFile,  "\n");
  1178. }
  1179.  
  1180. /**************************************************************************/
  1181.  
  1182. static void print_NotFreeList        (void)
  1183.  
  1184. /*
  1185.     DESCRIPTION:
  1186.         Print a list of all blocks not yet freed
  1187.         
  1188.     CLASS:
  1189.         Application specific
  1190.         
  1191.     ALGORITHM USED:
  1192.         Print a header
  1193.         Call NotFree tree iteration function for printing NotFree blocks
  1194.  
  1195. */
  1196.  
  1197. {
  1198.     if (g_CurrentNumber == 0)    /* won't print out an empty list    */
  1199.             return;
  1200.     
  1201.     fprintf(g_StatisticsFile,"****************************************\n");
  1202.     fprintf(g_StatisticsFile,"** List of currently allocated blocks **\n");
  1203.     fprintf(g_StatisticsFile,"****************************************\n");
  1204. /*                                123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890*/
  1205.     fprintf(g_StatisticsFile,  "                                     Size  Size Expression     Content String\n");
  1206.     
  1207.     print_NotFreeBlockTree();
  1208.  
  1209.     fprintf(g_StatisticsFile,  "\n");
  1210. }
  1211.  
  1212. /**************************************************************************/
  1213.  
  1214. void delete_Descriptor    (t_BlockDescriptor     *    p_data)
  1215.  
  1216. /*
  1217.     DESCRIPTION:
  1218.         Deletes a block descriptor
  1219.         
  1220.     CLASS:
  1221.         Application specific
  1222.         
  1223.     ALGORITHM USED:
  1224.         Another name for free(). Used by the free iterator functions of the two trees
  1225. */
  1226.  
  1227. {
  1228.     free (p_data);
  1229. }
  1230.  
  1231.  
  1232. /**************************************************************************/
  1233.  
  1234. static     void account_alloc      (    void          * p_Pointer,
  1235.                                 unsigned long    p_Size,
  1236.                                 t_CallKind        p_CallKind,
  1237.                                 char          *    p_SizeExpression,
  1238.                                 char          * p_FileName,
  1239.                                 long            p_LineNumber
  1240.                               )
  1241.                       
  1242. /*
  1243.     DESCRIPTION:
  1244.         Registers a call to malloc() or calloc()
  1245.     CLASS:
  1246.         Application specific
  1247.         
  1248.     ALGORITHM USED:
  1249.         Update global statistics
  1250.         Create a block descriptor and fill it up
  1251.         Insert this block descriptor into
  1252.             * the call sequence list
  1253.             * the NotFree tree 
  1254.  
  1255.     REMARK:        
  1256.         Low real memory disables memdebug
  1257. */
  1258.  
  1259. {
  1260. t_BlockDescriptor      *    l_BlockDescriptor;
  1261.  
  1262.     g_TotalNumber    ++;
  1263.     g_CurrentNumber    ++;
  1264.     
  1265.     g_TotalSize        += p_Size;
  1266.     g_CurrentSize    += p_Size;
  1267.     
  1268.     g_MaxNumber        = find_MaxValue(g_CurrentNumber,g_MaxNumber);
  1269.     g_MaxSize        = find_MaxValue(g_CurrentSize,    g_MaxSize);
  1270.     
  1271.     
  1272.     l_BlockDescriptor = (t_BlockDescriptor *) malloc(sizeof(t_BlockDescriptor));
  1273.  
  1274.     if (l_BlockDescriptor == NULL)
  1275.     {
  1276.         treat_InternalError(D_InternalOutOfMemoryError);
  1277.         return;
  1278.     }
  1279.  
  1280.     l_BlockDescriptor->f_Pointer        = p_Pointer;
  1281.     l_BlockDescriptor->f_Identifier        = NULL;
  1282.     
  1283.     insert_BlockDes_into_SeqList  (    l_BlockDescriptor,
  1284.                                     p_CallKind,
  1285.                                     p_Size,
  1286.                                     p_SizeExpression,
  1287.                                     p_FileName,
  1288.                                     p_LineNumber
  1289.                                   );
  1290.     
  1291.     insert_NotFreeBlock_into_Tree(l_BlockDescriptor);
  1292.     
  1293.     set_Watchdog(l_BlockDescriptor);
  1294.  
  1295.     if ( check_NotFreeBlockFull() )
  1296.         treat_InternalError(D_InternalOutOfMemoryError);
  1297. }
  1298.  
  1299.  
  1300. /**************************************************************************/
  1301.  
  1302. static void  * account_realloc      ( void          * p_Pointer,
  1303.                                     unsigned long    p_Size,
  1304.                                     char          *    p_NameString,
  1305.                                     char          *    p_SizeExpression,
  1306.                                     char          * p_FileName,
  1307.                                     long            p_LineNumber
  1308.                                   )
  1309.                                   
  1310. /*
  1311.     DESCRIPTION:
  1312.         Registers a call to realloc()
  1313.     CLASS:
  1314.         Application specific
  1315.         
  1316.     ALGORITHM USED:
  1317.         Check if reallocation is legal (pointer exists in NotFree tree)
  1318.         
  1319.         Test if out of memory simulation limit not reached
  1320.         
  1321.         Do a real realloc() and check if sucessful
  1322.         
  1323.         Remove old pointer from NotFree tree
  1324.         Update globl statistics
  1325.         Insert descriptor into sequence call list and NotFree tree
  1326.         
  1327.     REMARK:        
  1328.         memdebug aborts if no internal memory available, else realloc() behaves normally
  1329. */
  1330.  
  1331. {
  1332. void                  * l_NewPointer;
  1333. t_BlockDescriptor          l_OldBlock;            /* Temporary memory for search call    */
  1334. t_BlockDescriptor      *    l_BlockDescriptor;
  1335. unsigned long            l_SizeDifference;
  1336.  
  1337.     l_OldBlock.f_Pointer    = p_Pointer;
  1338.     l_BlockDescriptor        = &l_OldBlock;
  1339.     if (!search_NotFreeBlock_in_Tree(&l_BlockDescriptor))
  1340.     {
  1341.         print_Location(g_ErrorFile,p_FileName,p_LineNumber);
  1342.         fprintf(g_ErrorFile,"Reallocating unallocated block : %s\n",p_NameString);
  1343.         g_IllegalReallocs++;
  1344.         return(NULL);
  1345.     }
  1346.     else
  1347.     {
  1348.         if ((g_TotalSize - l_BlockDescriptor->f_BackLink->f_Size + p_Size) > g_OptionRecord.f_MaximalMemoryAvailable)
  1349.         {
  1350.             print_Location(g_ErrorFile,p_FileName,p_LineNumber);
  1351.             fprintf(g_ErrorFile,"Out of memory while reallocating %s for %s\n",p_SizeExpression,p_NameString);
  1352.             g_UnsuccessfulReallocs++;
  1353.             return (NULL);
  1354.         }
  1355.         else
  1356.         {
  1357.             check_Watchdog (l_BlockDescriptor,p_NameString);
  1358.             unwrap_Pointer (p_Pointer);
  1359.             l_NewPointer = realloc(p_Pointer,(size_t) p_Size + g_WatchdogSize);
  1360.             if (l_NewPointer == NULL)
  1361.             {
  1362.                 print_Location(g_ErrorFile,p_FileName,p_LineNumber);
  1363.                 fprintf(g_ErrorFile,"System out of memory while reallocating %s for %s\n",p_SizeExpression,p_NameString);
  1364.                 g_UnsuccessfulReallocs++;
  1365.             }
  1366.             else
  1367.             {
  1368.                 wrap_Pointer(l_NewPointer);
  1369.                 remove_NotFreeBlock_from_Tree(l_BlockDescriptor);
  1370.                 
  1371.                 l_SizeDifference                      = p_Size - l_BlockDescriptor->f_BackLink->f_Size;
  1372.                 l_BlockDescriptor->f_TotalAllocated    += l_SizeDifference;
  1373.                 g_CurrentSize                         += l_SizeDifference;
  1374.                 g_MaxSize                             = find_MaxValue(g_CurrentSize,    g_MaxSize);
  1375.                 if ((l_SizeDifference) > 0)
  1376.                     g_TotalSize                     += l_SizeDifference;
  1377.                 
  1378.                 l_BlockDescriptor->f_Pointer    = l_NewPointer;
  1379.                 l_BlockDescriptor->f_Identifier    = NULL;
  1380.                 
  1381.                 insert_BlockDes_into_SeqList  (    l_BlockDescriptor,
  1382.                                                 c_Realloc,
  1383.                                                 p_Size,
  1384.                                                 p_SizeExpression,
  1385.                                                 p_FileName,
  1386.                                                 p_LineNumber
  1387.                                               );
  1388.                 insert_NotFreeBlock_into_Tree(l_BlockDescriptor);
  1389.                 if ( check_NotFreeBlockFull() )
  1390.                     treat_InternalError(D_InternalOutOfMemoryError);
  1391.                     
  1392.                 set_Watchdog(l_BlockDescriptor);
  1393.             }
  1394.         }
  1395.     }
  1396.     return (l_NewPointer);
  1397. }
  1398.  
  1399. /**************************************************************************/
  1400.  
  1401. static t_ObjectState account_free      (    void      * p_Pointer,
  1402.                                         char      *    p_NameString,
  1403.                                         char      * p_FileName,
  1404.                                         long        p_LineNumber
  1405.                                       )
  1406.  
  1407. /*
  1408.     DESCRIPTION:
  1409.         Registers a call to free()
  1410.         
  1411.     CLASS:
  1412.         Application specific
  1413.         
  1414.     ALGORITHM USED:
  1415.         Search block in NotFree tree and remove it if found (else error returned)
  1416.         Fill in missing data
  1417.         
  1418.         Check if block already known (in alphabetic tree)
  1419.             yes:    free block descriptor
  1420.                     increase local statistics
  1421.             no:        init local statistics
  1422.                     insert block descriptor into tree
  1423.         
  1424.         Update global statistics
  1425.         
  1426.         Either remove block from sequence list, or add free sequence block to this list
  1427.         
  1428.         Fill released memory with a "@@@" string (NULL-terminated)
  1429.         
  1430.     REMARK:        
  1431.         Out of real memory terminates memdebug
  1432. */
  1433.  
  1434. {
  1435. t_BlockDescriptor          l_FreeBlock;
  1436. t_BlockDescriptor      *    l_BlockDescriptor;
  1437. t_BlockDescriptor      *    l_UnlinkedBlock;
  1438. t_CallSequenceLink      * l_MallocSequenceCall;
  1439. unsigned long            l_Size;
  1440.  
  1441.     l_FreeBlock.f_Pointer    = p_Pointer;
  1442.     l_UnlinkedBlock            = &l_FreeBlock;
  1443.     if (!search_NotFreeBlock_in_Tree(&l_UnlinkedBlock))
  1444.         return(c_Bad);
  1445.  
  1446.     check_Watchdog(l_UnlinkedBlock,p_NameString); /* do it here, we need pointer    */
  1447.  
  1448.     remove_NotFreeBlock_from_Tree(l_UnlinkedBlock);
  1449.  
  1450.     l_MallocSequenceCall     = l_UnlinkedBlock->f_BackLink;
  1451.     l_Size                    = l_MallocSequenceCall->f_Size;
  1452.     
  1453.     l_BlockDescriptor                    = l_UnlinkedBlock;
  1454.     l_BlockDescriptor->f_Pointer        = NULL;
  1455.     l_BlockDescriptor->f_Identifier        = p_NameString;
  1456.     
  1457.     if (! search_AlphaBlock_in_Tree(&l_BlockDescriptor))
  1458.     {    /* not found    */
  1459.         l_UnlinkedBlock->f_TimesUsed        = 1;
  1460.         l_UnlinkedBlock->f_TotalAllocated    = l_Size;
  1461.  
  1462.         insert_AlphaBlock_into_Tree(l_UnlinkedBlock);
  1463.         if ( check_AlphaBlockFull() )
  1464.             treat_InternalError(D_InternalOutOfMemoryError);
  1465.     }
  1466.     else
  1467.     {    /* found    */
  1468.         l_MallocSequenceCall->f_BlockDescriptor = l_BlockDescriptor;
  1469.         free(l_UnlinkedBlock);
  1470.  
  1471.         l_BlockDescriptor->f_TimesUsed        ++;
  1472.         l_BlockDescriptor->f_TotalAllocated    += l_Size;
  1473.     }
  1474.     
  1475.     l_BlockDescriptor->f_BackLink        = NULL;
  1476.  
  1477.     g_CurrentNumber    --;
  1478.     g_CurrentSize     -=  l_Size;
  1479.     
  1480.     if (g_OptionRecord.f_CallSequenceList)
  1481.         insert_BlockDes_into_SeqList  (    l_BlockDescriptor,
  1482.                                         c_Free,
  1483.                                         l_Size,
  1484.                                         l_MallocSequenceCall->f_SizeExpression,
  1485.                                         p_FileName,
  1486.                                         p_LineNumber
  1487.                                       );
  1488.     else
  1489.     {
  1490.     t_CallSequenceLink    * l_DeleteSequenceCall;
  1491.         l_DeleteSequenceCall = l_MallocSequenceCall;
  1492.         while (l_DeleteSequenceCall != NULL)
  1493.         {
  1494.             l_MallocSequenceCall = l_MallocSequenceCall->f_MallocLink;
  1495.             remove_CallSequence_from_List(l_DeleteSequenceCall);
  1496.             l_DeleteSequenceCall = l_MallocSequenceCall;
  1497.         }
  1498.     }
  1499.     
  1500.     if (g_OptionRecord.f_DestroyContents)
  1501.     {
  1502.         memset(p_Pointer,'@',(size_t)l_Size-1);
  1503.         *( (char*) p_Pointer + l_Size - 1) = '\0';
  1504.     }
  1505.  
  1506.     return(c_Ok);
  1507. }
  1508. /**************************************************************************/
  1509.  
  1510. static void    print_GeneralStatistics(void)
  1511.  
  1512. /*
  1513.     DESCRIPTION:
  1514.         Print global statistics
  1515.         
  1516.     CLASS:
  1517.         Application specific
  1518.         
  1519.     ALGORITHM USED:
  1520.         Trivial.
  1521. */
  1522.  
  1523. {
  1524. static int s_TimesCalled = 0;
  1525.  
  1526.     fprintf(g_StatisticsFile,"\n");
  1527.     fprintf(g_StatisticsFile,"************************************\n");
  1528.     fprintf(g_StatisticsFile,"**  Memory usage statistics: %3d  **\n",++s_TimesCalled);
  1529.     fprintf(g_StatisticsFile,"************************************\n");
  1530.     fprintf(g_StatisticsFile,"\n");
  1531.  
  1532.     fprintf (g_StatisticsFile,"Calls to Malloc               %6lu\n",    g_MallocCalls            );
  1533.     fprintf (g_StatisticsFile,"Calls to Calloc               %6lu\n",    g_CallocCalls            );
  1534.     fprintf (g_StatisticsFile,"Calls to Realloc              %6lu\n",    g_ReallocCalls            );
  1535.     fprintf (g_StatisticsFile,"Calls to Free                 %6lu\n",    g_FreeCalls                );
  1536.     fprintf (g_StatisticsFile,"\n");
  1537.  
  1538.     fprintf    (g_StatisticsFile,"Total blocks allocated        %6lu\n",    g_TotalNumber            );
  1539.     fprintf    (g_StatisticsFile,"Currently allocated blocks    %6lu\n",    g_CurrentNumber            );
  1540.     fprintf    (g_StatisticsFile,"Same time allocated blocks    %6lu\n",    g_MaxNumber                );
  1541.     fprintf (g_StatisticsFile,"\n");
  1542.  
  1543.  
  1544.     fprintf    (g_StatisticsFile,"Total memory allocated      %8lu\n",        g_TotalSize                );
  1545.     fprintf    (g_StatisticsFile,"Currently allocated memory  %8lu\n",        g_CurrentSize            );
  1546.     fprintf    (g_StatisticsFile,"Same time allocated memory  %8lu\n",        g_MaxSize                );
  1547.     fprintf (g_StatisticsFile,"\n");
  1548.  
  1549.  
  1550.     fprintf    (g_StatisticsFile,"Unsuccessful malloc calls     %6lu\n",    g_UnsuccessfulMallocs    );
  1551.     fprintf    (g_StatisticsFile,"Unsuccessful realloc calls    %6lu\n",    g_UnsuccessfulReallocs    );
  1552.     fprintf    (g_StatisticsFile,"\n");
  1553.  
  1554.     fprintf    (g_StatisticsFile,"Realloc of unallocated blocks %6lu\n",    g_IllegalReallocs        );
  1555.     fprintf    (g_StatisticsFile,"Free of unallocated blocks    %6lu\n",    g_IllegalFrees            );
  1556.     fprintf    (g_StatisticsFile,"Spurious free calls           %6lu\n",    g_SpuriousFrees            );
  1557.     fprintf    (g_StatisticsFile,"Non-portable malloc calls     %6lu\n",    g_NonPortableMalloc        );
  1558.     fprintf    (g_StatisticsFile,"Non-portable calloc calls     %6lu\n",    g_NonPortableCalloc        );
  1559.     fprintf    (g_StatisticsFile,"Non-portable realloc calls    %6lu\n",    g_NonPortableRealloc    );
  1560.     fprintf    (g_StatisticsFile,"Corrupted blocks              %6lu\n",    g_CorruptedBlock        );
  1561.     fprintf    (g_StatisticsFile,"\n");
  1562. }
  1563.  
  1564. /**************************************************************************/
  1565.  
  1566. static void print_FinalStatistics      ( void )
  1567.  
  1568. /*
  1569.     DESCRIPTION:
  1570.         Print final statistics
  1571.         
  1572.     CLASS:
  1573.         Application specific
  1574.         
  1575.     ALGORITHM USED:
  1576.         If not yet printed, this function launches the printing of the statistics
  1577.         
  1578.     REMARK:        
  1579.         Called by exit function
  1580. */
  1581.  
  1582. {
  1583.     if (g_memdebugDeactivated)
  1584.         return;
  1585.  
  1586.     if (g_StatisticsPrinted == c_No)
  1587.         print_MemdebugStatistics();
  1588. }
  1589.  
  1590. /**************************************************************************/
  1591.  
  1592. static void check_MallocFreeBalance      ( void )
  1593.  
  1594. /*
  1595.     DESCRIPTION:
  1596.         Prints an erro messag eif not all memory allocations have been matched by a free
  1597.         
  1598.     CLASS:
  1599.         Application specific
  1600.         
  1601.     ALGORITHM USED:
  1602.         Trivial
  1603.  
  1604. */
  1605.  
  1606. {
  1607.     if (g_memdebugDeactivated)
  1608.         return;
  1609.  
  1610.     if (g_CurrentNumber)
  1611.         fprintf(g_ErrorFile,"\n%lu pointers have not been freed.\n",g_CurrentNumber);
  1612. }
  1613.  
  1614. /**************************************************************************/
  1615.  
  1616. static void cleanup_Data    ( void )
  1617.  
  1618. /*
  1619.     DESCRIPTION:
  1620.         Cleans up all data structures at end of program
  1621.         
  1622.     CLASS:
  1623.         Application specific
  1624.         
  1625.     ALGORITHM USED:
  1626.         Call clean-up functions of all data structures
  1627.         
  1628. */
  1629.  
  1630. {
  1631.     if (g_memdebugDeactivated)
  1632.         return;
  1633.  
  1634.     delete_CallSequenceList            ();
  1635.     
  1636.     free_NotFreeBlockTree            ();
  1637.     delete_NotFreeBlockTree            ();
  1638.     
  1639.     free_AlphaBlockTree                ();
  1640.     delete_AlphaBlockTree            ();
  1641. }
  1642.     
  1643. /**************************************************************************/
  1644. /**************************** Global functions ****************************/
  1645. /**************************************************************************/
  1646.  
  1647. void  * __check_malloc(    size_t        p_Size,
  1648.                         char      *    p_SizeExpression,
  1649.                         char      * p_FileName,
  1650.                         long        p_LineNumber
  1651.                       )
  1652.  
  1653. /*
  1654.     DESCRIPTION:
  1655.         Replaces (and calls) standard malloc()
  1656.         
  1657.     CLASS:
  1658.         memdebug
  1659.         
  1660.     ALGORITHM USED:
  1661.         Init tool
  1662.         Update global statistics
  1663.         Call real malloc()
  1664.             adjust for watchdog
  1665.             account call and/or return error if not successful
  1666.         
  1667. */
  1668.  
  1669. {
  1670. void * l_NewBlock;
  1671.  
  1672.     init();
  1673.     g_MallocCalls++;
  1674.     
  1675.     if (p_Size == 0)
  1676.     {
  1677.         g_NonPortableMalloc++;
  1678.         p_Size = 1;
  1679.         print_Location(g_ErrorFile,p_FileName,p_LineNumber);
  1680.         fprintf(g_ErrorFile,"Malloc used with block size 0. ");
  1681.         print_80ColLineFeed(g_ErrorFile);
  1682.         fprintf(g_ErrorFile,"Potential portability problem, calling malloc(1) instead\n");
  1683.     }
  1684.  
  1685.     if (g_memdebugDeactivated)
  1686.     {
  1687.         l_NewBlock = malloc (p_Size + g_WatchdogSize);
  1688.         if (l_NewBlock)
  1689.             wrap_Pointer(l_NewBlock);
  1690.         return (l_NewBlock);
  1691.     }
  1692.     
  1693.     detab_String(p_SizeExpression);
  1694.  
  1695.     if ((g_TotalSize + p_Size) <= g_OptionRecord.f_MaximalMemoryAvailable)
  1696.     {
  1697.         l_NewBlock = malloc (p_Size + g_WatchdogSize);
  1698.         
  1699.         if (l_NewBlock)
  1700.         {
  1701.             wrap_Pointer(l_NewBlock);
  1702.  
  1703.             account_alloc(l_NewBlock,p_Size,c_Malloc,p_SizeExpression,p_FileName,p_LineNumber);
  1704.             return (l_NewBlock);
  1705.         }
  1706.         else
  1707.         {
  1708.             print_Location(g_ErrorFile,p_FileName,p_LineNumber);
  1709.             fprintf(g_ErrorFile,"System out of memory while allocating %s\n",p_SizeExpression);
  1710.             g_UnsuccessfulMallocs++;
  1711.             return (NULL);
  1712.         }
  1713.     }
  1714.     else
  1715.     {
  1716.         print_Location(g_ErrorFile,p_FileName,p_LineNumber);
  1717.         fprintf(g_ErrorFile,"Out of memory while allocating %s\n",p_SizeExpression);
  1718.         g_UnsuccessfulMallocs++;
  1719.         return (NULL);
  1720.     }
  1721. }
  1722.  
  1723. /**************************************************************************/
  1724.  
  1725. void  * __check_calloc(    size_t        p_Number,
  1726.                         size_t        p_Size,
  1727.                         char      *    p_SizeExpression,
  1728.                         char      * p_FileName,
  1729.                         long        p_LineNumber
  1730.                       )
  1731.  
  1732. /*
  1733.     DESCRIPTION:
  1734.         Replaces (and calls) standard calloc()
  1735.         
  1736.     CLASS:
  1737.         memdebug
  1738.         
  1739.     ALGORITHM USED:
  1740.         Init tool
  1741.         Update global statistics
  1742.         Call malloc,
  1743.         set watchdog
  1744.         init to '0's with memset
  1745.         account call and/or return error if not successful
  1746.  
  1747. */
  1748.  
  1749. {
  1750. void * l_NewBlock;
  1751.  
  1752.     init();
  1753.     g_CallocCalls++;
  1754.  
  1755.     if    (    (p_Number == 0)
  1756.         ||    (p_Size   == 0)
  1757.         )
  1758.     {
  1759.         g_NonPortableCalloc++;
  1760.         p_Size        = 1;
  1761.         p_Number    = 1;
  1762.         print_Location(g_ErrorFile,p_FileName,p_LineNumber);
  1763.         fprintf(g_ErrorFile,"Calloc used to allocate 0 bytes. ");
  1764.         print_80ColLineFeed(g_ErrorFile);
  1765.         fprintf(g_ErrorFile,"Potential portability problem, calling as calloc(1,1) instead\n");
  1766.     }
  1767.  
  1768.     if (g_memdebugDeactivated)
  1769.     {
  1770.         l_NewBlock = malloc((p_Number * p_Size) + g_WatchdogSize);
  1771.         if (l_NewBlock)
  1772.         {
  1773.             wrap_Pointer(l_NewBlock);
  1774.             l_NewBlock = memset(l_NewBlock,'\0',(p_Number * p_Size));
  1775.         }
  1776.         return (l_NewBlock);
  1777.     }
  1778.     
  1779.     detab_String(p_SizeExpression);
  1780.     
  1781.     if ((g_TotalSize + (p_Size * p_Number) ) <= g_OptionRecord.f_MaximalMemoryAvailable)
  1782.     {
  1783.         l_NewBlock = malloc((p_Number * p_Size) + g_WatchdogSize);
  1784.         if (l_NewBlock)
  1785.         {
  1786.             wrap_Pointer(l_NewBlock);
  1787.             l_NewBlock = memset(l_NewBlock,'\0',(p_Number * p_Size));
  1788.             
  1789.             account_alloc(l_NewBlock,(p_Size * p_Number),c_Calloc,p_SizeExpression,p_FileName,p_LineNumber);
  1790.             return (l_NewBlock);
  1791.         }
  1792.         else
  1793.         {
  1794.             print_Location(g_ErrorFile,p_FileName,p_LineNumber);
  1795.             fprintf(g_ErrorFile,"System out of memory while allocating %s\n",p_SizeExpression);
  1796.             g_UnsuccessfulCallocs++;
  1797.             return (NULL);
  1798.         }
  1799.     }
  1800.     else
  1801.     {
  1802.         print_Location(g_ErrorFile,p_FileName,p_LineNumber);
  1803.         fprintf(g_ErrorFile,"Out of memory reached while allocating %s\n",p_SizeExpression);
  1804.         g_UnsuccessfulCallocs++;
  1805.         return (NULL);
  1806.     }
  1807. }
  1808.  
  1809. /********************************************************************************/
  1810.                         
  1811. void  *    __check_realloc      ( void      * p_Pointer,
  1812.                             size_t        p_Size,
  1813.                             char      *    p_NameString,
  1814.                             char      *    p_SizeExpression,
  1815.                             char      * p_FileName,
  1816.                             long        p_LineNumber)
  1817.                         
  1818. /*
  1819.     DESCRIPTION:
  1820.         Replaces (and calls) standard realloc()
  1821.         
  1822.     CLASS:
  1823.         memdebug
  1824.         
  1825.     ALGORITHM USED:
  1826.         Init tool
  1827.         Update global statistics
  1828.         Call account_realloc which takes over all action
  1829.         
  1830.     REMARKS:
  1831.         if used as malloc() or free(), an error is posted and the right function is called
  1832.  
  1833.         account_realloc does its own internal wrapping and unwrapping of the pointer
  1834. */
  1835.  
  1836. {
  1837. void * l_NewPointer;
  1838.     init();                /* needed if realloc used as malloc (i.e. pointer passed == NULL)    */
  1839.     
  1840.     if (p_Pointer == NULL)
  1841.     {
  1842.         g_NonPortableRealloc++;
  1843.         print_Location(g_ErrorFile,p_FileName,p_LineNumber);
  1844.         fprintf(g_ErrorFile,"Realloc used with NULL initial pointer. ");
  1845.         print_80ColLineFeed(g_ErrorFile);
  1846.         fprintf(g_ErrorFile,"Potential portability problem, calling malloc() instead\n");
  1847.         return (__check_malloc(p_Size,p_SizeExpression,p_FileName,p_LineNumber));
  1848.     }
  1849.     
  1850.     if (p_Size == 0)
  1851.     {
  1852.         g_NonPortableRealloc++;
  1853.         print_Location(g_ErrorFile,p_FileName,p_LineNumber);
  1854.         fprintf(g_ErrorFile,"Realloc used with new block size 0. ");
  1855.         print_80ColLineFeed(g_ErrorFile);
  1856.         fprintf(g_ErrorFile,"Potential portability problem, calling free() instead\n");
  1857.         __check_free(p_Pointer,p_NameString,p_FileName,p_LineNumber);
  1858.         return (NULL);
  1859.     }
  1860.     
  1861.     g_ReallocCalls++;
  1862.     
  1863.     if (g_memdebugDeactivated)
  1864.     {
  1865.         unwrap_Pointer(p_Pointer);
  1866.         l_NewPointer = realloc(p_Pointer,p_Size);
  1867.         wrap_Pointer(l_NewPointer);
  1868.         return (l_NewPointer);
  1869.     }
  1870.     
  1871.     detab_String(p_NameString        );
  1872.     detab_String(p_SizeExpression    );
  1873.     l_NewPointer = account_realloc      (    p_Pointer,
  1874.                                         p_Size,
  1875.                                         p_NameString,
  1876.                                         p_SizeExpression,
  1877.                                         p_FileName,
  1878.                                         p_LineNumber
  1879.                                       );
  1880.     return (l_NewPointer);
  1881. }
  1882.  
  1883. /********************************************************************************/
  1884.                         
  1885. void __check_free      ( void      * p_Pointer,
  1886.                         char      *    p_NameString,
  1887.                         char      * p_FileName,
  1888.                         long        p_LineNumber)
  1889.                         
  1890. /*
  1891.     DESCRIPTION:
  1892.         Replaces (and calls) standard free()
  1893.         
  1894.     CLASS:
  1895.         memdebug
  1896.         
  1897.     ALGORITHM USED:
  1898.         Init tool
  1899.         Update global statistics
  1900.         Call real free(), account call and/or return error if not successful
  1901. */
  1902.  
  1903. {
  1904. t_ObjectState l_BlockStatus;
  1905.  
  1906.     init();
  1907.     g_FreeCalls++;
  1908.     
  1909.     if ( g_memdebugDeactivated )
  1910.     {
  1911.         unwrap_Pointer(p_Pointer);
  1912.         free(p_Pointer);
  1913.         return;
  1914.     }
  1915.  
  1916.     detab_String(p_NameString);
  1917.  
  1918.     if (p_Pointer != NULL)
  1919.     {
  1920.         l_BlockStatus = account_free(p_Pointer,p_NameString,p_FileName,p_LineNumber);
  1921.  
  1922.         unwrap_Pointer(p_Pointer);
  1923.         
  1924.         if (l_BlockStatus == c_Ok)
  1925.             free(p_Pointer);
  1926.         else
  1927.         {
  1928.             print_Location(g_ErrorFile,p_FileName,p_LineNumber);
  1929.             fprintf(g_ErrorFile,"Freeing unallocated block : %s\n",p_NameString);
  1930.             g_IllegalFrees++;
  1931.         }
  1932.     }
  1933.     else 
  1934.         if (g_OptionRecord.f_SpuriousFreeList)
  1935.         {
  1936.             print_Location(g_ErrorFile,p_FileName,p_LineNumber);
  1937.             fprintf(g_ErrorFile,"Spurious free : %s\n",p_NameString);
  1938.             g_SpuriousFrees++;
  1939.         }
  1940. }
  1941.  
  1942. /********************************************************************************/
  1943. void generate_MemdebugError          ( void )
  1944.  
  1945. /*
  1946.     DESCRIPTION:
  1947.         Enables the generation of memory allocation errors
  1948.         
  1949.     CLASS:
  1950.         memdebug
  1951.         
  1952.     ALGORITHM USED:
  1953.         Simply set available memory to 0 bytes (errors will then occur automatically...).
  1954. */
  1955.  
  1956. {
  1957.     init();
  1958.     if ( g_memdebugDeactivated )
  1959.         return;
  1960.         
  1961.     if (g_OptionRecord.f_GenerateErrorCount-- <= 0)
  1962.         g_OptionRecord.f_MaximalMemoryAvailable = 0;    /* it's as simple as that    */
  1963. }
  1964.  
  1965. /********************************************************************************/
  1966.  
  1967. void print_MemdebugStatistics      ( void )
  1968.  
  1969. /*
  1970.     DESCRIPTION:
  1971.         Explicitly prints memory usage statistics
  1972.         
  1973.     CLASS:
  1974.         memdebug
  1975.         
  1976.     ALGORITHM USED:
  1977.         According to options used, call print functions of the different data structures 
  1978.         
  1979.     REMARK:
  1980.         Once called, no more automatic final statistics will be printed.
  1981. */
  1982.  
  1983. {
  1984.     init();
  1985.  
  1986.     if ( g_memdebugDeactivated )
  1987.         return;
  1988.  
  1989.     g_StatisticsPrinted = c_Yes;
  1990.     
  1991.     if (g_OptionRecord.f_GeneralStatistics)
  1992.         print_GeneralStatistics();
  1993.     
  1994.     if (g_OptionRecord.f_AlphaList)
  1995.         print_AlphaList();
  1996.  
  1997.     if (g_OptionRecord.f_NotFreeList)
  1998.         print_NotFreeList();
  1999.  
  2000.     if (g_OptionRecord.f_CallSequenceList)
  2001.         print_CallSequenceList();
  2002.         
  2003.     fflush(g_StatisticsFile);
  2004. }
  2005.  
  2006. /********************************************************************************/
  2007.  
  2008. int check_memdebugError          ( void )
  2009.  
  2010. /*
  2011.     DESCRIPTION:
  2012.         Behind-the-scenes error check function
  2013.         
  2014.     CLASS:
  2015.         memdebug
  2016.         
  2017.     ALGORITHM USED:
  2018.         Set p_Error to sum of
  2019.             g_IllegalReallocs
  2020.             g_IllegalFrees
  2021.             g_SpuriousFrees
  2022.         
  2023.     REMARK:
  2024.         Once called, no more automatic final statistics will be printed.
  2025.  
  2026.     ATTENTION:
  2027.         When memdebug is not defined, the macro will always return 0 (== no error!)
  2028.         
  2029.     SUGGESTION:
  2030.         This function should be used for behind-the-scenes test programs.
  2031.         No final memory usage statistics are printed, but print_MemdebugStatistics()
  2032.         may be used to do so explicitly.
  2033. */
  2034.  
  2035. {
  2036.     init();
  2037.  
  2038.     if ( g_memdebugDeactivated )
  2039.         return 0;
  2040.  
  2041.     g_StatisticsPrinted = c_Yes;
  2042.     
  2043.     return (  g_IllegalReallocs
  2044.             + g_IllegalFrees
  2045.             + g_SpuriousFrees
  2046.             + g_CorruptedBlock
  2047.             + g_NonPortableMalloc
  2048.             + g_NonPortableCalloc
  2049.             + g_NonPortableRealloc
  2050.            );
  2051.  
  2052. }
  2053.  
  2054. /********************************************************************************/
  2055.  
  2056. void set_MemdebugOptions  ( t_biState        p_GeneralStatistics,
  2057.                             t_biState        p_AlphaList,
  2058.                             t_biState        p_NotFreeList,
  2059.                             t_biState        p_CallSequenceList,
  2060.  
  2061.                             t_biState        p_SpuriousFreeList,
  2062.                             
  2063.                             t_biState        p_PrintContents,
  2064.                             t_biState        p_DestroyContents,
  2065.                             
  2066.                             long            p_GenerateErrorCount,
  2067.                             unsigned long    p_MaximalMemoryAvailable,
  2068.                             
  2069.                             char          * p_StatisticsFileName,
  2070.                             char          * p_ErrorFileName
  2071.                           )
  2072.  
  2073. /*
  2074.     DESCRIPTION:
  2075.         Allows user to configure MEMCKECK
  2076.         
  2077.     CLASS:
  2078.         memdebug
  2079.         
  2080.     ALGORITHM USED:
  2081.         Copies parameters to global variables.
  2082.         Opens the given statistics and error file
  2083.         Set error file to line buffering 
  2084. */
  2085.  
  2086. {
  2087.     init();
  2088.     
  2089.     if ( g_memdebugDeactivated )
  2090.         return;
  2091.  
  2092.     g_OptionRecord.f_GeneralStatistics    = p_GeneralStatistics,
  2093.     g_OptionRecord.f_AlphaList            = p_AlphaList;
  2094.     g_OptionRecord.f_NotFreeList        = p_NotFreeList,
  2095.     g_OptionRecord.f_CallSequenceList    = p_CallSequenceList,
  2096.  
  2097.     g_OptionRecord.f_PrintContents        = p_PrintContents;
  2098.     g_OptionRecord.f_DestroyContents    = p_DestroyContents;
  2099.     
  2100.     g_OptionRecord.f_SpuriousFreeList    = p_SpuriousFreeList;
  2101.  
  2102.     g_OptionRecord.f_GenerateErrorCount = p_GenerateErrorCount;
  2103.     
  2104.     if     (    (p_MaximalMemoryAvailable)
  2105.         &&    (g_OptionRecord.f_MaximalMemoryAvailable == (unsigned long) LONG_MAX)
  2106.         )
  2107.         g_OptionRecord.f_MaximalMemoryAvailable    = p_MaximalMemoryAvailable;
  2108.     else
  2109.         g_OptionRecord.f_MaximalMemoryAvailable    = (unsigned long) LONG_MAX;
  2110.  
  2111.     
  2112.     if (*p_StatisticsFileName)
  2113.         g_OptionRecord.f_StatisticsFileName    =    p_StatisticsFileName;
  2114.     else
  2115.         g_OptionRecord.f_StatisticsFileName =    "stdout";
  2116.     open_File(&g_StatisticsFile,g_OptionRecord.f_StatisticsFileName,D_CouldNotOpenStatisticsFile);
  2117.  
  2118.     if (*p_ErrorFileName)
  2119.         g_OptionRecord.f_ErrorFileName        =    p_ErrorFileName;
  2120.     else
  2121.         g_OptionRecord.f_ErrorFileName        =    "stderr";
  2122.     open_File(&g_ErrorFile,g_OptionRecord.f_ErrorFileName,D_CouldNotOpenErrorFile);
  2123.     setvbuf(g_ErrorFile ,NULL,_IOLBF,255);
  2124. }
  2125.  
  2126. /********************************************************************************/
  2127.