Search code examples
carrayspointersmallocrealloc

Munmap_chunk(): invalid pointer, Aborted (core dumped), realloc(): invalid next size


I'm writing code where user enter fields for Minesweeper, where '.' is empty field and '*' is bomb. Program will read the size of the field from the input, and print whole game field, where field that is '.' is replaced by the number of bombs around that field, if the field doesn't have any it prints '.', and if the field is '*', it prints simply '*' .

We don't know how big the input (game field) will be. Input is ended with EOF. My program is working fine for "normal" (small) inputs, for example 10x10 game field, 50x50 game field, 20x4 game field, etc. I get input into arr and then copy each index into arr2, so I can get another input into arr and I don't lose the previous input. Both arrays are 1D. In arr2, I change values of indexes from '.' to numbers (i.e. 2) if the bomb (' * ') is around it.

Example of input:

.*.
*.*

Example of output:

2*2
*3*

However, when I try to input game field that has i.e. 216 rows and 10 columns (216x10), this is what happens:

  • If the code is same as you see, the program says: realloc(): invalid next size. Aborted (core dumped)
  • If I use &arr2 in realloc, it says the same.
  • If I remove the realloc line it says: munmap_chunk(): invalid pointer. Aborted (core dumped)
  • The printed game field with the numbers have "correctly printed field" and parts where newline occurs or where whole row is filled with numbers.

Valgrind says no memory leaks or errors with low inputs.

As I'm new to the memory management and pointers, I can't find out where is the problem. I'd appreciate if you ask questions and try to help me.

The code I show here should be the problematic part (and is the beginning of the program). The rest of the code should be fine and work based on this part.


    int main()
    {
      int err, size=200;
      char *arr=NULL;
      char *arr2=(char*)malloc(sizeof(char)*size);
      size_t bufsize=0;
      printf("Enter game field:\n");
      while(true)
      {
         for (int i=0;i<size;i++)
            {
                err=getline(&arr,&bufsize,stdin);
                if (i==(size-2))
                {
                    size *= 3;
                    arr2=(char*)realloc(arr2,sizeof(char)*size);
                }
                for (int j=0;j<(err-1);j++)
                {
                    arr2[l]=arr[j];
                    l++;
                }
                /*rest of the code*/
            }
      }

.
.
.


Solution

  • Short Answer:

    The allocation for arr2 is too small for large boards (>200 bytes total), consider resizing it on EVERY iteration to handle unknown size.

      // existing line
      err=getline(&arr,&bufsize,stdin);
      if ( err > 0 ) {
          size += err ;
          arr2 = realloc(arr2, size) ;
          // Append arr to arr2.
      }
    

    Or similar.

    Long Answer:

    There is a compile error - code reference variable 'l' (in arr2[] = arr[j]), without declaring it (or specifying it's value). Assuming this is declared in main (or as static) and initialized to zero.

    On every iteration, the code append the content of the input line arr to arr2. Given initial allocation of only 200 bytes to arr2. on large boards (216x10), this will overrun the size of arr2 in iteration 20.

    The allocation on iteration 198 (i==size-2) allows the code to work on small problem that where the board total size is < 200 bytes (10x10, ...).

    Valgrind:

    On my machine (Mint 19), valgrid correctly identified the buffer overrun with 216x10 board:

    ==61030== Memcheck, a memory error detector
    ==61030== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
    ==61030== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
    ==61030== Command: ./a.out
    ==61030== 
    Enter game field:
    ==61030== Invalid write of size 1
    ==61030==    at 0x10882A: main (gg.c:25)
    ==61030==  Address 0x522d108 is 0 bytes after a block of size 200 alloc'd
    ==61030==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==61030==    by 0x10878C: main (gg.c:9)
    ==61030==