kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit fbd324f8653a7f3a4ffb2e5fdaf4b0248e7d2e57
parent 894503f54469181fc620f67445d7fdec5e33a26e
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Mon, 25 May 2026 14:13:09 -0700

Fix parse harness public API boundaries

Diffstat:
Mtest/elf/cfree-roundtrip.c | 64+++++++++++++++++++++++++++++++---------------------------------
Mtest/link/harness/jit_runner.c | 22++++++++++++++++------
Mtest/parse/harness/parse_runner.c | 16++++++++++++++--
Mtest/parse/run.sh | 60+++++++++++++++++++++---------------------------------------
Mtest/test.mk | 3+--
5 files changed, 83 insertions(+), 82 deletions(-)

diff --git a/test/elf/cfree-roundtrip.c b/test/elf/cfree-roundtrip.c @@ -1,18 +1,14 @@ -/* cfree-roundtrip: read an ELF object via libcfree's read_elf, then re-emit - * via emit_elf. Used by test/elf/run.sh as the structural roundtrip oracle. +/* cfree-roundtrip: read an ELF object via libcfree's public object reader, + * then re-emit via the public object builder API. Used by test/elf/run.sh as + * the structural roundtrip oracle. * * Usage: cfree-roundtrip <in.o> <out.o> * - * Behavior: cfree_detect_target on the input bytes selects the Compiler - * target; read_elf parses into an ObjBuilder; emit_elf writes the - * canonical re-emit to out.o. Diagnostics go to stderr via the libc heap - * + stderr diag sink. compiler_panic exits the process with status 2 and - * the diagnostic text on stderr — this is the path the negative tests - * (test/elf/bad/) exercise. - * - * Mixes public (<cfree.h>) and internal (src/obj/obj.h, src/core/core.h) - * headers — this is a test binary, not a libcfree consumer, so seeing the - * internal surface is fine. */ + * Behavior: cfree_obj_open detects the input target and parses into a + * CfreeObjFile; cfree_obj_file_builder exposes the already-finalized builder; + * cfree_obj_builder_emit writes the canonical re-emit to out.o. Diagnostics go + * to stderr via the libc heap + stderr diag sink. Malformed recognized object + * files exit with status 2, matching the negative-test contract. */ #include <cfree/core.h> #include <cfree/object.h> @@ -24,9 +20,6 @@ #include <sys/stat.h> #include <unistd.h> -#include "core/core.h" -#include "obj/obj.h" - /* ---- env vtables (libc-backed) ---- */ static void* heap_alloc(CfreeHeap* h, size_t n, size_t a) { @@ -128,7 +121,8 @@ int main(int argc, char** argv) { } CfreeTarget target; - if (cfree_detect_target(in_data, in_len, &target) != CFREE_OK) { + if (cfree_detect_target(in_data, in_len, &target) != CFREE_OK || + target.obj != CFREE_OBJ_ELF) { fprintf(stderr, "error: %s: not a recognized object file\n", in_path); free(in_data); return 1; @@ -140,34 +134,39 @@ int main(int argc, char** argv) { ctx.diag = &g_diag; ctx.now = -1; - CfreeCompiler* c = NULL; - if (cfree_compiler_new(target, &ctx, &c) != CFREE_OK || !c) { - fprintf(stderr, "error: cfree_compiler_new failed\n"); + CfreeObjFile* obj = NULL; + CfreeSlice name = cfree_slice_cstr(in_path); + CfreeSlice input = {.data = in_data, .len = in_len}; + CfreeStatus st = cfree_obj_open(&ctx, name, &input, &obj); + if (st != CFREE_OK || !obj) { free(in_data); - return 1; + return 2; } - /* read_elf and emit_elf are called inside their own panic boundary. - * compiler_panic longjmps to c->panic, so we install setjmp here. */ - if (setjmp(((Compiler*)c)->panic)) { - compiler_run_cleanups((Compiler*)c); - cfree_compiler_free(c); + CfreeObjBuilder* ob = cfree_obj_file_builder(obj); + if (!ob) { + fprintf(stderr, "error: cfree_obj_file_builder failed\n"); + cfree_obj_free(obj); free(in_data); - return 2; + return 1; } - ObjBuilder* ob = read_elf((Compiler*)c, in_path, in_data, in_len); - CfreeWriter* w = NULL; if (cfree_writer_mem(&g_heap, &w) != CFREE_OK || !w) { fprintf(stderr, "error: cfree_writer_mem failed\n"); - obj_free(ob); - cfree_compiler_free(c); + cfree_obj_free(obj); free(in_data); return 1; } - emit_elf((Compiler*)c, ob, w); + st = cfree_obj_builder_emit(ob, w); + if (st != CFREE_OK) { + fprintf(stderr, "error: cfree_obj_builder_emit failed\n"); + cfree_writer_close(w); + cfree_obj_free(obj); + free(in_data); + return 1; + } size_t out_len = 0; const uint8_t* out_data = cfree_writer_mem_bytes(w, &out_len); @@ -176,8 +175,7 @@ int main(int argc, char** argv) { if (rc != 0) fprintf(stderr, "error: cannot write %s\n", out_path); cfree_writer_close(w); - obj_free(ob); - cfree_compiler_free(c); + cfree_obj_free(obj); free(in_data); return rc == 0 ? 0 : 1; } diff --git a/test/link/harness/jit_runner.c b/test/link/harness/jit_runner.c @@ -378,6 +378,19 @@ static void jit_tls_ctx_destroy(void* user, void* ctx_v) { } static CfreeJitTls g_jit_tls = {jit_tls_ctx_new, jit_tls_ctx_destroy, NULL}; +#if defined(__aarch64__) || defined(__arm64__) +__attribute__((noinline, no_sanitize("address", "undefined"))) +static int call_with_aarch64_tls(int (*fn)(void), void* tls_block) { + void* old_tp; + int result; + __asm__ volatile("mrs %0, tpidr_el0" : "=r"(old_tp) :: "memory"); + __asm__ volatile("msr tpidr_el0, %0" ::"r"(tls_block) : "memory"); + result = fn(); + __asm__ volatile("msr tpidr_el0, %0" ::"r"(old_tp) : "memory"); + return result; +} +#endif + #if defined(__x86_64__) && defined(__linux__) static long x64_arch_prctl_raw(long code, unsigned long addr) { register long rax __asm__("rax") = 158; /* SYS_arch_prctl */ @@ -641,13 +654,10 @@ int main(int argc, char** argv) { free(instance); } else if (fn) { #if defined(__aarch64__) || defined(__arm64__) - /* msr + blr in immediate succession; the compiler must not - * insert anything between. `volatile` and the "memory" - * clobber bracket the load of fn so the call uses the - * post-msr register state. */ - __asm__ volatile("msr tpidr_el0, %0" ::"r"(tls_block) : "memory"); -#endif + result = call_with_aarch64_tls(fn, tls_block); +#else result = fn(); +#endif #if defined(__x86_64__) && defined(__linux__) if (restore_fs) (void)x64_arch_prctl_raw(0x1002, old_fs); #endif diff --git a/test/parse/harness/parse_runner.c b/test/parse/harness/parse_runner.c @@ -464,6 +464,17 @@ static int mode_emit_impl(const char* src_path, const char* out_path, * lookups fail and the block stays zeroed — harmless. */ #if defined(__aarch64__) || defined(__arm64__) static char g_tls_block[8192] __attribute__((aligned(16))); + +__attribute__((noinline, no_sanitize("address", "undefined"))) +static int call_with_aarch64_tls(int (*fn)(void), void* tls_block) { + void* old_tp; + int result; + __asm__ volatile("mrs %0, tpidr_el0" : "=r"(old_tp) :: "memory"); + __asm__ volatile("msr tpidr_el0, %0" ::"r"(tls_block) : "memory"); + result = fn(); + __asm__ volatile("msr tpidr_el0, %0" ::"r"(old_tp) : "memory"); + return result; +} #endif static int mode_jit(const char* src_path) { @@ -552,9 +563,10 @@ static int mode_jit(const char* src_path) { if (fn) { #if defined(__aarch64__) || defined(__arm64__) - __asm__ volatile("msr tpidr_el0, %0" ::"r"(g_tls_block) : "memory"); -#endif + result = call_with_aarch64_tls(fn, g_tls_block); +#else result = fn(); +#endif } else { result = 1; } diff --git a/test/parse/run.sh b/test/parse/run.sh @@ -83,7 +83,6 @@ fi CLANG_TARGET="--target=$CLANG_TRIPLE" CC="${CC:-cc}" -HARNESS_CFLAGS="-std=c11 -Wall -Wextra -I$ROOT/include -I$ROOT/test" ALLOW_SKIP="${CFREE_TEST_ALLOW_SKIP:-0}" FILTER="${1:-${CFREE_TEST_FILTER:-}}" @@ -268,9 +267,9 @@ EXEC_TARGET_MOUNT_ROOT="$BUILD_DIR" # shellcheck source=../lib/exec_target.sh source "$ROOT/test/lib/exec_target.sh" -# ---- build harness binaries ------------------------------------------------ +# ---- harness binaries ------------------------------------------------------ -printf 'Building harness...\n' +printf 'Checking harness...\n' if [ ! -f "$LIB_AR" ]; then printf ' FATAL: %s not found — run "make lib" first\n' "$LIB_AR" >&2 @@ -278,57 +277,40 @@ if [ ! -f "$LIB_AR" ]; then fi # parse-runner -if $CC $HARNESS_CFLAGS \ - "$TEST_DIR/harness/parse_runner.c" \ - "$LIB_AR" -o "$PARSE_RUNNER" 2>"$BUILD_DIR/parse-runner.err"; then - printf ' %s parse-runner\n' "$(color_grn built)" +if [ -x "$PARSE_RUNNER" ]; then + printf ' %s parse-runner\n' "$(color_grn found)" else - printf ' %s parse-runner (see %s)\n' \ - "$(color_red FATAL)" "$BUILD_DIR/parse-runner.err" >&2 + printf ' %s parse-runner missing — run "make test-parse"\n' \ + "$(color_red FATAL)" >&2 exit 1 fi # cfree-roundtrip — for path R. -if [ ! -x "$ROUNDTRIP_BIN" ]; then - if $CC -I"$ROOT/include" -I"$ROOT/src" "$ROOT/test/elf/cfree-roundtrip.c" "$LIB_AR" \ - -o "$ROUNDTRIP_BIN" 2>"$BUILD_DIR/cfree-roundtrip.err"; then - have_roundtrip=1 - printf ' %s cfree-roundtrip\n' "$(color_grn built)" - else - printf ' %s cfree-roundtrip (see %s)\n' \ - "$(color_yel warn)" "$BUILD_DIR/cfree-roundtrip.err" >&2 - fi -else +if [ -x "$ROUNDTRIP_BIN" ]; then have_roundtrip=1 + printf ' %s cfree-roundtrip\n' "$(color_grn found)" +else + printf ' %s cfree-roundtrip missing — path R will skip\n' \ + "$(color_yel warn)" >&2 fi # link-exe-runner — for path E. -if [ ! -x "$LINK_EXE_RUNNER" ]; then - if $CC -I"$ROOT/include" -I"$ROOT/test" "$LINK_TEST_DIR/harness/link_exe_runner.c" \ - "$LIB_AR" -o "$LINK_EXE_RUNNER" 2>"$BUILD_DIR/link-exe-runner.err"; then - have_exe_runner=1 - printf ' %s link-exe-runner\n' "$(color_grn built)" - else - printf ' %s link-exe-runner (see %s)\n' \ - "$(color_yel warn)" "$BUILD_DIR/link-exe-runner.err" >&2 - fi -else +if [ -x "$LINK_EXE_RUNNER" ]; then have_exe_runner=1 + printf ' %s link-exe-runner\n' "$(color_grn found)" +else + printf ' %s link-exe-runner missing — path E will skip\n' \ + "$(color_yel warn)" >&2 fi # jit-runner — for path J. Only when host arch matches the cross-target. if [ $is_native_target -eq 1 ]; then - if [ ! -x "$JIT_RUNNER" ]; then - if $CC -I"$ROOT/include" -I"$ROOT/test" "$LINK_TEST_DIR/harness/jit_runner.c" \ - "$LIB_AR" -o "$JIT_RUNNER" 2>"$BUILD_DIR/jit-runner.err"; then - have_jit_runner=1 - printf ' %s jit-runner\n' "$(color_grn built)" - else - printf ' %s jit-runner (see %s)\n' \ - "$(color_yel warn)" "$BUILD_DIR/jit-runner.err" >&2 - fi - else + if [ -x "$JIT_RUNNER" ]; then have_jit_runner=1 + printf ' %s jit-runner\n' "$(color_grn found)" + else + printf ' %s jit-runner missing — path J will skip\n' \ + "$(color_yel warn)" >&2 fi fi diff --git a/test/test.mk b/test/test.mk @@ -269,10 +269,9 @@ JIT_RUNNER = build/test/jit-runner PARSE_RUNNER = build/test/parse-runner WASM_TOOL = build/test/wasm-tool -# cfree-roundtrip needs `-Isrc` for the internal obj.h surface it inspects. $(ROUNDTRIP_BIN): test/elf/cfree-roundtrip.c $(LIB_AR) @mkdir -p $(dir $@) - $(CC) $(HARNESS_CFLAGS) -Isrc test/elf/cfree-roundtrip.c $(LIB_AR) -o $@ + $(CC) $(HARNESS_CFLAGS) test/elf/cfree-roundtrip.c $(LIB_AR) -o $@ # Mach-O peer of cfree-roundtrip — read_macho + emit_macho. Used by # test-link's path R when CFREE_TEST_OBJ=macho.