C cleaning up on error/termination - c

I run a bunch of mallocs in sequence, and check each time to make sure it was successful. Something like this:
typedef struct {
int *aray;
char *string;
} mystruct;
mystruct *mystruct_init(int length)
{
mystruct *foo = malloc(sizeof(int *));
if (!foo) exit(1);
foo->array = malloc(length * sizeof(int));
if (!foo->array) exit(1);
foo->string = malloc(length * sizeof(char));
if (!foo->string) exit(1);
return foo;
}
So when a malloc fails, the program exits without freeing the previous ones. What are some techniques to make sure that in case something fails, the program exits safely with all the allocated memory freed?

Most modern operating systems would free the right memory after the process terminates after calling exit(...). These operating systems include:
all Unix variants, including Linux and Mac OS X
all Windows versions
all DOS variants

If you're designing a driver that runs as part of the OS, you'll need to take care of this more carefully. In this case, goto is often used. For example
mystruct *mystruct_init(int length)
{
mystruct *foo = malloc(sizeof(int *));
if (!foo) goto FOO_FAIL;
foo->array = malloc(length * sizeof(int));
if (!foo->array) goto ARRAY_FAIL;
foo->string = malloc(length * sizeof(char));
if (!foo->string) goto STRING_FAIL;
return foo;
STRING_FAIL:
free(foo->array);
ARRAY_FAIL:
free(foo);
FOO_FAIL:
REPORT_ERROR; // user defined behavior
return NULL;
}
So if, say, foo->string is not allocated successfully, foo->array and foo will be freed accordingly. If foo->array fails, only foo will be freed. When any of these fails, the function returns NULL, which allows the caller to check the return value and decide next step.

Here's one of my favorite tricks:
do {
a = malloc(...);
if (!a) break;
b = malloc(...);
if (!b) {
free(a);
break;
}
} while (0);
if (!a) {
...
return;
}
...
free(b);
free(a);

if you want to do post-mortem cleanup then you can register an atexit handler
http://man7.org/linux/man-pages/man3/atexit.3.html
BTW I am not saying its easy to do (or correct)

You can do it this way too, I think it's the cleanest way to do it and I use it very often, but to return from a function, not to exit from the program since it is true that system will free memory at exit.
By the way your program as is will give segmentation fault, since you are not allocating enough space for foo.
typedef struct {
int *aray;
char *string;
} mystruct;
mystruct *mystruct_init(int length)
{
mystruct *foo = malloc(sizeof(mystruct)); // you need to allocate space for string too
if (!foo)
return NULL;
memset(foo, 0, sizeof(mystruct)); // initialize all members to NULL
foo->array = malloc(length * sizeof(int));
if (!foo->array)
goto abort;
foo->string = malloc(length * sizeof(char));
if (!foo->string)
goto abort;
return foo;
abort:
if (foo->array)
free(foo->array);
if (foo->string)
free(foo->string);
return NULL;
}
now in the calling function you can do it cleanly like
mystruct *foo;
foo = mystruct_init(length /* assuming this is declared and set. */);
if (!foo)
exit(1);

Related

How to avoid valgrind (or other memcheck tools) misreporting when I initialize a struct which contain a dynamic array?

I want to initialize a struct which contains a dynamic array, I wrote all this stuff in a function. And there is another function for cleaning this struct, theoretically, there will be no memory leaks. However, when I run the program with valgrind, it report that there was memory leaks when at the entry or init function.
Firstly, I wrote this init function with malloc to allocate memory for this struct. It report memory leak.
Then, I change malloc to realloc(NULL, ...) to avoid this misreport but I failed.
I don't know what the standard way in C is to implement this function.
#include <stdlib.h>
typedef enum
{
RUN_SUCCESS,
/*Failure*/
RUN_FAILURE
} RunStat;
typedef struct
{
char *elements;
size_t top;
size_t size;
} Stack;
RunStat init_stack(Stack *stack)
{
stack->elements = (char *)realloc(NULL, 100 * sizeof(char));
stack->size = 100;
stack->top = 0;
return RUN_SUCCESS;
}
RunStat free_stack(Stack *stack)
{
free(stack->elements);
stack->elements = NULL;
stack->size = 0;
stack->top = 0;
return RUN_SUCCESS;
}
int main ()
{
Stack stack;
init_stack(&stack);
free_stack(&stack);
return EXIT_SUCCESS;
}
Every memory here is under my control, I want to make this struct initialized without any memory leak warning. And I want to know the standard way to do that.

Sigtrap with only one free in code

So here is my problem, I have created this struct:
typedef struct foo *fooPtr;
struct foo {
foo2Ptr node;
foo3Ptr node;
char *Random;
};
fooNew(char* String) {
int StringLength;
StringLength = strlen(String) + 1;
Newfoo = (fooPtr *)malloc(sizeof(fooPtr));
Newfoo->Random = (char*)malloc(StringLength * sizeof(char));
strcpy(Newfoo->Random, String);
/*Rest of foo members initialized below....*/
}
fooChangeRandom(fooPtr Foo, String) {
int StringLength;
StringLength = strlen(String) + 1;
free(Foo->Random);
Foo->Random = (char*)malloc(StringLength * sizeof(char));
strcpy(Foo->Random, String);
}
But whenever I try to print the new string I get random characters. As I recall C requires me to free everything I allocate with malloc, calloc, or realloc so how does Random change when the fooNew ends? Tried to debug and at free I get the SIGTRAP error, on the line that free() gets used, however this is the only dynamically allocated object I have created and I haven't used free before. So Is there something I am missing or something wrong with the syntax of malloc or free?
You need to correct
Newfoo = (fooPtr *)malloc(sizeof(fooPtr));
to
Newfoo = (fooPtr *)malloc(sizeof(struct foo));

freeing a structure array allocated with double pointer

Here is basically what I'm trying to do:
free memory that was allocated in a different scope using double pointers.
The following code is incomplete but fully describes what I'm trying to perform.
so here is my function to read the buffer (C pseudo code)
char *read_buffer(char *buf, myStruct **arr, int nbElm)
{
buf = malloc(...);
...//many things done (use of the read(),close()... functions
...//but not referencing any of the buffer to my structure
...
*arr = (myStruct *) = malloc(sizeof(myStruct) * nbElm);
return (buf);
}
Here is the kind of function I use between my memory allocation and my freeing attempt:
void using_struct(myStruct *ar, int nbElm)
{
int i;
i = 0;
while (i < nbElm)
{
// Here I use my struct with no problems
// I can even retrieve its datas in the main scope
// not memory is allocated to it.
}
}
my main function :
int main(void)
{
char *buf;
myStruct *arStruct;
int nbElm = 4;
buf = read_buffer(buf, &arStruct, nbElm);
using_struct(arStruct, nbElm);
free(buf);
buf = NULL;
free(arStruct);
while(1)
{;}
return (1);
}
The only problem is either I place my while loop before or after my free function, I can't see any memory change using top
on my terminal.
Is this normal?
Thanks in advance,
You always must have exactly same number of calls to free as a calls to malloc.
myStruct **arr;
*arr = malloc(sizeof(myStruct) * nbElm);
This means you need single call to free first nbElm structs:
free(arr);

how to correctly free a struct? ANSI C

How does one correctly free a structure? If I have is this right? Or just called free once is correct?
typedef struct AStruct{
char * buffer;
int size;
} AStruct;
typedef struct S_Session {
int Id;
AStruct* buff;
char * name;
} S_Session;
S_Session* S_Session_new() {
S_Session* s = (S_Session*)malloc(sizeof(S_Session));
s->Id = 1;
s->buff = (AStruct*)malloc(sizeof(AStruct));
s->buff->buffer = malloc(8196);
s->buff->size = 8196;
s->name = malloc(100);
return s;
}
int main(int argc, char *argv[])
{
S_Session* sess = S_Session_new();
free(sess->buff->buffer);
free(sess->buff);
free(sess->name);
free(sess);
}
The rule like others have already said is to free everything you allocate, so from your code, you have 4 malloc's and you call free for those mallocs when the programs ends, which is correct.
In C nothing is automatic, so if you decided to call free only over your allocated struct, the remaining memory that you allocated would not been freed.
But for just a simple program, after the program ends the process is killed and the memory is freed by the Operating System, so it would be the end of the world if your release just the struct.
As a good practice you should free all the allocate memory by your program before it's termination.
In C, you should not cast the return value of malloc(). It can mask an error in the case that the prototype is missing, and the worst case result of using that value may be a crash.
In general, you should check the validity of a function call result before acting upon it. In this case, checking to see if malloc() actually succeeds will avoid a likely unintended crash in the case the system ran out of memory.
Since you can calculate exactly how much memory you need, you can implement your S_Session_new() to perform a single allocation of all the memory you need, and set the pointers to the right places within that memory. Doing so allows you to release that memory with a single call to free().
S_Session* S_Session_new() {
char *mem;
S_Session* s = 0;
size_t sz = 0;
sz += sizeof(S_Session);
sz += sizeof(AStruct);
sz += 8196;
sz += 100;
mem = malloc(sz);
if (mem) {
s = (void *)mem;
s->Id = 1;
s->buff = (void *)(mem += sizeof(S_Session));
s->buff->buffer = (void *)(mem += sizeof(AStruct));
s->buff->size = 8196;
s->name = (void *)(mem += 8196);
}
return s;
}

how free() works?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main ()
{
int * ptr;
printf("before malloc pointer is :%p \n",ptr);
printf("before malloc valu is :%d \n",*ptr);
ptr = malloc(sizeof(int));
printf("after malloc pointer is %p \n",ptr);
printf("after malloc valu is :%d \n",*ptr);
int jig=32;
*ptr = jig;
printf("after assignment valu is : %d\n",*ptr);
free(ptr);
printf("after free %p \n",ptr); // after free pointer holds sane address then
printf("after fee is %d\n",*ptr); // why it coudnt print that???
return 0;
}
output is :
before malloc pointer is :0x6edff4
before malloc valu is :7265660
after malloc pointer is 0x9a52008
after malloc valu is :0
after assignment valu is : 32
after free 0x9a52008
after fee is 0
after free still pointer holds the address of that memory then why we can not print that memory's value.??
what does free() do.?
does it just make all memory as 0 ..??
after free still pointer holds the address of that memory then why we can not print that memory's value.??
Because the memory no longer belongs to you. You freed it, which means the OS is allowed to reuse it however it sees fit, wherever it needs to allocate more memory. You no longer own it, therefore you no longer have any business looking at the value of the data held by that memory.
Note also that:
int *ptr;
...
printf("Before malloc valu is :%d\n", *ptr);
is equally invalid. ptr holds a garbage value, and can point anywhere. Dereferencing it is not guaranteed to be a memory location you can access.
Both of these cases invoke undefined behavior, which means the standard says, "DON'T DO THIS," and if you ignore the standard your code will break in horrible ways whenever your boss is looking.
what does free() do.?
does it just make all memory as 0 ..??
No, not necessarily. The OS often zeroes out unused memory in the background to make calls to calloc faster, but free only tells the operating system "I'm done with this memory, do whatever you need to with it." The OS typically updates some housekeeping data to indicate that the block of memory is no longer owned by a process, so that a later call to malloc can use it if it's needed.
The interesting thing about malloc() and free() is that they don't actually change the memory they give you -- they just change how it's "thought of".
When you call malloc(), a segment of memory is chosen and dedicated to be yours. While it's yours you can use it how you like.
When you're done with it you free() it -- but it's still there. It's still the same memory[1], it's just not considered "yours" anymore. So someone else might be using it.
[1] I supposed with virtual addressing this might not be always true. But it's usually true.
free returns the memory to the system. It is the partner operation to malloc. Everything block of memory that you allocate with malloc should be returned to the system by calling free. After you call free you are no longer allowed to access that memory.
It's generally considered wise to set the pointer to NULL after you have called free, at least in debug builds, so that you can be sure that an error will be raised if you later attempt to dereference the pointer by mistake.
So, why can you still access memory that has been freed? Well, you can't reliably do so. It just so happens that the implementation of most memory management systems mean that you can sometimes get away with such abuses. Many memory managers allocate large blocks of memory from the operating systems and then, in turn, allocate small sub-blocks to the application. When you call free, the allocator returns that block back to its pool of readily available memory, but does not necessarily give the memory back to the OS, since OS memory allocation routines are typically expensive. Hence accessing it may still appear to work, because the memory is still allocated in your process. It's just that its now owned by the memory manager rather than by your app. Something like that is happening to you here.
Of course, sometimes you won't get away with abuses like this, most likely once you have deployed your software onto your most important client's machine!
Typically the memory manager will have something like a linked list of free blocks that are used to satisfy subsequent allocations.
Here's a minimal implementation I wrote several years ago. It's not really intended (or suitable) for serious use, but gives at least some general notion of one way to manage a heap:
#include <stddef.h>
typedef struct node {
size_t size;
struct node *next;
} node;
node *free_list;
static void *split_end(node *block, size_t new_size) {
size_t difference = block->size - new_size;
node *temp = (node *)((char *)block + difference);
temp->size = new_size;
block->size = difference;
return (void *)((size_t *)temp+1);
}
static void *split_begin(node *block, size_t new_size) {
size_t difference = block->size-new_size;
node *temp = (node *)((char *)block + new_size);
temp->size = difference;
temp->next = free_list;
free_list = temp;
return block;
}
void b_init(void *block, size_t block_size) {
((node *)block)->size = block_size - sizeof(node);
((node *)block)->next = NULL;
free_list = block;
}
void b_free(void *block) {
node *b = (node *)((size_t *)block -1);
b->next = free_list;
free_list = b;
}
void *b_malloc(size_t size) {
node *temp, **ptr;
size_t larger = size+sizeof(node);
size += sizeof(size_t);
for ( ptr = &free_list;
NULL != ptr;
ptr = &((*ptr)->next))
{
if ((*ptr)->size >= size) {
if ( (*ptr)->size <= larger) {
temp = (*ptr);
(*ptr) = (*ptr)->next;
return (void *)((size_t *)temp + 1);
}
else
return split_end(*ptr, size);
}
}
return NULL;
}
void *b_realloc(void *block, size_t new_size) {
node *b = (node *)((char *)block - sizeof(size_t));
char *temp;
size_t i, size;
if ( new_size == 0) {
b_free(block);
return NULL;
}
new_size += sizeof(size_t);
size = b->size;
if ( new_size <size)
size = new_size;
size -= sizeof(size_t);
if ( b->size >= new_size+sizeof(node *) )
return split_begin(b, new_size);
if ( b->size >= new_size)
return b;
temp = b_malloc(new_size);
if ( NULL == temp)
return NULL;
for ( i=0; i<size;i++)
temp[i] = ((char *)block)[i];
b_free(block);
return temp;
}
#ifdef TEST
#define num 10
int main(void) {
int i;
char block[4096];
char *temp[num];
char *big;
b_init(block, sizeof(block));
big = b_malloc(100);
for (i=0; i<num; i++)
temp[i] = b_malloc(10);
for (i=0; i<num; i++)
b_free(temp[i]);
b_realloc(big, 200);
b_realloc(big, 10);
b_realloc(big, 0);
return 0;
}
#endif

Resources