Integer overflow (--int-overflow)

August 18, 2026 · View on GitHub

CRuby's Integer is arbitrary precision: it never overflows, it grows. Spinel compiles Integer to a fixed-width 64-bit machine integer (sp_int, range -2**63 .. 2**63 - 1) because a machine word is what makes the generated C fast. --int-overflow=MODE chooses what happens when an Integer result crosses that 64-bit boundary.

spinel app.rb --int-overflow=raise     # default
spinel app.rb --int-overflow=wrap
spinel app.rb --int-overflow=promote

Modes

modeon overflowmatches CRuby?use it for
raise (default)raises RangeError (integer overflow in +)no — CRuby would grow the integercatching overflow loudly; never silently wrong
wraptwo's-complement wraparound, like C (a + b with no check)nomodular arithmetic, hashes, checksums, PRNGs — anywhere defined wraparound is the intent
promotepromotes the result to an arbitrary-precision integer (bigint)yesCRuby-faithful integer math (experimental, see below)

The mode applies to integer +, -, *, unary -, and (under promote) ** and shifts. It does not change division: 1 / 0 is always a ZeroDivisionError regardless of mode.

raise (default)

The default refuses to be silently wrong. A computation that exceeds 64 bits is almost always a bug or a case that needs promote; raising surfaces it at the point it happens rather than producing a truncated value. This is a deliberate deviation from CRuby (which would never raise here) in favour of loudness.

wrap

wrap skips the overflow check entirely, so arithmetic is plain C wraparound. Choose it when wraparound is the algorithm — hashing, checksums, fixed-width bit manipulation, RNGs — not as a blanket "make overflow go away", since it will silently truncate a value the program genuinely needed. It is the fastest mode (no checks); for example the optcarrot build uses wrap.

promote

promote makes integers behave like CRuby's: a result that exceeds 64 bits becomes a bigint instead of overflowing. Small values stay unboxed machine integers (like CRuby's fixnum), and only the ones that actually overflow pay the bigint cost, so it is more practical than widening everything.

promote is experimental: most integer code works, but coverage is not yet complete (some overflow paths through method arguments, closures, and certain containers still raise rather than promote, and very large integer literals are not yet represented). Treat it as opt-in CRuby fidelity, not a finished guarantee. It also carries a runtime cost (bigint allocation and GC pressure), so the default stays raise.

Using it when you compile the C yourself

In the normal spinel app.rb flow the driver compiles and links in one step and passes the matching -DSP_INT_OVERFLOW_MODE_{RAISE,WRAP,PROMOTE} to the C compiler for you, so --int-overflow=MODE is all you need.

If you emit C with -c and compile it separately, the generated code and the runtime must agree on the mode, so pass the same define to your own cc:

spinel app.rb --int-overflow=wrap -c -o app.c
cc app.c -DSP_INT_OVERFLOW_MODE_WRAP -Ilib libspinel_rt.a -lm -o app

See also

  • limitations.md — where Spinel's static, fixed-width model differs from CRuby, including integer precision.