memory leak in adding and deleting dynamic list - c

I really need your help in this matter. I have these two functions that do the following:
copy face struct and add it to a list of faces (_face_list_entry_t)
copy a pointer of struct and add it to a list of pointers (fib_entry_t )
I created these two functions to dynamically allocate and add new items (faces and pointers) to their respected list. (I don't want the function of removing item)
I am currently facing a memory leak and I am not sure if allocating/reallocating/freeing the memory in them causes this issue. Below is the the two functions:
int8_t face_list_add(_face_list_entry_t** face_list, int8_t* face_list_size, _face_list_entry_t* face)
{
if (*face_list == NULL) {
*face_list = malloc(sizeof(_face_list_entry_t));
if (*face_list == NULL) {
DEBUG("fail to allocate memory for face list\n");
return -1;
}
*face_list_size = 1;
(*face_list)[0].id = face->id;
(*face_list)[0].type = face->type;
return 0;
} else {
// check for existing face entry
for (int i = 0; i < *face_list_size; ++i) {
if ((*face_list)[i].id == face->id) {
DEBUG("wildcard: same face exists in the fib entry\n");
return 1;
}
}
// need to add a new entry to the face list
_face_list_entry_t *list = (_face_list_entry_t*) realloc( *face_list, (*face_list_size + 1) * sizeof(_face_list_entry_t));
DEBUG("facelist size = %d\n", (*face_list_size + 1) * sizeof(_face_list_entry_t));
if (list == NULL) {
DEBUG("fail to reallocate memory for face list (size=%d)\n", *face_list_size);
return -1;
}
*face_list = list;
(*face_list)[*face_list_size].id = face->id;
(*face_list)[*face_list_size].type = face->type;
++(*face_list_size);
return 0;
}
}
int8_t pointer_list_add(fib_entry_t ***fib_list, int8_t *fib_list_size, fib_entry_t **fib)
{
if (*fib_list == NULL) {
*fib_list = malloc(sizeof(fib_entry_t *));
if (!*fib_list) {
DEBUG("fail to allocate memory for fib list\n");
return -1;
}
*fib_list_size = 1;
**fib_list = *fib;
return 0;
} else {
// check for existing fib entry
for (int i = 0; i < *fib_list_size; ++i) {
if ((*fib_list)[i] == *fib) {
DEBUG("same fib exists in the fib entry\n");
return 1;
}
}
// need to add a new entry to the fib list
fib_entry_t **list = (fib_entry_t **)realloc(*fib_list, (*fib_list_size + 1) * sizeof(fib_entry_t *));
if (!list) {
DEBUG("fail to reallocate memory for fib list (size=%d)\n", *fib_list_size);
return -1;
}
**fib_list = *list;
(*fib_list)[*fib_list_size] = *fib;
++(*fib_list_size);
return 0;
}
}
I call them like this:
res = face_list_add(&list_faces, &lst_faces_size, face);
res = pointer_list_add(&list_fibs, &list_fibs_size, &fib);
I delete the list like below. I don't want to delete the memory that each pointer is pointing to, I just want to delete the allocated memory for the list of pointers and the list of faces:
free(list_faces);
free(list_fibs);
Please let me know if I am doing it wrong or suggest a better way (low cost) as the device I am working on has a constrained capability, very low memory (256KB), and low process power, i.e. maintaining memory is crucial. Besides, usually, both lists are relatively small but in some cases can become bigger.
Your help is highly appreciated

Given the face_list_add() and pointer_list_add() functions presented and these calls that (re)allocate memory ...
res = face_list_add(&list_faces, &lst_faces_size, face);
res = pointer_list_add(&list_fibs, &list_fibs_size, &fib);
, these free() calls ...
free(list_faces);
free(list_fibs);
... are correct for for freeing the memory allocated by those functions. Or they would be, if the functions were correct. face_list_add() appears to be ok, but there is an error in realloc branch of pointer_list_add(), here:
**fib_list = *list;
That should be
*fib_list = list;
, analogous to
*fib_list = malloc(sizeof(fib_entry_t *));
in the initial allocation branch.

Related

Realloc does not work (following the instruction in cs50 lecture 5)

I'm going to add a new value 4 to the list array.
The original values in list array are 1,2,3.
But when i run the following code, i didn't get 1,2,3,4 but several random numbers.
Each time I run I get different output.
Can someone help me figure out what's going wrong here?
Thanks a lot.
#include <stdio.h>
#include <stdlib.h>
int main(void){
int *list = malloc(3 * sizeof(int));
//如果直接写int list[3] 就没有办法修改大小了
if (list == NULL)
{
free(list);
return 1;
}
list[0] = 1;
list[1] = 2;
list[2] = 3;
//resize the old array to be of size 4
//用realloc指定下old array,无需再做copy的工作
int *tmp = realloc(list, 4 * sizeof(int));
if (list == NULL)
{
free(list);
//a safety check, free the original list
return 1;
}
tmp[3] = 4;
//free old array
free(list); //这里就可以free之前的list了
//remember new array
list = tmp;
//所以不需要在free(tmp), free(list)相当于free(tmp)
//print new array
for (int i = 0; i < 4; i++)
{
printf("%i\n", list[i]);
}
//free new array
free(list);
return 0; //最后记得加上这个
}
the output is like this:
1609039888
25764
2043
4
try this code
#include <stdio.h>
#include <stdlib.h>
int main(void){
int *list = malloc(3 * sizeof(int));
//如果直接写int list[3] 就没有办法修改大小了
if (list == NULL)
{
free(list);
return 1;
}
list[0] = 1;
list[1] = 2;
list[2] = 3;
//resize the old array to be of size 4
//用realloc指定下old array,无需再做copy的工作
int *tmp = realloc(list, 4 * sizeof(int));
if (list == NULL)
{
free(list);
//a safety check, free the original list
return 1;
}
tmp[3] = 4;
//free old array
//free(list); //这里就可以free之前的list了 // this free the last memory location which empty the array.
//remember new array
list = tmp;
//所以不需要在free(tmp), free(list)相当于free(tmp)
//print new array
for (int i = 0; i < 4; i++)
{
printf("%i\n", list[i]);
}
//free new array
free(list);
return 0; //最后记得加上这个
}
There's a fundamental misunderstanding on how dynamic memory management actually works...
At first, if an allocation fails (malloc returning a null pointer), then there's nothing to free anyway, so you simply don't need to (even though it's legal – then effectively a no-op...).
int* list = malloc(...);
if(!list) // shorter for list == NULL
{
return -1;
}
Then realloc replaces the old array for you already! You can imagine it to work like this:
void* realloc(void* oldData, size_t desired)
{
// retain currently allocated memory size from pointer
// that's OS/compiler specific knowledge, usually stored somewhere
// in front of the memory the pointer points to, but not (legally)
// accessible by you...
size_t old = ...;
if(desired <= old)
{
return oldData;
}
void* newData = malloc(desired);
if(newData)
{
memcpy(newData, oldData, oldSize);
free(oldData); // !!!
}
return newData;
}
Note how the old data remains intact if re-allocation fails, but gets deleted on success!
Correct usage of realloc thus looks as follows:
int* tmp = realloc(list, desiredSize);
if(!tmp)
{
// appropriate error handling
// usually you cannot meaningfully go on anyway, so let's just exit
// but HERE list still points to valid memory, so clean up first:
free(list);
return -1;
}
// we can safely use the temporary as the list now; note that the old
// memory already HAS been deleted!
list = tmp;
// and now we simply use it:
list[3] = 4;
free(list); // when done

Weird issue when reallocating memory in C

I am trying to get into C and as a training example, I decided to write a simple dynamically sized list. But I am facing a weird problem, where the code only works up to an initial list size of 4. Starting at List size 5, I get an error.
typedef struct {
int* data;
int alloc_size;
int length;
} List;
List create(int init_size) {
List out;
out.data = (int*) malloc(init_size * sizeof(int));
out.alloc_size = init_size;
out.length = 0;
return out;
}
void list_push(List* list, int elem) {
if (list->length == list->alloc_size) {
list->data = (int*) realloc(list->data, 2 * list->alloc_size);
list->alloc_size *= 2;
}
*(list->data + list->length) = elem;
list->length++;
}
int list_pop(List* list) {
list->length--;
return *(list->data + list->length);
}
int main() {
List list = create(5);
for (int i = 0; i < 100; i++) {
list_push(&list, i);
}
while (list.length > 0) {
printf("%d\n", list_pop(&list));
}
return 0;
}
Up to create(4), everything works as expected. But if the list is created with create(5) (i.e. an initial size of 5), I get the following error: malloc: Incorrect checksum for freed object 0x7f7ff5c01778: probably modified after being freed. Corrupt value: 0x700000006. I can't really wrap my head around what would cause this to only work up to specific initial sizes, as the list size is dynamically reallocated anyway.
There are a couple of problems with this line
list->data = (int*) realloc(list->data, 2 * list->alloc_size);
The most evident is that 2 * list->alloc_size should be multiplied by the size in bytes of each element (sizeof(int) or sizeof(*(list->data)) in this case).
The most subtle is that the return value of realloc (and of the previous malloc) is not checked, but unconditionally assigned to list->data. The problem is that, on failure, it returns NULL, while the passed pointer (list->data) is not invalidated and should be freed to avoid leaks.
change to reallocation statement
list->data = (int*) realloc(list->data,sizeof(int) * 2 * list->alloc_size);
Second time you are trying to re-allocate lesser bytes than you already allocated, that's the reason for this

C - Heap Corruption Detected

I got assigment from the professor to create a list using pointers. I'm having a problem with free() in all of my functions when I try to free memory. I keep getting a message:
"HEAP CORRUPTION DETECTED: after Normal block (#83) at 0x00D58CE0.
CRT detected that the application wrote to memory after end of heap buffer."
I have no idea how to fix it. I've tried different things but nothing worked so far. I'm not sure where to search for it either anymore. I know that my program is not properly secured yet, but it doesn't affect the problem. I'm trying to eliminate it first before going further with it. Also, do you have any advice on detecting memory leaks from the program in visual studio? Here are my functions, full source code is below in the link:
Full Source Code
struct ListElement
{
int value;
struct element *next;
};
typedef struct ListElement List;
typedef List *ListEl;
void ViewListBackwards(ListEl *list_el)
{
ListEl current_element = *list_el;
int size = 0;
int i = 0;
int *reversed_array;
while (current_element->next != NULL)
{
size++;
current_element = current_element->next;
}
current_element = *list_el;
reversed_array = (int*)malloc(size * sizeof(*reversed_array));
for (i = size; i >= 0; i--)
{
reversed_array[i] = current_element->value;
current_element = current_element->next;
}
for (i = 0; i <= size; i++)
{
printf(" %d. %d\n", i + 1, reversed_array[i]);
}
free(reversed_array);
}
void RemoveFromListFront(ListEl *list_el)
{
if (ListEmpty(list_el) == 0)
{
ListEl current_element = *list_el;
*list_el = current_element->next;
free(current_element);
}
else
{
printf("List is empty!\n");
}
}
void RemoveFromListBack(ListEl *list_el)
{
if (ListEmpty(list_el) == 0)
{
ListEl current_element = *list_el;
ListEl last_element = *list_el;
while (current_element->next != NULL)
{
last_element = current_element;
current_element = current_element->next;
}
last_element->next = NULL;
free(current_element);
}
}
In the following code:
reversed_array = (int*)malloc(size * sizeof(*reversed_array));
for (i = size; i >= 0; i--)
{
reversed_array[i] = current_element->value;
current_element = current_element->next;
}
for (i = 0; i <= size; i++)
{
printf(" %d. %d\n", i + 1, reversed_array[i]);
}
you are allocating (what amounts to) an int reversed_array[size] array, but then proceed to write to reversed_array[size], which is sizeof(int) past the end of the allocated memory segment.
You instead want to change your for loops to:
for (i = size - 1; i >= 0; i--)
so that the indices you write to start at reversed_array[size - 1].
EDIT:
As an aside, please, as other people have suggested in the comments, don't cast malloc(). This is unneeded in C, as void * can be assigned to any object pointer type variables, and in addition can hide bugs in your code, such as forgetting to include stdlib.h.
And FWIW, you don't need the parentheses around sizeof(*reversed_array), as parentheses are only needed when applying the sizeof operator to types.
This is mostly just a style suggestion; it is preferred by many (myself included) that you omit the extraneous parentheses and write that expression as sizeof *reversed_array, as that makes it clear that sizeof is a unary operator and not a function.

Memory Leaks in C

So I'm very new to C, and I'm writing a matrix compression function for a trivial Bitmap Image recognition program. I have the following code, and Valgrind in telling me I have memory leaks at the following marked lines, although I have no idea what's causing it. Any advice would be appreciated.
/* Returns a NULL-terminated list of Row structs, each containing a NULL-terminated list of Elem structs.
* See sparsify.h for descriptions of the Row/Elem structs.
* Each Elem corresponds to an entry in dense_matrix whose value is not 255 (white).
* This function can return NULL if the dense_matrix is entirely white.
*/
Row *dense_to_sparse(unsigned char *dense_matrix, int width, int height) {
Row *result = NULL;
_Bool first_row;
for (int row = height - 1; row >= 0; row--) {
first_row = 0;
for (int elem = width - 1; elem >= 0; elem--) {
unsigned char curr_item = dense_matrix[(row*width) + elem];
if (curr_item!= 255) {
if (!first_row) {
(Memory Leak) Row *curr_row = (Row *) malloc(sizeof(Row));
if (curr_row == NULL) {
allocation_failed();
}
curr_row->next = result;
curr_row->y = row;
curr_row->elems = NULL;
result = curr_row;
//free(curr_row);
first_row = 1;
}
(Memory Leak) Elem *curr_elem = (Elem *) malloc(sizeof(Elem));
if (curr_elem == NULL) {
allocation_failed();
}
curr_elem->value = curr_item;
curr_elem->x = elem;
curr_elem->next = result->elems;
result->elems = curr_elem;
//free(curr_elem);
}
}
}
return result;
}
I believe it may be a problem with freeing curr_row and curr_elem, although when I try to free them at the end of each loop, it gives me a runtime error:
parsify(73897,0x7fff75584310) malloc: * error for object 0x7fbf81403a48: incorrect checksum for freed object - object was probably modified after being freed.
You need to call free on every pointer that you get from malloc. C doesn't automatically free up memory that you allocate, so you need to tell it "I'm done." Free is how you do this.
EDIT: You should also probably call free at the very end of the function, after you know you're done with the memory. If you do it at the end of the loop, you may run into problems with using memory you already freed.
EDIT EDIT: When you free it, note that you have put result in curr_row->next. You're probably accessing this later, post-free, which is a serious problem. You likely want to free all of them at the same time, as clearly you still need the memory (you still have pointers to it).
You cannot free the memory in dense_to_sparse because the whole point of the function is to create and return the newly allocated data structure. Presumably, the code that calls dense_to_sparse wants to use the result.
You will need a separate function to deallocate the memory that you should call once you no longer need it.
void free_sparse_matrix (Row *matrix)
{
Row *row = matrix;
while (row != NULL) {
Row *next_row = row->next;
Elem *elem = row->elems;
while (elem != NULL) {
Elem *next_elem = elem->next;
free (elem);
elem = next_elem;
}
free (row);
row = next_row;
}
}

glibc detected - double free or corruption

this might be a bit long so my apologies.
consider the following code (i've left some irrelevant parts from it). this code receives a pointer to a struct (BoardP theBoard), x & y coords and a value.
the goal is to place the value in a 2D array that is found in the struct.
if the coords are out of bounds, i have to increase the size of the table, copy old data to new data and place the value in its place.
well this code works the first call but in the second call it crashes and writes:
*** glibc detected *** ./b: double free or corruption (top): 0x092ae138 ***
i couldn't find an answer to it and i hope you will help.
These are the calls from main()
BoardP p = CreateNewBoard(10,10);
PutBoardSquare(p,10,5,'X');
PutBoardSquare(p,5,10,'O');
Boolean PutBoardSquare(BoardP theBoard, int X, int Y, char val) {
if (inBounds(X,Y,theBoard->_rows,theBoard->_cols)) {
theBoard->_board[X * theBoard->_cols + Y] = val;
return TRUE;
}
else {
int newRows = (X>=theBoard->_rows) ? (2*X) : theBoard->_rows;
int newCols = (Y>=theBoard->_cols) ? (2*Y) : theBoard->_cols;
BoardP newBoard = CreateNewBoard(newCols,newRows); //this creates a new Board with the new dimensions
if (newBoard == NULL) {
//ReportError(MEM_OUT);
return FALSE;
}
else {
copyData(theBoard,newBoard);
freeBoardArray(&theBoard->_board[0]); //free old array
theBoard->_board = newBoard->_board; //old array point to new array
FreeBoard(newBoard); //free the temp copy THIS CAUSES THE PROBLEM
PutBoardSquare(theBoard,X,Y,val);//recursion, will be in bounds now
return TRUE;
}
}
}
These are the Free functions:
void FreeBoard(BoardP board) {
if (board != NULL) {
printf("FREE 1\n");
//free the board array:
if (board->_board != NULL) {
printf("FREE 2\n");
freeBoardArray(&board->_board[0]);
printf("FREE 3\n");
}
free(board);
}
}
static void freeBoardArray(char * arrP) {
free(arrP); //**PROGRAM CRASH HERE**
}
This is how i create a new board:
BoardP CreateNewBoard(int width, int high) {
BoardP board = (BoardP) malloc(sizeof(Board));
if (board != NULL) {
board->_board = allocateBoardArray(high,width);
if ( board->_board == NULL) {
FreeBoard(board);
//TODO make file ReportError(MEM_OUT);
return NULL;
}
initializeBoard(board,high,width,X_SIGN,SPACE);
return board;
}
else {
FreeBoard(board);
//TODO make file ReportError(MEM_OUT);
return NULL;
}
}
static char* allocateBoardArray(int row, int col) {
char* newBoard = (char*) malloc(row * col * sizeof(char));
if (newBoard == NULL) {
return NULL;
}
return newBoard;
}
this is BoardP:
typedef struct Board* BoardP;
You have to free memory which you have allocated and no longer want to hold a reference too.
from your code i can see the following line.
theBoard->_board = newBoard->_board;
Now you maintain reference to a allocated pointer and then free that same pointer itself.
Example code:
char *foo()
{
char *ref1;
char *ref2;
ref1 = malloc(256);
ref2=ref1;// Holding reference to a pointer in another pointer
strcpy(ref1,"stackoverflow");
printf("%s %s",ref1,ref2); // This prints stackoverflow twice
free(ref1); // This is valid but you can access ref2 or ref1 after this point
return ref2; /// This will cause problems
}
Try this:
copyData(theBoard, newBoard);
/* swap the _board pointers */
char * b = theBoard->_board;
theBoard->_board = newBoard->_board;
newBoard->_board = b;
FreeBoard(newBoard); /* cleanup the temp struct and the old array */
This errors says that you are trying to free the memory which is already freed by you. What i am suspecting here is this block of code
if (board != NULL) {
printf("FREE 1\n");
//free the board array:
if (board->_board != NULL) {
printf("FREE 2\n");
freeBoardArray(&board->_board[0]);
printf("FREE 3\n");
}
free(board);
once you are freeing the part of structure freeBoardArray(&board->_board[0]); and then you are freeing the whole structure free(board);, and it looks to me causing the problem.Why you passing the address of the _board pointer?I wrote the code on the same line of code,which causing the problem.
struct a{
int * next;
};
int main(){
struct a *aptr = (struct a *)malloc(sizeof(struct a));
aptr->next=(int *)malloc(5*sizeof(int));
free(&aptr->next);
free(aptr);
return 0;
}
this code will cause the same issue as you shown. Now again try this code after removing '&' from free(&aptr->next);statement.It will work fine.
So i think you got a clue where you have to modify.
Running this code under valgrind will tell you exactly on which line you a.) first freed the memory and b.) when you tried to free it again.
It will also tell you if you try and access any addresses which are inside a block that you have freed.

Resources