Calloc & realloc: Error in `./a.out': free(): invalid next size (normal)

1.7k views Asked by At

I have a little piece of code (in C) where I'am allocating an array and scaning numbers in it. If the array is too small I'm reallocating memory for my array. Sometimes it works fine but sometimes it returns "Error in `./a.out': free(): invalid next size (normal)."

Here is the code:

int *array;
int memory=0, i=0, scanreturn=0;
array = (int *)calloc(30, sizeof(int));
/*Allocating 30 ints*/
while ( scanf("%d", &array[i]) != EOF){
  if(i == (memory - 5)){
    /*There's only 5 ints left. Allocating 10 more*/
    memory = memory + 10;
    array = (realloc(array, memory * sizeof *array));
  }
  i++;
}
...
free(array);

I suppose it's cause freeing the memory at the end but I really don't know how to figure it out.

5

There are 5 answers

1
R Sahu On BEST ANSWER

Looking at your posted code,

int *array;
int memory=0, i=0, scanreturn=0;
array = (int *)calloc(30, sizeof(int));
/*Allocating 30 ints*/
while ( scanf("%d", &array[i]) != EOF){

  // ***********************************************
  // This conditional will never be true since
  // memory has been initialized to 0.
  // ***********************************************
  if(i == (memory - 5)){
    /*There's only 5 ints left. Allocating 10 more*/
    memory = memory + 10;
    array = (realloc(array, memory * sizeof *array));
  }

  // ***********************************************
  // What happens when 1 == 30?
  // You start writing over out of bounds memory, leading to undefined behavior.
  // ***********************************************
  i++;
}
...
free(array);

If you initialize memory correctly, the purpose of using

  if(i == (memory - 5)){

would've been served. Change the line

int memory=0, i=0, scanreturn=0;

to

int memory=30, i=0, scanreturn=0;

to solve the problem.

0
KevinDTimm On

Questions to ask yourself:

1) Since you have no error checking, it's hard to say whether any of your alloc's are working
2) i and memory start as 0, when will realloc ever be called?
2a) if realloc isn't called, what happens when you get to the end of your original alloc?

P.S. Never cast the result of an alloc
P.P.S.
values of i 0, 1, 2, 3, ....
values of memory 0, 0, 0, 0, 0, .....
values of memory - 5 -5, -5, -5, -5, .....
if (i == (memory - 5))
0 == -5 FALSE
1 == -5 FALSE
2 == -5 FALSE
3 == -5 FALSE
......

As you can see, it will take a long time for this to not be FALSE

0
2501 On

With your starting conditions for i and memory, you never enter the if statement in the loop
if(i == (memory - 5)), array is never reallocated, and when you scanf() into the array you are writing out of bounds. This is undefined behaviour and aparently you overwrite some internal data, because you get a warning when you call free().

0
Nik Bougalis On
int *array;
int memory=0, i=0, scanreturn=0;
array = (int *)calloc(30, sizeof(int));
/*Allocating 30 ints*/
while ( scanf("%d", &array[i]) != EOF){
  if(i == (memory - 5)){

What have we here? How can this if ever trigger? memory is set to 0 and never modified and i starts at 0 and gets incremented with every iteration of the loop. So your loop compares:

 i == (memory - 5)  result
 0 == (0 - 5)        false
 1 == (0 - 5)        false
 2 == (0 - 5)        false
           ...
30 == (0 - 5)        false
31 == (0 - 5)        false

As a result, you never get into the code which attempts to grow the buffer and you end up with a buffer overflow. After that, you're in undefined behavior land and anything goes.

The obvious solution? Set memory = 30 instead of memory = 0.

Also note that you never check the result of calloc or realloc. While it's extremely unlikely for a memory operation to fail with modern operating systems, you should not just ignore the possibility of an error.

0
Nisse Engström On

Cleaned up version of your code:

int memory=0, i=0;
array = calloc(30, sizeof(int));

while (scanf("%d", &array[i]) != EOF) {
  if (i == (memory - 5)) {
    memory = memory + 10;
    array = realloc(array, memory * sizeof *array);
  }
  i++;
}

You need to initialize memory = 30. With memory = 0, your comparison will become if (i == -5)..., and realloc() will never be called.

You should also check the return value of calloc() and realloc() in case the allocations fail.