Home > Net >  Misalignment of assigning the first element in void* arrays and malloc assigning more memory than ne
Misalignment of assigning the first element in void* arrays and malloc assigning more memory than ne

Time:09-23

I'm confused as to why the following code still runs even though i have not allocated enough memory for the void* arr[]; i'm still able to write to those locations and not run into a segfault.

void** arr;

arr = realloc(NULL, 1); // 1 Byte allocated
arr[0] = (void *)1;     // able to store a 8B pointer

arr = realloc(arr, 2); // 2 Bytes allocated
arr[1] = (void *)2;    // able to store yet another 8B pointer

arr = realloc(arr, 4); // 4 Bytes allocated
arr[2] = (void *)3;    // able to store yet another 8B pointer
arr[3] = (void *)4;    // able to store yet another 8B pointer

// Error
arr = realloc(arr, 8); // realloc():invalid next size thrown presumaby 
                       // because we wrote into the space for malloc metadata

Also, looking at this [screenshot of the program's memory layout] it seems that the first assignment a[0] = 1 takes up only the first 4B chunk even though void*s are 8Bytes. The rest of the assignments do take up 8Bs so i'm also curious why the first a[0] only takes up 4Bytes.

Thank you!

CodePudding user response:

realloc only reserves memory for use. Nothing in the C standard requires a C implementation to prevent you from using, or trying to use, memory you have not reserved.

When your program executes arr[0] = (void *)1;, it writes to memory it has not reserved. If nothing else is using that memory, you may “get away with it.” Memory allocation software generally does not reserve memory in one-byte pieces, so, when you ask for one byte, it actually provides whatever its smallest allocation unit is. (This does not mean you can safely use that memory. Compiler optimizers have become increasingly more aggressive and “knowledgeable” about C rules and semantics, so optimization effects may make a program that violates the rules go awry even if the memory is available.)

The screenshot does not show that only four bytes are written for that assignment. The high bytes are zeros, so they show up as “0x00000000”. The C implmentation you are using stores the low-value bytes in the low-addressed word and the high-value bytes in the high-addressed word, so a pointer to address 1 is stored as 0x00000001 in the first four bytes and 0x00000000 in the second four bytes.

CodePudding user response:

It is undefined behavour. In C nothing prevents you from writing to the invalid or not allocated memory.

it seems that the first assignment a[0] = 1 takes up only the first 4B chunk even though void*s are 8Bytes.

No, it is called little endian and less significant bytes are stored first.

example:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    unsigned long long x[] = {1,2,3};
    unsigned y[sizeof(x) / sizeof(unsigned)];

    memcpy(y,x,sizeof(x));
    for(int i = 0; i < sizeof(y) / sizeof(y[0]); i   )
        printf("0xx ", y[i]);
    printf("\n");
}

result:

0x00000001 0x00000000 0x00000002 0x00000000 0x00000003 0x00000000 

https://godbolt.org/z/a7vrrPWGx

You can also see it on the byte level: https://godbolt.org/z/b7xMMfxhc

or https://godbolt.org/z/scT7barvs

  •  Tags:  
  • c
  • Related