First add this to your CMakeLists.txt file:
if(BOARD STREQUAL "native_posix_64")
target_compile_options(app PRIVATE -fsanitize=address -fsanitize=undefined)
target_link_options(app PRIVATE -fsanitize=address -fsanitize=undefined)
target_link_libraries(app PRIVATE asan ubsan)
endif()
For testing I used the blinky example, and added this at the beginning of the main function:
char foo[10];
foo[11] = 0;
printk("%s", foo);
Then compile your project like this (remove an old build directory before it, if needed, or use -p) :
west build --board=native_posix_64
You can start it now on your PC or Mac, and it shows you when a buffer overflow happens, and where in the code it is:
frank@wopr:~/zephyr/samples/basic/blinky$ ./build/zephyr/zephyr.exe
*** Booting Zephyr OS build v3.2.99-ncs2 ***
/home/frank/zephyr/samples/basic/blinky/src/main.c:27:5: runtime error: index 11 out of bounds for type 'char [10]'
/home/frank/zephyr/samples/basic/blinky/src/main.c:27:10: runtime error: store to address 0x7fd748bf402b with insufficient space for an object of type 'char'
0x7fd748bf402b: note: pointer points here
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 c0 be 48 d7 7f 00 00 00 00 00 00 00 00 00
^
=================================================================
==361187==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fd748bf402b at pc 0x000000402501 bp 0x7fd74a6f4c60 sp 0x7fd74a6f4c58
WRITE of size 1 at 0x7fd748bf402b thread T2
#0 0x402500 in _posix_zephyr_main /home/frank/zephyr/samples/basic/blinky/src/main.c:27
Address 0x7fd748bf402b is located in stack of thread T2 at offset 43 in frame
#0 0x402436 in _posix_zephyr_main /home/frank/zephyr/samples/basic/blinky/src/main.c:23
This frame has 1 object(s):
[32, 42) 'foo' (line 26) <== Memory access at offset 43 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
Thread T2 created by T1 here:
#0 0x7fd74faecb01 in pthread_create ../../../../src/libsanitizer/asan/asan_interceptors.cpp:245
#1 0x40377f in posix_new_thread /home/frank/zephyr/arch/posix/core/posix_core.c:380
Thread T1 created by T0 here:
#0 0x7fd74faecb01 in pthread_create ../../../../src/libsanitizer/asan/asan_interceptors.cpp:245
#1 0x403acc in posix_boot_cpu /home/frank/zephyr/soc/posix/inf_clock/soc.c:209
SUMMARY: AddressSanitizer: stack-buffer-overflow /home/frank/zephyr/samples/basic/blinky/src/main.c:27 in _posix_zephyr_main
Shadow bytes around the buggy address:
0x7fd748bf3d80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fd748bf3e00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fd748bf3e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fd748bf3f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fd748bf3f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x7fd748bf4000: f1 f1 f1 f1 00[02]f3 f3 00 00 00 00 00 00 00 00
0x7fd748bf4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fd748bf4100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fd748bf4180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fd748bf4200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fd748bf4280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==361187==ABORTING
You can also run it with Valgrind. For this you have to remove the asan lines from your CMakeLists.txt file, because the asan library can't be used at the same time as Valgrind. Then start it like this:
frank@wopr:~/zephyr/samples/basic/blinky$ valgrind --tool=memcheck ./build/zephyr/zephyr.exe
==362465== Memcheck, a memory error detector
==362465== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==362465== Using Valgrind-3.20.0 and LibVEX; rerun with -h for copyright info
==362465== Command: ./build/zephyr/zephyr.exe
==362465==
*** Booting Zephyr OS build v3.2.99-ncs2 ***
==362465== Thread 3:
==362465== Conditional jump or move depends on uninitialised value(s)
==362465== at 0x4849C89: strlen (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==362465== by 0x401C75: z_cbvprintf_impl (cbprintf_complete.c:1594)
==362465== by 0x40149F: printk (printk.c:209)
==362465== by 0x401394: _posix_zephyr_main (main.c:28)
==362465== by 0x4046E1: bg_thread_main (init.c:330)
==362465== by 0x4014B6: z_thread_entry (thread_entry.c:36)
==362465== by 0x402287: posix_thread_starter (posix_core.c:305)
==362465== by 0x49F9042: start_thread (pthread_create.c:447)
==362465== by 0x4A775AF: clone (clone.S:100)
==362465==
^C
Stopped at 4.140s
==362465==
==362465== HEAP SUMMARY:
==362465== in use at exit: 544 bytes in 2 blocks
==362465== total heap usage: 13 allocs, 11 frees, 9,254 bytes allocated
==362465==
==362465== LEAK SUMMARY:
==362465== definitely lost: 0 bytes in 0 blocks
==362465== indirectly lost: 0 bytes in 0 blocks
==362465== possibly lost: 544 bytes in 2 blocks
==362465== still reachable: 0 bytes in 0 blocks
==362465== suppressed: 0 bytes in 0 blocks
==362465== Rerun with --leak-check=full to see details of leaked memory
==362465==
==362465== Use --track-origins=yes to see where uninitialised values come from
==362465== For lists of detected and suppressed errors, rerun with: -s
==362465== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
There are always some memory lost, which is normal, because Zephyr is not designed to exit and cleanup everything, but you can also see with the previous example code that it shows that unitialized memory was accessed, the beginning of the foo array.