(no title)
cokernel_hacker | 1 year ago
int f(int x) {
switch (x) {
case 0:
return 31;
case 1:
return 28;
case 2:
return 30;
}
}
This code on its own has no undefined behavior.In another translation unit, someone calls `f(3)`. What would you have compilers do in that case?
That path through the program has undefined behavior. However, the two translation units are separate and as such normal tooling will not be able to detect any sort of UB without some kind of whole program static analysis or heavy instrumentation which would harm performance.
zzo38computer|1 year ago
torstenvl|1 year ago
On most platforms, that would probably result in the return value of 3 (it would still be in AX, EAX, r0, x0, o0/i0, whatever, when execution hits the ret instruction or whatever that ISA/ABI uses to mark the end of the function). But it would be undefined. But that's fine.
[EDIT: I misremembered the x86 calling convention, so my references to AX and EAX are wrong above. Mea culpa.]
What isn't fine is ignoring the end of the function, not emitting a ret instruction, and letting execution fall through to the next label/function, which is what I suspect GCC does.
cokernel_hacker|1 year ago
nlewycky|1 year ago
qiqitori|1 year ago
Now, assume that you didn't compile this with those flags; what actually happens is entirely obvious but platform-dependent. Assume amd64 (and many other architectures) where the return value is in the "accumulator register", assume that int is 32 bits. The return value will be whatever was in eax. The called function doesn't set eax (or maybe does in order to implement some unrelated surrounding code). The caller takes eax without knowledge of where it came from.
loeg|1 year ago
In a C compiler, inserting a trap (x86 ud2, for example) might be reasonable.