assert(false, "...") doesn't terminate program?!
I'm investigating issue 8021, and found a strange problem in std.bigint. Somehow, checkDivByZero is getting called, and isZero correctly detects a zero denominator, YET the assert passes, and the integer division by zero doesn't trigger any division by zero signal. Here's the test case from the bugtracker: import std.stdio, std.bigint; void main() { BigInt n = BigInt(2) / BigInt(0); } Here's the instrumented Phobos code to show this strange effect (this is inside struct BigInt, I modified the code to show exactly what the code is doing, it's pretty strange): // Generate a runtime error if division by zero occurs //void checkDivByZero() pure const void checkDivByZero() const { import std.stdio; writeln(isZero()); // prints true writeln(!isZero()); // prints false // this should assert, but doesn't?! assert(!isZero(), "BigInt division by zero"); writeln("how did the assert not trigger??!!"); // how did we get here?! if (isZero()) { auto x = 1/toInt(); // generate a div by zero error // ... or not? writeln("div by zero was not triggered!!"); writeln(toInt()); // prints 0 assert(0); // segfaults??! } } Output: true false how did the assert not trigger??!! div by zero was not triggered!! 0 Segmentation fault It's beyond my imagination how assert(!isZero()) could possibly have continued execution when isZero() is clearly true and !isZero() is clearly false. What's going on here?? T -- Tell me and I forget. Teach me and I remember. Involve me and I understand. -- Benjamin Franklin
Re: assert(false, "...") doesn't terminate program?!
On 10/27/12, H. S. Teoh wrote: > writeln("how did the assert not trigger??!!");// how did we > get > here?! Maybe related to -release? If the expression is not evaluable at compile-time the assert goes away when -release is used.
Re: assert(false, "...") doesn't terminate program?!
On Sat, Oct 27, 2012 at 08:26:21PM +0200, Andrej Mitrovic wrote: > On 10/27/12, H. S. Teoh wrote: > > writeln("how did the assert not trigger??!!"); // how did we > > get > > here?! > > Maybe related to -release? [...] Haha, you're right, the assert is compiled out because of -release. But I disassembled the code, and didn't see the "auto x = 1/toInt()" either. Is the compiler optimizing that away? Also, is that even a good idea? Shouldn't we be throwing an exception here instead of trying to trigger integer division by zero (which may not even terminate the program, depending on the OS, etc.)? Not to mention, the failure of this line to stop the program causes the code to return to the division function, which never terminates because of the zero divisor. T -- The volume of a pizza of thickness a and radius z can be described by the following formula: pi zz a. -- Wouter Verhelst
Re: assert(false, "...") doesn't terminate program?!
On Saturday, 27 October 2012 at 18:36:57 UTC, H. S. Teoh wrote: On Sat, Oct 27, 2012 at 08:26:21PM +0200, Andrej Mitrovic wrote: Maybe related to -release? Haha, you're right, the assert is compiled out because of -release. Then it is a bug; Unless perhaps it is inside a contract (in/out) or debug statement. TDPL pg 326: [quote] An assertion against a constant that is known to be zero during compilation, such as assert(false), assert(0), or assert(null), behaves a tad differently from a regular assert. In non-release mode, assert(false) does not do anything special: It just throws an AssertError exception. In release mode, however, assert(false) is NOT compiled out of existence; it will always cause a program to stop. This time, however, there would be no exception and no chance of continuing to run after an assert(false) was hit. The program will CRASH. [/quote]
Re: assert(false, "...") doesn't terminate program?!
On Sat, Oct 27, 2012 at 09:03:05PM +0200, Era Scarecrow wrote: > On Saturday, 27 October 2012 at 18:36:57 UTC, H. S. Teoh wrote: > >On Sat, Oct 27, 2012 at 08:26:21PM +0200, Andrej Mitrovic wrote: > >>Maybe related to -release? > > > >Haha, you're right, the assert is compiled out because of > >-release. > > Then it is a bug; Unless perhaps it is inside a contract (in/out) > or debug statement. No it's not a bug, because the value is *not* known to be zero at compile-time (it depends on what value you put in the BigInt). > TDPL pg 326: > [quote] > An assertion against a constant that is known to be zero during > compilation, such as assert(false), assert(0), or assert(null), > behaves a tad differently from a regular assert. [...] T -- Ph.D. = Permanent head Damage
Re: assert(false, "...") doesn't terminate program?!
On Saturday, 27 October 2012 at 19:08:02 UTC, H. S. Teoh wrote: No it's not a bug, because the value is *not* known to be zero at compile-time (it depends on what value you put in the BigInt). I think I read the question wrong earlier. My apologies.
Re: assert(false, "...") doesn't terminate program?!
On 27/10/12 20:39, H. S. Teoh wrote: On Sat, Oct 27, 2012 at 08:26:21PM +0200, Andrej Mitrovic wrote: On 10/27/12, H. S. Teoh wrote: writeln("how did the assert not trigger??!!"); // how did we get here?! Maybe related to -release? [...] Haha, you're right, the assert is compiled out because of -release. But I disassembled the code, and didn't see the "auto x = 1/toInt()" either. Is the compiler optimizing that away? Yes, and I don't know on what basis it thinks it's legal to do that. Also, is that even a good idea? Shouldn't we be throwing an exception here instead of trying to trigger integer division by zero (which may not even terminate the program, depending on the OS, etc.)? The intention was that it should behave _exactly_ like an integer division by zero. It's bug 8021, BTW.
Re: assert(false, "...") doesn't terminate program?!
On 10/29/2012 7:51 AM, Don Clugston wrote:> On 27/10/12 20:39, H. S. Teoh wrote: >> On Sat, Oct 27, 2012 at 08:26:21PM +0200, Andrej Mitrovic wrote: >>> On 10/27/12, H. S. Teoh wrote: writeln("how did the assert not trigger??!!");// how did we get here?! >>> >>> Maybe related to -release? >> [...] >> >> Haha, you're right, the assert is compiled out because of -release. >> >> But I disassembled the code, and didn't see the "auto x = 1/toInt()" >> either. Is the compiler optimizing that away? > > Yes, and I don't know on what basis it thinks it's legal to do that. Because x is a dead assignment, and so the 1/ is removed. Divide by 0 faults are not considered a side effect. I think the code would be better written as: if (toInt() == 0) throw new Error(); If you really must have a divide by zero fault, if (toInt() == 0) divideByZero(); where: void divideByZero() { static int x; *cast(int*)0 = x / 0; }
Re: assert(false, "...") doesn't terminate program?!
On 29/10/12 18:38, Walter Bright wrote: On 10/29/2012 7:51 AM, Don Clugston wrote:> On 27/10/12 20:39, H. S. Teoh wrote: >> On Sat, Oct 27, 2012 at 08:26:21PM +0200, Andrej Mitrovic wrote: >>> On 10/27/12, H. S. Teoh wrote: writeln("how did the assert not trigger??!!");// how did we get here?! >>> >>> Maybe related to -release? >> [...] >> >> Haha, you're right, the assert is compiled out because of -release. >> >> But I disassembled the code, and didn't see the "auto x = 1/toInt()" >> either. Is the compiler optimizing that away? > > Yes, and I don't know on what basis it thinks it's legal to do that. Because x is a dead assignment, and so the 1/ is removed. Divide by 0 faults are not considered a side effect. Ah, that's interesting, I didn't know that. I think the code would be better written as: if (toInt() == 0) throw new Error(); If you really must have a divide by zero fault, if (toInt() == 0) divideByZero(); where: void divideByZero() { static int x; *cast(int*)0 = x / 0; } And that works because writes to 0 _are_ considered a side-effect? Is that guaranteed to work?
Re: assert(false, "...") doesn't terminate program?!
On 10/30/2012 5:53 AM, Don Clugston wrote: > > I think the code would be >> better written as: >> >> if (toInt() == 0) throw new Error(); >> >> If you really must have a divide by zero fault, >> >> if (toInt() == 0) divideByZero(); >> >> where: >> >> void divideByZero() >> { >> static int x; >> *cast(int*)0 = x / 0; >> } > > And that works because writes to 0 _are_ considered a side-effect? > Is that guaranteed to work? Writing through a pointer is considered a side effect.