BPF backend: constant offsets into globals fail silently, global pointer initializers become null, constant-false conditions skip the rest of the function
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 45/100
- Tipo di issue
- Bug
- Chiarezza
- Abbastanza chiara
- Stato di attività
- Attiva
- Stack tecnologico
- c
- Ambito
- compilers, operating-systems
Direzione di ricerca
Reproduce the three failures through spinfoam's sf.build.submit, sf.object.load, and sf.object.start using the stated TCC_EBPF_TARGET=bpf setup. Trace BPF relocation handling for global-symbol addends and data initializers, then inspect constant-condition branch emission around calls. Done means non-zero global offsets work or diagnose cleanly, pointer initializers are handled explicitly, and all shown constant-condition programs return 42.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Fork revision: 120e1619c7b3913e9ec2a10d06e431d17b23648e (the revision spinfoam v0.1.0 embeds, built with TCC_EBPF_TARGET=bpf TCC_EBPF_VFS=1, run inside async-ebpf 7e8a7cbce195d68a1d579608b7a28b55f6fce7fd).
Observed through spinfoam's sf.build.submit / sf.object.load / sf.object.start on Linux x86_64. Every program below includes spinfoam.h and defines SF_MAIN sf_i64 main(void).
1. Global symbol + non-zero constant offset does not compile (exit status -1, no diagnostic)
tcc_ebpf_diagnostic is never called; the compiler guest returns 0xffffffff and spinfoam reports compiler failed (0xffffffff).
Fails:
static char buf[64];
SF_MAIN sf_i64 main(void) { buf[5] = 1; return 0; } /* store, constant index */
static long arr[8];
SF_MAIN sf_i64 main(void) { return arr[1]; } /* load, constant index */
static char buf[64];
SF_MAIN sf_i64 main(void) { return *(buf + 1); } /* explicit pointer arithmetic */
static char buf[64];
SF_MAIN sf_i64 main(void) { memset(&buf[1], 3, 2); return 0; } /* address of element */
struct S { sf_u64 a; sf_u64 b; }; static struct S s;
SF_MAIN sf_i64 main(void) { return (sf_i64)s.b; } /* field at offset 8 */
static const char C[] = "abc";
SF_MAIN sf_i64 main(void) { return C[1]; } /* const data, constant index */
Compiles and runs correctly (same programs with the offset removed or made dynamic):
static char buf[64];
SF_MAIN sf_i64 main(void) { return buf[0]; } /* offset 0 */
struct S { sf_u64 a; sf_u64 b; }; static struct S s;
SF_MAIN sf_i64 main(void) { return (sf_i64)s.a; } /* field at offset 0 */
static char buf[64];
SF_MAIN sf_i64 main(void) { unsigned i = 5; buf[i] = 1; return buf[i]; } /* variable index */
static char buf[64];
SF_MAIN sf_i64 main(void) { char *p = buf; p[5] = 1; return p[5]; } /* through a pointer */
struct S { sf_u64 a; sf_u64 b; }; static struct S s;
SF_MAIN sf_i64 main(void) { struct S *p = &s; p->b = 5; return (sf_i64)p->b; }
So the failing case is exactly "address of a global symbol plus a non-zero compile-time constant" (symbol relocation with addend). At minimum this should produce a diagnostic instead of a silent -1; ideally the addend should be folded into the relocation or emitted as a separate add.
2. Global pointer initializers referencing another symbol are silently null
These compile, but the pointer holds 0 at run time (data relocation not emitted or not applied):
static const char *S = "hello";
SF_MAIN sf_i64 main(void) { return S == 0 ? 77 : 78; } /* returns 77 */
static const char *S = "hello";
SF_MAIN sf_i64 main(void) { return (sf_i64)sf_strlen(S); } /* memory fault at 0x0 */
static const char *T[2] = {"a", "bb"};
SF_MAIN sf_i64 main(void) { unsigned i = 1; return (sf_i64)sf_strlen(T[i]); } /* fault at 0x0 */
static char buf[8]; static char *P = buf;
SF_MAIN sf_i64 main(void) { return P == 0 ? 77 : 78; } /* returns 77 */
A local const char *s = "hello"; works, and string literals passed directly to functions work. If data relocations are out of scope for the BPF target, a compile-time error for a pointer initializer would be much better than a null pointer at run time.
3. A constant-false condition skips the rest of the function
Compiles without diagnostics; at run time everything after the statement is skipped and the function returns 0.
SF_MAIN sf_i64 main(void) { if (0 > 0) sf_sleep_ms(1); return 42; } /* returns 0 */
SF_MAIN sf_i64 main(void) { if (0) sf_sleep_ms(1); return 42; } /* returns 0 */
SF_MAIN sf_i64 main(void) { if (1 > 2) sf_sleep_ms(1); return 42; } /* returns 0 */
SF_MAIN sf_i64 main(void) { while (0) { sf_sleep_ms(1); } return 42; } /* returns 0 */
SF_MAIN sf_i64 main(void) { if (0 > 0) { sf_sleep_ms(1); } else { sf_yield(); } return 42; } /* returns 0 */
Works as expected:
SF_MAIN sf_i64 main(void) { volatile int x = 1; if (0) x = 2; return 40 + x + 1; } /* 42 */
SF_MAIN sf_i64 main(void) { if (1) sf_sleep_ms(1); return 42; } /* 42 */
SF_MAIN sf_i64 main(void) { const sf_u64 v = 0; if (v > 0) sf_sleep_ms(v); return 42; } /* 42 */
The dead branch containing a call seems to be what triggers it (a dead assignment is fine), which suggests the constant-condition fast path emits a jump past the wrong label when the skipped block contains a call.
Notes
- Also observed: a recursive function faults with
local call stack exhaustedat depth 50 (async-ebpf limit, mentioned only for completeness), and local arrays of 8000 and 20000 bytes ran despite the documented 4096-byte frame. - Reproduction harness (Python over spinfoam's stdio JSON-RPC) available on request.
- Lingua principale
- C
- Stelle
- 1
- Fork
- 1
- Merge medio
- 3m
- PR unite (30g)
- 1
Guida per i contributori
Nessuna guida per i contributori indicizzata per questo repository
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 90/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
NVIDIA/k8s-device-plugin#2061 · 1 commento ·
-
task
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
vsanthanam/JBird#429 ·