private memory usage keep raising using c in Linux - c

I'm writing a service in Linux using c, so I need to keep the memory usage stable.
But after tracing a day, the memory raise.
If I monitor from the System Monitor in Linux, it raise 1M and the mem%(0 -> 0.1).
In pmap command, it raise 1M, too.
I have use valgrind to check if there are any memory leak, and it report none if I run once.
If I start the service and use valgrind, it will report that I free invalid pointer.
So, I think it should have something to do about my pointer.
struct list {
int no;
BYTE parm[SLEN];
struct list *next;
};
struct list *memory_current;
struct list *memory_head;
struct list *memory_prev;
int getMemoryUsage(int sendCmd) {
pthread_mutex_lock(&lock);
FILE *fp = NULL;
BYTE buffer[10] = "";
BYTE memorys[10] = "";
int flag = 0;
TRY {
if ((fp = popen("free_data=$(free -m | grep Mem);total=$(echo $free_data | cut -f2 -d' ');"
"free_data=$(free -m | grep 'buffers/cache');buffers=$(echo $free_data | cut -f3 -d' ');echo $(($buffers*100/$total))", "r")) == NULL) {
THROW(CMD_NOT_FND);
}
else {
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
strcat(memorys, buffer);
memory_current = (struct list *)malloc(sizeof(struct list));
if (memory_current == NULL) {
THROW(MALLOC_ERROR);
}
memory_current->next = NULL;
strncpy(memory_current->parm, buffer, SLEN -1);
memory_current->parm[SLEN -1] = '\0';
if (memory_head == NULL)
memory_head = memory_current;
else
memory_prev->next = memory_current;
memory_prev = memory_current;
memset(buffer, 0, sizeof(buffer));
flag = 1;
}
if (flag == 0)
THROW(CMD_NOT_FND);
}
}
CATCH (CMD_NOT_FND) {
memorys[0] = 'n';
memorys[1] = '/';
memorys[2] = 'a';
printf("Memory Usage % : %s\n", memorys);
printLog("Memory Usage % ->", memorys);
}
CATCH (MALLOC_ERROR) {
memorys[0] = 'n';
memorys[1] = '/';
memorys[2] = 'a';
printf("Memory Usage malloc error : %s\n", memorys);
printLog("Memory Usage malloc error ->", memorys);
}
FINALLY {
pclose(fp);
// printf("Memory Usage % : %s\n", memorys);
// printf("Memory Usage length %d\n", strlen(memorys));
}
ETRY;
if (sendCmd == 1) {
if (flag != 0) {
memory_current = memory_head;
int totalMemory = 0;
int count = 0;
int avg = 0;
int perc = 0;
BYTE avg_memory[10] = "";
while (memory_current != NULL) {
sscanf(memory_current->parm, "%d", &perc);
totalMemory += perc;
memory_current = memory_current->next;
count++;
}
avg = totalMemory / count;
snprintf(avg_memory, sizeof(avg_memory), "%d", avg); ;
strcat(avg_memory, ";");
printf("Memory Usage % : %s\n", avg_memory);
printLog("Memory Usage % ->", avg_memory);
// free linked list
memory_current = memory_head;
while (memory_current != NULL) {
memory_prev = memory_current;
memory_current = memory_current->next;
free(memory_prev);
memory_prev = NULL; //fix dangling
}
head_memory = NULL; //fix dangling
current_memory = NULL; //fix dangling
}
}
pthread_mutex_unlock(&lock);
return 0;
}
I have the global pointer to keep record the memory usage in a timer, and I will use the result and clear the list in a interval of time.
I use the same way to use in other function and the memory usage is fine, but the pointers are local and will free at the end.
Could you please help to advice or pointer out what is wrong about my pointer usage.
Thanks.
[Update]
I found that this might be a dangling pointer, so I set the pointer to NULL after the free.
So far the memory won't raise, but I'll keep watching it for more days.
Solved
The memory won't raise again, so I guess it's the dangling pointer issue.

memory_current, memory_head and memory_prev were not initialized to NULL.
you check:
if (memory_head == NULL)
when memory_head was not initialized, therefore you maybe loose some memory allocations
also look like they should be local variables, not global.

Related

asprint memory leak need help understand where leak is coming from and possible fixes

Note: I did call this function and free it main but valgrind still shows error.
This code basically takes in a singly linked-list with two data coeff and exp. This is basically converting a polynomial store in a linked list converted to readable string. I looking to have it dynamic allocated.
char *Poly_to_string(const Polynomial *p)
{
char *x = malloc(1);
int size;
while (p != NULL)
{
if((p->exp != 0) && (p->exp != 1))
{
size = asprintf(&x, "%s%dx^%d + ", x, p->coeff, p->exp);
if (size == -1)
{
exit(-1);
}
}
else if(p->exp == 1)
{
size = asprintf(&x, "%s%dx + ", x, p->coeff);
if (size == -1)
{
exit(-1);
}
}
else if(!p->exp)
{
size = asprintf(&x, "%s%d + ", x, p->coeff);
if (size == -1)
{
exit(-1);
}
}
p = p->next;
}
x[strlen(x) - 3] = '\0';
return x;
}
From the Linux asprintf() man page (bolding mine):
DESCRIPTION
The functions asprintf() and vasprintf() are analogs of
sprintf(3) and vsprintf(3), except that they allocate a string
large enough to hold the output including the terminating null
byte ('\0'), and return a pointer to it via the first argument.
This pointer should be passed to free(3) to release the allocated
storage when it is no longer needed.
RETURN VALUE
When successful, these functions return the number of bytes
printed, just like sprintf(3). If memory allocation wasn't
possible, or some other error occurs, these functions will return
-1, and the contents of strp are undefined.
This line is wrong:
char *x = malloc(1);
It should just be
char *x;
because if asprintf() works, it will overwrite the contents of x and cause the memory allocated in char *x = malloc(1); to be leaked.
EDIT
The looping also needs to be addressed, as you're trying to grow the string:
char *Poly_to_string(const Polynomial *p)
{
// start with an empty string that can be free()'d
// (if you don't have strdup() use malloc() and strcpy())
char *x = strdup("");
int size;
while (p != NULL)
{
// save the old malloc()'d value so it can be free()'d
char *oldValue = x;
if((p->exp != 0) && (p->exp != 1))
{
size = asprintf(&x, "%s%dx^%d + ", x, p->coeff, p->exp);
if (size == -1)
{
exit(-1);
}
}
else if(p->exp == 1)
{
size = asprintf(&x, "%s%dx + ", x, p->coeff);
if (size == -1)
{
exit(-1);
}
}
else if(!p->exp)
{
size = asprintf(&x, "%s%d + ", x, p->coeff);
if (size == -1)
{
exit(-1);
}
}
// free() the old value
free(oldValue);
p = p->next;
}
x[strlen(x) - 3] = '\0';
return x;
}
There are other ways to do this without the initial char *x = strdup(""); but the code then becomes a lot more complex.
You're not deallocating variable x

Dynamic Memory Allocation Hardfault Problem

I am using stm32f4 microproccessor and lwip library for the some ethernet process.
I have a problem with dynamic memory allocation. For some reason when I send ping to my hardware, this device experience Hardfault problem after 1 hour.
These are my firmware routine in main.c
while(1)
{
uint8_t * incomingData = ethernetif_input(&gnetif);
if(incomingData != NULL)
{
if(incomingData[0] == 0x01)
{
// doing some process
}
incomingData = NULL;
free(incomingData)
}
}
in ethernetif.c :
uint8_t * ethernetif_input(struct netif *netif)
{
struct pbuf *p;
p = low_level_input(netif);
if (p == NULL) {
return NULL;
}
uint8_t * data = (uint8_t*)(malloc(sizeof( uint8_t) * 61U));
if ((memcmp (p->payload, EXPECTED_ETHERNET_FRAME, 6) == 0))
{
for(int i = 0; i < 61; i++)
{
data[i]=(((uint8_t*)p->payload)[i]);
}
}
else
{
err = netif->input(p, netif);
data = NULL;
free(data);
if (err != ERR_OK)
{
pbuf_free(p);
p = NULL;
}
{
if(p != NULL)
{
pbufFreeErr = pbuf_free(p);
if( !(_Bool)pbufFreeErr)
{
}
}
return data;
}
You're running out of memory.
As already mentioned in the comments: data=NULL; free(data) does not make sense. It says forget what data pointed to and then do nothing with it.
You should first free(data)before setting it to NULL. That will make the memory pointed to by data available to future malloccalls.
And you should also call pbuf_free in all cases, you will run out of memory if you don't.
As a final remark, do not use a for loop to copy the buffer, use memcpy.

c free() crashing: No source available for "ntdll!RtlpNtEnumerateSubKey()

My program crached on Eclipse when i try to free my object - PokemonTrainer.I have tried the solution in this article, but it didn't help.
PokemonTrainer pokemonTrainerCreate(char* name, Pokemon initial_pokemon,
int max_num_local, int max_num_remote)
{
PokemonTrainer trainer = malloc(sizeof(PokemonTrainer));
if ((name == NULL) || (initial_pokemon == NULL) || (trainer == NULL) ||
(max_num_local < 0) || (max_num_remote < 0))
return NULL;
char tmp_name[strlen(name)];
strcpy(tmp_name, name);
trainer->name = tmp_name;
trainer->max_num_local = max_num_local;
trainer->max_num_remote = max_num_remote;
trainer->pokemons_local = malloc(sizeof(Pokemon)
trainer->max_num_local);
trainer->pokemons_remote = malloc(sizeof(Pokemon)
trainer->max_num_remote);
if (trainer->pokemons_remote == NULL) {
free(trainer->pokemons_local);
return NULL;
} else if (trainer->pokemons_local == NULL) {
free(trainer->pokemons_remote);
return NULL;
}
trainer->pokemons_local[0] = pokemonCopy(initial_pokemon);
trainer->curr_num_local = 1;
trainer->curr_num_remote = 0;
return trainer;
}
void pokemonTrainerDestroy(PokemonTrainer trainer)
{
if (trainer == NULL)
return;
if (trainer->curr_num_local > 0)
for (int i = trainer->curr_num_local - 1; i >= 0; i--)
pokemonDestroy(trainer->pokemons_local[i]);
if (trainer->curr_num_remote > 0)
for (int i = trainer->curr_num_remote - 1; i >= 0; i--)
pokemonDestroy(trainer->pokemons_remote[i]);
free (trainer); // here it's crashed
}
It is during the execution of free() in the stack that I am getting a "No source available for "ntdll!RtlpNtEnumerateSubKey() at 0x77cf04e5" error.
PokemonTrainer trainer = malloc(sizeof(PokemonTrainer)); is unlikely to work properly since you're allocating the size of the pointer, not the real data.
You won't have enough storage => undefined behaviour happens, and for you it happens when freeing the memory (corrupt memory list)
I would do this:
PokemonTrainer trainer = malloc(sizeof(*PokemonTrainer));
so the sizeof takes the size of the structure pointed by PokemonTrainer.
EDIT: for completeness, BLUEPIXY suggests that you've missing 1 byte here (because of null-termination char):
char tmp_name[strlen(name)];
strcpy(tmp_name, name);
and moreover this allocated space is temporary, so I'd suggest:
char *tmp_name = strdup(name);
which will allocate the correct size and performs a dynamic allocation that stays valid even after returning from the routine.

linear normalization segfault and memory errors

I have a segfault in this function...the error message it gives me is this...
*** glibc detected *** /double free or corruption (fasttop): 0x0000000000603250 ***
*** glibc detected *** / memory corruption: 0x00007ffff7dd3710 ***
This is all my code:
struct Image * loadImage(const char* filename)
{
//VARIABLES
struct ImageHeader * hdr2; // on heap, malloc, free
FILE * fptr = fopen(filename, "r");
if (fptr == NULL)
{
return NULL;
}
int retval;
hdr2 = malloc(sizeof(struct ImageHeader));
if (hdr2 == NULL)
{
free(hdr2);
fclose(fptr);
return NULL;
}
retval = fread(hdr2, sizeof(struct ImageHeader), 1, fptr);
if (retval != 1)
{
free(hdr2);
fclose(fptr);
return NULL;
// error
}
if (hdr2 -> magic_bits != ECE264_IMAGE_MAGIC_BITS)
{
free(hdr2);
fclose(fptr);
return NULL;
// error
}
if (hdr2->width == 0||hdr2->height ==0)
{
free(hdr2);
fclose(fptr);
return NULL;
// error
}
struct Image * img = NULL;
img = malloc(sizeof(struct Image));
if(img == NULL)
{
fclose(fptr); // free(img);
return NULL;
//do something
}
img -> width = hdr2 -> width;
img ->height=hdr2->height;
img -> comment = malloc(sizeof(char) * (hdr2->comment_len));
img -> data = malloc(sizeof(uint8_t) * hdr2->width * hdr2->height);
retval = fread(img->comment, sizeof(char), hdr2->comment_len, fptr);
if(img -> comment == NULL)
{
free(hdr2);
free(img->data);
free(img->comment);
free(img);
fclose(fptr);
return NULL;
//do something, don't forget to free whatever you have allocated
}
//lookg at the img-> comment (should free)
if (retval != hdr2->comment_len)
{
free(hdr2);
free(img->data);
free(img->comment);
free(img);
fclose(fptr);
return NULL;
// error
}
/*
if(img->comment[hdr2->comment_len-1]=='\0')/////////////////////////THIS IS THE PROBLEM AREA
{
free(hdr2);
free(img->data);
free(img->comment);
free(img);
fclose(fptr);
return NULL;
}*/
if(img->data==NULL)
{
free(hdr2);
free(img->comment);
free(img);
fclose(fptr);
return NULL;
}
retval = fread(img->data, sizeof(uint8_t),hdr2->width * hdr2->height, fptr);
if (retval != (hdr2->width * hdr2->height))
{
free(hdr2);
free(img->data);
free(img->comment);
free(img);
fclose(fptr);
return NULL;
}
uint8_t j = 0;
if(fread(&j, sizeof(uint8_t),2,fptr)==2)
{
free(hdr2);
free(img->data);
free(img->comment);
fclose(fptr);
}
retval = fread(img ->data, sizeof(uint8_t), hdr2->width * hdr2->height +1, fptr);
if(retval==hdr2->width*hdr2->height+1)
{
free(hdr2);
free(img);
//error
fclose(fptr);
return NULL;
}
fclose(fptr);
return (img);
}
void freeImage(struct Image * image)
{
if(image!=NULL)
{
free(image->data);
free(image->comment);
}
free(image);
}
void linearNormalization(struct Image * image)
{
int index1 = 0;
int index2 = 0;
//int totaldata = image->height * image->width;
int max = 0;
int min = 255;
// if(image -> data[i] > max)
// set max equal to this image
for(index1=0; index1<(image->height * image->width); index1++)
{
if(image->data[index1] > max)
{
max= image->data[index1];
}
if(image->data[index1]<min)
{
min = image->data[index1];
}
}
for(index2 = 0; index2<(image->height * image->width);index2++)
{
image->data[index2] = (image->data[index2]- min) * 255.0 / (max - min);
}
}
I marked the area that is giving me issues...when I leave it in my function does not output the correct data, but does not get a segfault. Can someone tell me what this error code means with respect to that line?
The error message means you are using free on a pointer that you have already freed. The problem is that this kind of error is a bit difficult to find since using free only tells the SO that the memory is free to be used if it needs, but it does not necessarily prevents you from accessing that memory. For example:
int *a = malloc(sizeof(int));
*a = 5;
free(a);
printf("%d", *a);
Will not generate an error, and if you try to free a again, then you will get an error of double free.
From the man pages, free has undefined behaviour if you try to double free something, but if you try free(NULL) there will be no errors. So instead of using a bunch of if's to control what pointers you have to free, just use:
free(ptr);
ptr = NULL;
This way, if you try to free again you won't get and error.
Here's a couple of errors:
uint8_t j = 0;
if(fread(&j, sizeof(uint8_t),2,fptr)==2)
There is surely not room for two uint8_t's in j
retval = fread(img ->data, sizeof(uint8_t), hdr2->width * hdr2->height +1, fptr);
You have a +1 there, but you have not allocated room for that byte when you allocated img->data
For additional help, run your program in valgrind , it is of great help when tracking down bugs such as these.
Both what nos cenouro have pointed out are valid things. Instead of picking all your memory errors apart piece by piece though. Try this thing called Valgrind. It runs your whole program and checks for memory errors everywhere. It's really a life saver.

Desperately seeking the answer to my pointer problem

I have been working on a college C assignment, and have been trying to make sense of a bug I seem to be having with my code. Basically, it seems like something is wrong with my pointers (and or memory allocation).
This assignment is primarily about linked lists, so the structs contain pointers to the next element in the list. Obviously, to traverse the list until I find that the current element has a NULL pointer to the next element (and then I change that to be the pointer to the 'new' element I want to add.
The problem I have though, is for some reason my code seems to be completely screwing with my memory pointers, because they're getting garbled somehow. They seem fine for moment but very soon go rubbish.
Here is what my watches in XCode's debugger are showing me:
The first circle shows me the values as the first element in the list, which as far as I can tell are initially set correctly, and should be "C0001\0". The second circle shows the current->nextCategory pointer which should be NULL (0x0) but instead show that weird memory address (look at the size of it!). I assume that these problems are related, but as I am new to C, I don't know how or why.
In either case, when I check current->nextCategory != NULL in my while statement, it throws EXC_BAD_ACCESS:
I've spent the past few hours pulling my hair out becasue I cannot work out what the heck is happening to my program. Am I doing something wrong with my pointers, or using malloc() improperly?
Here is the relevant part of my program:
/****************************************************************************
* Initialises the system to a safe empty state.
****************************************************************************/
void systemInit(GJCType* menu)
{
if (menu == NULL) {
fprintf(stderr, "can't initialize system with a null menu pointer.\n");
exit(EXIT_FAILURE);
}
menu->headCategory = NULL;
menu->numCategories = 0;
}
/****************************************************************************
* Loads all data into the system.
****************************************************************************/
int loadData(GJCType* menu, char* menuFile, char* submenuFile)
{
FILE *fp;
size_t len;
char *line;
char *buffer;
CategoryTypePtr category_p;
ItemTypePtr item_p;
char *catId;
if (menu == NULL)
return FALSE;
fp = fopen(menuFile, "r");
if(fp == NULL) {
fprintf(stderr, "can't open %s\n", menuFile);
return FALSE;
}
buffer = malloc(MAX_BUFFER_SIZE);
len = MAX_BUFFER_SIZE;
catId = malloc(ID_LEN + 1);
while((buffer = fgetln(fp, &len))) {
line = strtok(buffer, "\n\0");
category_p = malloc(sizeof(CategoryTypePtr));
if (!tokenizeCategory(line, category_p)) {
fprintf(stderr, "can't tokenize category:> %s\n", line);
free(category_p);
category_p = NULL;
free(buffer);
free(catId);
return FALSE;
}
pushCategory(menu, category_p);
free(category_p);
category_p = NULL;
}
fp = fopen(submenuFile, "r");
if(fp == NULL) {
fprintf(stderr, "can't open %s\n", submenuFile);
return FALSE;
}
while((buffer = fgetln(fp, &len))) {
line = strtok(buffer, "\n\0");
item_p = malloc(sizeof(ItemTypePtr));
if (!tokenizeItem(line, item_p, catId)) {
fprintf(stderr, "can't tokenize item:> %s\n", line);
free(item_p);
item_p = NULL;
free(buffer);
free(catId);
return FALSE;
}
category_p = findCategory(menu, catId);
pushItem(category_p, item_p);
free(item_p);
item_p = NULL;
}
free(buffer);
free(catId);
return TRUE;
}
void pushItem(CategoryTypePtr category, ItemTypePtr item)
{
ItemTypePtr current;
ItemTypePtr new;
if ((new = malloc(sizeof(ItemTypePtr))) == NULL) {
fprintf(stderr, "can't malloc enough memory for new item pointer.\n");
exit(EXIT_FAILURE);
}
*new = *item;
if (category->headItem == NULL) {
category->headItem = new;
} else {
current = category->headItem;
while (current->nextItem != NULL) {
current = current->nextItem;
}
current->nextItem = new;
}
category->numItems++;
}
void pushCategory(GJCType* menu, CategoryTypePtr category)
{
CategoryTypePtr current;
CategoryTypePtr new;
if ((new = malloc(sizeof(CategoryTypePtr))) == NULL) {
fprintf(stderr, "can't malloc enough memory for new category pointer.\n");
exit(EXIT_FAILURE);
}
*new = *category;
if (menu->headCategory == NULL) {
menu->headCategory = new;
} else {
current = menu->headCategory;
while (current->nextCategory != NULL) {
current = current->nextCategory;
}
current->nextCategory = new;
}
menu->numCategories++;
}
CategoryTypePtr findCategory(GJCType* menu, char* id)
{
CategoryTypePtr current;
current = menu->headCategory;
while (current != NULL) {
if (!strcmp(current->categoryID, id))
return current;
current = current->nextCategory;
}
return NULL;
}
/* This function takes the character delimited string and converts it into
* a category structure at the location of the category pointer supplied.
*/
int tokenizeCategory(char *data, CategoryTypePtr category)
{
char* buffer;
if (category == NULL || strlen(data) < 1)
return FALSE;
buffer = malloc(MAX_BUFFER_SIZE);
strcpy(buffer, data);
strcpy(category->categoryID, strtok(buffer, "|\n"));
category->drinkType = *(strtok(NULL, "|\n"));
strcpy(category->categoryName, strtok(NULL, "|\n"));
strcpy(category->categoryDescription, strtok(NULL, "|\n"));
category->numItems = 0;
category->nextCategory = NULL;
category->headItem = NULL;
free(buffer);
return TRUE;
}
/* This function takes the character delimited string and converts it into
* an item structure at the location of the item pointer supplied.
*/
int tokenizeItem(char *data, ItemTypePtr item, char* categoryId)
{
char* buffer;
int i;
if (item == NULL || strlen(data) < 1)
return FALSE;
buffer = malloc(MAX_BUFFER_SIZE);
strcpy(buffer, data);
strcpy(item->itemID, strtok(buffer, "|\n"));
strcpy(categoryId, strtok(NULL, "|\n"));
strcat(categoryId, "\0");
strcpy(item->itemName, strtok(NULL, "|\n"));
for (i = 0; i < NUM_PRICES; i++)
sscanf(strtok(NULL, "|\n"),"%d.%d",&(item->prices[i].dollars),&(item->prices[i].cents));
strcpy(item->itemDescription, strtok(NULL, "|\n"));
item->nextItem = NULL;
free(buffer);
return TRUE;
}
Header definitions:
/* System-wide constants. */
#define ID_LEN 5
#define MIN_NAME_LEN 1
#define MAX_NAME_LEN 25
#define MIN_DESC_LEN 1
#define MAX_DESC_LEN 250
#define NUM_PRICES 3
#define HOT 'H'
#define COLD 'C'
#define FALSE 0
#define TRUE 1
#define MAX_BUFFER_SIZE 1024
typedef struct category* CategoryTypePtr;
typedef struct item* ItemTypePtr;
/* Structure definitions. */
typedef struct price
{
unsigned dollars;
unsigned cents;
} PriceType;
typedef struct item
{
char itemID[ID_LEN + 1];
char itemName[MAX_NAME_LEN + 1];
PriceType prices[NUM_PRICES];
char itemDescription[MAX_DESC_LEN + 1];
ItemTypePtr nextItem;
} ItemType;
typedef struct category
{
char categoryID[ID_LEN + 1];
char categoryName[MAX_NAME_LEN + 1];
char drinkType; /* (H)ot or (C)old. */
char categoryDescription[MAX_DESC_LEN + 1];
CategoryTypePtr nextCategory;
ItemTypePtr headItem;
unsigned numItems;
} CategoryType;
typedef struct gjc
{
CategoryTypePtr headCategory;
unsigned numCategories;
} GJCType;
It looks to me like you're not allocating memory properly.
category_p = malloc(sizeof(CategoryTypePtr));
This only allocates enough memory to store a single address, not an entire category structure. Try something like:
category_p = malloc(sizeof(CategoryType));
The problem is these lines:
category_p = malloc(sizeof(CategoryTypePtr));
item_p = malloc(sizeof(ItemTypePtr));
These lines, as written, only allocate enough memory to store a pointer, not the structure you want to point to.
Try:
category_p = malloc(sizeof(CategoryType));
item_p = malloc(sizeof(ItemType));
Also, your push functions are overly complicated. There's no need to copy the list nodes before you add them to the list. Just assign the address in the pointer to the new node to the ->next... pointer in the current tail:
void pushCategory(GJCType* menu, CategoryTypePtr category)
{
CategoryTypePtr current;
// no need to allocate space just for a pointer
if (menu->headCategory == NULL) {
menu->headCategory = category;
} else {
current = menu->headCategory;
while (current->nextCategory != NULL) {
current = current->nextCategory;
}
current->nextCategory = category;
}
menu->numCategories++;
}
Then you don't want the free(item_p) and free(category_p) calls in the main routine because the memory you've allocated is now being referenced by the list. You will need to free this memory when you dispose of the list.
To debug this kind of issues, I can only suggest to use valgrind : it will provide you very valuable help on buffer overflow, out of bound writing, memory loss. It's installed in the developper package.
You have multiple issues. Besides incorrectly allocating memory you are doing
*new = *category;
in your pushCategory function expecting to automagically copy the internal contents of the category structure: that simply doesn't work. You'll need to allocate a new CategoryType object and then copy each individual element appropriately. Something like this:
void pushCategory(GJCType* menu, CategoryTypePtr category)
{
CategoryTypePtr newCategory;
CategoryTypePtr current;
if ((newCategory = malloc(sizeof(CategoryType))) == NULL) {
fprintf(stderr, "can't malloc enough memory for new category pointer.\n");
exit(EXIT_FAILURE);
}
// copy individual elements here and set values properly
newCategory->headItem = NULL;
strncpy(newCategory->categoryID, category->categoryID, ID_LEN);
// copy other strings and NULL-initialize other pointers
if (menu->headCategory == NULL) {
menu->headCategory = new;
} else {
current = menu->headCategory;
while (current->nextCategory != NULL) {
current = current->nextCategory;
}
current->nextCategory = newCategory;
}
menu->numCategories++;
}
You will need to do the same thing for pushItem.
In the following code
category_p = malloc(sizeof(CategoryTypePtr));
.
.
.
pushCategory(menu, category_p);
free(category_p);
category_p = NULL;
and
item_p = malloc(sizeof(ItemTypePtr));
.
.
.
pushItem(category_p, item_p);
free(item_p);
item_p = NULL;
You have allocated the memory first, linked it in the list, and that very address you have deallocated. I think this is the problem.
And also you have done:
item_p = malloc(sizeof(ItemTypePtr));
and
category_p = malloc(sizeof(CategoryTypePtr));
the ItemTypePtr and CategoryTypePtr are pointers, so what you allocate is only the size of the pointer, and the memory cannot accomodate the entire data of the structure. You need to do
item_p = malloc(sizeof(ItemType));
category_p = malloc(sizeof(CategoryType));
Also in other locations you need to change the ItemTypePtr to ItemType as needed. I will tell not to typedef the pointers as you have done. This can bring difficulty in reading the code. If you have complex function pointer expressions then typedef ing it okay; in my opinion.

Resources