fix(v4): a manage request with too few values, or no room, is refused (#169)

v4_manage_serve took its arguments with v4_dstack_pop and never checked the
stack's depth: a request with too few values acted on stale ring values, and
one whose results did not fit dropped the oldest silently -- around the D-16
guards. Now each request's arity (manage.h) is checked first: fewer values
than it takes, or no room for what it leaves, is error 12 with the stack as it
was -- as a block request is refused (blocks.c).

test_manage.c, written first and seen to fail (12 of 13 requests at both cell
widths; NODE-BORN passed only because the stale value read was below 1): every
request with one value fewer than it takes, and NODE-ME and CAPSULE-CELL on a
stack with no room -- refused, the stack unchanged. After: 78 checks, 0
failures at 32 and 64 bits; all v4 tests at 64 bits, 40 programs, 1,871,313
checks, 0 failures (logs/20261112-152602/v4-test).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
This commit is contained in:
Claude
2026-11-12 15:26:02 +00:00
parent c28cc0191b
commit c642af541b
3 changed files with 49 additions and 0 deletions
+10
View File
@@ -87,15 +87,25 @@ int v4_manage_enter(const v4_manage *m, v4_cell number, unsigned place, v4_cell
return 0;
}
/* The values each request takes from the asker's stack and leaves there, from NODE-ME (-6) to
* NODE-PLACE (-18), as manage.h gives them: a request with fewer, or with no room for what it
* leaves, is refused before anything is taken (#169) -- as a block request is (blocks.c). */
static const unsigned char req_in[13] = { 0, 1, 4, 2, 1, 1, 1, 2, 2, 0, 1, 2, 1 };
static const unsigned char req_out[13] = { 1, 1, 1, 0, 0, 0, 0, 0, 1, 2, 1, 1, 1 };
int v4_manage_serve(const v4_manage *m, unsigned place, v4_cell request)
{
v4_fabric_node *at = v4_fabric_node_at(m->f, place);
v4_manage_entry *me, *e;
v4_node *n;
v4_cell a, b, c, d;
unsigned in, out;
if (!at || request > V4_REQ_NODE_ME || request < V4_REQ_NODE_PLACE) return 0;
n = &at->n;
in = req_in[V4_REQ_NODE_ME - request];
out = req_out[V4_REQ_NODE_ME - request];
if (n->ds.depth < in || n->ds.depth - in + out > V4_DATA_DEPTH) return refuse(n);
me = by_place(m, place);
switch (request) {