Diluvium 5.5.1_build5
[5.5.1_build5] - 2026-08-12
v5.5.1_build5 · Lua 5.5.1 · bytecode format 0x46
Hibernation is on, and stable is true again.
5.5.1_build4 shipped stable: false for exactly one reason: an
ungated dv_restore with a known corruption path. That block --
profile C of the M0-M7 audit, hibernation at scale -- is closed.
Every confirmed finding from the audit is now fixed, each with a
named test that fails when its fix is removed, and hibernation is
on by default: park an instance, snapshot it, free it, restore the
bytes into a fresh instance and resume, with the failure paths as
tested as the happy one. A restored program that raises gets the
right error with a traceback; a restored pcall still catches and
re-arms the handler it displaced; a woken runaway is stopped with
both residencies charged against the one instruction budget; an
endpoint reference held across the gap still binds; and a
malformed snapshot is refused, never a crash -- the fuzzer's
known-failure set is empty and stays that way.
dvs_allow_hibernation survives as a host's opt-out. The comment
that made it off by default is struck rather than edited, which is
what its own text asked for.
The release also builds out the host story. doc/Hostcall.md
reserves the hostcall encoding -- correlation token required from
the first prototype -- and doc/Host.md states the protocol both
planned hosts implement, the lab JavaScript host and the generic C
one, with the acceptance test that a guest cannot tell them apart.
The swarm layer reaches WebAssembly: a new
diluvium_swarm_wasi.wasm carries it with the host vtable crossing
the boundary as "env" imports, so a swarm can be driven by a
JavaScript host -- which is what lab picks up. And the generic host
itself now exists (host/, make build_host): a deployment is a
supervisor program plus a typed *.host.lua configuration, not C,
with connectors for the wall clock, SQLite and an HTTP listener,
each off until wired and gated by the capability grammar.
Added
- The generic host (
host/,make build_host): the host
protocol as one configurable binary, so a deployment is a
supervisor program plus a*.host.luaconfiguration rather than
bespoke C. The config is Lua's syntax without its power --
evaluated in an empty environment, every unknown key refused by
name -- and typed by a LuaCATS schema (host/types/host.lua).
Three connectors, all off until wired and each gated by a
host:capability the same way queues are gated: the wall clock,
SQLite (sql/queryreads,sql/execwrites, confined to one
file by an authorizer), and an HTTP listener behind a
TLS-terminating load balancer (a request is a message, a message
is a response,connechoed like a hostcall token).
examples/discofetch/swarmd.cis the bespoke ancestor this
retires. - The swarm layer reaches WebAssembly.
dvs.cjoins both wasm
archives, anddiluvium_swarm_wasi.wasmis a new artifact
carrying it plusdvs_shim.c: a JavaScript host cannot make the
C function pointersdvs_newwants, so the trampolines live on
the C side as mandatory "env" imports anddvsjs_newstands in
as the constructor. A separate module on purpose -- mandatory
imports linked intodiluvium_wasi.wasmwould have broken
wasmtime diluvium_wasi.wasmand every other pure-WASI
consumer, which keep the module they had. The JS binding always
supplies the trampolines,setSwarmHostinstalls the real host,
andinstantiateis exported as the layer a host builds on. dvs_set_host_identity: a swarm can hold an identity, and every
snapshot it takes carries it. A foreign stamp is refused at
wake, and so is a missing one on a stamped host -- 10.10's
asymmetry, now true of the swarm layer and not only the ABI
under it. Not authentication; a label that fails loudly.diluvium_snap_headerusage: read a snapshot's instruction count
from its header without restoring it. In the header rather than
the payload so a host deciding whether it can afford to wake a
cached instance can ask the bytes -- the same reasoning that
made the budget a query at the swarm layer.doc/Hostcall.mdanddoc/Host.md: the hostcall request/reply
encoding with the correlation token reserved before any host
ships a handler, and the host protocol -- construction, drive
loop, roster, queue pump, hostcalls, hibernation policy,
shutdown -- written so the lab JavaScript host and the generic C
host are two implementations of one contract.- Tests for every path the audit found untested, each verified to
fail with its fix removed: a woken instance still budgeted (the
test that never existed), a restored program's traceback, a
restoredpcall's handler chain, all four host-identity stamp
quadrants, a nested coroutine refused by name and capturable
once dropped, an endpoint reference surviving hibernation, and a
woken program re-binding its own endpoint with ordering held
across the gap.
Changed
- Hibernation is on by default;
dvs_allow_hibernationis a
host's opt-out. The swarm's budget test the audit caught
certifying only readback now wakes what it caches and asserts
the counter came through. - The snapshot fuzzer labels mutants with the format-2 record
layout and its known-failure set is empty -- audit S2's two
crashers are refusals now, and adding an entry to that set needs
a better reason than a red run. - Refusal sentences widened where the checks did: a to-be-closed
slot can be refused for holding nothing closable, a permanents
mismatch speaks of named values rather than only C functions,
and restore refusals gained their own distinctness test.
Fixed
- Any error raised in any restored program corrupted memory
(audit finding 0, the reason hibernation shipped off). The
thread record now round-trips what it dropped, and
a_restored_program_can_raise-- the first test in the tree to
ever resume a restored thread into an error -- holds it. - A woken instance's instruction budget was never re-armed, and
the counter did not travel, so a budget quietly became
per-residency (finding 1).dv_restorearms the count hook and
the header carriesinsn_used; both residencies charge one
limit. - A restored program's error was correct but bare (old_errfunc).
The record carries the thread's error-handler slot and each
pcall frame's saved one, in slot units so the stream does not
depend on a build'ssizeof; validation refuses rather than
asserts, which is S2's lesson applied ahead of time. - Two malformed snapshots reached an abort instead of a refusal
(audit S2). A crafted to-be-closed list naming a non-closable
slot reached the raise insideluaF_newtbcupval, which escapes
the lock convention -- one extra unlock, the counter at -1, the
opposite of the leaked lock the audit predicted at the same
site.diluvium_shim_settbcrefuses it first now; the full
corpus runs 0 crashed. - Nested coroutines were captured rather than refused (finding
14). A program parked holding a suspended coroutine is refused
by name and told what to do -- let it finish or drop it -- and
the same program snapshots once it has. - An endpoint reference did not survive a snapshot, and
bind
refused it with a false statement (finding 12). The reference
metatable is the permanentdendpoint.refmt;bindadopts an
endpoint queue no token claims, which is how a woken program
re-binds its own endpoint and the only route by which the
host's drain path returns after a wake; and messages buffered
before a hibernate drain out in order after it. - A crafted to-be-closed count could send record reads four
gigabytes out of bounds on platforms with a 32-bitunsigned long(pre-existing; LP64 was never affected). Every marked
slot is a distinct stack slot, so a count above the slot count
is refused as not credible.
Known issues
-
A sealed program still has no way to ask for the time -- but
the encoding it will use is now fixed.The hostcall needs no ABI: it is a message on a queue the host
drains and an answer on a queue it pushes to, and
doc/Hostcall.mdnow reserves the request and reply shapes with
the correlation token required from the first prototype. What
does not exist yet is any host that connects a call: until one
ships, a program that genuinely needs a clock or a file has
DV_FLAG_UNSAFE_STDLIBand nothing better, which is exactly why
that flag is scaffolding rather than a configuration. -
DV_FLAG_UNSAFE_DEBUGis a real hole, deliberately.Unchanged from 5.5.1_build4: a host that sets it gets the whole
debuglibrary back and, with it, the endpoint forgery route
and the budget escape. Supported for trusted code; recorded in a
test rather than only here. -
The swarm's snapshot cache is in-memory only, and the swarm's
own topology has no serializer. A host may persist any
instance's snapshot bytes and restore them after a process
restart -- the header checks make stale or foreign bytes a
refusal, never a corruption -- but recording which bytes
belonged to what, and every parent, capability and budget
relationship around them, is the host's own bookkeeping.
Instance ids restart with a new swarm, so ids a program
remembers from a previous life are volatile and must not be
trusted across generations. -
The rebuilt
u2.funcidxof a restored vararg pcall frame
differs from the organic value by the argument count -- the
"agree by construction" claim at the reconstruction site is
measurably false for vararg callees. Benign on every tested
path, recorded indoc/Hibernate.mdso nobody extending the
frame rebuild trusts the comment.
Upgrading
Snapshots taken by 5.5.1_build3 or 5.5.1_build4 are refused by
this release. Three stream changes land together so the cost is
paid once: the snapshot header carries the instruction count
(DILUVIUM_SNAP_FORMAT 2), the thread record carries the error
handler slots (DS_THREAD_VERSION 2), and the endpoint reference
metatable joins the permanents set, which moves the permanents
fingerprint. A restore of older bytes fails cleanly with the
format-mismatch sentence; nothing half-loads. There is no
converter, deliberately: those releases said to treat
dv_snapshot/dv_restore as unsupported, so bytes from them are
exactly the thing a refusal is for.
Bytecode is unaffected. LUAC_FORMAT is unchanged at 0x46;
chunks compiled by build3 or build4 load without recompiling.
Hibernation is on by default. A swarm that relied on the old
refusal as policy should call dvs_allow_hibernation(sw, 0); a
host that called it with 1 keeps working unchanged. The opt-out's
refusal names the call that switched it off rather than pointing
at a defect that no longer exists.
endpoint.bind's failure message changed. It now says the
value "does not carry this runtime's reference identity" instead
of asserting the program built the value itself -- the old text
was false in exactly the case this release fixes. A program
matching on the old wording needs updating; matching on error
prose was never promised to survive.
Built from commit 4ddd65f65d15.
Download guide
| Platform | File | Notes |
|---|---|---|
| Linux (standard) | diluvium_linux_static_x86_64 |
Static; works on Ubuntu, Fedora, CentOS, Arch |
| Raspberry Pi 3/4/5 | diluvium_linux_static_aarch64 |
64-bit OS only |
| Raspberry Pi Zero | diluvium_linux_static_armv7l |
32-bit ARM |
| macOS (Apple silicon) | diluvium_darwin_arm64 |
M1/M2/M3/M4 |
| macOS (Intel) | diluvium_darwin_x86_64 |
|
| Windows | diluvium_windows_x86_64.exe |
64-bit |
| WASI | diluvium_wasi.wasm |
Needs a runtime with wasm exception-handling (wasmtime 28+ with -W exceptions=y) |
| Browser | libdiluvium_wasm_unknown.a |
wasm32-unknown-unknown static library |
Each platform also ships a diluvium_compiler_* binary (luac
with the -r analysis report flag) and a libdiluvium_*.a static
library for embedding.
Verifying a download
sha256sum -c SHA256SUMS.txt --ignore-missing
BUILDINFO.txt records the exact commit, build time and workflow run.