First of all, if you're still using TurboC or some other decades old fossil on DOS/Windows, then you need to get with the times. Your leak detection approach is crude, cumbersome and occasionally ineffective.
> #define MYDEBUGM1(x) DEBUGTEMP1+=(long long)x;
> #define MYDEBUGF1(x) DEBUGTEMP1-=(long long)x;
...
> temp3=(struct str1 *)malloc( sizeof(struct str1) );
...
> MYDEBUGM1(temp3)
Your basic approach is to sum all the pointers, then subtract them again hoping that if the result ends up back at zero, then everything is fine.
But your big assumption is that numeric overflow doesn't happen, or if it does, that nothing bad happens (like a processor exception).
If numeric overflow happens, you're assuming that some subset of MYDEBUGF1 calls doesn't result in DEBUGTEMP1 ending up at zero, giving you the false impression that there are no leaks.
Your further assumption is that pointers can be cast into integers to begin with.
Index of /jtc1/sc22/wg14/www/docs/n869
You really want to be avoiding 'implementation-defined' and 'undefined' behaviour in your code.
Finally, read
this on how to create statement-like macros. Your trailing semicolon (whether present or absent) can lead to some nasty surprises in some cases.
Don't forget to read the rest of the FAQ.
Now, if you were using proper tools for the job, you would be using something like
valgrind.
Without editing the code at all, you can get output like this.
Code:
$ valgrind ./a.out
==3527== Memcheck, a memory error detector
==3527== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==3527== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==3527== Command: ./a.out
==3527==
Original = 9223372036854775807
New = 9223372036854775807
Original = -9223372036854775808
New = -9223372036854775808
Original = 0
New = 0
Original = 1
New = 1
Original = 2
New = 2
Original = 3
New = 3
Original = 4
New = 4
Original = -1
New = -1
Original = -2
New = -2
Original = -3
New = -3
Original = -4
New = -4
Original = 9
New = 9
Original = 99
New = 99
Original = 999
New = 999
Original = -9
New = -9
Original = -99
New = -99
Original = -999
New = -999
==3527==
==3527== HEAP SUMMARY:
==3527== in use at exit: 0 bytes in 0 blocks
==3527== total heap usage: 59 allocs, 59 frees, 1,952 bytes allocated
==3527==
==3527== All heap blocks were freed -- no leaks are possible
==3527==
==3527== For counts of detected and suppressed errors, rerun with: -v
==3527== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
If leaks are detected, it gives you nice file / line numbers of where the leaked memory was allocated.
Valgrind can also detect other things for you, such as buffer overrun errors and use-after-free errors.
Even if you don't have valgrind (or expensive commercial tools on windows), you can still make a much better job than manually having to edit the code every time you call malloc or free.
Code:
#include<stdio.h>
#include<stdlib.h>
#include<limits.h>
#ifdef MY_CRUDE_LEAKCHECK
void *myMalloc(const char *file, int line, size_t size ) {
void *mem = malloc(size);
fprintf(stderr,"%p allocated to %s:%d\n", mem, file, line);
return mem;
}
void myFree(const char *file, int line, void *mem ) {
free(mem);
fprintf(stderr,"%p released by %s:%d\n", mem, file, line);
}
#define malloc(x) myMalloc(__FILE__,__LINE__,x)
#define free(x) myFree(__FILE__,__LINE__,x)
#endif
struct str1 {
unsigned char thevalue;
struct str1 *theprior;
};
typedef struct str1 llnode;
llnode *newNode(unsigned char value, llnode *next) {
llnode *n = malloc( sizeof(*n) );
if ( n ) {
n->thevalue = value;
n->theprior = next;
}
return n;
}
void freeNodes(llnode *head) {
while ( head != NULL ) {
llnode *next = head->theprior;
free(head);
head = next;
}
}
void printNodes(llnode *head) {
while ( head != NULL ) {
putchar(head->thevalue+'0');
head = head->theprior;
}
}
void printll2(long long arg) {
if ( arg == 0 ) {
putchar('0');
} else {
llnode *list = NULL;
int negFlag = 0;
if ( arg < 0 ) {
negFlag = 1;
if ( arg == LLONG_MIN ) {
// negating most negative number is numeric overflow in 2's complement - careful!
long long temp = (arg+1)*-1;
unsigned char c = temp % 10;
c = c == 9 ? 0 : c+1; // undo the +1 hack at negation
list = newNode(c,NULL);
arg = temp / 10;
} else {
arg *= -1;
list = newNode(arg % 10,NULL);
arg /= 10;
}
} else {
list = newNode(arg % 10,NULL);
arg /= 10;
}
while ( arg != 0 ) {
list = newNode(arg%10,list);
arg /= 10;
}
if ( negFlag ) putchar('-');
printNodes(list);
freeNodes(list);
}
}
int main(int argc, char *argv[])
{
long long tests[] = {
LLONG_MAX, LLONG_MIN,
0,
+1, +2, +3, +4,
-1, -2, -3, -4,
+9, +99, +999,
-9, -99, -999,
};
size_t i;
for ( i = 0 ; i < sizeof(tests)/sizeof(*tests) ; i++ ) {
printf("Original = %lld\n", tests[i] );
printf(" New = " );
printll2(tests[i]);
printf("\n");
}
return 0;
}
$ gcc -DMY_CRUDE_LEAKCHECK -Wall -g foo.c
$ ./a.out
Original = 9223372036854775807
<<snipped verbosity>>
New = 9223372036854775807
Original = -9223372036854775808
<<snipped verbosity>>
New = -9223372036854775808
Original = 0
New = 0
Original = 1
0x6d2420 allocated to foo.c:27
0x6d2420 released by foo.c:38
New = 1
Original = 2
0x6d2420 allocated to foo.c:27
0x6d2420 released by foo.c:38
New = 2
Original = 3
0x6d2420 allocated to foo.c:27
0x6d2420 released by foo.c:38
New = 3
Original = 4
0x6d2420 allocated to foo.c:27
0x6d2420 released by foo.c:38
New = 4
Original = -1
0x6d2420 allocated to foo.c:27
0x6d2420 released by foo.c:38
New = -1
Original = -2
0x6d2420 allocated to foo.c:27
0x6d2420 released by foo.c:38
New = -2
Original = -3
0x6d2420 allocated to foo.c:27
0x6d2420 released by foo.c:38
New = -3
Original = -4
0x6d2420 allocated to foo.c:27
0x6d2420 released by foo.c:38
New = -4
Original = 9
0x6d2420 allocated to foo.c:27
0x6d2420 released by foo.c:38
New = 9
Original = 99
0x6d2420 allocated to foo.c:27
0x6d2440 allocated to foo.c:27
0x6d2440 released by foo.c:38
0x6d2420 released by foo.c:38
New = 99
Original = 999
0x6d2420 allocated to foo.c:27
0x6d2440 allocated to foo.c:27
0x6d2460 allocated to foo.c:27
0x6d2460 released by foo.c:38
0x6d2440 released by foo.c:38
0x6d2420 released by foo.c:38
New = 999
Original = -9
0x6d2420 allocated to foo.c:27
0x6d2420 released by foo.c:38
New = -9
Original = -99
0x6d2420 allocated to foo.c:27
0x6d2440 allocated to foo.c:27
0x6d2440 released by foo.c:38
0x6d2420 released by foo.c:38
New = -99
Original = -999
0x6d2420 allocated to foo.c:27
0x6d2440 allocated to foo.c:27
0x6d2460 allocated to foo.c:27
0x6d2460 released by foo.c:38
0x6d2440 released by foo.c:38
0x6d2420 released by foo.c:38
New = -999
Here are some things for you to study and take note of.
1. There aren't any goto statements.
2. Note the use of small utility functions to encapsulate repeated behaviour. See how my printll2 is
only 30 lines long, compared to your printll function is way over 100 lines long.
3. The leak check macros can be switched in and out with a simple command line switch, and NO editing of the real source code is required.
4. The output of the leak check macros could be redirected to either memory (as a separate memory tracking data structure), or to a file (for post-run analysis).