free pointers not working even though they're allocated - c

I have two pointers in my program which freeing them doesn't work, I don't get an error of any sort, just an error sound from visual studio..
The program runs perfectly fine if I don't free them (but I know I must do that).
This is my code with everything that uses those two pointers, hopefully you'll help me.
void gameProcess(char *word, int len)
{
int i, letterExist, life = 7, temp;
char *pGuess, *bank, c;
if (!(bank = (char*)malloc(N)))
printf("Error!! Allocated memory failure!");
bank[N] = '\0';
if (!(pGuess = (char*)malloc(len)))
printf("Error!! Allocated memory failure!");
pGuess[len] = '\0';
guessVisual(pGuess);
while (life > 0 && len > 0)
{
letterExist = 0;
printf("\n\nEnter your guess please:\n");
c = guessInterface(word, pGuess, bank);
letterExist = checkIfExist(word, c, len);
temp = replaceIfExist(word, c, pGuess);
if (letterExist > 0)
len = rightGuess(pGuess, len, temp);
else
life = wrongGuess(life);
if (len == 0)
win();
if (life == 0)
lose();
}
free(pGuess);//***************
free(bank);//***************
}
Thank you!
If any other info is needed, let me know.

Related

Malloc error: incorrect checksum for freed object - object was probably modified after being freed

I've been trying to fix this for 2 days now. I really don't understand what is going on.
I wrote a function to read from a file line per line. It's called get_next_line(). This is a project for school, I'm only allowed to use my own C library and read(), malloc() and free().
Here is a link to the full GitHub repo, including the instructions. I can only submit get_next_line.c and get_next_line.h at the end.
Basically, my program seems to run fine if don't handle memory leaks. When I start fixing leaks by using my ft_strdel() function, my program still runs fine for most test cases.
void ft_strdel(char **as)
{
if (!as || !*as)
return ;
free(*as);
*as = 0;
}
Yet, if I pass it through the advanced unit test we have at school, I have different errors. They seem to appear randomly sometimes as I can pass 3 times in a row and get a malloc error the 4th time.
The current version seems to handle all memory leaks. Thus, I have this error from the filechecker:
get_next_line_tests(43165,0x7fff9e83d340) malloc: *
error for object 0x7fe0e3403748: incorrect checksum for freed object -
object was probably modified after being freed.
* set a breakpoint in malloc_error_break to debug
Here is the full function:
#include "get_next_line.h"
static t_list *get_current_node(const int fd, t_list **line_list)
{
t_list *tmp;
tmp = *line_list;
while (tmp)
{
if ((int)tmp->content_size == fd)
return (tmp);
tmp = tmp->next;
}
return (NULL);
}
static t_list *create_new_node(int fd, t_list **line_list)
{
t_list *new;
new = ft_lstnew("\0", fd);
ft_lstadd(line_list, new);
return (new);
}
char *read_until_newline(int fd)
{
char buf[BUFF_SIZE + 1];
char *tmp;
char *stack;
int ret;
if (read(fd, buf, 0) < 0)
return (NULL);
stack = ft_strnew(1);
if (!stack)
return (NULL);
while ((ret = read(fd, buf, BUFF_SIZE)) > 0)
{
buf[ret] = '\0';
tmp = ft_strjoin(stack, buf);
ft_strdel(&stack);
stack = tmp;
if (ft_strchr(buf, '\n'))
break;
}
return (stack);
}
int get_index_newline(char *str)
{
int i;
i = 0;
while (str[i] && str[i] != '\n')
i++;
return (i);
}
int get_next_line(const int fd, char **line)
{
static t_list *line_list;
t_list *current;
char *buffer;
char *tmp;
int index_newline;
if (fd < 0 || line == NULL)
return (-1);
current = get_current_node(fd, &line_list);
if (!current)
current = create_new_node(fd, &line_list);
if (!ft_strchr(current->content, '\n'))
buffer = read_until_newline(fd);
else
buffer = ft_strnew(1);
if (!buffer)
return (-1);
if (!ft_strlen(buffer) && !ft_strlen(current->content))
return (0);
tmp = current->content;
current->content = ft_strjoin(tmp, buffer);
if (tmp)
ft_strdel(&tmp);
if (buffer)
ft_strdel(&buffer);
index_newline = get_index_newline(current->content);
*line = ft_strsub(current->content, 0, index_newline);
tmp = current->content;
current->content = ft_strsub(tmp, index_newline + 1, ft_strlen(tmp) - index_newline - 1);
if (tmp)
ft_strdel(&tmp);
return (1);
}
Feel free to comment on any beginner error I could be doing in my code. Please note however that I have to follow a certain norm, that explain my variable declarations and initializations. I cannot use for loops. And have many restrictions like those.
Protecting my ft_strdel() calls with if statements was my last attent at solving the issue, obviously it failed and it's useless.
EDIT:
I handle multiple fd by using a static linked list. Each node contains a string with the last read buffer (whatever is left from the reading after substracting the most recently read line). And each node contains an int to store the fd it was read from. This way, I loop through the list until I find the corresponding fd to check for preexisting reading. If no node is returned, it means I have nothing stored for the specific fd so I'll just create a new node.
I hope you have answers! I'm not a regular user on Stack Overflow, I did my best to format my post and be specific. Tell me if I need to edit something.
And thanks for your help!

Calloc/Malloc and freeing to often or too large a space?

Disclaimer, this is help with a school assignment. That being said, my issue only occurs about 50% of the time. Meaning if I compile and run my code without edits sometimes it will make it through to the end and other times it will not. Through the use of multiple print statements I know exactly where the issue is occurring when it does. The issue occurs in my second call to hugeDestroyer(right after the print 354913546879519843519843548943513179 portion) and more exactly at the free(p->digits) portion.
I have tried the advice found here (free a pointer to dynamic array in c) and setting the pointers to NULL after freeing them with no luck.
Through some digging and soul searching I have learned a little more about how free works from (How do malloc() and free() work?) and I wonder if my issue stems from what user Juergen mentions in his answer and that I am "overwriting" admin data in the free list.
To be clear, my question is two-fold.
Is free(p->digits) syntactically correct and if so why might I have trouble half the time when running the code?
Secondly, how can I guard against this kind of behavior in my functions?
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
typedef struct HugeInteger
{
// a dynamically allocated array to hold the digits of a huge integer
int *digits;
// the number of digits in the huge integer (approx. equal to array length)
int length;
} HugeInteger;
// Functional Prototypes
int str2int(char str) //converts single digit numbers contained in strings to their int value
{
return str - 48;
}
HugeInteger *parseInt(unsigned int n)
{
int i = 0, j = 0;
int *a = (int *)calloc(10, sizeof(int));
HugeInteger *p = (HugeInteger *)calloc(1, sizeof(HugeInteger));
if(n == 0)
{
p->digits = (int *)calloc(1, sizeof(int));
p->length = 1;
return p;
}
while(n != 0)
{
a[i] = n % 10;
n = n / 10;
i++;
}
p->length = i;
p->digits = (int *)calloc(p->length, sizeof(int));
for(i = 0; i <= p->length; i++, j++)
p->digits[j] = a[i];
return p;
}
HugeInteger *parseString(char *str) //notice datatype is char (as in char array), so a simple for loop should convert to huge int array
{
int i = 0, j = 0;
HugeInteger *p = (HugeInteger *)calloc(1, sizeof(HugeInteger));
if(str == NULL)
{
free(p);
p = NULL;
return p;
}
else
{
for(i=0; str[i] != '\0'; i++)
;
p->length = i;
p->digits = (int *)calloc(p->length, sizeof(int));
for(; i >= 0; i--)
p->digits[j++] = str2int(str[i - 1]);
}
return p;
} //end of HugeInteger *parseString(char *str)
HugeInteger *hugeDestroyer(HugeInteger *p)
{
//printf("No problem as we enter the function\n");
if(p == NULL)
return p;
//printf("No problem after checking for p = NULL\n");
if(p->digits == NULL)
{
free(p);
p = NULL;
return p;
}
//printf("No Problem after checking if p->digits = NULL\n");
//else
//{
free(p->digits);
printf("We made it through free(p->digits)\n");
p->digits = NULL;
printf("We made it through p->digits = NULL\n");
free(p);
printf("We made it through free(p)\n");
p = NULL;
printf("We made it through p = NULL\n");
return p;
//}
//return NULL;
}//end of HugeInteger *hugeDestroyer(HugeInteger *p)
// print a HugeInteger (followed by a newline character)
void hugePrint(HugeInteger *p)
{
int i;
if (p == NULL || p->digits == NULL)
{
printf("(null pointer)\n");
return;
}
for (i = p->length - 1; i >= 0; i--)
printf("%d", p->digits[i]);
printf("\n");
}
int main(void)
{
HugeInteger *p;
hugePrint(p = parseString("12345"));
hugeDestroyer(p);
hugePrint(p = parseString("354913546879519843519843548943513179"));
hugeDestroyer(p);
hugePrint(p = parseString(NULL));
hugeDestroyer(p);
hugePrint(p = parseInt(246810));
hugeDestroyer(p);
hugePrint(p = parseInt(0));
hugeDestroyer(p);
hugePrint(p = parseInt(INT_MAX));
hugeDestroyer(p);
//hugePrint(p = parseInt(UINT_MAX));
//hugeDestroyer(p);
return 0;
}
First of all, really outstanding question. You did a lot of research on topic and generally speaking, solved this issue by yourself, I'm here mainly to confirm your findings.
Is free(p->digits) syntactically correct and if so why might I have trouble half the time when running the code?
Syntax is correct. #Shihab suggested in comments not to release p->digits and release p only, but such suggestion is wrong, it leads to memory leakages. There is a simple rule: for each calloc you must eventually call free, so your current approach in freeing p->digits and then p is totally fine.
However, program fails on a valid line. How is it possible? Quick answer: free can't do its work due to corruption of meta information responsible for tracking allocated/free blocks lists. At some point program corrupted meta information, but this was revealed only on attempt to use it.
As you already discovered, in most implementations memory routines such as calloc results into allocation of buffer with prepended meta-info. You receives pointer to buffer itself, but small piece of information right before this pointer is crucial for further buffer managing (e.g. freeing). Writing 11 integers into buffer intended for 10, you're likely to corrupt meta-info of block following the buffer. Whether corruption actually happens and what would be its consequences, is heavily dependent on both implementation specifics and current memory alignment (what block follows the buffer, what exactly meta-data is corrupted). It doesn't surprise me, that you see one crash per two executions, neither surprises me observing 100% crash reproduction on my system.
Secondly, how can I guard against this kind of behavior in my functions?
Let's start with fixing overflows. There are couple of them:
parseString: loop for(; i >= 0; i--) is executed length+1 times, so p->digits is overflown
parseInt: loop for (i = 0; i <= p->length; i++, j++) is executed length+1 times, so p->digits is overflown
Direct access to memory managing in C++ is error prone and troublesome to debug. Memory leakages and buffers overflows are the worst nightmare in programmers life, it's usually better to simplify/reduce direct usage of dynamic memory, unless you are studying to cope with it, of course. If you need to stick with a lot of direct memory managing, take a look at valgrind, it's intended to detect all such things.
By the way, there is also a memory leakage in your program: each call to parseInt allocates buffer for a, but never frees it.

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.

Possible heap corruption, debugging with valgrind

I'm working on a project that makes use of a string buffer. I've been getting random errors with free() and malloc() - Like "invalid next size (fast)" and suspects if it is due to some memory heap corruption. I'm using gcc. I used valgrind on the binary file and this is the summary :
ERROR SUMMARY: 26887 errors from 39 contexts (suppressed: 0 from 0)
I think that's a bit too high. I'm attaching a pastebin of the valgrind memcheck output here
Most of the problems seem to be from a single function : strbuf_addc(). strbuf is a string buffer that can grow automatically. I'm pasting some strbuf functions here.
int strbuf_add(struct strbuf *string, const char *c)
{
if(string == NULL || c == NULL) return 0;
while(*c != '\0') {
if(!strbuf_addc(string, *c++))
return 0;
}
return 1;
}
int strbuf_addc(struct strbuf *string, char c)
{
size_t space_available;
assert(string != NULL);
space_available = string->allocated - string->length;
if(space_available <= 1) {
if(!grow_buffer(string)) {
return 0;
}
}
string->buffer[string->length++] = c;
string->buffer[string->length] = '\0';
return 1;
}
static int grow_buffer(struct strbuf *string)
{
char *tmp;
size_t toallocate;
assert(string != NULL);
toallocate = string->allocated + (string->allocated / 2);
tmp = (char*) realloc(string->buffer, toallocate);
if(tmp) {
string->buffer = tmp;
string->allocated = toallocate;
return 1;
}
return 0;
}
I'm not sure if strbuf_addc is the culprit or some other function that I wrote. Please take a look. I am basically passing string literals as the second argument to strbuf_add. I'm not sure if they will be null terminated, but I suppose string literals in c are null terminated. I've also tried reading strings from a file, still some errors.
toallocate = string->allocated + (string->allocated / 2);
there might be situations where toallocate won't be bigger than string->allocated. so, realloc won't reserve more space for your string and you won't be able to add a character. valgrind keeps saying that :
==4755== Invalid write of size 1
so you just don't have space to append a char.

Initializing an infinite number of char **

I'm making a raytracing engine in C using the minilibX library.
I want to be able to read in a .conf file the configuration for the scene to display:
For example:
(Az#Az 117)cat universe.conf
#randomcomment
obj:eye:x:y:z
light:sun:100
light:moon:test
The number of objects can vary between 1 and the infinite.
From now on, I'm reading the file, copying each line 1 by 1 in a char **tab, and mallocing by the number of objects found, like this:
void open_file(int fd, struct s_img *m)
{
int i;
char *s;
int curs_obj;
int curs_light;
i = 0;
curs_light = 0;
curs_obj = 0;
while (s = get_next_line(fd))
{
i = i + 1;
if (s[0] == 'l')
{
m->lights[curs_light] = s;
curs_light = curs_light + 1;
}
else if (s[0] == 'o')
{
m->objs[curs_obj] = s;
curs_obj = curs_obj + 1;
}
else if (s[0] != '#')
{
show_error(i, s);
stop_parsing(m);
}
}
Now, I want to be able to store each information of each tab[i] in a new char **tab, 1 for each object, using the ':' as a separation.
So I need to initialize and malloc an undetermined number of char **tab. How can I do that?
(Ps: I hope my code and my english are good enough for you to understand. And I'm using only the very basic function, like read, write, open, malloc... and I'm re-building everything else, like printf, get_line, and so on)
You can't allocate an indeterminate amount of memory; malloc doesn't support it. What you can do is to allocate enough memory for now and revise that later:
size_t buffer = 10;
char **tab = malloc(buffer);
//...
if (indexOfObjectToCreate > buffer) {
buffer *= 2;
tab = realloc(tab, buffer);
}
I'd use an alternative approach (as this is c, not c++) and allocate simply large buffers as we go by:
char *my_malloc(size_t n) {
static size_t space_left = 0;
static char *base = NULL;
if (base==NULL || space_left < n) base=malloc(space_left=BIG_N);
base +=n; return base-n;
}
Disclaimer: I've omitted the garbage collection stuff and testing return values and all safety measures to keep the routine short.
Another way to think this is to read the file in to a large enough mallocated array (you can check it with ftell), scan the buffer, replace delimiters, line feeds etc. with ascii zero characters and remember the starting locations of keywords.

Resources