fix(#716): item 3 — document headless getenv path; refactor legacy guard#719
Conversation
…uard #716 item 3 audit pointed at Common/source/shellsysverbs.c:594 as a potential truncation surface for >255-byte env vars piped through copyctopstring. Investigation showed that file is the legacy (full Mac app) impl, NOT linked into the headless frontier-cli build. The real headless path is tests/headless_sys_verbs.c::sysv_getenvironmentvariable, which uses newfilledhandle + setheapvalue to return a heap-allocated string handle -- no bigstring, no 255-byte limit, no truncation surface by construction. Changes: - tests/headless_sys_verbs.c: expand the @implemented comment to document the heap-handle design intent and explicitly call out that this path has NO bigstring truncation surface, with a back-reference to #716 item 3 so a future audit doesn't waste cycles re-flagging it. Marks the path as "do not add a bigstring length guard". - Common/source/shellsysverbs.c (legacy/full-app path): collapse the pre-#707 pattern (strlen + manual >255 check + unguarded copyctopstring) into the canonical post-#707 pattern (copyctopstring's boolean return with langerrormessage on truncation). Functionally equivalent -- same user-visible "exceeds 255 characters" error message, same return contract. Matches frontier-cli/window_registry.c:116 and PR #718's langerror.c:163 fix. Reduces the code from 12 to 8 lines and removes the redundant strlen. - tests/integration/sys_getenv_long_value_test.sh + tests/Makefile: new shell integration test that locks in the headless behavior -- 200-byte env var reads back at length 200 (control), 300-byte env var reads back at length 300 with content preserved verbatim (regression guard against someone mistakenly applying a bigstring guard to the heap-handle path). 3/3 GREEN. This PR addresses ONLY #716 item 3. Items 2, 4, 5 remain open and will be addressed in separate PRs. Verified: - make build: clean - ./tools/run_headless_tests.sh: 589/589 pass - tests/integration/sys_getenv_long_value_test.sh: 3/3 pass - cd tests && make test-integration: TBD (in progress as of commit) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…rkers Security reviewer P2: original doc said "Do not add a bigstring length guard to this path" which could be misread as forbidding any future overflow-safety check. Tighten to "Do not add a 255-byte bigstring length guard" and explicitly note that an overflow-safe larger-limit check remains future-compatible. Security reviewer P2: shell test used a uniform 'y' payload; a length-preserving mid-buffer corruption would have passed the length-only + final-byte assertions. Upgrade payload to 150 'A's + 150 'B's and probe at byte 150 (A), 151 (B), and 300 (B). Catches truncation, mid-buffer corruption, and tail corruption in a single CLI invocation (the three probes are concatenated in one --batch -e script). Bar-raiser P2 items (3 invocation count, strip_warnings regex robustness, pre-existing 108-col line) declined: current diagnosability and behavior are correct; not blocking. Test still 3/3 GREEN. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
/auto SummaryWhat went well: The TDD-first habit caught the audit misdirection — writing the test first surfaced that the original target (Common/source/shellsysverbs.c) wasn't on the live verb-dispatch path, and led to discovering that the real headless verb (tests/headless_sys_verbs.c) uses heap handles by design. Rescoping the PR from "fix a bug" to "document the design + small legacy cleanup + lock-in regression test" was straightforward once the layout was understood. What could improve: The original #716 audit greps for Recommendations: For items 4 (langsqlite errmsg) and 5 (tcpverbs INDIRECT), verify live reachability through 🤖 Generated with Claude Code /auto |
Summary
Closes item 3 of #716 with two findings and a small refactor:
The audit pointed at the wrong file.
Common/source/shellsysverbs.c::getenvironmentvariablefuncis the legacy (full Mac app) impl; it is not linked into the headlessfrontier-clibuild. The actual headless verb dispatch goes totests/headless_sys_verbs.c::sysv_getenvironmentvariable.The headless path has no truncation surface by construction. It uses
newfilledhandle+setheapvalueto return a heap-allocated string handle. There is no bigstring on this path, so the >255-byte concern raised in the issue does not apply. A regression test now locks this in.Legacy file got a small post-copyctopstring: silent truncation + buffer overflow risk on >255-byte input #707 refactor. The legacy guard worked, but it predated the post-copyctopstring: silent truncation + buffer overflow risk on >255-byte input #707 boolean-return convention. Collapsed 12 lines to 8, matching
frontier-cli/window_registry.c:116and PR fix(#716): parseerror signature now const char *; drop Pascal-string laundering #718'slangerror.c:163fix. Same observable behavior, same user-visiblelangerrormessage.Changes
tests/headless_sys_verbs.c— expand the@IMPLEMENTEDcomment to document the heap-handle design intent, explicitly call out "no bigstring truncation surface here", and mark the path as "do not add a bigstring length guard" with a back-reference to copyctopstring audit tail: 6 sibling defects surfaced during #712 (bucket) #716 item 3Common/source/shellsysverbs.c— refactor the legacy guard fromstrlen + manual >255 check + unguarded copyctopstringto the canonical post-copyctopstring: silent truncation + buffer overflow risk on >255-byte input #707 form (copyctopstring's boolean return)tests/integration/sys_getenv_long_value_test.sh(new) — shell-level integration test asserting:tests/Makefile— wiretest-sys-getenv-long-valueintotest-alland.PHONYTest plan
make build— clean./tools/run_headless_tests.sh— 589/589 passcd tests && make test-sys-getenv-long-value— 3/3 passcd tests && make test-integration— 21 baseline failures match PR test(#715): behavioral coverage for copyctopstring deep-stack defenses #717's stated baseline (html / tcp / startup flakiness, unrelated to env-var code)Scope
This PR addresses only item 3 of #716. Items 2, 4, 5 remain open and will be addressed in separate PRs:
strings.cpush-after-copyctopstringtruncationlangsqlite.csqlite3_errmsgtruncationtcpverbs.c/WinSockNetEvents.cINDIRECT callsitesItem 6 was already closed via PR #717's analysis.
Investigative process
I initially wrote a test that called
sys.getenvironmentvariablewith a >255-byte env var expecting an error (matching the original issue framing). The test returned the full 300 bytes — which surfaced that the audit target wasn't on the live path. Traced the verb dispatch through the kernel-verbs generator totests/headless_sys_verbs.cand found the heap-handle design. The test was reframed as a regression guard for the actual headless behavior.🤖 Generated with Claude Code