Proof of concept mechanical port of ircnet/ircd to Rust as part of a bit about C being insecure for network services
0

Configure Feed

Select the types of activity you want to include in your feed.

ircd.rs / docs / claude-memory / p0c-l1-harness-constraints.md
2.8 kB

name: p0c-l1-harness-constraints description: L1 differential harness (ircd-testkit) design + the cref_-oracle-vs-OBJS split phase 1 must wire metadata: node_type: memory type: project originSessionId: 705a4c1c-df44-45b8-b804-d362decb1bc5#

P0c stood up the L1 differential-unit harness (ircd-testkit crate; PLAN.md "L1"). Merged to master 2026-06-02.

How it works:

  • ircd-sys/build.rs exports cargo:cbuild= / cargo:objs= over its links = "ircd_c" channel → dependents read DEP_IRCD_C_CBUILD / DEP_IRCD_C_OBJS.
  • ircd-testkit/build.rs builds libcref.a: nm -g --defined-only over the OBJS objects → rename map <sym> cref_<sym> (sorted+deduped) → objcopy --redefine-syms on a copy of each .oar crDs (deterministic). Renames defs AND internal refs; libc/zlib/crypt untouched. ~450 symbols from 31 objects (an all-objects prototype incl. version/ctruth showed 509).
  • Tests link libcref.a (cref_ reference) beside ircd-sys's whole-archive libircd_c.a (originals) and diff cref_match vs original match over a corpus.

Two non-obvious gotchas that bit during implementation (both now documented in ircd-testkit/src/lib.rs):

  1. Integration tests need a link anchor. A tests/ file is a separate crate; a build script's cargo:rustc-link-lib (-l cref, and ircd-sys's -l ircd_c) reaches it only by replaying a linked dependency rlib's native libs. A test with only raw extern blocks references no Rust item → rustc drops both rlibs → all C symbols undefined at link. Fix: pub fn link_reference_archives() (references ircd_sys::c_ircd_main); every L1 #[test] must call it first.

  2. The cref_ oracle list must diverge from OBJS once porting starts. libcref.a is built from DEP_IRCD_C_OBJS == OBJS. If a ported module is just dropped from OBJS, its cref_<sym> vanishes too → nothing to diff the Rust against → tests fail to LINK (loud, never silently vacuous). Phase-1 wiring task: a module being ported must leave the to-be-Rust OBJS (so the Rust #[no_mangle] provides the original name) yet stay in a SEPARATE reference-object list that ircd-sys still compiles + exports for the cref_ oracle. Not done in P0c.

Harness is non-vacuous by construction: every project global is renamed, so match exists only in libircd_c.a and cref_match only in libcref.a (distinct addresses, verified). myncmp self-check uses explicit in-domain (a,b,n) triples because myncmp does its end-of-string check AFTER advancing pointers (common/match.c:316) → OOB read for the empty string with n≥2.

Still unbuilt from PLAN.md's P0: L2 golden (clock-pin + canonicalizer), L3 fuzz (ircd-fuzz), L4 conformance, iauth-rs. See [[rust-migration-plan]], [[p0b-bindgen-constraints]].