realloc after free problem ("realloc: invalid next size") [duplicate] - c

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?

Related

Reallocating a string that is passed in as a parameter

I want to dynamically allocate only a portion of a character array.
So part of an array of size 100 is concrete. Say 10 is permanent memory, the other 90 is dynamic memory.
I made some attempt to read character by character until I decided to give up and take a shortcut idea I thought would work. However I end up getting an error that is
incorrect checksum for freed object - object was probably modified
after being freed
I use this method in a while loop in main and I pretty much free everything after the while loop processes. Because, I have the declaration outside of the while loop. I wanted to read an object in a while loop session since these objects end up being added into a list of objects. However the scope of the while loop causes segmentation problems, it cannot remember anything about the object. (I digress).
Here is my attempt.
Object* read(char* str)
{
Object* object = (Object*)malloc(sizeof(*object));
object->identity[0] = 0;
int capacity = (100 + 1) - (10);
object->name = (char*)malloc(capacity * sizeof(*object->name));
object->value = 0.0;
int length = strlen(str);
if (length > capacity)
object->name = (char*)realloc(object->name, (capacity * 2) * sizeof(*object->name));
int arguments = sscanf(str, "%" STRING_SPACE "s %lf %[^\n]s",
object->identity,
&object->value,
object->name);
if (arguments == MATCHER) {
return object;
} else {
return NULL;
}
return object;
}
In this case, an object has a variable sized name but a fixed amount of space allocated for its identity.
I tried something else with sscanf but realized it will never work because I read the string too late to assign memory to name. See;
/*
int len = 0;
for (char* itemObserve = item->name; *itemObserve; itemObserve++) {
if (len == sizeof(item->name)) {
capacity *= MULTIPLIER;
item->name = (char*)realloc(item->name, capacity * sizeof(*item->name));
}
len++;
}
*/
Here is the code in main, everything undefined is probably irrelevant to the bug:
int main()
{
FILE* stream;
Object* object;
ObjectList* list = initList();
while (true) {
char* line;
char cmd[15] = {0};
char* arg;
char* rest;
printf("> ");
line = getline(stdin);
arg = (char*)malloc(35 * sizeof(*arg));
rest = (char*)malloc(35 * sizeof(*rest));
int arguments = sscanf(line, "%s %s %[^\n]", cmd, arg, rest);
free(line);
line = NULL;
printf("\n");
if (strcmp(cmd, "add") == 0) {
arg = (char*)realloc(arg, (35 * 2) * sizeof(*arg));
sprintf(arg, "%s %s", arg, rest);
if ((object = read(arg)) == NULL) {
continue;
}
objectListAdd(list, object);
} else {
free(rest);
free(arg);
exit(EXIT_SUCCESS);
}
free(rest);
free(arg);
}
freeObject(object);
freeObjectList(list);
return EXIT_SUCCESS;
}
Separate getline function in main file
char* getline(FILE* stream)
{
int capacity = LINE_MAX + 1;
char* buffer = (char*)malloc(capacity * sizeof(*buffer));
int len = 0;
int ch;
while ((ch = fgetc(stream)) != '\n' && (ch != EOF)) {
if (len == capacity) {
capacity *= MULTIPLIER;
buffer = (char*)realloc(buffer, capacity * sizeof(*buffer));
}
buffer[len++] = ch;
}
if (ch == EOF) {
return NULL;
}
buffer[len] = '\0';
if (buffer == NULL)
return NULL;
return buffer;
}
There are other conditionals which work as a kind of command switch but they are irrelevant to the errors my program is exhibiting. This much I have narrowed the problem down to.

segmentation fault during realloc

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.

How to realloc properly?

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.

double free or corruption error happens when call free in c

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.

Help with malloc and free: Glibc detected: free(): invalid pointer

I need help with debugging this piece of code. I know the problem is in malloc and free but can't find exactly where, why and how to fix it. Please don't answer: "Use gdb" and that's it. I would use gdb to debug it, but I still don't know much about it and am still learning it, and would like to have, in the meanwhile, another solution.
Thanks.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#define MAX_COMMAND_LENGTH 256
#define MAX_ARGS_NUMBER 128
#define MAX_HISTORY_NUMBER 100
#define PROMPT ">>> "
int num_elems;
typedef enum {false, true} bool;
typedef struct {
char **arg;
char *infile;
char *outfile;
int background;
} Command_Info;
int parse_cmd(char *cmd_line, Command_Info *cmd_info)
{
char *arg;
char *args[MAX_ARGS_NUMBER];
int i = 0;
arg = strtok(cmd_line, " ");
while (arg != NULL) {
args[i] = arg;
arg = strtok(NULL, " ");
i++;
}
num_elems = i;precisa em free_mem
if (num_elems == 0)
return 0;
cmd_info->arg = (char **) ( malloc(num_elems * sizeof(char *)) );
cmd_info->infile = NULL;
cmd_info->outfile = NULL;
cmd_info->background = 0;
bool b_infile = false;
bool b_outfile = false;
int iarg = 0;
for (i = 0; i < num_elems; i++)
{
if ( !strcmp(args[i], "<") )
{
if ( b_infile || i == num_elems-1 || !strcmp(args[i+1], "<") || !strcmp(args[i+1], ">") || !strcmp(args[i+1], "&") )
return -1;
i++;
cmd_info->infile = malloc(strlen(args[i]) * sizeof(char));
strcpy(cmd_info->infile, args[i]);
b_infile = true;
}
else if (!strcmp(args[i], ">"))
{
if ( b_outfile || i == num_elems-1 || !strcmp(args[i+1], ">") || !strcmp(args[i+1], "<") || !strcmp(args[i+1], "&") )
return -1;
i++;
cmd_info->outfile = malloc(strlen(args[i]) * sizeof(char));
strcpy(cmd_info->outfile, args[i]);
b_outfile = true;
}
else if (!strcmp(args[i], "&"))
{
if ( i == 0 || i != num_elems-1 || cmd_info->background )
return -1;
cmd_info->background = true;
}
else
{
cmd_info->arg[iarg] = malloc(strlen(args[i]) * sizeof(char));
strcpy(cmd_info->arg[iarg], args[i]);
iarg++;
}
}
cmd_info->arg[iarg] = NULL;
return 0;
}
void print_cmd(Command_Info *cmd_info)
{
int i;
for (i = 0; cmd_info->arg[i] != NULL; i++)
printf("arg[%d]=\"%s\"\n", i, cmd_info->arg[i]);
printf("arg[%d]=\"%s\"\n", i, cmd_info->arg[i]);
printf("infile=\"%s\"\n", cmd_info->infile);
printf("outfile=\"%s\"\n", cmd_info->outfile);
printf("background=\"%d\"\n", cmd_info->background);
}
void get_cmd(char* str)
{
fgets(str, MAX_COMMAND_LENGTH, stdin);
str[strlen(str)-1] = '\0';
}
pid_t exec_simple(Command_Info *cmd_info)
{
pid_t pid = fork();
if (pid < 0)
{
perror("Fork Error");
return -1;
}
if (pid == 0)
{
if ( (execvp(cmd_info->arg[0], cmd_info->arg)) == -1)
{
perror(cmd_info->arg[0]);
exit(1);
}
}
return pid;
}
void type_prompt(void)
{
printf("%s", PROMPT);
}
void syntax_error(void)
{
printf("msh syntax error\n");
}
void free_mem(Command_Info *cmd_info)
{
int i;
for (i = 0; cmd_info->arg[i] != NULL; i++)
free(cmd_info->arg[i]);
free(cmd_info->arg);
free(cmd_info->infile);
free(cmd_info->outfile);
}
int main(int argc, char* argv[])
{
char cmd_line[MAX_COMMAND_LENGTH];
Command_Info cmd_info;
//char* history[MAX_HISTORY_NUMBER];
while (true)
{
type_prompt();
get_cmd(cmd_line);
if ( parse_cmd(cmd_line, &cmd_info) == -1)
{
syntax_error();
continue;
}
if (!strcmp(cmd_line, ""))
continue;
if (!strcmp(cmd_info.arg[0], "exit"))
exit(0);
pid_t pid = exec_simple(&cmd_info);
waitpid(pid, NULL, 0);
free_mem(&cmd_info);
}
return 0;
}
Since strings in C are null-terminated, their actuall size in memory is length+1, so instead of
cmd_info->infile = malloc(strlen(args[i]) * sizeof(char));
You should have
cmd_info->infile = malloc((strlen(args[i])+1) * sizeof(char));
EDIT: As Aeth said, you need to change every single occurence of malloc to contain space for that additional null character:
cmd_info->arg = (char **) ( malloc(num_elems * sizeof(char *)) ); //this one can stay, since it determines number of strings, not string length
cmd_info->outfile = malloc((strlen(args[i])+1) * sizeof(char));
cmd_info->arg[iarg] = malloc((strlen(args[i])+1) * sizeof(char));
You need to allocate an extra char for each of your strings to handle the terminating null.
cmd_info->arg[iarg] = malloc((strlen(args[i])+1) * sizeof(char));
You need to allocate an additional char* in the cmd_info->arg array. This extra element will store the NULL that signifies the end of the array of arguments.
cmd_info->arg = (char **) ( malloc((num_elems+1) * sizeof(char *)) );
I have confirmed on my system that the program successfully frees all its memory without error after both of the changes listed were made.
When you are dynamically allocating memory for cmd_info->infile as:
cmd_info->infile = malloc(strlen(args[i]) * sizeof(char));
you are not allocating space for the terminating null char.
Same is the case with allocation for cmd_info->outfile
When you allocate space for n char and copy a string of length n into it, I think that overwrites the metadata that malloc maintains at the end of the array and this bug shows up when you call free to deallocate the memory as free does not find that meta data.
EDIT:
Change:
num_elems = i;
to
num_elems = i+1;
Since you are marking the end of the arguments with NULL
cmd_info->arg[iarg] = NULL;
you need to allocate the space for this.
In general, this error is usually the result of something writing data outside a malloc()'d block (off the end or before the beginning). This can corrupt the memory allocator's internal bookkeeping structures.
Others have already pointed out the particular problem in your code. In cases where it's more deeply hidden, I have found Valgrind to be useful for debugging. At the expense of noticable code slowdown, it is able to detect illegal memory accesses (in the form of "invalid reads" and "invalid writes") at a very fine-grained level. Memory debuggers such as dmalloc can also be helpful, and don't impose nearly as much overhead, but in my experience aren't quite as good as Valgrind for finding everything.
Valgrind, in its 'memcheck' mode, will output memory access errors with a stack trace of where in the program they occurred. Usually, when I have an "invalid pointer" error in free(), it will be preceeded at some point by an invalid write which memcheck will find.

Resources