Proof of concept mechanical port of ircnet/ircd to Rust as part of a bit about C being insecure for network services
3.5 kB
Progress log — P4 (Parser & dispatch)#
See PLAN.md for the phase table and migration model.
- 2026‑06‑02 — P4 (Parser & dispatch) merged. All of
common/parse.cported intoircd-common/src/parse.rsandparse.odropped outright (added toPORTED, likelist.o/match.o) — noparse_link.o, because every symbol parse.c defined is portable now: themsgtab[]table, all 11find_*wrappers,parse,getfield, the four stub handlers (m_nop/m_nopriv/m_unreg/m_reg), and the three file‑statics (find_sender/cancel_clients/remove_unknown). Spec:docs/superpowers/specs/2026-06-02-p4-parse-dispatch-design.md; plan:docs/superpowers/plans/2026-06-02-p4-parse-dispatch.md.- Refines the hazard table (variadic dispatch): the ~14
sendto_*senders parse.c calls stay C, but Rust calls them through bindgen variadic declarations (sendto_one(to, c"…".as_ptr(), …)) — the exact s_numeric.rs pattern. Calling a C variadic is stable Rust; only defining one is not. So no trampoline is needed on the call side; the senders themselves still vanish in P8. msgtab[]as a Rust#[no_mangle] static mut [Message; 66]: built with arow!/m!macro; handler fn‑pointers reference the still‑Cm_*(and the four Rust stubs) and coerce in thestaticinitializer; the mutablecount/rcount/bytes/rbytescounters mutate in place exactly as C (read by STATS in still‑Cs_serv.o). Config‑resolved for this build:TKLINEon (TKLINE+UNTKLINE rows),USE_SERVICES/KLINE/ENABLE_SIDTRACEoff (no SERVSET/KLINE/SIDTRACE rows),MOTD_UNREGoff (MOTD unreg slot =m_unreg),IDLE_FROM_MSGon (idle guard =fhandler == m_private),DEBUGMODEoff (everyDebug(())omitted). The msgtab L1 test compares cmd/min/max/row‑count, not handler pointers (Rust rows point atm_join, the oracle atcref_m_join).- Bug caught by L1:
IRCDCONF_DELIMITERis'|'(config.h:500), not':'— the firstgetfielddraft used':'and the differential failed immediately. (find_mask/find_name L1 also surfaced that the hash tables are null untilinithashtables(); the test now inits both sets.) - L1 coverage / L2‑L3 deferrals: L1 zero‑diff vs
cref_on themsgtab[]structure,getfield(delimiter/escape/trailing/empty),find_mask/find_nameempty‑hash fallbacks, andparse()'s no‑me/no‑hash/no‑sender paths (IsDead early‑out, empty message, unknown‑command‑from‑non‑person, 3‑digit numeric, and anENCAP→m_nopdispatch — asserting return code +cptr.flags+ircstpcounter deltas). Deferred to L3 (parser fuzz) / L2: the fullparse()post‑state differential (dispatch into the still‑Cm_*, mutatedaClient+ handler counters) and hash‑populatedfind_*— both need the populated‑server fixture. - Deliverable: the per‑handler‑file static‑symbol cluster map for P5 (
docs/superpowers/specs/2026-06-02-p5-handler-cluster-map.md): clusters + entry points + suggested porting order (s_zip/s_debug → s_auth/s_service → s_user → s_misc → channel.c → s_serv.c). - Verification:
cargo buildwarning‑free; the Rust‑drivenircdbinary links withparse.odropped (parse/msgtab/find_*/getfield/m_nopresolve to Rust); fullcargo testgreen (all prior*_diff+parse_diff4/4 + layout); 0 warnings.
- Refines the hazard table (variadic dispatch): the ~14