I have the following main code :
struct trncn c0 = {
.dgr = 1,
.accs = malloc(sizeof(enum direction)),
.parcourue = 0
};
c0.accs[5] = RIGHT;
which includes the following header:
#ifndef TRNCN_H
#define TRNCN_H
enum direction {
UP,
DOWN,
LEFT,
RIGHT
};
// trncn : tronçon
struct trncn {
// accs : access
enum direction *accs;
int dgr; // degree of freedom: number of accesses
int parcourue; // boolean
};
#endif
I was wondering why I haven't had an access violation when I had called c0.accs[5] = RIGHT;
.
CodePudding user response:
From @Jabberwocky's comment : "In the expression c0.accs[5], 5 is out of bounds, but an out of bounds access does not guarantee a segfault. It's undefined behaviour. Anyway reading a few bytes past memory allocated via malloc is pretty unlikely to trigger a segfault."
From @Rup's comment : "Broadly the C runtime is given memory by the OS in large pages, say 4K or 16K chunks, and then gives you smaller amounts of memory from that pool when you malloc. It's only if you go out of bounds of one of the pages that you'll get a segfault. Otherwise you'll just overwrite other memory that's technically owned by the process, which may cause errors further down the line if e.g. that was a pointer to something, or one of the data structures that the C runtime is using to manage the memory it's been given by the OS."
CodePudding user response:
Why don't I have an access violation (i.e segmentation fault)?
Because: accessing an array out of bounds is undefined behavior. What is undefined behavior and how does it work?
This is like asking why one doesn't get hit by the car when running around across the highway. Passing cars have no obligation to hit you - it's just one likely scenario and if you keep running around there, it will no doubt eventually end up with a crash. The highway is simply off limits for pedestrians - just don't go there and there will be no problems.
Fun demo of undefined behavior using your code on gcc x86_64 Linux https://godbolt.org/z/T3Pz8ndG1
for(int i=0; i<1; i )
{
printf("Index %d: %s\n", i, i==0?"this is safe":"out of bounds undefined behavior");
c0.accs[i] = RIGHT;
}
i<1
prints:Index 0: this is safe
i<2
prints:Index 0: this is safe
Index 1: out of bounds undefined behavior
I'm guessing that malloc grabs an 8 bytes aligned chunk, so going beyond 8 is where things get really interesting:
i<9
printsx 0: this is safe
Index 1: out of bounds undefined behavior
...i<10
prints:this is safe
Index 1: out of bounds undefined behavior
...i<11
prints:s is safe
Index 1: out of bounds undefined behavior
...
No seg faults but instead the output goes haywire. The text it was supposed to print when we are not accessing out of bounds got mangled somehow. The important part here is to understand the root cause of this, rather than trying to making sense of the weird symptoms.
Related to your question: an enum
variable can have any implementation-defined size large enough to contain all enumeration constants listed. The enumeration constants in themselves (UP
etc) are guaranteed to be of type int
though.