Memory Allocation Tracking in C -- Am I doing this right? - c

Just for fun (and for C programming practice) I wrote the following piece of code that does the following:
Acts as a tracking system for memory allocations
Frees all dynamically allocated memory with a function call
Here is the code:
typedef enum _OpMode {
OM_APPEND,
OM_DESTROY
} OP_MODE;
void refOp(void *ptr, OP_MODE mode) {
/* contains static array of pointers and provides an interface to that
array */
static void **references = NULL;
static int size = 0;
static int reset = 0;
if (reset) {
reset = 0;
references = NULL;
size = 0;
}
switch (mode) {
case OM_APPEND:
//add a pointer to reference array
references = (void**) realloc(references, sizeof(void*) * (size + 1));
references[size++] = ptr;
break;
case OM_DESTROY:
//free memory at all pointers kept in reference array
for (int i = 0; i < size; i++) {
free(references[i]);
references[i] = NULL;
}
free(references);
reset = 1;
break;
default:
printf("Invalid enum value '%d' passed as mode.\n", mode);
break;
}
}
void refDestroyAll() {
//Wrapper function
refOp(NULL, OM_DESTROY);
}
void *myAlloc(void* ptr, size_t size) {
/* Allocates memory and stores pointer copy in reference array */
void *tmp_ptr;
tmp_ptr = realloc(ptr, size);
refOp(tmp_ptr, OM_APPEND);
return tmp_ptr;
}
The idea is that one would use myAlloc() instead of malloc or realloc to dynamically allocate memory. And one would use refDestroyAll() to free all memory that was created with myAlloc().
I've done some testing, and it seems to be working, but I can't help feeling that I'm missing something important. Does this code actually work as intended, or am I leaking memory when I call refDestroyAll()?

You have a bug, that could cause a segmentation fault. realloc() could return the same pointer as it is given, in which case you would have added it twice to the array. When you call your free function, it would try and free the same pointer twice, resulting in a segmentation fault error.
Additionally, I don't understand why you have the reset parameter. Why not simply set references and size to 0 in the OM_DESTROY case? It is good practice to always set a pointer to NULL immediately after freeing it.

Related

Segmentation fault when strdupa void pointer

I'm fairly new to pointers, and void pointers is still black art to me.
In the following code I get a segfault when tmp->item = strdup(item);
I'm not sure how to fix.
int springmap_add(SpringMap *sm, char *key, void *item) {
SpringMap *tmp = sm;
.
.
.
while (tmp) {
if (!tmp->next) {
tmp->next = springmap_init();
tmp->next->key = strdup(key);
tmp->next->item = strdup(item); // Segfault here
return 1;
}
tmp = tmp->next;
}
return 0
}
int main(int argc, char* argv[]) {
char* key[ESTS] = {"alpha"};
void* ptr[ESTS] = {(void*)0xdeadbeef};
SpringMap* map = springmap_init();
for(int i = 0; i < TESTS; i++) {
int status = springmap_add(map, key[i], ptr[i]);
}
springmap_free(map);
return 0;
I'm not up to speed on void pointers.
The function name already tells: strdup composes of string duplicate, and it only is able to duplicate null-terminated C-strings (well, admittedly any data as long as it contains a null byte somewhere, though it would get cut off too early unless this null byte was the very last byte within the data).
void pointers in C have the unfortunate nature of implicitly converting to any other pointer type, happening in your code as well. However these pointers do not point to null-terminated C-strings, actually, they aren't even valid at all (most of most likely, at least)! Thus trying to read from them yields undefined behaviour.
So at first make sure that your void pointers point to valid memory. To use strdup they should point to C-strings, otherwise memcpy is the way to go, though you need to malloc storage space as target first. For both, you need the size of the object available, though. However you cannot get that back from the void pointer any more, thus you need yet another parameter.
You could write your own objdup function covering the duplication:
void* objdup(size_t size, void* object)
{
void* copy = malloc(size);
if(copy)
{
memcpy(copy, object, size);
}
return copy;
}
Still your pointers need to be valid! Some possible example might look like:
int main()
{
SomeDataType o1;
AnotherDataType o2;
AnotherDatatType* ptr = &o2; // create a valid pointer
// (could be done by malloc'ing memory, too)
void* c1 = objdup(sizeof(o1), &o1);
// ^ take the address of a REAL object!
if(c1)
{
void* c2 = objdup(sizeof(*o2), o2); // or via pointer to REAL object
if(c2)
{
// ...
free(c2);
}
free(c1);
}
return 0;
}

Fortune while returning C arrays?

I'm newbie with C and stunned with some magic while using following C functions. This code works for me, and prints all the data.
typedef struct string_t {
char *data;
size_t len;
} string_t;
string_t *generate_test_data(size_t size) {
string_t test_data[size];
for(size_t i = 0; i < size; ++i) {
string_t string;
string.data = "test";
string.len = 4;
test_data[i] = string;
}
return test_data;
}
int main() {
size_t test_data_size = 10;
string_t *test_data = generate_test_data(test_data_size);
for(size_t i = 0; i < test_data_size; ++i) {
printf("%zu: %s\n", test_data[i].len, test_data[i].data);
}
}
Why function generate_test_data works only when "test_data_size = 10", but when "test_data_size = 20" process finished with exit code 11? HOW does it possible?
This code will never work perfectly, it just happens to be working. In C, you have to manage the memory yourself. If you make a mistake, the program might continue to work... or something might scribble all over the memory you thought was yours. This often manifests itself as weird errors like you're having: it works when the length is X, but fails when the length is Y.
If you turn on -Wall, or if you're using clang even better -Weverything, you'll get a warning like this.
test.c:18:12: warning: address of stack memory associated with local variable 'test_data' returned
[-Wreturn-stack-address]
return test_data;
^~~~~~~~~
The two important kinds of memory in C are: stack and heap. Very basically, stack memory is only good for the duration of the function. Anything declared on the stack will be freed automatically when the function returns, sort of like local variables in other languages. The rule of thumb is if you don't explicitly allocate it, it's on the stack. string_t test_data[size]; is stack memory.
Heap memory you allocate and free yourself, usually using malloc or calloc or realloc or some other function doing this for you like strdup. Once allocated, heap memory stays around until it's explicitly deallocated.
Rule of thumb: heap memory can be returned from a function, stack memory cannot... well, you can but that memory slot might then be used by something else. That's what's happening to you.
So you need to allocate memory, not just once, but a bunch of times.
Allocate memory for the array of pointers to string_t structs.
Allocate memory for each string_t struct in the array.
Allocate memory for each char string (really an array) in each struct.
And then you have to free all that. Sound like a lot of work? It is! Welcome to C. Sorry. You probably want to write functions to allocate and free string_t.
static string_t *string_t_new(size_t size) {
string_t *string = malloc(sizeof(string_t));
string->len = 0;
return string;
}
static void string_t_destroy(string_t *self) {
free(self);
}
Now your test data function looks like this.
static string_t **generate_test_data_v3(size_t size) {
/* Allocate memory for the array of pointers */
string_t **test_data = calloc(size, sizeof(string_t*));
for(size_t i = 0; i < size; ++i) {
/* Allocate for the string */
string_t *string = string_t_new(5);
string->data = "test";
string->len = 4;
test_data[i] = string;
}
/* Return a pointer to the array, which is also a pointer */
return test_data;
}
int main() {
size_t test_data_size = 20;
string_t **test_data = generate_test_data_v3(test_data_size);
for(size_t i = 0; i < test_data_size; ++i) {
printf("%zu: %s\n", test_data[i]->len, test_data[i]->data);
}
/* Free each string_t in the array */
for(size_t i = 0; i < test_data_size; i++) {
string_t_destroy(test_data[i]);
}
/* Free the array */
free(test_data);
}
Instead of using pointers you could instead copy all the memory you use, which is sort of what you were previously doing. That's easier for the programmer, but inefficient for the computer. And if you're coding in C, it's all about being efficient for the computer.
Because the space for test_data in v1 gets created in the function, and that space gets reclaimed when the function returns (and can thus be used for other things); in v2, the space is set aside outside of the function, so doesn't get reclaimed.
Why function generate_test_data_v1 works only when "test_data_size = 10", but when "test_data_size = 20" process finished with exit code 11?
I see no reason why function generate_test_data_v1() should ever fail, but you cannot use its return value. It returns a pointer to an automatic variable belonging to the function's scope, and automatic variables cease to exist when the function to which they belong returns. Your program produces undefined behavior when it dereferences that pointer. I can believe that it appears to work as you intended for some sizes, but even in those cases the program is wrong.
Moreover, your program is very unlikely to be producing an exit code of 11, but it may well be terminating abruptly with a segmentation fault, which is signal 11.
And why generate_test_data_v2 works perfectly?
Function generate_test_data_v2() populates elements of an existing array belonging to function main(). That array is in scope for substantially the entire life of the program.

Freeing all allocated memory in case of failure

I'm working on a C project (assignment for school). One of the demands is that in case of malloc() failure, the program must free() all allocated memory and exit().
Consider a case where function A() constructs a linked-list and in each iteration it calls to another function, B(). Now, if a malloc failure occured at B(), it must free() the memory it allocated but function A() should do that as well.
Things are getting quite complicated when you have a tree of function calls larger than two.
In my previous project I used a flag to notify a malloc() failure - if a function uses another function which may use malloc(), it has to check the flag right after. It worked, but code got kinda messy.
Is there a neat solution for this problem?
Of course, with "real" applications all memory is de-allocated by the OS, but I guess this demand is pedagogical..
I think the easiest approach is to create a custom allocator (as somebody already noted in a deleted post) to keep track of all your allocations, then do a custom deallocator, use these for all your heap memory needs.
if a malloc fails you have the list of previously allocated blocks at easy reach.
e.g.
(you need to redo this cause it is not effective and should be optimized but shows the principle and only ocular compilation)
typedef struct
{
void* pMemory; /* for the allocated memory */
size_t size; /* for better debugging */
} MemoryBlock;
#define MAXBLOCKS 1000
MemoryBlock myheap[MAXBLOCKS]; // global so zero:ed
static int block = 0;
void* myalloc(size_t size)
{
static int block = 0;
// you should check vs MAXBLOCKS
myheap[block].pMemory = malloc(size);
myheap[block].size = size;
// check if it failed.
if ( myheap[block].pMemory == NULL )
{
for (int i = 0; i < block; ++i)
{
myfree(myheap[i].pMemory);
}
fprintf( stderr, "out of memory\n");
exit(EXIT_FAILURE);
}
else
{
return myheap[block++].pMemory;
}
}
void myfree(void* p)
{
for (int i = 0; i < block; ++i)
{
if ( p == myheap[i].pMemory )
{
free(myheap[i].pMemory);
myheap[i].pMemory = NULL;
return;
}
}
}
Yes. The best (and conventional) way is to initialize every pointer value to zero. Then set it during the malloc() assignment. Ex: myPtr = malloc( 10 );
It will be zero in case of failure, and you check that. And finally, when you go about freeing, you always check the pointer value before calling free():
if ( myPtr != 0 )
free( myPtr );
There is no need for an extra flag.
Are you having issue checking for errors or handling them? If you want info on catching them, use donjuedo's suggestion.
For ideas on freeing memory in the event of error, try one of these two methods:
1) For a uni-directional linked-list, keep a special pointer that points to the head of the list. In your cascading free function, start at the head, capture the next-pointer in a temp variable, free the head, move to the next structure in the list using the temp-pointer, and repeat the process until the next-pointer == 0.
2) For a bi-directional linked-list (my preference) you don't need to keep a special pointer to the head of the list. Assuming you are still at the tail, just capture the previous-pointer into a temp variable, free the tail, move back using the temp-pointer, and repeat the process until the previous-pointer == 0
You could look into the atexit() function, to register code that will be executed when the program terminates. Such code can then check if there is anything that needs to be free()d.
Note that atexit() has no way to unregister. So you need to make sure that you register each cleanup function only once, and that it does the right thing when there is nothing to clean up.
#include <stdlib.h>
#include <stdio.h>
int *ptr1;
char *ptr2;
int clean1_registered, clean2_registered;
void clean1(void)
{
printf("clean1 called\n");
if (ptr1) {
free(ptr1);
ptr1 = NULL;
}
}
void clean2(void)
{
printf("clean2 called\n");
if (ptr2) {
free(ptr2);
ptr2 = NULL;
}
}
void B(void)
{
ptr2 = malloc(100);
if (!clean2_registered) {
atexit(clean2);
}
}
void A(void)
{
ptr1 = malloc(100 * sizeof(int));
if (!clean1_registered) {
atexit(clean1);
}
B();
}
int main(int argc, char **argv)
{
A();
}

When to free pointers

I'm a bit of a C newbie, so I'm still trying to get my head fully around when to worry about memory issues.
Suppose I have the following simple program:
#include <stdlib.h>
/* this returns a malloc()'d string */
char *get_str(int whichone);
int main(void)
{
char *s;
if ((s = get_str(0)) == NULL) {
exit(1);
}
/* position 1 */
if ((s = get_str(1)) == NULL) { /* position 2 */
exit(2);
}
return 0;
}
Obviously, this simple of a program has no worries about memory. It allocates a few bytes (for all intents and purposes), and it exits provided our dear function didn't fail.
Now, suppose I am running similar code inside of a looping and fork()ing program. Should I be using free(s) at position 1 since at position 2 I leave the old value behind and assign a new location for the pointer?
Yes. free releases the memory associated with the pointer that is being free'd. Once you reassign s so that it holds a different memory location, you will have lost your opportunity to free the memory associated with the original value of s.
You should definetly free the memory at position 1, because once you reassigned s you lost any chance to do so. And I'd do it one way or another because you can never know when somebody else is instructed to build a fork into your application and he will assume you did everything right.
If you have a pointer to memory that have been allocated using one of the malloc() type calls then when you are done with the memory area, you should deallocate the memory using free(). Similarly using calloc(), which also allocates from the heap, should be followed by the use free() to deallocate the memory when done with it.
The other memory allocator such as alloca() which allocates from the stack and not the heap see On the use and abuse of alloca does not use the free() function and that memory will be recovered automatically as the stack pointers are adjusted when the function in which it is used returns. Naturally that means that using a pointer from alloca() is only good for the function and any functions it calls and the address becomes invalid as soon as the function using alloca() returns.
In your simple example, I would use free() just before the call to the get_str(1) function at position 2 so the source would look something like"
int main(void)
{
char *s;
if ((s = get_str(0)) == NULL) {
exit(1);
}
// doing stuff with the string pointed to by s
/* position 1 */
// free up the string area so that we can get another one.
free (s);
if ((s = get_str(1)) == NULL) { /* position 2 */
exit(2);
}
return 0;
}
I might also be tempted to modify your example a touch and do something like the following. This was all written without testing in a compiler so there may be a compilation error or two however this should provide the basic idea.
The idea with this approach is to have a struct that contains state information as well as a pointer so that you will know which type of get_str() pointer came from, if you are interested, and when you call the get_str() function, it will deallocate the memory for you. You could also add intelligence so that if there is memory already allocated and it is the correct type, then you do not do a free() followed by a malloc() but instead just return back.
Another bonus provided by this approach is when a free() is done, the char * member of the struct is set to NULL which should give you a crash if you try to dereference the pointer and since the whichone member of the struct indicates the last type of get_str() used, your debugging may be easier depending on how good you are with interpreting a crash dump.
#include <stdlib.h>
typedef struct {
int whichone;
char *s;
} GetStrStruct;
/* this returns a malloc()'d string */
GetStrStruct *get_str(int whichone, GetStrStruct *pStruct)
{
free(pStruct->s); // we depend on pStruct->s being valid or NULL here
pStruct->s = NULL;
pStruct->whichone = -1;
switch (whichOne) {
case 0: // allocate string one
pStruct->s = malloc (32); // string one type of memory allocation
pStruct->whichone = whichone;
break;
case 1: // allocate string two
pStruct->s = malloc (64); // string two type of memory allocation
pStruct->whichone = whichone;
break;
default:
break;
}
// if the malloc() failed then return a NULL pointer
// we just reuse the pStruct pointer here, it is local and one less variable to make
if (pStruct->s == NULL) pStruct = NULL;
return pStruct;
}
int main(void)
{
GetStrStruct myStruct = {0}; // create and initialize the struct
if (get_str(0, &myStruct) == NULL) {
exit(1);
}
// do things with myStruct.s, the string from last get_str() call
// this would be using myStruct.s and not just myStruct or s so maybe awkward?
/* position 1 */
if (get_str(1, &myStruct) == NULL) { /* position 2 */
exit(2);
}
// do things with the second type of get_str()
// this would be using myStruct.s and not just myStruct or s so maybe awkward?
// release the memory as I am done. This may seem a bit strange to get a nothing string.
get_str (-1, &myStruct);
return 0;
}
If you added a debug facility you could even track which line of source did the last allocation and the last deallocation. Or if the malloc() fails, you could implement a debugger interrupt or other mechanism to immediately stop so you will know exactly which line the function call failed.
In the include file with the prototype for the get_str() function and the GetStrStruct struct you would use C Preprocessor as follows. If you change the 0 in the #if 0 to a 1 then the debug version is enabled otherwise it is not. The idea is to use a macro through the C Preprocessor to replace calls to get_str() with a call to get_str_Debug() and provide additional arguments with the source file path and the line number in the source file.
#if 0
typedef struct {
int whichone;
char *s;
struct {
int lineNo;
char file[64];
} myDebug;
} GetStrStruct;
GetStrStruct *get_str_Debug(int whichone, GetStrStruct *pStruct, char *file, int line);
#define get_str(wo,ps) get_str_Debug (wo,ps,__FILE__,__LINE__)
#else
typedef struct {
int whichone;
char *s;
} GetStrStruct;
GetStrStruct *get_str(int whichone, GetStrStruct *pStruct);
#endif
And then in the implementation file you could use the C Preprocessor with something like the following to allow you to specify whether the get_str() function should be replaced by a get_str_Debug() function with additional debug aids at compile time.
#if defined(get_str)
// provide a prototype for the replacement function signature.
GetStrStruct *get_str_Special(int whichone, GetStrStruct *pStruct);
// provide the debug information wrapper so that we can track where the last use came from
GetStrStruct *get_str_Debug(int whichone, GetStrStruct *pStruct, char *file, int line)
{
GetStrStruct *pTemp = get_str_Special (whichone, pStruct);
if (pTemp) {
// update the debug information. we keep only last 60 chars of file path.
int iLen = strlen (file);
if (iLen > 60) iLen -= 60; else ilen = 0;
strcpy (pStruct->myDebug.file, file + iLen);
pStruct->myDebug.lineNo = line;
} else {
// cause a debugger interrupt or a crash dump or something.
}
return pTemp;
}
GetStrStruct *get_str_Special (int whichone, GetStrStruct *pStruct)
#else
/* this returns a malloc()'d string */
GetStrStruct *get_str(int whichone, GetStrStruct *pStruct)
#endif
{
free(pStruct->s);
pStruct->s = NULL;
pStruct->whichone = -1;
switch (whichOne) {
case 0: // allocate string one
pStruct->s = malloc (32); // string one type of memory allocation
pStruct->whichone = whichone;
break;
case 1: // allocate string two
pStruct->s = malloc (64); // string two type of memory allocation
pStruct->whichone = whichone;
break;
default:
break;
}
// if the malloc() failed then return a NULL pointer
if (pStruct->s == NULL) pStruct = NULL;
return pStruct;
}
Then where ever you use get_str() if you turn on the debugging, the C Preprocessor will substitute a call to get_str_Debug() with the arguments used in the get_str() call along with two additional arguments, a char pointer to the source file name where the get_str() is being replaced by the get_str_Debug() and the source file line number.

malloc convert memory for struct

What is the right way to malloc memory ? And what is the difference between them ?
void parse_cookies(const char *cookie, cookie_bank **my_cookie, int *cookies_num)
{
*my_cookie = malloc(sizeof(cookie_bank) * 1);
*my_cookie = (cookie_bank *)malloc(sizeof(cookie_bank) * 1);
my_cookie = (cookie_bank **)malloc(sizeof(cookie_bank) * 1);
///
}
I'm trying to malloc array of cookie_bank structs function.
I'm assuming that you want the function to allocate memory for an array and passing the result via a pointer parameter. So, you want to write T * x = malloc(...), and assign the result to a pointer argument, *y = x:
cookie_bank * myarray;
parse_cookies(..., &myarray, ...);
/* now have myarray[0], myarray[1], ... */
So the correct invocation should be, all rolled into one line,
parse_cookies(..., cookie_bank ** y, ...)
{
*y = malloc(sizeof(cookie_bank) * NUMBER_OF_ELEMENTS);
}
Your second example is the most correct. You don't need the *1 obviously.
*my_cookie = (cookie_bank *)malloc(sizeof(cookie_bank) * 1);
Your first example is also correct, although some compilers/flags will cause a complaint about the implicit cast from void*:
*my_cookie = malloc(sizeof(cookie_bank) * 1);
It you want to allocate more than one entry you'd generally use calloc() because it zeros the memory too:
*my_cookie = (cookie_bank*)calloc(sizeof(cookie_bank), 1);
your third example is just wrong:
my_cookie = (cookie_bank **)malloc(sizeof(cookie_bank) * 1);
This will overwrite the local my_cookie pointer, and the memory will be lost on function return.
I just would like to recommend you to read some C textbook. It seems to me that you do not have clear understanding on how pointers work in C language.
Anyway, here is some example to allocate memory with malloc.
#include <stdlib.h>
void parse_cookies(const char *cookie, cookie_bank **my_cookie, int *cookies_num)
{
if (cookies_num == NULL || *cookies_num == 0) {
return;
}
if (my_cookie == NULL) {
my_cookie = (cookie_bank**)malloc(sizeof(cookie_bank*) * *cookies_num);
}
for (int i = 0; i < *cookies_num; i++) {
*my_cookie = (cookie_bank*)malloc(sizeof(cookie_bank));
my_cookie++;
}
}
Of course, this example does not cover any error handling. Basically, my_cookie is pointer to pointer which means my_cookie is just pointer to point memory location where it holds array of pointers. The first malloc allocate the memory using size of pointer and requested number of cookie structure. Then second malloc actually allocate memory for each structure.
The problem of this function is that it can easily cause memory leak unless using this very carefully.
Anyway, it is important to understand how C pointer works.

Resources