Search code examples
cvalgrind

"Invalid read of size 4" when trying to realloc memory


I'm writing a Snake game as the first "serious" project in C. But when I try to grow the snake, program crashes with SEGFAULT error. So, i tried to run the game in Valgrind, and got this:

==11312== 30 errors in context 7 of 7:
==11312== Invalid read of size 4
==11312==    at 0x10969E: collide (game.c:238)
==11312==    by 0x108FBD: main (game.c:120)
==11312==  Address 0x5897c60 is 0 bytes inside a block of size 40 free'd
==11312==    at 0x4C31D2F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11312==    by 0x109724: snake_grow (game.c:250)
==11312==    by 0x108F7D: main (game.c:113)
==11312==  Block was alloc'd at
==11312==    at 0x4C31B25: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11312==    by 0x109278: start (game.c:159)
==11312==    by 0x108EC0: main (game.c:91)
==11312== 
==11312== ERROR SUMMARY: 80 errors from 7 contexts (suppressed: 0 from 0)

As I can suggest, I did realloc wrong and that is why the game crashes. So, the problem should be here:

void snake_grow(snake_t *snake){
  snake->length++;
  snake->body = realloc(snake->body, sizeof(snake->body[0]) * (snake->length));
  snake->end = snake->body + snake->length - 1;
  snake->end->x = snake->prev_x;
  snake->end->y = snake->prev_y;
}

Or maybe I just use pointer in fuction wrong?

bool collide(snake_t *snake, block map[MAXY][MAXX]){
  bool ret = FALSE;
  if(map[snake->head->y][snake->head->x].collision == COLLIDABLE){
    ret = TRUE;
  }
  for(int i = 1; i < snake->length; i++){
    if(snake->body[i].x == snake->head->x){
      if(snake->body[i].y == snake->head->y){
    ret = TRUE;
      }
    }    
  }
  return ret;
}

Strange, but I can't find anything similar to my problem. But maybe I just didn't understand solutions.


Solution

  • Accidentally, when I tried to make minimal reproducible example and debug, as it was advised by WhozCraig, I solve this problem.

    void snake_grow(snake_t *snake){
      snake->length++;
      snake->body = realloc(snake->body, sizeof(snake->body[0]) * (snake->length));
      snake->end = snake->body + snake->length - 1;
      snake->end->x = snake->prev_x;
      snake->end->y = snake->prev_y;
    }
    

    This function, besides reallocating memory, sets new address for snake->end. But there is also the snake->head, which after realloc points to the same address. So, everything that I needed to do is just set snake->head to new address.

    snake->head = snake->body;