Menu ▾ ▴

#4119 Signed minimum divided by minus one can crash SDCC

closed-fixed
None
Front-end
5
4 days ago
4 days ago
No

1: Sample code that reproduces the problem.

long long quotient = (-9223372036854775807LL - 1LL) / -1LL;

Replacing / with % also crashes. The 32-bit long version is:

long quotient = (-2147483647L - 1L) / -1L;

2: Exact command used to run SDCC on this sample code.

sdcc -mz80 --std=c2y --nostdinc -S division-crash.c -o output.asm

3: SDCC version tested.

SDCC 4.6.4 #0 (Linux), built from clean official SVN r16984 sources.
This also reproduces with Compiler Explorer's SDCC trunk #16974.

4: Observed and expected behaviour.

The local compiler process terminates with SIGFPE (signal 8). Compiler Explorer reports Program terminated with signal SIGFPE (8).

The mathematical quotient is one greater than the signed maximum, so this is overflowing arithmetic. The compiler should handle the invalid expression without crashing. This report concerns the compiler crash; the missing overflow diagnostic is covered separately by #4093.

The same problem occurs when folding the corresponding remainder. Although the mathematical remainder is zero, the host's signed remainder operation can trap when the corresponding quotient is unrepresentable.

5: Additional checks.

Compiler Explorer: SDCC trunk and GCC 16.2 side by side.
Both panes use the first sample above. SDCC uses -mz80 --std=c2y; GCC uses
-std=c2y -pedantic-errors -fsyntax-only. Checked 8 October 2026: SDCC trunk crashes; GCC 16.1 diagnoses the overflow and exits normally with an error.

The focused local comparison tests covered int, long, long long and signed _BitInt widths 2, 8, 16, 17, 24, 32, 33, 63 and 64. Each type was tested with minimum / -1, minimum % -1, minimum / 1 and (minimum + 1) / -1. Explicit casts on both operands retained the arithmetic type under test.

Arithmetic type Minimum / -1 Minimum % -1
int (16 bits) Minimum value Zero
long (32 bits) Compiler SIGFPE Compiler SIGFPE
long long (64 bits) Compiler SIGFPE Compiler SIGFPE
Signed _BitInt(64) Compiler SIGFPE Compiler SIGFPE
Signed _BitInt, tested widths 2–63 Inconsistent widening/sign interpretation Zero

The narrower _BitInt observation is related but distinct from the crash: after division, converting the quotient directly to unsigned long long produces the positive magnitude rather than the sign-extended minimum. For tested widths 16–63, comparing the quotient with zero nevertheless says
it is negative. For widths 2 and 8, that comparison says it is nonnegative.

Configurations tested: MCS51 default, Z80, Rabbit R2K, S08, STM8 default and PDK14, all with --std=c2y. The type-dependent behaviour agreed across all six.

Implementation observation: valDiv and valMod evaluate signed host C division or remainder after converting the operands to TYPE_TARGET_LONG (int32_t) or TYPE_TARGET_LONGLONG (int64_t). Minimum divided by minus one can overflow that host operation. Narrower _BitInt arithmetic also uses the 64-bit value field, so this division needs normalization to the computed signed result type even when the host operation itself fits.

Related

Bugs: #4093

Discussion

  • Christopher Bazley

    Please consider this candidate bugfix.

     

    Last edit: Christopher Bazley 4 days ago
  • Christopher Bazley

    I expect the fix for this bug to be a prerequisite for fixing [#4093].

     

    Related

    Bugs: #4093

  • Philipp Klaus Krause

    • status: open --> closed-fixed
    • assigned_to: Philipp Klaus Krause
     
  • Philipp Klaus Krause

    Thanks Fixed in [r16993] via your patch.

     

    Related

    Commit: [r16993]


Log in to post a comment.