How to be safe with memory? - c

I would like to actually use this wrapper, but the problem is i don't know if it's very safe, yet.
I have a few simple questions regarding using malloc(), calloc(), and realloc(). Here's what I have so far:
string.h
typedef struct str str; // pointer for encapsulation
string.c
struct str
{
char *buf;
size_t len;
}
Say i have a helper function that simply does this:
str *NEW_STRING()
{
str *temp = calloc(1, sizeof (struct str));
temp->len = 0;
temp->buf = (char *) malloc(1);
return temp;
}
Is this safe? If it is, what would happen if i did something like this:
str *A_STRING = NEW_STRING();
A_STRING = NEW_STRING();
It would call malloc and calloc twice, is that bad? Would an initializer be better?
void str_init(str *A_STRING)
{
if (A_STRING)
{
free(A_STRING);
}
if (A_STRING->buf)
{
free(A_STRING->buf);
}
A_STRING = calloc(1, sizeof (struct str));
A_STRING->buf = (char *) malloc(1);
A_STRING->len = 0;
}
Finally, is this a good way to free memory?
void free_string(str *A_STRING)
{
if (A_STRING->buf)
{
free(A_STRING->buf);
}
else
{
A_STRING->buf = NULL;
}
if (A_STRING)
{
free(A_STRING);
}
else
{
A_STRING = NULL;
}
A_STRING->len = 0;
}
Any additional information would be great if included. I don't want to release anything to the public as if it were a good library, because i am primarily doing this for learning purposes.

Lots of errors:
is this safe? if it is, what would happen if i did something like this:
No.
str *NEW_STRING()
{
str *temp = calloc(1, sizeof (struct str));
// If calloc fails and returns NULL all the code below is invalid and blows the code up.
Next:
it would call malloc and calloc twice, is that bad? would an initializer be better?
You leak memory.
The second call basically generates a new object the old object is lost and leaks.
Problems in str_init
void str_init(str *A_STRING)
{
Is this the first time that his method is called?
If so then A_STRING contains a random value (that you are about to FREE).
This will blow the code up.
if (A_STRING)
{
free(A_STRING);
}
A_STRING is freed (you can now no longer accesses it).
Any code that does so is bad.
if (A_STRING->buf) // Bang blow up code.
{
free(A_STRING->buf);
}
A_STRING = calloc(1, sizeof (struct str));
No checking the result of calloc.
A_STRING->buf = (char *) malloc(1);
A_STRING->len = 0;
}
is this a good way to free memory?
void free_string(str *A_STRING)
{
if (A_STRING->buf)
{
free(A_STRING->buf);
}
else
{
A_STRING->buf = NULL; // Its already NULL pointless work
}
if (A_STRING)
{
free(A_STRING);
}
else
{
A_STRING = NULL; // ITs already NULL pointless work
}
// BANG you just blew up the space shuttle.
A_STRING->len = 0;
}

Related

C Memory leak issue

Program is leaking memory and not able to fix it... This Program is reading data from text files and after reading data, it perform certain operation on data during this it leaks memory. Device has very limited memory & flash drive due to this I cannot run memory leaks checking tools.
Please advise to fix the memory leak issue
Please find code snippet below
int LanguageRequiredData(void)
{
char *data=NULL;
int retValue = 0 ;
retValue = GetString_English(&data);
if(retValue>0 && strlen(data)>0)
{
// Do Some Operation
}
if (data!=NULL)
{
Mem_free(data);
data = NULL;
}
}
int GetString_English(char **data)
{
int retValue = 0 ;
retValue = File_LoadContent(LANGSENGFILE,&(*data));
return retValue;
}
int File_LoadContent (char *file, char **content)
{
long size = File_Size(file);
char buf[256]={};
memset(buf,0x00,sizeof(buf));
if (*content)
{
Mem_free(*content);
}
*content = (char*) Mem_alloc((size+1) * sizeof(char));
TFILE * fd; fd=File_Open(file,"r"); if (fd==NULL) return 0;
while (File_Gets(buf,sizeof(buf),fd)!=NULL)
{
strcat(*content,buf);
memset(buf,0x00,sizeof(buf));
}
File_Close(fd); return 1;
}
void * Mem_alloc(size_t size)
{
int i;
void * ptr = NULL;
for (i = 0; i < 2; i++)
{
ptr = malloc(size);
if (ptr)
{
break;
}
}
if (ptr)
{
memset(ptr, 0, size);
}
return ptr;
}
void Mem_free(void * ptr)
{
if (ptr != NULL)
{
free(ptr);
}
ptr = NULL;
}
This part seems suspect:
while (File_Gets(buf,sizeof(buf),fd)!=NULL)
{
strcat(*content,buf);
memset(buf,0x00,sizeof(buf));
}
Specifically the strcat(). Is File_Gets() null-terminating what it writes to buf[]? If not then the strcat() may be reading/copying beyond the bounds of buf[], since it requires null-termination to know when to stop.
EDIT: I should point out that this is one of the reasons to recommend strncat() over strcat(). Using the "n" variants of the string functions (i.e. strncat(), strncpy(), strncmp()) helps prevent buffer overruns and is generally a good practice.

Segfault using dynamic array

Apologies for the really bad question - I wasn't really sure how to word it.
I'm executing a piece of code where I'm trying to use a dynamic array. It is segfault-ing at this line:
void myFunction(....) {
// other code up here
Stack *s = stack_new(); //segfault here
}
The relevant header file for my struct is:
typedef struct {
void **A;
int size;
int top; // the index of the current top of the stack
} Stack;
and the function stack_new() is:
Stack
*stack_new() {
Stack *s;
s->size = 1;
s->top = -1;
s->A = (void **)malloc(s->size);
return s;
}
I think I've included everything that is relevant, but please let me know if you need more code.
I think that the problem is with the way I'm using malloc, but have had a search online and have tried a few different options and am still getting the segfault. Is anyone able to offer some insight?
Thank you heaps
This is your problem:
Stack *s;
s->size = 1;
you're not actually allocating a Stack. s is uninitialized and points to an arbitrary location in the memory. s->size will obviously fail then.
Try:
Stack *s = malloc(sizeof(*s));
if (s == NULL)
{
fprintf(stderr, "Memory allocation error\n");
exit(1);
}
s->size = 1;
Note: you should also check if s->A is NULL. If so, return an error code (such as NULL) and before that remember to free the Stack you allocated, or alternatively print an error message and exit the program. If you exit the program, the operating system will reclaim all memory used so no need to do it explicitly then.
Another note: when doing
s->size = 1;
s->top = -1;
s->A = (void **)malloc(s->size);
...you allocate 1 byte of memory even though you should be allocating sizeof(void*) bytes of memory. Try doing
s->A = (void **)malloc(s->size*sizeof(void*));
instead.
Here's your first problem:
Stack *s;
s->size = 1;
What do you actually expect the value of s is at this point? It could be literally anything. You can't set a field of a struct if the struct itself isn't already allocated.
Try:
Stack *s = malloc(sizeof(*s));
if(!s){
//... error checking / exiting ..
}
and then everything else you were doing.
You are accessing a not initialized pointer!
Stack
*stack_new() {
Stack *s = std::nullptr; // initialize this pointer with nullptr
// and then you will see later (one line
// beyond) that you will try to access a
// null pointer
s->size = 1; // the problem occurs here!!
// you are accessing a pointer, for which has never
// been allocated any memory
s->top = -1;
s->A = (void **)malloc(s->size);
return s;
}
You will have to use "malloc" to allocate some memory for this pointer.
sth. like this is missing between those two lines, I commented:
Stack
*stack_new() {
Stack *s = (Stack*)malloc(sizeof(Stack));
s->size = 1;
s->top = -1;
s->A = (void **)malloc(s->size);
return s;
}

Homework: Freeing data in a struct

I'm just learning to use valgrind and c, and I have an invalid free() output when trying to free data from a struct. I believe it's because data is not being freed from the struct correctly.
This is my struct:
typedef struct song_
{
char *artist;
char *title;
mtime *lastPlayed;
} song;
And this is the function which tries to free it:
void songDelete(song *s)
{
//artist
free(s->artist) ;
//title
free(s->title) ;
//time
if(NULL != s->lastPlayed)
mtimeDelete(s->lastPlayed) ;
//song
free(s);
}
mtime and mtimeDelete are some user-defined variables and methods, but I feel like they're not relevant to my question. I know it's wrong to ask someone to do my homework for me, I'd just like a push in the right direction if possible.
No, that's definitely the right way to do it.
So, if valgrind is complaining, it's probably because the values in artist, title or lastPlayed are not actually valid pointers.
That's the first thing I'd be checking.
In other words, make sure what you put in there are valid pointers. Simply creating a song with:
song *AchyBreakyHeart = malloc (sizeof (song));
won't populate the fields (they'll be set to arbitrary values). Similarly,
AchyBreakyHeart->artist = "Bill Ray Cyrus";
will populate it with a string constant rather than a valid pointer in the heap.
The ideal thing would be to have a "constructor", similar to the destructor you've provided, something like:
song *songCreate (char *artist, char *title, mtime *lastPlayed) {
song *s = malloc (sizeof (song));
if (s == NULL) return NULL;
s->artist = strdup (artist);
if (s->artist == NULL) {
free (s);
return NULL;
}
s->title = strdup (title);
if (s->title == NULL) {
free (s->artist);
free (s);
return NULL;
}
s->lastPlayed = mtimeDup (lastPlayed);
if (s->lastPlayed == NULL) {
free (s->title);
free (s->artist);
free (s);
return NULL;
}
return s;
}
This guarantees that the object is either fully constructed or not constructed at all (ie, no half-states).
Better yet would be to adapt the constructor/destructor pair to handle NULLs in conjuction with each other, to simplify the pair. First, a slightly modified destructor, the only change being that it can accept NULL and ignore it:
void songDelete (song *s) {
// Allow for 'songDelete (NULL)'.
if (s != NULL) {
free (s->artist); // 'free (NULL)' is valid, does nothing.
free (s->title);
if (s->lastPlayed != NULL) {
mtimeDelete (s->lastPlayed) ;
}
free (s);
}
}
Next, the constructor which, rather than trying to remember what has been allocated, instead sets them all to NULL initially and just calls the destructor if something goes wrong:
song *songCreate (char *artist, char *title, mtime *lastPlayed) {
// Create song, null all fields to ease destruction,
// then only return it if ALL allocations work.
song *s = malloc (sizeof (song));
if (s != NULL) {
s->artist = s->title = s->lastPlayed = NULL;
s->artist = strdup (artist);
if (s->artist != NULL) {
s->title = strdup (title);
if (s->title != NULL) {
s->lastPlayed = mtimeDup (lastPlayed);
if (s->lastPlayed != NULL) {
return s;
}
}
}
}
// If ANY allocation failed, destruct the song and return NULL.
songDelete (s);
return NULL;
}
Your code appears correct.
Make sure that your struct is initialized correctly (with pointers set to NULL or a valid value).
int main() {
song_ *s = calloc(sizeof(song_));
free(s);
return 0;
}
Did you create an object/pointer to your Struct using malloc (heap allocation)? or just song s; (stack allocation) ??
You can't free it if it hasn't been malloc'd, or in other words you can't free a variable on stack, it has to be on the heap.

Am I calling free() correclty on my struct pointer?

So while testing my struct I use the following method. You can see that I call free on the pointer at the end of the method. Is this right?
void test() {
VariableVector *labelVector = initVariableVector();
VariableVector *variableVector = initVariableVector();
// do some stuff with labelVector and variableVector
free(labelVector);
free(variableVector);
}
This is what my struct init methods look like:
Variable* initVariable(char *variableName, char *arrayOfElements,
int32_t address) {
Variable* initializedVariable = malloc(sizeof(Variable));
if (initializedVariable != NULL ) {
initializedVariable->variableName = variableName;
initializedVariable->arrayOfElements = arrayOfElements;
initializedVariable->address = address;
return initializedVariable;
} else {
return NULL ;
}
}
VariableVector* initVariableVector() {
VariableVector* initializedVariableVector = malloc(
sizeof(VariableVector));
if (initializedVariableVector != NULL ) {
initializedVariableVector->size = 0;
initializedVariableVector->capacity = VECTOR_INITIAL_CAPACITY;
initializedVariableVector->variables = malloc(
sizeof(Variable) * VECTOR_INITIAL_CAPACITY);
return initializedVariableVector;
} else {
return NULL ;
}
}
Your idea is correct, but your implementation is not.
initVariableVector() does 2 malloc's for one object, but you only do 1 free.
You should have function to destroy it too.
void destroyVariableVector(VariableVector* vector)
{
if(vector) {
free(vector->variables);
free(vector);
}
}
EDIT: You're not checking whether the memory allocation for the member "variables" in structure VariableVector is successful. Which means that even at the end you do not free it manually, so it leads to memory leak.
My advice:
Use "init*" functions, but at the same time use "free*" functions. It keeps the code clearer and takes care of all memory releasing.
initVariableVector, the opposite should be freeVariableVector
And the latter function could look like:
void freeVariableVector(VariableVector *vv)
{
if (vv) {
if (vv->variables)
free(vv->variables);
free(vv);
}
}

segfault when allocate memory dynamically in C

I've been trying to build a priority queue in C.
First of all, I do some initialization work such as allocating space.
The following is the Initialize routine and PriorityQueue is a pointer.
void Initialize(int MaxElement, PriorityQueue H)
{
if (MaxElement < MinPQSize)
printf("Priority queue size is too small");
if (!(H = (PriorityQueue)malloc(sizeof(struct HeapStruct))))
printf("Out of space!!!");
if (!(H->Elements = (ElementType *)malloc((MaxElement+1) * sizeof(ElementType))))
printf("Out of space!!!");
H->Capacity = MaxElement;
H->Size = 0;
H->Elements[0] = MinData;
}
Here is how the test code is like
int MaxElement = 15;
PriorityQueue myHeap;
Initialize(MaxElement, myHeap);
But when I try to insert elements into the heap, a segmentation fault pops out.
It can be solved by simply returning the PriorityQueue pointer from Initialize routine.
PriorityQueue Initialize(int MaxElement, PriorityQueue H)
{
...
return H;
}
myHeap = Initialize(MaxElement, myHeap);
So what's happening under the hood?
Is free() invoked when the function returns without a return value?
Thx in advance!
No, even though the H that you're passing in is a pointer, you're trying to change it within the function (with your first malloc). In order to change something, you need to pass a pointer to it. In this case, that means a pointer to a pointer:
void Initialize (int MaxElem, PriorityQueue *H) {
if (MaxElem < MinPQSize)
printf("Priority queue size is too small");
if (!(*H = (PriorityQueue)malloc(sizeof(struct HeapStruct))))
printf("Out of space!!!");
if (!((*H)->Elements = (ElemType *)malloc((MaxElem+1) * sizeof(ElemType))))
printf("Out of space!!!");
(*H)->Capacity = MaxElem;
(*H)->Size = 0;
(*H)->Elements[0] = MinData;
}
Without the extra level on indirection, the H that you change within the function is isolated to the function - it is not reflected back to the caller.
A couple of other points you may want to consider:
You shouldn't cast the return from malloc, it can hide certain errors that you really do want to know about.
If your second malloc fails, you should free the result of the first malloc.
If either of your malloc calls fail, you should return rather than continue, since continuing will cause undefined behaviour if you dereference the null pointer.
You probably don't want to print things from general purpose functions since that's probably an unwanted behaviour. If you must indicate a problem, you're better off passing back an indication to the caller to let them handle it in their own way.
Although to be honest, I actually like the versions that return a value (with no need to pass it in beforehand since you're clearly creating a new thing). Something like this should do:
PriorityQueue Initialize (int MaxElem) {
PriorityQueue H;
if (MaxElem < MinPQSize) {
printf("Priority queue size is too small");
return NULL;
}
if (!(H = malloc(sizeof(*H)))) {
printf("Out of space!!!");
return NULL;
}
if (!(H->Elements = malloc((MaxElem+1) * sizeof(ElementType)))) {
printf("Out of space!!!");
free (H);
return NULL;
}
H->Capacity = MaxElem;
H->Size = 0;
H->Elements[0] = MinData;
return H;
}
PriorityQueue myHeap = Initialize (MaxElement);
You are passing the pointer by value, allow me to illustrate:
char* c = 0;
void set_c(char* ptr)
{
ptr = (char*) malloc(sizeof(char) * 10);
}
// a copy of c is sent in,
set_c(c);
// c doesn't point to the newly allocated data!
To set it correctly, you have to pass your pointer BY pointer, like this:
void set_c_correctly(char** ptr)
{
*ptr = (char*) malloc(sizeof(char) * 10);
}
// a pointer to c is passed in
set_c_correctly(&c);
// now c points to the newly allocated data

Resources