D381 - The dispatch path runs on the guest's stack
decided - 2026-08-29
klogsrv opens a listening socket on port 3232 under
orbistoun, and something outside the process can connect to it. That is
the milestone this project set for itself - pros check does
exactly one thing per service, and it is that connect.
What stood between here and there was three lines of this project's own reporting code.
The backtrace that ended a long afternoon
A -1 read had survived eight eliminations. The fault
reported itself as being inside vsnprintf - which is an
attribution, the last import the guest called, not a location
(D380) - and every pointer into that path had been guarded without
moving it.
So the fault handler learned to capture the host stack when the fault is in orbistoun's own code. The first capture:
11: orbistoun_thunk::syscall::first_time_seen
12: orbistoun_thunk::syscall::orbistoun_syscall_dispatch
The guest was calling the syscall gadget. The crash
was in the reporting inside the dispatcher, and vsnprintf
was simply the last thing the guest had called before it.
Why the dispatcher must not allocate, print, or lock
A guest calls the gadget; the gadget calls the dispatcher; every frame from there down is on whatever stack the guest was using. That is a stack this emulator did not size and does not own.
The first version kept a BTreeSet behind a mutex -
exactly as the sysctl and dlsym reports do,
and those are fine, because they are reached from the ordinary import
path on a frame this project arranged. This one is not. It faulted
inside BTreeSet::insert on the first syscall a guest ever
made here.
Making it a bitmap of atomics removed the allocation and moved the
fault four lines down, into the eprintln! - which formats,
allocates and takes a lock, all on the same stack. So the rule is not
"avoid the container", it is:
The dispatch path records. The reporting layer prints.
Which is what call_counts and
recorded_calls have always done, and this had simply not
been built that way.
What was on the other side
With nothing printing from the dispatcher, klogsrv went
from 10 imports and 19 calls to 23 and 39, and stopped faulting entirely
- it ran to the time limit, which is what a server does.
socket -> setsockopt -> bind -> listen -> select
It binds 0.0.0.0:3232 - the address dumped as
00 02 0c a0, which is AF_INET, port 3232,
INADDR_ANY - prints its own interface address through
getifaddrs and __inet_ntop, asks for a
notification, and waits in select for a connection.
A TcpStream from outside the process connects to it.
What it is not
It is not a clean run of a payload. It is entered past its own runtime, with the globals that runtime would have filled written in by the loader (D376) and the handoff structure's unestablished fields still markers. That mode declares itself, and every fill is reported.
What is real is the socket: the guest asked for it, bound it,
listened on it, and something outside connected. No part of that was
faked, and orbistoun never implements FTP has its
counterpart here - orbistoun never opened this port,
klogsrv did.