Skip to content

fix(lockdown): #503 guard must not fire on locals shadowing a stdlib namespace name (#1701) - #1703

Merged
proggeramlug merged 1 commit into
mainfrom
worktree-fix-1701-path-guard-false-positive
May 24, 2026
Merged

proggeramlug merged 1 commit into
mainfrom
worktree-fix-1701-path-guard-false-positive

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

Summary

Fixes #1701. The #503 dynamic-stdlib-dispatch guard refused any computed member access on a bare ident whose name equals a stdlib namespace (path, fs, crypto, …) — without checking it was actually the imported namespace rather than a local variable / parameter that happens to share the name.

hono's trie-router has a path string parameter and does path[0] === "/". The guard treated that local as the node:path namespace and refused the index as the path[runtimeVar]() obfuscation pattern, blocking the entire hono package from compiling:

Error: dynamic dispatch on stdlib namespace `path` is refused at compile time (in package `hono`) … (#503)

(Surfaced while verifying #1698 / unblocking the #1655 Hono c.req.json() path.)

Fix

In stdlib_namespace_receiver (crates/perry-hir/src/lower/expr_member.rs), skip the direct name-match when the ident is bound to a local (ctx.lookup_local(name).is_some()). A local that shadows a namespace name is the user's own variable, never the namespace — and a real stdlib namespace is the global process or an import, both of which the alias / namespace-import branches resolve independently. So the refusal path for genuine namespace receivers is unchanged.

Verification

Test

test-files/test_issue_1701_local_shadows_stdlib_namespace.ts — locals named after stdlib namespaces (path/fs/crypto/os/url) with computed index + computed method call, all matching Node.

Related: #1698 (Request body methods), #1655 (Hono tracker), #503 (the guard).

…name (#1701)

The #503 dynamic-stdlib-dispatch guard (`stdlib_namespace_receiver` in
`lower/expr_member.rs`) matched any bare ident whose NAME equals a stdlib
namespace (`path`, `fs`, …) as the namespace itself — without checking it
wasn't a local variable / parameter shadowing that name.

hono's trie-router has a `path` string parameter and does `path[0] === "/"`.
The guard treated that local as the `node:path` namespace and refused the
computed index as the `path[runtimeVar]()` obfuscation pattern, blocking the
entire `hono` package from compiling (surfaced while verifying #1698 /
unblocking the #1655 Hono `c.req.json()` path).

Fix: a local binding that shadows a namespace name is the user's own variable,
never the namespace (real namespaces are the global `process` or an import,
which the alias / namespace-import branches resolve). Skip the direct
name-match when `ctx.lookup_local(name).is_some()`.

The refusal path for genuine namespace receivers is unchanged — verified a real
`(fs as any)[k]()` is still refused, while a local `path[i]` now compiles. With
this + #1698, a Hono `POST /api/echo` doing `await c.req.json()` compiles and
runs by default (no `PERRY_ALLOW_DYNAMIC_STDLIB` bypass): status 200,
body {"body":{"x":1}}.

Test: test-files/test_issue_1701_local_shadows_stdlib_namespace.ts
@proggeramlug
proggeramlug merged commit a66ccb4 into main May 24, 2026
9 checks passed
@proggeramlug
proggeramlug deleted the worktree-fix-1701-path-guard-false-positive branch May 24, 2026 17:39
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.

#503 dynamic-stdlib guard false-positives on a local variable named path (blocks hono compile)

1 participant