Skip to content

fix(io): get_env rejects a name with a "=" - #1795

Merged
Lorenzobattistela merged 1 commit into
bendlang:mainfrom
orezraey:fix-get-env-eq-name
Oct 21, 2026
Merged

Lorenzobattistela merged 1 commit into
bendlang:mainfrom
orezraey:fix-get-env-eq-name

Conversation

@orezraey

Copy link
Copy Markdown
Contributor

Problem

Closes #1794.

IO.get_env passed a name containing = straight to the host. glibc's getenv("A=B") matches the entry A=B=C and answers C, so on the C lane and on the Node lane (whose process.env uses getenv) the call read part of another variable's value, while Bun, which looks up the exact key, failed with ENOENT. The lanes disagreed, and a name the caller built could read a variable it never named.

Lane A (with A='B=C') A=B (before) A=B (after)
C Done("B=C") Done("C") Fail(ENOENT)
Node Done("B=C") Done("C") Fail(ENOENT)
Bun Done("B=C") Fail(ENOENT) Fail(ENOENT)

Change

  • bend2/effs/get_env.c: reject a name containing = with the same ENOENT the NUL guard (io_nul) and the unset path already return, before calling getenv.
  • bend2/effs/get_env.js: the same check next to the NUL check from IO.get_env on Node truncates names at embedded NUL #1449.
  • tests/io/get_env_eq.bend (+ get_env_eq.c / get_env_eq.js): a foreign put_eq effect sets BEND_ENV_EQ=x=y; the test pins exact=x=y and eq=unset for get_env("BEND_ENV_EQ=x").

Valid names, values containing =, own-property semantics and the error codes are unchanged: the guard only fires on a name no variable can have.

Verification

On Linux x86_64 (clang 23.1.1, Bun 1.4.3, Node v26.10.0), each test checked and interpreted with bun bend2/main.ts <t>.bend, then built with -o t.js -o t.c and run under Bun, Node and the clang binary:

  • tests/io/get_env_eq.bend before the fix: interp and Bun print eq=unset, Node and C print eq=y. After: all four print exact=x=y / eq=unset. So the test discriminates the bug.
  • tests/io/get_env.bend, get_env_nul.bend, get_env_own.bend, nul_bytes.bend: unchanged output on all four lanes.
  • bun gates/repo.ts: PASS: 54 / 54 (the new files match tests/... and bend2/effs/[a-z0-9_]+\.(c|js); no capped file is touched).
  • --check-only refuses the test the same way it refuses tests/io/exit_status.bend (it depends on a foreign effect).
  • get_env.js merges cleanly with the open fix(runtime): correct JS text boundaries after the Char rewrite #1549, which edits the line above.

glibc's getenv("A=B") matches the entry "A=B=C" and answers "C", so on the
C lane and on Node a name with a "=" read part of another variable's value,
while Bun failed. Reject such a name like one with a NUL (bendlang#1449), so every
lane answers ENOENT.
@Lorenzobattistela Lorenzobattistela self-assigned this Oct 21, 2026

@Lorenzobattistela Lorenzobattistela left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gates green merged onto main 042e797 (repo, test, ping, safe; perf matches main). Checked on macOS too: with main's effects the C and Node lanes print eq=x=y, with this PR every lane prints eq=unset, so the test discriminates on the gate's hardware.

Optional nit: macOS getenv cuts the name at the first = and answers A's whole value, not part of it, so the comments in get_env.c and the test header could say "A's value or part of it".

@Lorenzobattistela
Lorenzobattistela merged commit e9055f7 into bendlang:main Oct 21, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

IO.get_env with a "=" in the name reads part of another variable on the C lane and Node

2 participants