First allow me to apologize for the formatting and the difficult code. I am new to C and Stack. Most of the messy code here are probably irrelevant to the problem but necessary to include for the context.
The code below runs into segmentation fault after the first call to realloc (noted in the comments). return_file->target_line is simply a 3D array, i is an element count of the first dimension of the 3D array. So I'm calling realloc on it to store additional 2D arrays (of type char **).
NULL returns of memory allocations were purposely omitted b/c the developement protocol specifically stated all memory allocations will be successful (which I have a doubt of).
I'm using my own memory check program. The error code I get is:
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7ac63fb in reallochook () from /lib64/libc.so.6
I have looked at it for a very long time but can't seem to find what the problem is.
Mockfile *read_mockfile(const char filename[]) {
Mockfile *return_file = NULL;
FILE *input;
if(filename != NULL && (input = fopen(filename, "r")) != NULL) {
char **split_tmp, line[MAX] = {0};
return_file = malloc(sizeof(Mockfile));
return_file->rule_count = 0;
/*read lines*/
while(fgets(line, MAX, input) != NULL){
if(line[0] != '#' && line[0] != '\n'){
int j, i = return_file->rule_count;
split_tmp = split(line);
if(line[0] != '\t'){
j = 0;
/*target line. Realloc every string in three steps. Segementation fault occurs after this line below.*/
return_file->target_line = realloc(return_file->target_line, (i + 1) * sizeof(char **));
while(split_tmp[j] != NULL){
return_file->target_line[i] = realloc(return_file->target_line[i], (j + 1) * sizeof(char *));
return_file->target_line[i][j] = malloc(strlen(split_tmp[j]) + 1);
strcpy(return_file->target_line[i][j], split_tmp[j]);
j++;
}
return_file->target_line[i] = realloc(return_file->target_line[i], (j + 1) * sizeof(char *));
return_file->target_line[i][j] = NULL;
} else {
j = 0;
/*action line. Allocate every string in three steps*/
return_file->action_line = realloc(return_file->action_line, (i + 1) * sizeof(char **));
while(split_tmp[j] != NULL){
return_file->action_line[i] = realloc(return_file->action_line[i], (j + 1) * sizeof(char *));
return_file->action_line[i][j] = malloc(strlen(split_tmp[j]) + 1);
strcpy(return_file->action_line[i][j], split_tmp[j]);
j++;
}
return_file->action_line[i] = realloc(return_file->action_line[i], (j + 1) * sizeof(char *));
return_file->action_line[i][j] = NULL;
return_file->rule_count++;
}
}
}
fclose(input);
}
return return_file;
}
realloc() expects its first argument to point to a valid block of memory or NULL, so after malloc() you should initialise:
return_file = malloc(sizeof(Mockfile));
return_file->rule_count = 0;
return_file->target_line = NULL; /* Add this */
This should resolve that crash.
Note also that foo = realloc(foo, N); is a bug, as realloc() can return NULL, so you need to handle that for completeness.
Related
I wrote a little function to return a string made from the input given to the program, it worked fine until i traded constant size for dynamic memory allocation. After i tested with a few printf() it looks like the program crashes when realloc() is called. Am i doing something wrong with realloc(), or is it something else?
char* get_line()
{
size_t ptr_pos = 0, size = 50;
int c;
char* line = malloc(size * sizeof *line);
char* temp;
while((c = getchar()) != EOF)
{
if(++ptr_pos >= size)
{
size += 50;
temp = realloc(line, size * sizeof *line); // The program crashes on this intruction.
if(temp != NULL)
{
line = temp;
printf("Reallocation success.\n");
}
else
{
printf("Reallocation error.\n");
free(line);
exit(1);
}
}
*line++ = c;
if(c == '\n')
break;
}
if(ptr_pos == 0)
return NULL;
*line = '\0';
return line - ptr_pos;
}
Thanks for your help.
When you call realloc, you must give it the address of the beginning of the allocated memory, the same address as was originally returned by malloc. The same is true of free.
But you are modifying the value of line, so it is no longer pointing to the beginning of the block when realloc is called.
That is Undefined Behaviour, so a segfault is definitely possible.
I'm a newer in c, for learning it, i'm trying to write a function to manually read characters from std input. The program will read lines from std and output them, ant it will end when meets an empty line.
But it works well if the input stream only contains three lines or lesser, but it always stopped with an error if the input contains 4+ lines. The error happens when call realloc and free function: 'double free or corruption (fasttop): 0x0000000001f46030 *', why?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *readline(int *length) {
char ch, *s = NULL, *temp = NULL;
int UNIT = 3, size = 0, index = 0;
while ((ch = getchar()) != EOF) {
if (size == 0 || index >= size) {
size += UNIT;
temp = realloc(s, sizeof(char) * size);
if (s != NULL && temp != s) free(s);
s = temp;
temp = NULL;
}
s[index++] = (ch == '\n') ? '\0' : ch;
if (ch == '\n') break;
}
*length = index - 1;
return s;
}
char **readlines(int *count) {
char **lines = NULL, **tempLines = NULL;
int UNIT = 1, size = 0, index = 0;
int length = 0;
char *line = NULL;
while ((line = readline(&length)) != NULL) {
if (strlen(line) == 0) break;
if (size == 0 || index >= size) {
size += UNIT;
tempLines = realloc(lines, size * sizeof(char *));
if (lines != NULL && tempLines != lines) free(lines);
lines = tempLines;
tempLines = NULL;
}
lines[index++] = line;
}
*count = index;
return lines;
}
int main(int argc, char *argv[]) {
int length = 0, index = 0;
char **lines = readlines(&length);
printf("The lines you typed are: \n");
for (; index < length; index++) {
printf("%5s %s.\n", "-", lines[index]);
}
return 0;
}
The execute result is:
xxx#xxx:~/vmshared$ ./mylib2
abc
def
hij
The lines you typed are:
- abc.
- def.
- hij.
xxx#xxx:~/vmshared$ ./mylib2
11
22
33
44
*** Error in `./mylib2': double free or corruption (fasttop): 0x00000000017f1030 ***
your problem is here:
temp = realloc(s, sizeof(char) * size);
if (s != NULL && temp != s) free(s);
in case realloc succeeded, you free s after realloc already freed it.
you can see this answer for more details.
there's a problem with your readlines and readline function. your error is caused by freeing a pointer after realloc call.
tempLines = realloc(lines, size * sizeof(char *));
if (lines != NULL && tempLines != lines) free(lines); // wrong
temp = realloc(s, sizeof(char) * size);
if (s != NULL && temp != s) free(s); //wrong
if memory content was moved to another location, realloc frees the old pointer for you.
in your main function you never free your lines pointer.
Because you are freeing your data and then using it:
temp = realloc(s, sizeof(char) * size);
if (s != NULL && temp != s) free(s);
which then means that you are writing to freed memory - which is bad.
The function realloc can be seen as doing:
void *realloc(void *ptr, size_t new_size)
{
void* newptr = malloc(size);
size_t oldsize = find_size(ptr);
memcpy(newptr, ptr, oldsize);
free(ptr);
return newptr;
}
Of course, the REAL realloc is a lot more complex (because it checks the current block to see if it can be expanded before it allocates new data), and probably doesn't call regular malloc, but the functionality is roughly this.
The reason for storing the result of realloc in a different variable than the old pointer is for the case where it returns NULL - it couldn't expand to the new size - at that point, you need a temp and the original pointer, so you don't leak the old pointer's memory.
When you call realloc() and it is successful, the old memory location has already been freed and the new location is returned. There is a chance that the old and new locations are the same. However, either way, it is incorrect to release the old pointer. It would be eccentric to immediately release the new pointer.
Thus, this code is incorrect:
temp = realloc(s, sizeof(char) * size);
if (s != NULL && temp != s)
free(s);
s = temp;
temp = NULL;
It should probably be:
temp = realloc(s, size);
if (temp == NULL)
…report error and exit function…
s = temp;
There's no need to set temp = NULL; after the assignment, though it does no particular harm beyond marginally (immeasurably) slowing the program down.
You should not free the original memory area after a successful call to realloc.
temp = realloc(s, sizeof(char) * size);
if (s != NULL && temp != s) free(s); // This is wrong!
If realloc moves your data, it will also free the old area. You don't need to do that yourself.
This question already has answers here:
Facing an error "*** glibc detected *** free(): invalid next size (fast)"
(2 answers)
Closed 8 years ago.
I've got a strange problem with realloc, here's my code (relevant parts only, too big to post the full code here):
char * print_bar(struct bar *ptr) {
char *buf = NULL;
char *buftmp = NULL;
size_t size = 60;
int count = 0;
if (ptr) {
while (count == 0 || count+4 >= size) {
buftmp = (char *) realloc((void *) buf, size * sizeof (char));
if (buftmp == NULL) {
if (buf != NULL) free(buf);
exit(EXIT_FAILURE);
}
buf = buftmp;
count = snprintf(buf, size, "%04d-%02d-%02d\t%02d:%02d:00\t%d\t%.2f\t%.2f\t%.2f\t%.2f\t%d",
ptr->year,
ptr->month,
ptr->day,
ptr->hour,
ptr->minute,
ptr->timeframe,
ptr->open,
ptr->high,
ptr->low,
ptr->close,
ptr->volume
);
size += 4;
}
}
return buf;
}
char * print_historico(short timeframe) {
struct barlist *tmp = get_barlist(timeframe);
struct bar *ptr;
char * result = NULL;
char * resulttmp = NULL;
char * buf;
int len;
if (tmp) {
ptr = tmp->first;
while (ptr) {
buf = print_bar(ptr);
len = (result != NULL) ? strlen(result)+strlen(buf)+1 : strlen(buf)+1;
resulttmp = (char *)realloc((void *)result, len);
if (resulttmp == NULL)
{
if (result != NULL) free(result);
exit (EXIT_FAILURE);
}
result = resulttmp;
strncat(result, buf, strlen(buf));
free(buf);
ptr = ptr->next;
}
}
return result;
}
In my main function i've got the following loop:
for (i = 1; i <= 27; i++) {
historico = print_historico(i);
if (historico != NULL)
{
puts(historico);
free(historico);
}
}
If i compile and run it fails with "realloc(): invalid next size: 0x0000000001704f60". If i run with the debugger i see it finishes the first iteration of the main loop ok, freeing the 'historico' variable. When it executes "print_historico" with i=2 it fails on the second iteration of the "while(ptr)" loop.
I can't find a reason, any clue? I've also tried to make a small program to isolate the problem, but i wasn't able.
strncat(result, buf, strlen(buf));
This is a problem. (It might be the cause of the problem you are reporting having.)
When the first realloc occurs, the result is not initialized. You really need to put a '\0' in the first char position for the strncat to work (reliably).
resulttmp = (char *)realloc((void *)result, len);
if (resulttmp == NULL)
{
if (result != NULL) free(result);
exit (EXIT_FAILURE);
}
if(result == NULL) *resulttmp = '\0' // YOU NEED THIS!! First time initialization.
Try using valgrind to isolate possible memory leaks or misuses.
Or keep trying to distill the broken code into an example you can post.
Edit: I think the while condition may be faulty:
while (count == 0 || count+4 >= size)
Why don't you print out the values each time and run the program and see what it looks like?
How can I compare the first letter of the first element of a char**?
I have tried:
int main()
{
char** command = NULL;
while (true)
{
fgets(line, MAX_COMMAND_LEN, stdin);
parse_command(line, command);
exec_command(command);
}
}
void parse_command(char* line, char** command)
{
int n_args = 0, i = 0;
while (line[i] != '\n')
{
if (isspace(line[i++]))
n_args++;
}
for (i = 0; i < n_args+1; i++)
command = (char**) malloc (n_args * sizeof(char*));
i = 0;
line = strtok(line," \n");
while (line != NULL)
{
command[i++] = (char *) malloc ( (strlen(line)+1) * sizeof(char) );
strcpy(command[i++], line);
line = strtok(NULL, " \n");
}
command[i] = NULL;
}
void exec_command(char** command)
{
if (command[0][0] == '/')
// other stuff
}
but that gives a segmentation fault. What am I doing wrong?
Thanks.
Could you paste more code? Have you allocated memory both for your char* array and for the elements of your char* array?
The problem is, you do allocate a char* array inside parse_command, but the pointer to that array never gets out of the function. So exec_command gets a garbage pointer value. The reason is, by calling parse_command(line, command) you pass a copy of the current value of the pointer command, which is then overwritten inside the function - but the original value is not affected by this!
To achieve that, either you need to pass a pointer to the pointer you want to update, or you need to return the pointer to the allocated array from parse_command. Apart from char*** looking ugly (at least to me), the latter approach is simpler and easier to read:
int main()
{
char** command = NULL;
while (true)
{
fgets(line, MAX_COMMAND_LEN, stdin);
command = parse_command(line);
exec_command(command);
}
}
char** parse_command(char* line)
{
char** command = NULL;
int n_args = 0, i = 0;
while (line[i] != '\n')
{
if (isspace(line[i++]))
n_args++;
}
command = (char**) malloc ((n_args + 1) * sizeof(char*));
i = 0;
line = strtok(line," \n");
while (line != NULL)
{
command[i] = (char *) malloc ( (strlen(line)+1) * sizeof(char) );
strcpy(command[i++], line);
line = strtok(NULL, " \n");
}
command[i] = NULL;
return command;
}
Notes:
in your original parse_command, you allocate memory to command in a loop, which is unnecessary and just creates memory leaks. It is enough to allocate memory once. I assume that you want command to contain n_args + 1 pointers, so I modified the code accordingly.
in the last while loop of parse_command, you increment i incorrectly twice, which also leads to undefined behaviour, i.e. possible segmentation fault. I fixed it here.
The following piece of code gives a segmentation fault when allocating memory for the last arg. What am I doing wrong? Thanks.
int n_args = 0, i = 0;
while (line[i] != '\0')
{
if (isspace(line[i++]))
n_args++;
}
for (i = 0; i < n_args; i++)
command = malloc (n_args * sizeof(char*));
char* arg = NULL;
arg = strtok(line, " \n");
while (arg != NULL)
{
arg = strtok(NULL, " \n");
command[i] = malloc ( (strlen(arg)+1) * sizeof(char) );
strcpy(command[i], arg);
i++;
}
Thanks.
You don't reset the value of i after the for loop, so i is equal to n_args when you reach the bottom block. Trying to access command[i] at that point accesses uninitialized memory and segfaults.
The real lesson here is not to reuse variables in this manner without a good reason. Your code will be more robust and easier to read if you use something other than i in the middle for loop.
for (i = 0; i < n_args; i++)
command = malloc (n_args * sizeof(char*));
should become just
command = malloc (n_args * sizeof(char*))
because you just want to alloc an array of n_args elements, and
while (arg != NULL)
{
arg = strtok(NULL, " \n");
command[i] = malloc ( (strlen(arg)+1) * sizeof(char) );
strcpy(command[i], arg);
i++;
}
should become:
arg = strtok(NULL, " \n");
while (arg != NULL) {
command[i] = malloc ( (strlen(arg)+1) * sizeof(char) );
strcpy(command[i], arg);
i++;
arg = strtok(NULL, " \n");
}
to avoid strlen on a null pointer.
For a line comprising two arguments separated by a single space, n_args will be 1 rather than 2. This is probably not what you want.
I think you have a few funny things going on here (if I'm reading this correctly).
This block:
for (i = 0; i < n_args; i++)
command = malloc (n_args * sizeof(char*));
Should be this:
command = malloc (n_args * sizeof(char*));
No need to reallocate command over and over again.
As for the seg fault though, could be because you are re-using the i variable without resetting it to zero again first.
You're throwing away your first arg? Is that intentional? In case it isn't
int n_args = 1; /* We need one element more than spaces */
int i = 0;
while (line[i])
{
if (isspace(line[i++]))
n_args++;
}
command = malloc (n_args * sizeof(char*));
char* arg = NULL;
arg = strtok(line, " \n");
i = 0; /***** You forgot to reset that value, that was your segfault !!! */
while (arg)
{
command[i++] = strdup(arg); /* It does your malloc/strlen/strcpy */
arg = strtok(NULL, " \n");
}
You forgot to reset your i index, which reaches outside your allocated array in your code.
Try arranging this loop properly:
while (arg != NULL)
{
arg = strtok(NULL, " \n");
command[i] = malloc ( (strlen(arg)+1) * sizeof(char) );
strcpy(command[i], arg);
i++;
}
the line "arg=strtok..." does 2 things wrongs:
Skips the first argument.
Doesn't check the return code, so if arg==NULL then strlen(arg) will SEGFAULT.
Do this instead:
while (arg != NULL)
{
command[i] = malloc ( (strlen(arg)+1) * sizeof(char) );
strcpy(command[i], arg);
i++;
arg = strtok(NULL, " \n");
}
It is hard to figure out what you are trying to do.
It looks like you are looking at the number of spaces in the command line to see how many command line arguments you have. Are all of your command line args a single character?
The malloc is only reserving enough space for one character per arg.
If your args are just one char each:
command = malloc(strlen(line));
i = 0;
j = 0;
while(line[j]) {
if(!isspace(line[j])){
command[i++] = line[j];
}
j++;
}