From 4db992b5e4eb81afce6c5b94d64b8fe8d74475b5 Mon Sep 17 00:00:00 2001 From: Rongsong Shen Date: Sat, 19 Sep 2026 14:45:20 +0000 Subject: [PATCH] fix(scheduler): close core_clock.c isolation-test coverage gap (bug-1827) core_clock.c joined the mechanically-enforced isolation archive (sched_core_isolation_lib) and its own doc comment claimed coverage by the forbidden-headers/forbidden-symbols text scans, but was actually absent from both -- only the nm(1) undefined-symbol layer covered it, which cannot catch a forbidden #include resolving to no undefined symbol (a macro-only header). Added XCE_CORE_CLOCK_C_PATH (meson.build, mirroring the existing per-file path macros) and extended both test_core_never_includes_forbidden_headers() and test_core_never_calls_forbidden_symbols() to scan core_clock.c. It remains excluded only from the wall-clock scan, for its one sanctioned clock_gettime() call. TDD: confirmed RED by temporarily inserting a forbidden #include into core_clock.c (84/85, correctly attributed failure), reverted (byte-identical to HEAD), reconfirmed GREEN (85/85). No live violation existed -- this closes a coverage gap in the mechanism itself. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01RLSNJhNoULvVcUhXEFafQC --- .wolf/buglog.json | 7 ++- src/scheduler/testsuite/meson.build | 3 ++ src/scheduler/testsuite/test_core_isolation.c | 45 +++++++++++++++---- 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/.wolf/buglog.json b/.wolf/buglog.json index 2006bbf0..6df42f58 100644 --- a/.wolf/buglog.json +++ b/.wolf/buglog.json @@ -24528,7 +24528,7 @@ "error_message": "NOT A CRASH -- coverage gap found during an /xce-audit-invariants scheduler run (dimension 2: core module I/O isolation), while investigating driver state-equivalence for bug-1826. test_core_isolation.c's own header comment claims core_clock.c joins ONLY the nm(1) undefined-symbol enforcement layer, not the wall-clock text-scan check -- implying it is still covered by the OTHER two text-scan checks (forbidden #include list, forbidden symbol substrings). In reality, core_clock.c is absent from all three text-scan functions (test_core_never_includes_forbidden_headers(), test_core_never_calls_forbidden_symbols(), and the wall-clock scan), not just the wall-clock one -- no XCE_CORE_CLOCK_C_PATH macro is defined anywhere in test_core_isolation.c or testsuite/meson.build's c_args for that test.", "file": "src/scheduler/testsuite/test_core_isolation.c", "root_cause": "core_clock.c was added to the mechanically-enforced sched_core_isolation_lib archive (meson.build) and given a documented single exception (the wall-clock text scan, for its one sanctioned clock_gettime() call), but the two OTHER text-scan functions (forbidden-headers, forbidden-symbols) were never extended to also read core_clock.c's source text -- only core.h/core.c/core_events.c/core_session.c are read by those two checks (via XCE_CORE_H_PATH/_C_PATH/_EVENTS_C_PATH/_SESSION_C_PATH macros; no clock-file variant exists). The nm(1) undefined-symbol layer (which DOES include core_clock.c in the archive) only catches an actual undefined-symbol reference at link time -- it cannot catch a bare forbidden #include (e.g. client.h/netio.h/xceapi.h/delay.h/idgen.h/xce/cluster.h) that resolves to no undefined symbol (a macro-only or inline-only header), so the doc comment's implied coverage is narrower in practice than stated. No evidence found that core_clock.c's actual current content violates isolation today -- this is a gap in what the mechanism would CATCH if it did, not a confirmed live violation.", - "fix": "NOT FIXED -- audit-only finding, reported to the user for triage, not bundled into the concurrent scheduler-sim-limit-matching spec work. Straightforward fix when picked up: add a XCE_CORE_CLOCK_C_PATH macro (testsuite/meson.build's c_args for test_core_isolation) and extend test_core_never_includes_forbidden_headers()/test_core_never_calls_forbidden_symbols() to also scan core_clock.c's source text, matching the coverage the file's own doc comment already claims it has.", + "fix": "FIXED (2026-09-19). Added XCE_CORE_CLOCK_C_PATH (testsuite/meson.build c_args for sched_core_isolation_test, mirroring the existing XCE_CORE_H_PATH/_C_PATH/_EVENTS_C_PATH/_SESSION_C_PATH pattern) and extended both test_core_never_includes_forbidden_headers() and test_core_never_calls_forbidden_symbols() (test_core_isolation.c) to also scan core_clock.c -- it remains excluded ONLY from the wall-clock scan (test_core_never_calls_wallclock_functions), for the same sanctioned-single-clock_gettime()-call reason as before. TDD: confirmed RED by temporarily inserting #include \"netio.h\" into core_clock.c and rebuilding -- the extended test correctly failed with the message \"core_clock.c directly includes forbidden header '#include \"netio.h\"'\" (test_core_isolation.c:226) while every other test stayed green (84/85); reverted (git diff confirms core_clock.c byte-identical to HEAD) and reconfirmed GREEN (85/85). No live violation existed in core_clock.c -- this closes the coverage gap the mechanism itself had, matching what its own header/doc comments already claimed.", "tags": [ "scheduler", "core-isolation", @@ -24536,12 +24536,11 @@ "test_core_isolation", "core_clock", "audit-finding", - "unfixed", "discovered-during-xce-audit-invariants", - "not-fixed" + "fixed" ], "occurrences": 1, - "last_seen": "2026-09-19T09:00:00Z" + "last_seen": "2026-09-19T14:30:00Z" }, { "id": "bug-1828", diff --git a/src/scheduler/testsuite/meson.build b/src/scheduler/testsuite/meson.build index b7072c7f..c383db64 100644 --- a/src/scheduler/testsuite/meson.build +++ b/src/scheduler/testsuite/meson.build @@ -231,6 +231,9 @@ sched_core_isolation_test = executable( '-DXCE_CORE_SESSION_C_PATH="' + (meson.current_source_dir() / '..' / 'src' / 'core_session.c') + '"', + '-DXCE_CORE_CLOCK_C_PATH="' + + (meson.current_source_dir() / '..' / 'src' / 'core_clock.c') + + '"', '-DXCE_CORE_LIB_PATH="' + sched_core_isolation_lib.full_path() + '"'], diff --git a/src/scheduler/testsuite/test_core_isolation.c b/src/scheduler/testsuite/test_core_isolation.c index 31cf0a09..d01ca4f3 100644 --- a/src/scheduler/testsuite/test_core_isolation.c +++ b/src/scheduler/testsuite/test_core_isolation.c @@ -22,18 +22,32 @@ * incorrectly fail. It has no legitimate reason to reference any * networking/API symbol, so it fully participates in layer 2. * + * CORRECTED 2026-09-19 (bug-1827, /xce-audit-invariants scheduler): the + * paragraph above was accurate about layer 2 but the claim was narrower + * than what layer 1 actually enforced -- core_clock.c was excluded from + * ALL of layer 1's text scans (forbidden-headers, forbidden-symbols, AND + * wall-clock), not only the wall-clock one. The forbidden-headers/ + * forbidden-symbols scans have no legitimate reason to exempt + * core_clock.c (it has no legitimate reason to include a networking/API + * header or reference a networking/API symbol, same as its siblings), and + * the nm(1) layer alone cannot catch a forbidden #include that resolves to + * no undefined symbol (a macro-only or inline-only header). core_clock.c + * now fully participates in the forbidden-headers and forbidden-symbols + * scans too -- it remains excluded ONLY from the wall-clock scan, for the + * reason stated above. + * * Two layers, same genre as test_picker_core_loop_boundary.c / * test_picker_pendreason_factory_audit.c (source-text scans of the real, * current on-disk files, not a frozen snapshot): * - * 1. Source-text scan of core.h/core.c/core_events.c/core_session.c: no - * #include of client.h, netio.h, xceapi.h, delay.h, idgen.h, or - * xce/cluster.h (the "Allowed Dependencies" list in design.md names - * exactly these as forbidden); no call-site substring matching a - * symbol exported only by those libraries; no wall-clock call - * (time()/clock_gettime()/gettimeofday()) anywhere in core.c, - * core_events.c, or core_session.c (core_clock.c excepted -- see - * above). + * 1. Source-text scan of core.h/core.c/core_events.c/core_session.c/ + * core_clock.c: no #include of client.h, netio.h, xceapi.h, delay.h, + * idgen.h, or xce/cluster.h (the "Allowed Dependencies" list in + * design.md names exactly these as forbidden); no call-site substring + * matching a symbol exported only by those libraries; no wall-clock + * call (time()/clock_gettime()/gettimeofday()) anywhere in core.c, + * core_events.c, or core_session.c (core_clock.c excepted from this + * one sub-check only -- see above). * * 2. The literal build-time/link-time proof the Observable asks for, * not achievable by a text scan alone: core.c/core_events.c/ @@ -80,6 +94,10 @@ #error \ "XCE_CORE_SESSION_C_PATH must be defined by meson.build to core_session.c's absolute path" #endif +#ifndef XCE_CORE_CLOCK_C_PATH +#error \ + "XCE_CORE_CLOCK_C_PATH must be defined by meson.build to core_clock.c's absolute path" +#endif #ifndef XCE_CORE_LIB_PATH #error \ "XCE_CORE_LIB_PATH must be defined by meson.build to the absolute path of core.c's isolated static_library() archive" @@ -177,16 +195,19 @@ static void test_core_source_paths_are_readable(void) char* c = read_whole_file(XCE_CORE_C_PATH); char* ce = read_whole_file(XCE_CORE_EVENTS_C_PATH); char* cs = read_whole_file(XCE_CORE_SESSION_C_PATH); + char* cc = read_whole_file(XCE_CORE_CLOCK_C_PATH); TEST_ASSERT_NOT_NULL_MESSAGE(h, XCE_CORE_H_PATH); TEST_ASSERT_NOT_NULL_MESSAGE(c, XCE_CORE_C_PATH); TEST_ASSERT_NOT_NULL_MESSAGE(ce, XCE_CORE_EVENTS_C_PATH); TEST_ASSERT_NOT_NULL_MESSAGE(cs, XCE_CORE_SESSION_C_PATH); + TEST_ASSERT_NOT_NULL_MESSAGE(cc, XCE_CORE_CLOCK_C_PATH); free(h); free(c); free(ce); free(cs); + free(cc); } /* Scans one file's text for every FORBIDDEN_INCLUDES entry, tagging each @@ -212,21 +233,25 @@ static void test_core_never_includes_forbidden_headers(void) char* c = read_whole_file(XCE_CORE_C_PATH); char* ce = read_whole_file(XCE_CORE_EVENTS_C_PATH); char* cs = read_whole_file(XCE_CORE_SESSION_C_PATH); + char* cc = read_whole_file(XCE_CORE_CLOCK_C_PATH); TEST_ASSERT_NOT_NULL(h); TEST_ASSERT_NOT_NULL(c); TEST_ASSERT_NOT_NULL(ce); TEST_ASSERT_NOT_NULL(cs); + TEST_ASSERT_NOT_NULL(cc); assert_no_forbidden_includes(h, "core.h"); assert_no_forbidden_includes(c, "core.c"); assert_no_forbidden_includes(ce, "core_events.c"); assert_no_forbidden_includes(cs, "core_session.c"); + assert_no_forbidden_includes(cc, "core_clock.c"); free(h); free(c); free(ce); free(cs); + free(cc); } /* Shared by test_core_never_calls_forbidden_symbols() -- see @@ -252,21 +277,25 @@ static void test_core_never_calls_forbidden_symbols(void) char* c = read_whole_file(XCE_CORE_C_PATH); char* ce = read_whole_file(XCE_CORE_EVENTS_C_PATH); char* cs = read_whole_file(XCE_CORE_SESSION_C_PATH); + char* cc = read_whole_file(XCE_CORE_CLOCK_C_PATH); TEST_ASSERT_NOT_NULL(h); TEST_ASSERT_NOT_NULL(c); TEST_ASSERT_NOT_NULL(ce); TEST_ASSERT_NOT_NULL(cs); + TEST_ASSERT_NOT_NULL(cc); assert_no_forbidden_symbols(h, "core.h"); assert_no_forbidden_symbols(c, "core.c"); assert_no_forbidden_symbols(ce, "core_events.c"); assert_no_forbidden_symbols(cs, "core_session.c"); + assert_no_forbidden_symbols(cc, "core_clock.c"); free(h); free(c); free(ce); free(cs); + free(cc); } /* core_clock.c is deliberately NOT scanned here -- it is the one