$ ./bin/10_return_local.asan
what it printed on the machine that wrote this lab
==NNNNN==ERROR: AddressSanitizer: stack-use-after-return on address 0x....
#0 0x... in main .../10_return_local.c:84
Address 0x.... is located in stack of thread T0 at offset 32 in frame
#0 0x... in get_ptr .../10_return_local.c:77
How to read it:
"stack-use-after-return" -> you used a stack slot after its function
returned. ASan names BOTH ends: the USE in main (line 84) and the
FRAME it belonged to — get_ptr (line 77). That second name is the
whole bug. (stack-use-after-return is ON by default in this clang.)
$ valgrind -q ./bin/10_return_local
what it printed on the machine that wrote this lab
==NNNNN== Use of uninitialised value of size 8
==NNNNN== at 0x...: _itoa_word (...) # deep inside printf
==NNNNN== by 0x...: main (10_return_local.c:84)
META-LESSON: valgrind does NOT say "stack-use-after-return". The dead
stack slot is still MAPPED memory, so memcheck can't call the address
invalid; it only notices, indirectly, that the bytes are uninitialised
once printf consumes them. ASan (with frame red zones) is the right tool
for dangling-stack bugs; valgrind is weak here.
ROOT CAUSE vs CRASH SITE:
The symptom shows up in main (the deref, line 84) or even deep inside
printf — far from the cause. The ROOT CAUSE is `return &local;` (line
79): a pointer escaping its object's lifetime. ASan's "in frame get_ptr"
line walks you straight back to the guilty function.