fix(runtime): #5437 — CJS-interop probe on module-default wrapper must not auto-call it (fixes #5546 boot crash) - #5553
Conversation
…ault wrapper must not auto-call it
The W6 wrapper-resolve fallback in js_object_get_field_by_name auto-calls a
registered module-default wrapper closure on a property miss to obtain
module.exports. For a CJS module whose module.exports IS a plain function
(next/dist/compiled/debug -> createDebug), the registered wrapper is that
function itself. _interop_require_default(require('debug')) reads .__esModule
off it: the auto-call ran createDebug() with no args -> enabled(undefined) ->
undefined.length -> 'Cannot read properties of undefined (reading length)',
crashing the Next.js server at boot.
Short-circuit the two CJS-interop probe keys on a registered wrapper:
- .__esModule -> undefined (a function-export CJS module is not an ES module)
- .default -> the wrapper closure itself (interop default of a non-ESM
module is module.exports)
Both also excluded from the auto-call exclusion list. The genuine W6
SharedCacheControls path (non-default member reads) is unaffected.
Bundle: .length-on-undefined throw gone; Next.js server now BINDS (was
HTTP 000 boot-exit) and serves; next wall = request-time uS_constructor
new uw.SharedCacheControls captured mis-box (separate, pre-documented).
Regression test: module_default_wrapper_interop_probe_does_not_call_wrapper.
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (5)
📝 WalkthroughWalkthroughVersion bumped to ChangesCJS interop probe short-circuit for module-default wrappers
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
…ery (wrong layer, can't close W6) (#5558) The captured uw reads a mis-boxed closure at request time, but is a correct module.exports object at every registration/auto-call site (require + capture store). So registering wrappers is a guaranteed no-op for W6, and the auto-call introduced a CJS-function-export boot-crash regression. The real root is the class-capture pointer mis-box; tracked under #5437. Co-authored-by: Ralph Küpper <ralph2@skelpo.com>
Why
Follow-up to #5546 (merged). That change auto-calls a registered CJS module-default wrapper closure on a property miss to obtain
module.exports. For a CJS module whosemodule.exportsis a function (e.g.debug→createDebug), the wrapper is that function, and the ubiquitous_interop_require_default(require("debug"))reads.__esModuleoff it → miss → the fallback callscreateDebug()with no args →enabled(undefined)→undefined.length→ throws at module-init. The server exits at boot (regressed the Next.js #5437 bundle from HTTP 500-serving to HTTP 000-boot-crash, and can break other SWC/Babel-compiled-CJS programs).This also means #5546's reported "undefined-ctor 1→0" was a measurement artifact — the server crashed at boot before the request render where
SharedCacheControlsis evaluated. (Completing the actual W6 close — making the auto-call fire for the captureduw— is tracked separately and in progress.)Fix (runtime-only, +87/-3)
crates/perry-runtime/src/object/field_get_set.rs: on a registered module-default wrapper, short-circuit the two CJS-interop probe keys before the auto-call:.__esModule→undefined(a function-export CJS module is not an ES module).default→ the wrapper closure itself (interop-default of a non-ESM module ismodule.exports)Both added to the auto-call exclusion list. Genuine non-
defaultmember reads (the #5437SharedCacheControlspath) are unaffected.Validation
module_default_wrapper_interop_probe_does_not_call_wrapper— wrapperpanic!s if invoked; asserts the probe keys resolve without calling it..lengthboot crash is gone — server boots and serves again (back to HTTP 500; the remaining 1×SharedCacheControlsthrow is the in-progress real W6 close).cargo test -p perry-runtime: 1071 pass incl. the new test.Refs #5437, #5546.
Summary by CodeRabbit
Bug Fixes