Search code examples
cmemorypipefree

free() crashing on char array, but only if the array holds exactly 7 elements


I have a simple C program that is supposed to read a message sent from another program, from an UNIX named pipe and show it to the user.

The way the program does this is the following :

  1. Reads the incomming message size from the pipe
  2. Allocates enough memory for the incoming message, plus another byte for the null terminator
  3. Reads the incoming data to the allocated memory
  4. Appends the null terminator and returns

The code is the following :

void* ReceiveFromPipe(char* Pipe, int* StuffSize){
    printf("Opening pipe\n");
    int FD = open(Pipe,O_RDONLY);
    printf("Pipe opened from the write side\n");
    read(FD,StuffSize,sizeof(StuffSize));
    printf("Incoming message size : %d\n",*StuffSize);
    void* StuffPointer = calloc((*StuffSize) + 1,1);//allocate stuffsize bytes
    printf("Allocated memory for stuff\n");
    read(FD,StuffPointer,*StuffSize);
    printf("Read stuff from pipe\n");
    close(FD);
    printf("Closed pipe\n");
    ((int*)StuffPointer)[*StuffSize] = 0x00;
    return StuffPointer;
}

And the code in the main function is a simple read-free loop, like this :

int main(void){
    char* message;
    int msgSize = -1;
    while(1){
        message = (char*)ReceiveFromPipe("./PSender0",&msgSize);
        printf("Got :: %s\n",message);
        fflush(stdout);
        free(message);
    }
}

This will work on any kind of message, unless the message has exactly 6 bytes (7 with the appended null terminator). For example, that exact program with an "HelloWorld!" message will output this :

Opening pipe
Pipe opened from the write side
Incoming message size : 11
Allocated memory for stuff
Read stuff from pipe
Closed pipe
Got :: HelloWorld!
Opening pipe

Which is the expected behaviour, however with the message 123456, the output turns to

Opening pipe
Pipe opened from the write side
Incoming message size : 6
Allocated memory for stuff
Read stuff from pipe
Closed pipe
Got :: 123456
*** Error in `./Receiver': free(): invalid next size (fast): 0x0000008869995420 ***
======= Backtrace: =========
/usr/lib/libc.so.6(+0x72bdd)[0x7f12da646bdd]
/usr/lib/libc.so.6(+0x792ec)[0x7f12da64d2ec]
/usr/lib/libc.so.6(+0x7a6d1)[0x7f12da64e6d1]
./Receiver(+0xb13)[0x8867c07b13]
/usr/lib/libc.so.6(__libc_start_main+0xea)[0x7f12da5f44ca]
./Receiver(+0x9ba)[0x8867c079ba]
======= Memory map: ========
8867c07000-8867c09000 r-xp 00000000 08:05 6030989                        /home/andre/EI/SO/PipesTest/Receiver
8867e08000-8867e09000 r--p 00001000 08:05 6030989                        /home/andre/EI/SO/PipesTest/Receiver
8867e09000-8867e0a000 rw-p 00002000 08:05 6030989                        /home/andre/EI/SO/PipesTest/Receiver
8869995000-88699b6000 rw-p 00000000 00:00 0                              [heap]
7f12d4000000-7f12d4021000 rw-p 00000000 00:00 0
7f12d4021000-7f12d8000000 ---p 00000000 00:00 0
7f12da3bd000-7f12da3d3000 r-xp 00000000 08:02 545366                     /usr/lib/libgcc_s.so.1
7f12da3d3000-7f12da5d2000 ---p 00016000 08:02 545366                     /usr/lib/libgcc_s.so.1
7f12da5d2000-7f12da5d3000 r--p 00015000 08:02 545366                     /usr/lib/libgcc_s.so.1
7f12da5d3000-7f12da5d4000 rw-p 00016000 08:02 545366                     /usr/lib/libgcc_s.so.1
7f12da5d4000-7f12da771000 r-xp 00000000 08:02 526947                     /usr/lib/libc-2.25.so
7f12da771000-7f12da970000 ---p 0019d000 08:02 526947                     /usr/lib/libc-2.25.so
7f12da970000-7f12da974000 r--p 0019c000 08:02 526947                     /usr/lib/libc-2.25.so
7f12da974000-7f12da976000 rw-p 001a0000 08:02 526947                     /usr/lib/libc-2.25.so
7f12da976000-7f12da97a000 rw-p 00000000 00:00 0
7f12da97a000-7f12da99d000 r-xp 00000000 08:02 526937                     /usr/lib/ld-2.25.so
7f12dab34000-7f12dab36000 rw-p 00000000 00:00 0
7f12dab9c000-7f12dab9d000 rw-p 00000000 00:00 0
7f12dab9d000-7f12dab9e000 r--p 00023000 08:02 526937                     /usr/lib/ld-2.25.so
7f12dab9e000-7f12dab9f000 rw-p 00024000 08:02 526937                     /usr/lib/ld-2.25.so
7f12dab9f000-7f12daba0000 rw-p 00000000 00:00 0
7ffe4c462000-7ffe4c483000 rw-p 00000000 00:00 0                          [stack]
7ffe4c495000-7ffe4c498000 r--p 00000000 00:00 0                          [vvar]
7ffe4c498000-7ffe4c49a000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Aborted (core dumped)

I can't really find the problem in this code, and can't even imagine why it only fails on 6 char messages, and would appreciate any help


Solution

  • This line:

    ((int*)StuffPointer)[*StuffSize] = 0x00;
    

    You are casting StuffPointer as an integer pointer, so the array access will be using sizeof int to calculate where to write the 0 integer value.

    This will be writing outside the boundaries of your array, which could then cause the problem you are seeing.

    Edit: To fix the issue, you could cast to (char *), or make StuffPointer a char * to begin with.

    Also

    read(FD,StuffSize,sizeof(StuffSize));
    

    should be

    read(FD,StuffSize,sizeof(*StuffSize));
    

    as sizeof(StuffSize) is the size of the pointer, which may not be the same as the size of an integer.