Skip to content

codegen: fix segfault on numeric literal assigned to a pointer type - #22

Merged
Hedede merged 3 commits into
masterfrom
test/gen-local-null-store
Jul 16, 2026
Merged

Hedede merged 3 commits into
masterfrom
test/gen-local-null-store

Conversation

@Hedede

@Hedede Hedede commented Jul 16, 2026

Copy link
Copy Markdown
Member

Summary

  • var p: int* = 0; reliably segfaulted the compiler. Root cause: propagate_type(numeric_literal) assigned any target type — including a pointer type — onto a literal with no validation, and gen(numeric_literal) had no case for pointer types, falling through to return nullptr. That nullptr then flowed unchecked into gen_local()'s builder.CreateStore(), which dereferences it immediately.
  • type_inference.c++: only a literal 0 may now propagate a pointer type (the null-pointer idiom); anything else assigned to a pointer type produces a clean Type mismatch: '<type>' vs 'numeric_literal'. diagnostic instead of crashing or silently emitting bad IR.
  • backend_llvm.c++ (gen(numeric_literal)): pointer-typed literals now emit ConstantPointerNull, so var p: T* = 0; generates correct IR (store ptr null, ...).
  • backend_llvm.c++ (gen_local): added a null check before CreateStore, so any future unhandled case fails cleanly instead of segfaulting — the same unchecked-null pattern flagged by the pre-existing // TODO: this bit crashes sometimes comment in gen(function).

Test plan

  • Confirmed the crash with gdb before the fix: SIGSEGV inside backend_llvm::gen_local, called via gen(decl_statement) → gen(statement_block) → gen(function).
  • Added test/codegen/pointer_null_init.aw (previously segfaulting, now compiles cleanly and passes) and test/errors/pointer_nonzero_init.aw (negative test for the new diagnostic).
  • Full ctest: 19/19 pass, excluding the pre-existing, unrelated codegen/pointer.aw failure.
  • Spot-checked normal pointer/int/float/bool variable usage is unaffected.

Generated by Claude Code

@Hedede
Hedede force-pushed the test/gen-local-null-store branch from 6fbfd93 to 6cd11d8 Compare July 16, 2026 13:48
@Hedede
Hedede merged commit 011edda into master Jul 16, 2026
1 check failed
claude and others added 3 commits July 16, 2026 17:15
`var p: int* = 0;` segfaults the compiler. Root cause: gen(numeric_literal)
falls through to `return nullptr` when the literal's inferred type doesn't
match integer/float/double (a plain int literal used to initialize a
pointer-typed local isn't handled), and gen_local() passes that nullptr
straight into builder.CreateStore() without checking it, which dereferences
it and crashes.

Confirmed via gdb: SIGSEGV inside backend_llvm::gen_local, called from
gen(decl_statement) -> gen(statement_block) -> gen(function) -- the same
call chain that flows into the "TODO: this bit crashes sometimes" comment
a few frames up in gen(function); this is a concrete, 100% reproducible
instance of that class of bug (a null Value* from gen() reaching a raw
LLVM builder call unchecked), not a fix.
Root cause of the crash reproduced by codegen/pointer_null_init.aw:
propagate_type(numeric_literal) would blindly assign any target type
(including a pointer type) onto a literal's expr.type with no check,
and gen(numeric_literal) had no case for a pointer-typed literal, so
it fell through to `return nullptr`. That nullptr then flowed
unchecked into gen_local()'s builder.CreateStore(), which
dereferences it immediately and segfaults.

Fix:
- type_inference: allow only a literal `0` to propagate a pointer
  type (the null-pointer idiom); anything else assigned to a pointer
  type is now a clean "Type mismatch" diagnostic instead of silently
  producing bad IR (or worse, corrupting the compiler's own state).
- codegen: gen(numeric_literal) now emits ConstantPointerNull for a
  pointer-typed literal, so `var p: T* = 0;` generates correct IR.
- gen_local(): check gen(var.value) for null before handing it to
  CreateStore(), so any future unhandled case fails cleanly instead
  of segfaulting -- this is the same unchecked-null pattern flagged
  by the "TODO: this bit crashes sometimes" comment in gen(function).

Added test/errors/pointer_nonzero_init.aw as a negative test for the
new diagnostic. codegen/pointer_null_init.aw now passes cleanly.
The crash is fixed, so the test can be re-enabled
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.

2 participants