C realloc: invalid next size, aSan says heap-use-after-free

250 views Asked by At

I'm very sorry if this is a duplicate question, but I have looked at various other answers and they do not seem to apply to my code.
I have defined a struct Coord which is simply an x and y limited to 4 bits each.

typedef struct {
    unsigned int x:4;
    unsigned int y:4;
} Coord;

I am using an array of Coords by doing Coord* snakeArr = malloc(2 * sizeof(Coord)); and keeping track of the array's size with int snakeArrSize = 2;. I have made this function to mimic the unshift() javaScript function.

void unshiftCoord(Coord *arr, Coord value, int *arrSize) {
  // Debugging
  printf("%li\n", (*arrSize + 1) * sizeof(Coord));
  fflush(stdout);

  // Allocate an extra slot in the array
  arr = realloc(arr, (*arrSize + 1) * sizeof(Coord));

  // Shift everything over
  for (int i = *arrSize; i > 0; i--) {
    arr[i] = arr[i - 1];
  }

  // Set the first value in the array
  arr[0] = value;
  // Update arrSize variable
  *arrSize += 1;
}

This works perfectly fine but for some reason it gives the "invalid next size" error when I call the function for the 5th time. Here is the output of my program:

12
16
20
24
28
realloc(): invalid next size
Aborted (core dumped)

As you can see when the new size is increased to 28, realloc() fails.
One solution I came across was to use aSan. I did this with -fsanitize=address in my compiler flags, and I get this right when I run: ERROR: AddressSanitizer: heap-use-after-free... and a really long message. If you need it, I put it in this google doc.

1

There are 1 answers

3
MikeCAT On BEST ANSWER

After successful

  arr = realloc(arr, (*arrSize + 1) * sizeof(Coord));
  *arrSize += 1;

arr has *arrSize element, so arr[*arrSize] is out-of-range and you cannot use that to store something.

The loop

  for (int i = *arrSize; i > 0; i--) {

should be

  for (int i = *arrSize - 1; i > 0; i--) {

Also results of realloc() shouldbe checked to avoid dereferencing NULL.

And there is one more critical point: the argument arr is a copy of what is passed, so modification to that won't affect what is passed. Therefore, if realloc() returns new buffer, it will get lost and original invalidated arr will be used in later process. To avoid this, a pointer to variable should be passed instead of arr and modification of the variable should be done via the pointer.