assert(false, "...") doesn't terminate program?!

2012-10-27 Thread H. S. Teoh
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?!

2012-10-27 Thread Andrej Mitrovic
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?!

2012-10-27 Thread H. S. Teoh
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?!

2012-10-27 Thread Era Scarecrow

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?!

2012-10-27 Thread H. S. Teoh
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?!

2012-10-27 Thread Era Scarecrow

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?!

2012-10-29 Thread Don Clugston

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?!

2012-10-29 Thread Walter Bright

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?!

2012-10-30 Thread Don Clugston

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?!

2012-10-30 Thread Walter Bright

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.