ww: drop wwstage peekpackage 2048-byte cap, align to cstage line-scan (#16 PREP-peek)

Pre-existing rule-10 asymmetry: 4 lib files (decimal/ftos/stof/memio)
declare package past byte 2048, so the capped wwstage peek returned nil
where cstage's uncapped line-scan found the decl — corrupting the
strict-package check and any peek consumer. Mirrors cstage peek_package
semantics exactly; prerequisite for the upcoming package-less boundary
directive to inject identically in both twins.
This commit is contained in:
2026-06-10 13:27:12 +09:00
parent 12346c35f8
commit 2227d698c6
2 changed files with 48 additions and 36 deletions

View File

@@ -3323,32 +3323,38 @@ fn expand(c: *expctx, pathcs: *u8) void = {
// starts with `package <name>;` return the package name as a fresh
// heap-allocated NUL-terminated *u8, else nil. Same shape as cstage
// peek_package.
//
// Reads the WHOLE file (via slurp), not a fixed prefix: cstage's
// peek_package scans line-by-line with fgets and no total cap, stopping
// at the first non-comment-non-blank line. A prior 2048-byte read cap
// here diverged from cstage on files whose `package` decl sits behind a
// >2048-byte comment header (strconv decimal/ftos/stof, memio) —
// returning nil and making the #16 D-i injection asymmetric (rule-10
// break, byte-id divergence in the regenerated combined). The corpus has
// no line >2047 chars, so a whole-file line scan matches cstage's
// per-line fgets byte-for-byte on every real input.
fn peekpackage(pathcs: *u8) *u8 = {
let fd: i32 = os.open(pathstr(pathcs), os.flag.RDONLY, 0i32);
if (fd < 0) { return nil; };
let buf: []u8 = alloc([], 2048u64)!;
buf.len = 2048;
let n: i64 = os.read(fd, buf.ptr, 2048u64);
os.close(fd);
if (n <= 0i64) { return nil; };
let nu: u64 = n: u64;
let bufp: *u8;
let nu: u64;
bufp, nu = slurp(pathcs);
if (bufp == nil) { return nil; };
let p: u64 = 0u64;
for (p < nu) {
let q: u64 = p;
for (q < nu) {
if (buf[q] == 10u8) { break; }; // '\n'
if (bufp[q] == 10u8) { break; }; // '\n'
q += 1u64;
};
let s: u64 = p;
for (s < q) {
if (buf[s] != 32u8) {
if (buf[s] != 9u8) { break; };
if (bufp[s] != 32u8) {
if (bufp[s] != 9u8) { break; };
};
s += 1u64;
};
if (s < q) {
let line: str;
line.ptr = buf.ptr + s;
line.ptr = bufp + s;
line.len = (q - s): i32;
// hasprefix("//") subsumes the old s+1<q guard.
if (strings.hasprefix(line, "//")) {
@@ -3356,22 +3362,22 @@ fn peekpackage(pathcs: *u8) *u8 = {
continue;
};
// s+8<=q guard kept: hasprefix("package") needs only 7
// bytes, but the sep read at buf[s+7] needs s+7 < q.
// bytes, but the sep read at bufp[s+7] needs s+7 < q.
if (s + 8u64 <= q) {
if (strings.hasprefix(line, "package")) {
let sep: u8 = buf[s + 7u64];
let sep: u8 = bufp[s + 7u64];
if (sep == 32u8) { }
else { if (sep != 9u8) { return nil; }; };
let t: u64 = s + 8u64;
for (t < q) {
if (buf[t] != 32u8) {
if (buf[t] != 9u8) { break; };
if (bufp[t] != 32u8) {
if (bufp[t] != 9u8) { break; };
};
t += 1u64;
};
let start: u64 = t;
for (t < q) {
let ch: u8 = buf[t];
let ch: u8 = bufp[t];
let isalpha: bool = false;
if (ch >= 97u8) { if (ch <= 122u8) { isalpha = true; }; };
if (ch >= 65u8) { if (ch <= 90u8) { isalpha = true; }; };
@@ -3384,7 +3390,7 @@ fn peekpackage(pathcs: *u8) *u8 = {
if (plen == 0u64) { return nil; };
let r: []u8 = alloc([], plen + 1u64)!;
let k: u64 = 0u64;
for (k < plen) { r[k] = buf[start + k]; k += 1u64; };
for (k < plen) { r[k] = bufp[start + k]; k += 1u64; };
r[plen] = 0u8;
return r.ptr;
};

View File

@@ -537,32 +537,38 @@ fn expand(c: *expctx, pathcs: *u8) void = {
// starts with `package <name>;` return the package name as a fresh
// heap-allocated NUL-terminated *u8, else nil. Same shape as cstage
// peek_package.
//
// Reads the WHOLE file (via slurp), not a fixed prefix: cstage's
// peek_package scans line-by-line with fgets and no total cap, stopping
// at the first non-comment-non-blank line. A prior 2048-byte read cap
// here diverged from cstage on files whose `package` decl sits behind a
// >2048-byte comment header (strconv decimal/ftos/stof, memio) —
// returning nil and making the #16 D-i injection asymmetric (rule-10
// break, byte-id divergence in the regenerated combined). The corpus has
// no line >2047 chars, so a whole-file line scan matches cstage's
// per-line fgets byte-for-byte on every real input.
fn peekpackage(pathcs: *u8) *u8 = {
let fd: i32 = os.open(pathstr(pathcs), os.flag.RDONLY, 0i32);
if (fd < 0) { return nil; };
let buf: []u8 = alloc([], 2048u64)!;
buf.len = 2048;
let n: i64 = os.read(fd, buf.ptr, 2048u64);
os.close(fd);
if (n <= 0i64) { return nil; };
let nu: u64 = n: u64;
let bufp: *u8;
let nu: u64;
bufp, nu = slurp(pathcs);
if (bufp == nil) { return nil; };
let p: u64 = 0u64;
for (p < nu) {
let q: u64 = p;
for (q < nu) {
if (buf[q] == 10u8) { break; }; // '\n'
if (bufp[q] == 10u8) { break; }; // '\n'
q += 1u64;
};
let s: u64 = p;
for (s < q) {
if (buf[s] != 32u8) {
if (buf[s] != 9u8) { break; };
if (bufp[s] != 32u8) {
if (bufp[s] != 9u8) { break; };
};
s += 1u64;
};
if (s < q) {
let line: str;
line.ptr = buf.ptr + s;
line.ptr = bufp + s;
line.len = (q - s): i32;
// hasprefix("//") subsumes the old s+1<q guard.
if (strings.hasprefix(line, "//")) {
@@ -570,22 +576,22 @@ fn peekpackage(pathcs: *u8) *u8 = {
continue;
};
// s+8<=q guard kept: hasprefix("package") needs only 7
// bytes, but the sep read at buf[s+7] needs s+7 < q.
// bytes, but the sep read at bufp[s+7] needs s+7 < q.
if (s + 8u64 <= q) {
if (strings.hasprefix(line, "package")) {
let sep: u8 = buf[s + 7u64];
let sep: u8 = bufp[s + 7u64];
if (sep == 32u8) { }
else { if (sep != 9u8) { return nil; }; };
let t: u64 = s + 8u64;
for (t < q) {
if (buf[t] != 32u8) {
if (buf[t] != 9u8) { break; };
if (bufp[t] != 32u8) {
if (bufp[t] != 9u8) { break; };
};
t += 1u64;
};
let start: u64 = t;
for (t < q) {
let ch: u8 = buf[t];
let ch: u8 = bufp[t];
let isalpha: bool = false;
if (ch >= 97u8) { if (ch <= 122u8) { isalpha = true; }; };
if (ch >= 65u8) { if (ch <= 90u8) { isalpha = true; }; };
@@ -598,7 +604,7 @@ fn peekpackage(pathcs: *u8) *u8 = {
if (plen == 0u64) { return nil; };
let r: []u8 = alloc([], plen + 1u64)!;
let k: u64 = 0u64;
for (k < plen) { r[k] = buf[start + k]; k += 1u64; };
for (k < plen) { r[k] = bufp[start + k]; k += 1u64; };
r[plen] = 0u8;
return r.ptr;
};