fix(native): emitError chained method call caused segv on every compile error#521
Merged
fix(native): emitError chained method call caused segv on every compile error#521
Conversation
…use emitError chained getErrors() twice per expression — extract to intermediate vars and add module-scope Date fixtures
Contributor
Benchmark Results (Linux x86-64)
CLI Tool Benchmarks
|
cs01
added a commit
that referenced
this pull request
Apr 18, 2026
…elegates to canonical, revert #521 emitError workaround canonical path (rich.arrayDepth>0 + rich.fields) now fires for all indexed-object-array element-field accesses; legacy branches remain as fallback for shapes canonical doesn't yet enrich. with canonical in place, #521's emitError intermediate-variable workaround is no longer necessary — reverted to the original chained method_call+index_access form; native compiler emits the expected diagnostic (no segv). zero fuzz regression; stage 2 self-hosting + fixture suite green.
Merged
4 tasks
cs01
added a commit
that referenced
this pull request
Apr 18, 2026
…elegates to canonical, revert #521 emitError workaround (#527) canonical path (rich.arrayDepth>0 + rich.fields) now fires for all indexed-object-array element-field accesses; legacy branches remain as fallback for shapes canonical doesn't yet enrich. with canonical in place, #521's emitError intermediate-variable workaround is no longer necessary — reverted to the original chained method_call+index_access form; native compiler emits the expected diagnostic (no segv). zero fuzz regression; stage 2 self-hosting + fixture suite green. Co-authored-by: cs01 <cs01@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
User impact
The native self-hosted compiler (`.build/chad`) segfaulted instead of printing any compile error whose upstream code path ran through `emitError`. Concretely: fuzz A2-A5 repros (`new Date()` at module scope, `instanceof` with class hierarchy, `typeof d.getTime()`, etc.) all crashed with no output. Users saw a silent SIGSEGV where they should have seen a diagnostic.
After this PR, every one of those inputs prints the clean error the Node compiler already prints:
```
error: cannot determine type of module-scope variable 'd' (expression type: new). Move the declaration inside a function, or add a type annotation
```
Root cause
`emitError` in `src/codegen/llvm-generator.ts` built the output via a chained expression:
```typescript
this.diagnostics.formatDiagnostic(
this.diagnostics.getErrors()[this.diagnostics.getErrors().length - 1],
)
```
This is `method_call()[method_call().length - 1]` — an index access into the result of a method call. The native compiler's codegen for this pattern does not propagate the result's `elementInterfaceName` through, so the indexed element is handed to `formatDiagnostic` as a bare `i8*` pointing to memory the reader treats as a `%Diagnostic` struct with a different layout than what was stored. Subsequent `diag.message` GEP loads garbage; `strlen` on the garbage pointer crashes.
Confirmed under lldb: backtrace lands in `strlen` called from `formatDiagnostic + 260` (the `bold(": " + diag.message)` expression), with x1 holding ANSI-escape byte values instead of a string pointer. Debug prints before and after the intermediate-variable refactor prove the fix: with intermediates, `severity` reads `0` and `message` reads the correct string; without, severity reads `9.48606e-322` (garbage) and the message read segfaults.
Change
Follow-up
The underlying codegen bug (method-call-result indexed access loses element interface type) is still present and worth fixing at the root in `access/member.ts` / `handleIndexAccessPropertyAccess`. This PR is the targeted workaround to immediately unblock A2-A5. Filed as future work.
Test plan