www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Acces Violation: assert with null instance

reply "Lionello Lunesu" <lionello lunesu.remove.com> writes:
I really think this used to work (like in C++) :

#class Class {}
#void main(){
#    Class c;
#    assert(c);
#}

With 1.0, I get an access violation in 
_D9invariant12_d_invariantFC6ObjectZv, but why? I have to rewrite it as 
assert(c !is null), but I don't recall having to do this before....

L. 
Jan 04 2007
next sibling parent Lionello Lunesu <lio lunesu.remove.com> writes:
Lionello Lunesu wrote:
 I really think this used to work (like in C++) :

..Guess not. I've just tested with some old versions, as old as 0.119, and I still got the Access Violation. Odd. Shouldn't it work though? Class c = null; assert(c); L.
Jan 05 2007
prev sibling next sibling parent Lionello Lunesu <lio lunesu.remove.com> writes:
Lionello Lunesu wrote:
 _D9invariant12_d_invariantFC6ObjectZv

For the record: When linking against a debug build of Phobos (-unittest -g -w), I get: Error: AssertError Failure internal\invariant.d(14) Posted on bugzilla as Issue 796. L.
Jan 05 2007
prev sibling parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Lionello Lunesu wrote:
 I really think this used to work (like in C++) :
 
 #class Class {}
 #void main(){
 #    Class c;
 #    assert(c);
 #}
 
 With 1.0, I get an access violation in 
 _D9invariant12_d_invariantFC6ObjectZv, but why?

For some strange reason, assert on an object reference checks that the invariants are satisfied instead of that the reference isn't null. There's nothing to this effect in the spec, so I don't know how it came about. While it may be useful, it certainly shouldn't do it _instead of_ checking it isn't null. Stewart.
Jan 10 2007
next sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Stewart Gordon wrote:
 For some strange reason, assert on an object reference checks that the 
 invariants are satisfied instead of that the reference isn't null. 
 There's nothing to this effect in the spec, so I don't know how it came 
 about.  While it may be useful, it certainly shouldn't do it _instead 
 of_ checking it isn't null.

As I commented recently when this bug was added to bugzilla, it's in the spec. It's just not where you'd expect it. It's noted at http://www.digitalmars.com/d/class.html#invariants (the section on class invariants) instead of in the section on asserts. I've since added a warning about this on the comments page for the page containing the section on asserts. Also, the null check *is* in the code, but when Phobos is compiled in release mode (which the pre-compiled version is) the assert isn't performed...
Jan 10 2007
parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Frits van Bommel wrote:
 Stewart Gordon wrote:
 For some strange reason, assert on an object reference checks that the 
 invariants are satisfied instead of that the reference isn't null. 
 There's nothing to this effect in the spec, so I don't know how it 
 came about.  While it may be useful, it certainly shouldn't do it 
 _instead of_ checking it isn't null.

As I commented recently when this bug was added to bugzilla, it's in the spec. It's just not where you'd expect it.

What is the Bugzilla issue number? I can't seem to find it.
 It's noted at http://www.digitalmars.com/d/class.html#invariants (the 
 section on class invariants) instead of in the section on asserts.
 I've since added a warning about this on the comments page for the page 
 containing the section on asserts.
 
 Also, the null check *is* in the code, but when Phobos is compiled in 
 release mode (which the pre-compiled version is) the assert isn't 
 performed...

"The invariant can be checked when a class object is the argument to an assert() expression, as:" I see this as giving an _additional_ use of assert, something that assert on a class object may do as an extra. The general contract of assert is supposed to remain, and the fact that out of the box it doesn't certainly constitutes a bug, at least IMO. Stewart.
Jan 10 2007
next sibling parent Lionello Lunesu <lio lunesu.remove.com> writes:
Stewart Gordon wrote:
 Frits van Bommel wrote:
 Stewart Gordon wrote:
 For some strange reason, assert on an object reference checks that 
 the invariants are satisfied instead of that the reference isn't 
 null. There's nothing to this effect in the spec, so I don't know how 
 it came about.  While it may be useful, it certainly shouldn't do it 
 _instead of_ checking it isn't null.

As I commented recently when this bug was added to bugzilla, it's in the spec. It's just not where you'd expect it.

What is the Bugzilla issue number? I can't seem to find it.

796
 It's noted at http://www.digitalmars.com/d/class.html#invariants (the 
 section on class invariants) instead of in the section on asserts.
 I've since added a warning about this on the comments page for the 
 page containing the section on asserts.

 Also, the null check *is* in the code, but when Phobos is compiled in 
 release mode (which the pre-compiled version is) the assert isn't 
 performed...

"The invariant can be checked when a class object is the argument to an assert() expression, as:" I see this as giving an _additional_ use of assert, something that assert on a class object may do as an extra. The general contract of assert is supposed to remain, and the fact that out of the box it doesn't certainly constitutes a bug, at least IMO.

I agree, that why I filed that bug :) L.
Jan 10 2007
prev sibling parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Stewart Gordon wrote:
 "The invariant can be checked when a class object is the argument to an 
 assert() expression, as:"
 
 I see this as giving an _additional_ use of assert, something that 
 assert on a class object may do as an extra.  The general contract of 
 assert is supposed to remain, and the fact that out of the box it 
 doesn't certainly constitutes a bug, at least IMO.

Huh. I must've read that wrong. I thought it said "is checked". I guess this one makes more sense. That definitely makes it a bug.
Jan 11 2007
prev sibling parent reply Walter Bright <newshound digitalmars.com> writes:
Stewart Gordon wrote:
 Lionello Lunesu wrote:
 I really think this used to work (like in C++) :

 #class Class {}
 #void main(){
 #    Class c;
 #    assert(c);
 #}

 With 1.0, I get an access violation in 
 _D9invariant12_d_invariantFC6ObjectZv, but why?

For some strange reason, assert on an object reference checks that the invariants are satisfied instead of that the reference isn't null. There's nothing to this effect in the spec, so I don't know how it came about. While it may be useful, it certainly shouldn't do it _instead of_ checking it isn't null. Stewart.

It does check if it's null. That's how the access violation exception gets thrown.
Jan 24 2007
next sibling parent reply Sean Kelly <sean f4.ca> writes:
Walter Bright wrote:
 Stewart Gordon wrote:
 Lionello Lunesu wrote:
 I really think this used to work (like in C++) :

 #class Class {}
 #void main(){
 #    Class c;
 #    assert(c);
 #}

 With 1.0, I get an access violation in 
 _D9invariant12_d_invariantFC6ObjectZv, but why?

For some strange reason, assert on an object reference checks that the invariants are satisfied instead of that the reference isn't null. There's nothing to this effect in the spec, so I don't know how it came about. While it may be useful, it certainly shouldn't do it _instead of_ checking it isn't null. Stewart.

It does check if it's null. That's how the access violation exception gets thrown.

But that's generated by the hardware, isn't it? Shouldn't assert explicitly check whether c is null before calling its invariant? Sean
Jan 24 2007
parent reply Walter Bright <newshound digitalmars.com> writes:
Sean Kelly wrote:
 Walter Bright wrote:
 It does check if it's null. That's how the access violation exception 
 gets thrown.

But that's generated by the hardware, isn't it?

Yes.
 Shouldn't assert 
 explicitly check whether c is null before calling its invariant?

Why, if the hardware does it for you (without extra bloat)?
Jan 25 2007
next sibling parent "Frank Benoit (keinfarbton)" <benoit tionex.removethispart.de> writes:
 Why, if the hardware does it for you (without extra bloat)?

Is it possible to catch a segmentation fault and convert it into a InvalidPointerException and continue?
Jan 26 2007
prev sibling parent reply Sean Kelly <sean f4.ca> writes:
Walter Bright wrote:
 Sean Kelly wrote:
 Walter Bright wrote:
 It does check if it's null. That's how the access violation exception 
 gets thrown.

But that's generated by the hardware, isn't it?

Yes.
 Shouldn't assert explicitly check whether c is null before calling its 
 invariant?

Why, if the hardware does it for you (without extra bloat)?

Just so a file and line number are available. Though someone mentioned the code already does something like "assert(obj); obj.invariant();" and the problem here was that it was a release build? If this is the case I'm fine with the current behavior. I really only care about this sort of thing if asserts are enabled. Sean
Jan 26 2007
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Sean Kelly wrote:
 Walter Bright wrote:
 Sean Kelly wrote:
 Walter Bright wrote:
 It does check if it's null. That's how the access violation 
 exception gets thrown.

But that's generated by the hardware, isn't it?

Yes.
 Shouldn't assert explicitly check whether c is null before calling 
 its invariant?

Why, if the hardware does it for you (without extra bloat)?

Just so a file and line number are available. Though someone mentioned the code already does something like "assert(obj); obj.invariant();" and the problem here was that it was a release build? If this is the case I'm fine with the current behavior. I really only care about this sort of thing if asserts are enabled.

Yes, an assert(o !is null) is performed. But it's performed *inside* _d_invariant, which is part of Phobos. And since Phobos is only distributed as a release build, that means the assert is off by default _even if *your* program has asserts enabled_. You need to recompile Phobos to change this behavior. This is bad. Perhaps that assert should just be converted to an "if (!o) _d_assert(__FILE__, __LINE__)" since _d_invariant will (presumably) only be called if the application has assertions enabled?
Jan 26 2007
parent reply Sean Kelly <sean f4.ca> writes:
Frits van Bommel wrote:
 Sean Kelly wrote:
 Walter Bright wrote:
 Sean Kelly wrote:
 Walter Bright wrote:
 It does check if it's null. That's how the access violation 
 exception gets thrown.

But that's generated by the hardware, isn't it?

Yes.
 Shouldn't assert explicitly check whether c is null before calling 
 its invariant?

Why, if the hardware does it for you (without extra bloat)?

Just so a file and line number are available. Though someone mentioned the code already does something like "assert(obj); obj.invariant();" and the problem here was that it was a release build? If this is the case I'm fine with the current behavior. I really only care about this sort of thing if asserts are enabled.

Yes, an assert(o !is null) is performed. But it's performed *inside* _d_invariant, which is part of Phobos. And since Phobos is only distributed as a release build, that means the assert is off by default _even if *your* program has asserts enabled_. You need to recompile Phobos to change this behavior. This is bad. Perhaps that assert should just be converted to an "if (!o) _d_assert(__FILE__, __LINE__)" since _d_invariant will (presumably) only be called if the application has assertions enabled?

I think the problem is more that Phobos only ships with a release build rather than that the code is broken. What should probably be the case is that DMD should link phobos.lib if -release is set and link phobosd.lib otherwise. Specifying both -debug and -release... well, I'm not sure what that does so I can't say :-) Sean
Jan 26 2007
parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Sean Kelly wrote:
 Frits van Bommel wrote:
 Yes, an assert(o !is null) is performed. But it's performed *inside* 
 _d_invariant, which is part of Phobos. And since Phobos is only 
 distributed as a release build, that means the assert is off by 
 default _even if *your* program has asserts enabled_. You need to 
 recompile Phobos to change this behavior. This is bad.

 Perhaps that assert should just be converted to an "if (!o) 
 _d_assert(__FILE__, __LINE__)" since _d_invariant will (presumably) 
 only be called if the application has assertions enabled?

I think the problem is more that Phobos only ships with a release build rather than that the code is broken. What should probably be the case is that DMD should link phobos.lib if -release is set and link phobosd.lib otherwise. Specifying both -debug and -release... well, I'm not sure what that does so I can't say :-)

Separate libraries is also an option, of course ;).
Jan 26 2007
prev sibling next sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Walter Bright wrote:
 Stewart Gordon wrote:
 Lionello Lunesu wrote:
 I really think this used to work (like in C++) :

 #class Class {}
 #void main(){
 #    Class c;
 #    assert(c);
 #}

 With 1.0, I get an access violation in 
 _D9invariant12_d_invariantFC6ObjectZv, but why?

For some strange reason, assert on an object reference checks that the invariants are satisfied instead of that the reference isn't null. There's nothing to this effect in the spec, so I don't know how it came about. While it may be useful, it certainly shouldn't do it _instead of_ checking it isn't null.

It does check if it's null. That's how the access violation exception gets thrown.

Access violations are hardware-generated, and not a particularly nice way to detect an error. Especially since no usable file & line information is generated. The invariant checking code also contains "assert(o !is null)" before it does anything else, but that code is in Phobos. And the Phobos libs distributed with DMD seem to be compiled with '-release', stripping that code. And even if it wasn't, the file & line displayed on failure would be Phobos' internal/invariant.d:14 or similar instead of the place the user put an assert(obj).
Jan 24 2007
parent Walter Bright <newshound digitalmars.com> writes:
Frits van Bommel wrote:
 Walter Bright wrote:
 It does check if it's null. That's how the access violation exception 
 gets thrown.

way to detect an error. Especially since no usable file & line information is generated.

If you run it under the debugger, it should pop up with the cursor on where it faulted (line and file). If it doesn't, it's a bug in the debugger or the debug output of the compiler.
Jan 25 2007
prev sibling parent reply Bradley Smith <digitalmars-com baysmith.com> writes:
Walter Bright wrote:
 Stewart Gordon wrote:
 Lionello Lunesu wrote:
 I really think this used to work (like in C++) :

 #class Class {}
 #void main(){
 #    Class c;
 #    assert(c);
 #}

 With 1.0, I get an access violation in 
 _D9invariant12_d_invariantFC6ObjectZv, but why?

For some strange reason, assert on an object reference checks that the invariants are satisfied instead of that the reference isn't null. There's nothing to this effect in the spec, so I don't know how it came about. While it may be useful, it certainly shouldn't do it _instead of_ checking it isn't null. Stewart.

It does check if it's null. That's how the access violation exception gets thrown.

Perhaps this is a better example. import std.stdio; import std.asserterror; class Class {} void main() { Class c; try { version (alt) { assert(false); } assert(c); } catch (AssertError e) { writefln("An assert failed: ", e); } } C:\>dmd assertNull.d c:\dmd\bin\..\..\dm\bin\link.exe assertNull,,,user32+kernel32/noi; C:\>assertNull Error: Access Violation C:\>dmd assertNull.d -version=alt c:\dmd\bin\..\..\dm\bin\link.exe assertNull,,,user32+kernel32/noi; C:\>assertNull An assert failed: AssertError Failure assertNull(7)
Jan 24 2007
parent reply Walter Bright <newshound digitalmars.com> writes:
Bradley Smith wrote:
   } catch (AssertError e) {

You can catch access errors by catching Exception, at least under Windows, because I haven't figured out how to do it under Linux.
Jan 26 2007
next sibling parent reply Bradley Smith <digitalmars-com baysmith.com> writes:
Walter Bright wrote:
 You can catch access errors by catching Exception, at least under 
 Windows, because I haven't figured out how to do it under Linux.

I know. That is not the point. The point is that evaluation of a null reference is inconsistent. For an if statement, null is evaluated as false, but for an assert it is an access violation. See code below. Conceptually, assert (expression) is nothing more that "if (!expression) throw new AssertError;". However, it doesn't act that way. import std.stdio; class Class {} void main() { Class c; if (!c) { writefln("c is false?"); } assert(c); }
Jan 26 2007
parent "Frank Benoit (keinfarbton)" <benoit tionex.removethispart.de> writes:
 Conceptually, assert (expression) is nothing more that "if (!expression)
 throw new AssertError;". However, it doesn't act that way.

I think it is more like if ( expression != 0 ) throw new AssertError; that means .opEquals is called probably on a null reference, and so the segfault is caused. Hm... Or is that what '!' does?
Jan 26 2007
prev sibling parent Sean Kelly <sean f4.ca> writes:
Walter Bright wrote:
 Bradley Smith wrote:
   } catch (AssertError e) {

You can catch access errors by catching Exception, at least under Windows, because I haven't figured out how to do it under Linux.

With Unix you have to set up a signal handler for SIGSEGV. However, I'm not entirely sure whether exceptions can be thrown from within signal handlers. If anyone knows I'd love to hear the answer. Sean
Jan 26 2007