Division by zero
Division by zero
Posted Jan 3, 2025 21:44 UTC (Fri) by Wol (subscriber, #4433)In reply to: Division by zero by quotemstr
Parent article: Preventing data races with Pony
Makes debugging a pain when you need to mess about creating an unusual setup to try and replicate the problem. Oh well ...
Cheers,
Wol
Posted Jan 3, 2025 21:56 UTC (Fri)
by dskoll (subscriber, #1630)
[Link] (21 responses)
In IEEE 754 floating point, 0.0 / 0.0 gives you NaN if you don't trap it. Once an expression yields a NaN, the NaN "infects" every other operator... any operator involving a NaN returns the NaN.
But that's floating point. Most CPUs don't have a way to represent a NaN in a variable of integer type. (Nor Inf nor -Inf, though I guess you could co-opt INT_MAX and INT_MIN respectively.)
Posted Jan 3, 2025 22:19 UTC (Fri)
by quotemstr (subscriber, #45331)
[Link] (20 responses)
Posted Jan 3, 2025 22:29 UTC (Fri)
by dskoll (subscriber, #1630)
[Link] (19 responses)
Yes, I agree. And most CPUs will raise an exception on integer divide by zero. This
little C program:
Posted Jan 4, 2025 9:56 UTC (Sat)
by pm215 (subscriber, #98099)
[Link] (18 responses)
Posted Jan 4, 2025 13:06 UTC (Sat)
by pizza (subscriber, #46)
[Link] (7 responses)
Historically, Arm processor didn't actually implement a hardware integer divider, so any faults/exceptions had to be triggered by the low-level software runtime library.
But starting with armv7-m and armv8, there are integer divide instructions, and they can generate divide by zero exceptions -- something I can personally attest to triggering numerous times. Here is the documentation on the UDIV/SDIV instructions on armv7-m:
https://developer.arm.com/documentation/ddi0403/d/Applica...
Meanwhile, IIRC the various Arm FPUs always supported faults/exceptions, including for divide-by-zero.
Posted Jan 4, 2025 18:03 UTC (Sat)
by khim (subscriber, #9252)
[Link] (4 responses)
Yes. No. Take your own link that, with one click, tells us how SDIV works on ARM 7-m. It looks like this: Now compare that to ARM8 specification: See that call to Just why ARM decided that embedded version have to have “division by zero” exception while “big” CPUs have to silently produce zero is good question, but that's how things work currently. P.S. Of course if you recall that RISC-V does things differently and x86, too… then question of codifying ARM-specific behavior in the language arises… but I guess it one of these “looked good at the time” ideas.
Posted Jan 4, 2025 18:10 UTC (Sat)
by dskoll (subscriber, #1630)
[Link] (1 responses)
Huh, you are right! Even though my Pi 4 is running an aarch64 kernel, userspace is 32-bit armhf and the test program raised SIGFPE. I tried the test program on a fully 64-bit Pi 4 with 64-bit userspace and it ran without complaint, assigning
Posted Jan 4, 2025 20:34 UTC (Sat)
by pm215 (subscriber, #98099)
[Link]
You can probably pass the compiler some kind of -march or -mcpu options to tell it to generate code assuming the v8 CPU you have, and then it ought to emit the udiv or sdiv inline, if you want to look at the behaviour in that situation.
Posted Jan 5, 2025 0:05 UTC (Sun)
by pm215 (subscriber, #98099)
[Link] (1 responses)
Apparently various theorem provers also define their division this way:
Posted Jan 6, 2025 0:38 UTC (Mon)
by Heretic_Blacksheep (guest, #169992)
[Link]
Given the alternatives, I'd much rather have a 'mathematically incorrect' deterministic result that I can take to the bank rather than depending on disparate architectural dependent error states that are really just as mathematically arbitrary as assigning X/0 == 0 but a lot more messy to deal with.
Posted Jan 4, 2025 20:19 UTC (Sat)
by pm215 (subscriber, #98099)
[Link]
And yeah, as noted in the sibling comments M-profile has configurable trapping of integer division by zero, but A profile does not. (M profile diverges from A in various more or less obvious ways.) R profile also permits configuring trapping on div by zero. A profile never traps.
The v7A/R Arm ARM has a section that describes the various options:
https://developer.arm.com/documentation/ddi0406/c/Applica...
v8 got to clean this up by just having them be always present.
Posted Jan 4, 2025 20:54 UTC (Sat)
by pm215 (subscriber, #98099)
[Link]
Posted Jan 4, 2025 13:22 UTC (Sat)
by dskoll (subscriber, #1630)
[Link] (6 responses)
I get the same SIGFPE on a Raspberry Pi 4 with an aarch64 kernel.
Posted Jan 4, 2025 18:09 UTC (Sat)
by khim (subscriber, #9252)
[Link] (5 responses)
SIGFPE sounds suspiciously like result of floating-point operation. We are talking about integer division here.
Posted Jan 4, 2025 18:12 UTC (Sat)
by dskoll (subscriber, #1630)
[Link] (2 responses)
Yes, I know. Nevertheless, SIGFPE is the signal that gets raised.
Posted Jan 4, 2025 22:56 UTC (Sat)
by khim (subscriber, #9252)
[Link] (1 responses)
How do you compile that? GCC is smart enough to recognize UB and produce appropriate brk if optimizations are enabled, but that's not related to what CPU is doing. And unoptimized version calls function that can check the divisior. Try to invoke
Posted Jan 4, 2025 23:18 UTC (Sat)
by dskoll (subscriber, #1630)
[Link]
I compiled in both cases with but on the
Posted Jan 4, 2025 19:15 UTC (Sat)
by excors (subscriber, #95769)
[Link] (1 responses)
> The SIGFPE signal reports a fatal arithmetic error. Although the name is derived from “floating-point exception”, this signal actually covers all arithmetic errors, including division by zero and overflow.
(It notes the integer overflow exception is "impossible in a C program unless you enable overflow trapping in a hardware-specific fashion".)
Posted Jan 4, 2025 22:58 UTC (Sat)
by khim (subscriber, #9252)
[Link]
I'm surprised not by SIGFPE per see, but by the fact that If you avoid UB and functions that do manual checks, at least.
Posted Jan 6, 2025 15:52 UTC (Mon)
by paulj (subscriber, #341)
[Link] (2 responses)
Posted Jan 6, 2025 17:39 UTC (Mon)
by farnz (subscriber, #17727)
[Link] (1 responses)
Not for the integer UDIV and SDIV instructions. You can see in the "Operation" section (which uses Arm Pseudocode to describe the behaviour in abstract terms) that the instruction unconditionally outputs a 0 result if the input divisor is 0.
Posted Jan 7, 2025 11:01 UTC (Tue)
by paulj (subscriber, #341)
[Link]
GCC seems to have some useful options to help catch int-div-0 in testing, including for its analyzer and sanitizer, and also a -mcheck-zero-division - which is enabled by default for -O0 and -Og.
Division by zero
Division by zero
Division by zero
int main()
{
int x = 0;
int y = 0;
int z = x/y;
return 0;
}
Does this when you run it:
$ ./test
Floating point exception
$ echo $?
136
Division by zero
Division by zero
> But starting with armv7-m and armv8, there are integer divide instructions
Division by zero
if ConditionPassed() then
EncodingSpecificOperations();
if SInt(R[m]) == 0 then
if IntegerZeroDivideTrappingEnabled() then
GenerateIntegerZeroDivide();
else
result = 0;
else
result = RoundTowardsZero(SInt(R[n]) / SInt(R[m]));
R[d] = result<31:0&rt;
constant bits(datasize) operand1 = X[n, datasize];
constant bits(datasize) operand2 = X[m, datasize];
constant integer dividend = SInt(operand1);
constant integer divisor = SInt(operand2);
integer result;
if divisor == 0 then
result = 0;
elsif (dividend < 0) == (divisor < 0) then
result = Abs(dividend) DIV Abs(divisor); // same signs - positive result
else
result = -(Abs(dividend) DIV Abs(divisor)); // different signs - negative result
X[d, datasize] = result<datasize-1:0>;
GenerateIntegerZeroDivide
? I don't see it either.Division by zero
0
to z
.
Division by zero
Division by zero
https://xenaproject.wordpress.com/2020/07/05/division-by-...
and https://www.ponylang.io/blog/2017/05/an-early-history-of-... suggests that the inventory of Pony has some background in that kind of academic type theory/theorem proving area, so it seems plausible that the motivation for choosing 0 might been influenced by existing languages like that. Early 2010s seems a bit early for it to be very likely that a language designer was much influenced by fine details of codegen for Arm.
Division by zero
Division by zero
Division by zero
Division by zero
Division by zero
Division by zero
$ cat /tmp/test.c
#include <stdio.h>
int main()
{
int x = 0;
int y = 0;
int z = x/y;
printf("z = %d\n", z);
return 0;
}
$ strace /tmp/test
[... bunch of stuff elided ...]
--- SIGFPE {si_signo=SIGFPE, si_code=FPE_INTDIV, si_addr=0x55c090d59153} ---
+++ killed by SIGFPE +++
Floating point exception
Division by zero
sdiv
directly, then CPU should do what it does. At least for me it produces zero, as CPU manual promised.Division by zero
make test
which simply invoked gcc with no optimization. I checked the assembly output and you are right. On the armhf
architecture, it looks like gcc calls into a library function:
bl __aeabi_idiv
aarch64
architecture, it calls an assembly instruction:
sdiv w0, w1, w0
Division by zero
Division by zero
SDIV
suddenly started producing exceptions. Raspberri Pi 4 uses ARM Cortex-A72 which uses ARMv8-A and on ARMv8-A result should be zero, not exception.Division by zero
Division by zero
Division by zero