diff --git a/logs/20261112-152602/v4-test/v4-test-64.log b/logs/20261112-152602/v4-test/v4-test-64.log new file mode 100644 index 00000000..60f0340f --- /dev/null +++ b/logs/20261112-152602/v4-test/v4-test-64.log @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:05e6eb4e0a3c624db84ca4648e4a3a8b7fb1b7c066c237d0672c7c157a300635 +size 66344 diff --git a/v4/src/manage.c b/v4/src/manage.c index 4b8a79a9..85c66d0e 100644 --- a/v4/src/manage.c +++ b/v4/src/manage.c @@ -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) { diff --git a/v4/tests/test_manage.c b/v4/tests/test_manage.c index bcbf2e9d..39da0b90 100644 --- a/v4/tests/test_manage.c +++ b/v4/tests/test_manage.c @@ -93,6 +93,42 @@ int main(void) CHECK(v4_manage_enter(&m, 10, h, 0) == 0 && v4_manage_enter(&m, 0, h, 0) == 0, "a number that is live, or 0, is not entered again"); CHECK(v4_manage_serve(&m, h, V4_REQ_NODE_ME) == 1 && pop(h) == (v4_cell)h, "NODE-ME is her place"); + /* #169: a request with fewer values than it takes, or with no room for what it leaves, is + * refused, error 12, the stack as it was -- as a block request is (v4/system/blocks.c). The + * values a request takes and leaves, from manage.h. */ + { + static const struct { v4_cell req; unsigned in, out; const char *name; } arity[] = { + { V4_REQ_NODE_ME, 0, 1, "NODE-ME" }, { V4_REQ_NODE_BORN, 1, 1, "NODE-BORN" }, + { V4_REQ_NODE_WIRE, 4, 1, "NODE-WIRE" }, { V4_REQ_NODE_UNWIRE, 2, 0, "NODE-UNWIRE" }, + { V4_REQ_NODE_SLEEP, 1, 0, "NODE-SLEEP" }, { V4_REQ_NODE_WAKE, 1, 0, "NODE-WAKE" }, + { V4_REQ_NODE_KILL, 1, 0, "NODE-KILL" }, { V4_REQ_NODE_PARITY, 2, 0, "NODE-PARITY" }, + { V4_REQ_CAPSULE_OPEN, 2, 1, "CAPSULE-OPEN" }, { V4_REQ_CAPSULE_CELL, 0, 2, "CAPSULE-CELL" }, + { V4_REQ_CAPSULE_LINE, 1, 1, "CAPSULE-LINE" }, { V4_REQ_NODE_CHILD, 2, 1, "NODE-CHILD" }, + { V4_REQ_NODE_PLACE, 1, 1, "NODE-PLACE" }, + }; + unsigned k, j; + for (k = 0; k < sizeof arity / sizeof arity[0]; k++) { + unsigned have; + if (arity[k].in > 0) { /* one value fewer than it takes */ + v4_dstack_reset(&N(h)->ds); + for (j = 0; j + 1 < arity[k].in; j++) push(h, 1); + have = depth(h); + CHECK(refused(h, arity[k].req) && depth(h) == have, + "%s with %u value(s), not %u: refused, the stack as it was (depth %u)", + arity[k].name, have, arity[k].in, depth(h)); + } + if (arity[k].out > arity[k].in) { /* no room for what it leaves */ + v4_dstack_reset(&N(h)->ds); + while (depth(h) + (arity[k].out - arity[k].in) <= V4_DATA_DEPTH) push(h, 1); + have = depth(h); + CHECK(refused(h, arity[k].req) && depth(h) == have, + "%s on a stack with no room for its %u: refused, the stack as it was (depth %u of %u)", + arity[k].name, arity[k].out - arity[k].in, depth(h), have); + } + } + v4_dstack_reset(&N(h)->ds); + } + /* births */ r = birth(h, 11); CHECK(r >= 0 && place_of(h, 11) == r && child(h, 10, 0) == 11 && child(h, 10, 1) == 0, "Hera births 11: the registry has it, with her as its parent");