py/gc: no_sanitize_address on gc_get_ptr() is not applied with clang, so ASan reports every gc_collect()

Aperta Adatta ai principianti
#19,784 2 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
2/5
Tempo stimato
1-3 ore
Idoneità per principianti
72/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
c, linux, macos

Direzione di ricerca

Inizia in py/gc.c, in gc_get_ptr(), e controlla la condizione del compilatore attorno all’attributo no_sanitize_address; il report spiega perché clang lo ignora e propone una modifica alla condizione. Riproduci il problema con la port unix e clang AddressSanitizer usando i comandi dell’issue, poi verifica che gc.collect() stampi «ok» e che i gruppi di test elencati passino.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Note: this report was researched, reproduced and written by an AI coding agent
(Claude Code), and filed with my authorization. See "Use of generative AI" at the end.

Port, board and/or hardware

unix port, standard variant. Linux aarch64 (Ubuntu 24.04, clang 18.1.3) and
macOS arm64 (Apple clang 21). Any clang build with AddressSanitizer.

MicroPython version

v1.29.0 (0fd6c573e). The code is the same on master (b70ae1aca, 2026-10-19).

Reproduction

Build the unix port with clang and AddressSanitizer (the flags of
CI_UNIX_OPTS_SANITIZE_ADDRESS in tools/ci.sh, with clang's spelling of
--param asan-use-after-return=0):

make -C mpy-cross CC=clang
F="-fsanitize=address -fsanitize-address-use-after-return=never"
make -C ports/unix VARIANT=standard CC=clang STRIP= CFLAGS_EXTRA="$F" LDFLAGS_EXTRA="$F"
ASAN_OPTIONS=detect_leaks=0 ports/unix/build-standard/micropython -c "import gc; gc.collect(); print('ok')"

Expected behaviour

ok, as with gcc (the unix sanitize_address CI job uses gcc and passes).

Observed behaviour

The first garbage collection aborts:

==8961==ERROR: AddressSanitizer: stack-buffer-overflow on address 0xffffd4464638 at pc 0xaaaab37cfc58 bp 0xffffd44644c0 sp 0xffffd44644b8
READ of size 8 at 0xffffd4464638 thread T0
    #0 0xaaaab37cfc54 in gc_get_ptr /mp/ports/unix/../../py/gc.c:777:12
    #1 0xaaaab37cfc54 in gc_collect_root /mp/ports/unix/../../py/gc.c:496:21
    #2 0xaaaab38cff34 in gc_helper_collect_regs_and_stack /mp/ports/unix/../../shared/runtime/gchelper_generic.c:286:5
    #3 0xaaaab38c9f88 in gc_collect /mp/ports/unix/gccollect.c:38:5
    #4 0xaaaab3821110 in py_gc_collect /mp/ports/unix/../../py/modgc.c:35:5
    #5 0xaaaab382577c in mp_execute_bytecode /mp/ports/unix/../../py/vm.c:1069:21
    ...
Address 0xffffd4464638 is located in stack of thread T0 at offset 344 in frame
    #0 0xaaaab38cfe80 in gc_helper_collect_regs_and_stack /mp/ports/unix/../../shared/runtime/gchelper_generic.c:281

  This frame has 1 object(s):
    [32, 344) 'regs' (line 282) <== Memory access at offset 344 overflows this variable

In a real program this happens on the first allocation that triggers a
collection, so nothing non-trivial runs under clang ASan.

Additional Information

gc_get_ptr() exists so the conservative stack scan can read red zones, and
is marked no_sanitize_address behind this guard (py/gc.c:768):

#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
__attribute__((no_sanitize_address))
#endif
static void *gc_get_ptr(void **ptrs, int i) {

clang defines __GNUC__ as 4 and __GNUC_MINOR__ as 2, so the condition is
false and the attribute is dropped, although clang has supported
no_sanitize_address since 3.x.

Possible fix (tested):

-#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
+#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))
 __attribute__((no_sanitize_address))
 #endif

With it, the reproduction prints ok and run-tests.py -d basics float micropython misc stress passes under clang ASan on Linux aarch64 (685 passed,
0 failed). gcc builds are not affected: the preprocessor result is the same
for them.

Found while running the tests of a user C module
(https://github.com/Tangerino/micropython-msgpackc) under clang ASan; the
workaround there is a -fsanitize-ignorelist with fun:gc_get_ptr.

Related, for clang UBSan: #17924.

Use of generative AI

This issue was produced with generative AI: an AI coding agent (Claude Code,
Anthropic's Claude) found the problem while testing a user C module, reproduced
it on a clean v1.29.0 checkout in Docker, tested the suggested fix with
run-tests.py, wrote this text and filed it from my account, at my request.
The commands and outputs above were actually run; the outputs are copied
verbatim, not written by hand. The suggested fix is a suggestion for review,
not a finished patch.

Code of Conduct

Yes, I agree

Lingua principale
C
Stelle
22.2k
Fork
9.1k
Merge medio
6g 8h
PR unite (30g)
33

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di micropython/micropython

Tutte le issue di micropython/micropython

Issue simili

Altre issue su C

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.