You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
IO.get_env with a "=" in the name reads part of another variable on the C lane and Node #1794
bend envq.bend -o envq -o envq.js, then A='B=C' ./envq, A='B=C' node envq.js, A='B=C' bun envq.js
What happened
$ A='B=C' ./envq # C lane (glibc)
A=Done:B=C
A=B=Done:C
$ A='B=C' node envq.js # Node
A=Done:B=C
A=B=Done:C
$ A='B=C' bun envq.js # Bun
A=Done:B=C
A=B=Fail:2
IO.get_env("A=B") names a variable that does not exist, so it should fail with ENOENT, as it does on Bun. On the C lane and on Node it answers Done("C"), the tail of A's value: glibc's getenv compares the name up to its length and then wants a =, so "A=B" matches the entry A=B=C. Node's process.env goes through the same getenv. Bun looks the exact key up in its own object and fails. So the lanes disagree, and a name built from input ("PATH=x", say) can read a variable the program never named. macOS's getenv stops the name at the first = instead, so there get_env("A=B") likely answers all of A's value (not verified here).
This is the = twin of #1449 (a NUL in the name). get_env.c already rejects a NUL with io_nul before calling getenv; a = can never be part of a variable name either (POSIX setenv refuses one with EINVAL).
The file
importBaselawreport:
fortag : Stringforr : Result<&1, &1, (U32&String), String>IO(Unit)
defreport(tag, r):
matchr:
caseDone{value}:
IO.print(String.append(tag, String.append("=Done:", value)))
caseFail{error}:
(code, message) =errorIO.print(String.append(tag, String.append("=Fail:", U32.show(code))))
lawmain:
IO(U32)
defmain():
doIO<U32>:
a : Result<&1, &1, (U32&String), String><-IO.get_env("A")
x : Unit<-report("A", a)
b : Result<&1, &1, (U32&String), String><-IO.get_env("A=B")
y : Unit<-report("A=B", b)
return0
Activity