#include
#include
#include
void main ()
{
char *imsi;
unsigned int i;
int val;
char *dest;
imsi = \"4057501
Assuming you compiled this C source code into machine code for some "normal" architecture and then ran it, the possible effects of read-undefined UB basically boil down to what value floating around in registers or memory ends up getting used.
If the compiler happens to use the same value both times, and that value happened to point to a writeable memory address (and didn't overwrite anything that would break printf), it could certainly happen to work. UB doesn't guarantee a crash. It doesn't guarantee anything. Part of the point of UB is to let the compiler make assumptions and optimize based on them.
Any changes to surrounding code will affect code-gen for that function, and thus will can affect what's in the relevant register when the call happens, or which stack slot is used for dest
. Reading from a different stack address will give dest
a different value.
Before main, calls to dynamic-linker functions might have dirtied some memory, leaving some pointers floating around in there, maybe including apparently some to writeable memory.
Or main's caller might have a pointer to some writeable memory in a register, e.g. a stack address.
Although that's less likely; if a compiler was going to just not even set a register before making a call, strncpy
would probably get main's first arg, an integer argc, unless the compiler used that register as a temporary first. But string literals normally go in read-only memory so that's an unlikely explanation in this case. (Even on an ISA / calling convention like ARM where gcc's favourite register for temporaries is R0, the return-value register but also the first arg-passing register. If optimization is disabled so statements compile separately, most expressions will use R0.)