getopt: free opts at size(option) (32B), not a stale 24B literal (F-E)
option = struct{flag:rune, value:str} is 32B now that str is 24B (Phase 3: cstage type.c:68, wwstage typ.ww:239 -- rune 4 + pad 4 + str 24). The three free sites (tryparse's two error paths + finish) freed (cap)*24u64 -- an 8-byte-per-element under-free of a buffer that append() grew at the real 32B stride, plus a rule-13 hardcoded-size-literal violation. Route all three through size(option).
Also corrects the stale 16B-era layout comments, including the error struct: error is 32B, so its (void|error) return rides sret/MEMORY (the 40B slot exceeds the 24B register cap), not the register ABI -- verified sound at runtime (ken; see #38).
Test (getopttest.ww, test 982_getopt_run): optionsizepin pins size(option)==32 as the regression guard; freeroundtrip is a table over {0,1,3} options exercising tryparse-then-finish. Full make test: 450 green incl. 990-997 byte-id.
This commit is contained in:
@@ -28,9 +28,10 @@
|
||||
// the same reason (task #5), and because task #6 (arr[i].field
|
||||
// = v) blocks the obvious `h[i].kind = ...` callsite spelling.
|
||||
// * [[option]] is a `struct { flag: rune, value: str }` rather
|
||||
// than Hare's `(rune, str)` 2-tuple: ww's cgen mis-sizes a
|
||||
// tuple of (i32, str) as 20B (no 4B pad before the str field).
|
||||
// The struct shape lays out as 24B as expected.
|
||||
// than Hare's `(rune, str)` 2-tuple: ww's cgen mis-pads a
|
||||
// tuple of (i32, str) (no 4B pad before the str field). The
|
||||
// struct shape lays out as rune (4) + pad (4) + str (24) = 32B
|
||||
// as expected.
|
||||
// * [[error]] is a flat 24B struct (kind + flag + name). Hare's
|
||||
// `!(str, []help, (requiresarg | unknownopt | unknownsubcmd))`
|
||||
// 3-tuple-with-nested-union doesn't map onto ww's single-payload
|
||||
@@ -161,8 +162,9 @@ export type errorkind = enum i32 {
|
||||
UNKNOWNOPT = 1, // -X isn't in the help list
|
||||
};
|
||||
|
||||
// error — parse failure. 24B layout (i32 kind + rune flag + str
|
||||
// name) so `(void | error)` rides the tagged-union return ABI.
|
||||
// error — parse failure. 32B (i32 kind + rune flag + str name);
|
||||
// the 40B `(void | error)` slot exceeds the 24B register cap, so
|
||||
// it returns via sret/MEMORY, not the register ABI (see #38).
|
||||
export type error = struct {
|
||||
kind: errorkind,
|
||||
flag: rune, // the offending letter
|
||||
@@ -170,9 +172,9 @@ export type error = struct {
|
||||
};
|
||||
|
||||
// option — one element of the parsed option list. Hare's getopts
|
||||
// uses a `(rune, str)` 2-tuple; ww's cgen mis-sizes that as 20B
|
||||
// (no 4B pad before the str field), so we use a named struct — the
|
||||
// struct layout pads correctly.
|
||||
// uses a `(rune, str)` 2-tuple; ww's cgen mis-pads that (no 4B pad
|
||||
// before the str field), so we use a named struct — the struct
|
||||
// layout pads correctly to rune (4) + pad (4) + str (24) = 32B.
|
||||
export type option = struct {
|
||||
flag: rune,
|
||||
value: str,
|
||||
@@ -283,7 +285,7 @@ export fn tryparse(out: *command, argv: []str, help: []help) (void | error) = {
|
||||
case void => {
|
||||
if (opts.cap > 0) {
|
||||
os.free(opts.ptr: *void,
|
||||
(opts.cap: u64) * 24u64);
|
||||
(opts.cap: u64) * size(option): u64);
|
||||
};
|
||||
let e: error;
|
||||
e.kind = errorkind.UNKNOWNOPT;
|
||||
@@ -317,7 +319,7 @@ export fn tryparse(out: *command, argv: []str, help: []help) (void | error) = {
|
||||
if (i + 1 >= argv.len) {
|
||||
if (opts.cap > 0) {
|
||||
os.free(opts.ptr: *void,
|
||||
(opts.cap: u64) * 24u64);
|
||||
(opts.cap: u64) * size(option): u64);
|
||||
};
|
||||
let e: error;
|
||||
e.kind = errorkind.REQUIRESARG;
|
||||
@@ -352,8 +354,8 @@ export fn tryparse(out: *command, argv: []str, help: []help) (void | error) = {
|
||||
// tryparse; args is a borrowed view into argv.
|
||||
export fn finish(cmd: *command) void = {
|
||||
if (cmd.optscap > 0) {
|
||||
// option layout: rune (4) + pad (4) + str (16) = 24B.
|
||||
os.free(cmd.optsptr: *void, (cmd.optscap: u64) * 24u64);
|
||||
// option layout: rune (4) + pad (4) + str (24) = 32B.
|
||||
os.free(cmd.optsptr: *void, (cmd.optscap: u64) * size(option): u64);
|
||||
};
|
||||
cmd.optsptr = nil: *option;
|
||||
cmd.optslen = 0;
|
||||
|
||||
Reference in New Issue
Block a user