Fix Rational.zero producing 0/0 that SIGFPEs on any arithmetic - #8
Merged
Conversation
`(derive Rational zero)` generated a zero struct with both numerator and denominator set to 0. Any operation dividing by the denominator (e.g. `(add x (zero))`) then crashed with SIGFPE. Replace the derive with an explicit `(defn zero [] (init 0 1))`, so `zero` is 0/1 and safe in arithmetic, and add tests covering the value and the additive-identity laws.
There was a problem hiding this comment.
Build & Tests
Checked out claude/fix-zero-sigfpe and ran the suite locally (carp -x tests/rational.carp): 127 passed, 0 failed. CI is green on ubuntu + macos. Builds clean.
Findings
Verified the root cause and the fix in full:
- Mechanism confirmed. On
master,(derive Rational zero)expands to(init 0 0)— a0/0struct.add/sub/mulcompute the result denominator asda*db, so any op against(zero)hitsd = 0, andnewthen evaluates(/ n (gcd n 0))=(/ n 0)→ SIGFPE. The reproduction in the description is accurate. - Fix is minimal and idiomatic.
(defn zero [] (init 0 1))mirrors the existingfrom-int((init i 1)) exactly —initis the raw private constructor and needs no reduction for a unit denominator.0/1is a true additive identity andzero?(numerator-only) still reports it as zero. - No stale dependencies. Nothing else in the module relied on the derived
zero; the(implements zero Rational.zero)keeps generic(zero)dispatch working.
I also ran an edge-case script beyond the test suite — every operation that divides by the denominator, applied to (zero):
add 3/4 + zero => (Rational 3/4) ; the exact expr that SIGFPEd on master
zero + zero => (Rational 0/1)
zero / (3/4) => (Rational 0/1)
sign/floor/ceil/round zero => (Rational 0/1)
to-double zero => 0 to-int zero => 0 zero? zero => true
All clean, no crashes. No CHANGELOG exists in this repo, so nothing to update there.
Verdict: merge
Correct, minimal, well-tested fix for a genuine whole-program crash on the most basic use of a core constructor. Builds, passes tests and CI, and holds up under edge-case probing.
hellerve
approved these changes
Jul 11, 2026
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.
What
(Rational.zero)returned a struct with both numerator and denominator set to0(i.e.0/0), because the module used(derive Rational zero). Every arithmetic operation divides by the denominator, so the most basic use —x + 0— crashed the program with a SIGFPE (confirmed: exit136):Fix
Replace the broken derive with an explicit constructor inside the module, mirroring how
Semverdefines its ownzero:zerois now0/1, so it is a proper additive identity and safe to divide by. The same call now returns(Rational 3/4)and exits cleanly.Tests
Added assertions covering the constructor's value (
0/1) and the identity laws that previously crashed —x + 0,x - 0, andx * 0. The full suite passes (127 tests), andcarp-fmt -c/anglerare clean on both changed files.Opened by the carpentry-org heartbeat agent (Claude). Veit has not reviewed this yet.