I'm trying to code my own malloc and free in C for a project. For the most part, it's going fine but I can't wrap my head around a strange Segmentation Fault it's giving me. I reproduced the code that was giving the error in a simplified form:
#include <stdio.h>
#define MEMORY_SIZE 4096
static char memory[MEMORY_SIZE];
typedef struct metaData{
unsigned short isFree; //1 if free, 0 if allocated
unsigned short size;
} metaData;
int main(){
metaData *head = (metaData *) memory;
printf("%d\n", (head 2031)->size);
printf("%d\n", (head 2032)->size);
puts("Segmentation up here???");
return 0;
}
memory
is a static array of chars of size 4096. The first printf
prints out a 0. But the next printf
is a segfault. I am able to manipulate the metaData
struct at every pointer up until head 2032
. Does anyone have any idea why?
CodePudding user response:
Pointer arithmetic in C is performed in base units of the size of the pointed-to type. Your head
is a pointer to a metaData
structure, which has a size of 2 × sizeof(unsigned short)
. Assuming (as is likely, but not certain) that an unsigned short
has a size of 2 bytes on your platform, then that "base unit" will be 4 bytes.
Thus, when the head 2031
calculation is made, the value of 4 × 2031
(which is 8124) will be added to the address in head
to give the result of that expression. So, with the following ->size
operator, you are attempting to reference memory that is 8,126 bytes1 from the location of the beginning of your memory
array – but that array is declared as only 4096 bytes (sizeof(char)
is, by definition, 1 byte).
Accessing memory beyond the declared size of an array is undefined behaviour (UB); once you have invoked such UB (as you do in both printf
calls), many different things can happen, and in unpredictable ways. A "segmentation fault" (trying to read or write memory to which your program does not have access) is one possible manifestation of UB. (Another possible manifestation is that no error is reported and the program appears to work properly; in many people's opinion, that's the worst kind!)
1 8,124 bytes will be the offset of the start of the potentially pointed-to meteData
structure; because size
is preceded by another unsigned short
member, then another two bytes will be added.