www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Empty associative array crashes program

reply =?UTF-8?B?Ikx1w61z?= Marques" <luismarques gmail.com> writes:
I added a bug to the database, because the following code results 
in a segfault (DMD v2.062, OS X 10.8.3, 64-bit):

     #!/usr/local/bin/rdmd

      safe:

     void main()
     {
         int[string] a;
         a["foo"] = 0;
         a.remove("foo");
         assert(a != null); // segfault (not exception)
     }

Now I come here for some further clarifications. While it seems 
fairly clear to me that the assert should not crash the program 
with a segmentation fault (at least with  safe), is the assert 
actually true? (Is it even specified by the language if the AA 
can become null again, after removing the last item?)

Second, I didn't test this in other OSes, but assuming the bug is 
reproducible, am I actually the first one to trip on this issue? 
It seems too basic, but I didn't find a duplicate in the bug 
database.

Best regards,
Luís
Apr 01 2013
next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Monday, April 01, 2013 22:32:01 =?UTF-8?B?Ikx1w61z?=.Marques 
<luismarques gmail.com> puremagic.com wrote:
 I added a bug to the database, because the following code results
 in a segfault (DMD v2.062, OS X 10.8.3, 64-bit):
 
 #!/usr/local/bin/rdmd
 
  safe:
 
 void main()
 {
 int[string] a;
 a["foo"] = 0;
 a.remove("foo");
 assert(a != null); // segfault (not exception)
 }
 
 Now I come here for some further clarifications. While it seems
 fairly clear to me that the assert should not crash the program
 with a segmentation fault (at least with  safe), is the assert
 actually true? (Is it even specified by the language if the AA
 can become null again, after removing the last item?)
 
 Second, I didn't test this in other OSes, but assuming the bug is
 reproducible, am I actually the first one to trip on this issue?
 It seems too basic, but I didn't find a duplicate in the bug
 database.

The problem is that you're using != with null. Don't do that. If you want to check whether something is null, use the is operator: assert(a !is null); If you use == or !=, it's going to do compare the objects, not their pointers/references, and in the case of an AA, that means that it's going to dereference them both and compare their contents. And since null is well, null, dereferencing it results in a segfault. If you try and compare objects with null with ==, you get an error. The compiler should probably do the same with AAs but apparently doesn't. So, if there's a bug, it's the fact that the compiler allows the comparison in the first place. Otherwise, there's no bug here. - Jonathan M Davis
Apr 01 2013
prev sibling next sibling parent =?UTF-8?B?Ikx1w61z?= Marques" <luismarques gmail.com> writes:
Oops, I knew that but totally forgot --;;
I shouldn't spend so much time without using D *shame*

Thanks!
Apr 01 2013
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 01 Apr 2013 19:12:52 -0400, Jonathan M Davis <jmdavisProg gmx.com>  
wrote:

 On Monday, April 01, 2013 22:32:01 =?UTF-8?B?Ikx1w61z?=.Marques
 <luismarques gmail.com> puremagic.com wrote:
 I added a bug to the database, because the following code results
 in a segfault (DMD v2.062, OS X 10.8.3, 64-bit):

 #!/usr/local/bin/rdmd

  safe:

 void main()
 {
 int[string] a;
 a["foo"] = 0;
 a.remove("foo");
 assert(a != null); // segfault (not exception)
 }

 Now I come here for some further clarifications. While it seems
 fairly clear to me that the assert should not crash the program
 with a segmentation fault (at least with  safe), is the assert
 actually true? (Is it even specified by the language if the AA
 can become null again, after removing the last item?)

 Second, I didn't test this in other OSes, but assuming the bug is
 reproducible, am I actually the first one to trip on this issue?
 It seems too basic, but I didn't find a duplicate in the bug
 database.

The problem is that you're using != with null. Don't do that. If you want to check whether something is null, use the is operator: assert(a !is null); If you use == or !=, it's going to do compare the objects, not their pointers/references, and in the case of an AA, that means that it's going to dereference them both and compare their contents. And since null is well, null, dereferencing it results in a segfault. If you try and compare objects with null with ==, you get an error. The compiler should probably do the same with AAs but apparently doesn't. So, if there's a bug, it's the fact that the compiler allows the comparison in the first place. Otherwise, there's no bug here.

No, AA's are not classes (which BTW have had that problem fixed), they are pImpl structs. The equals operator should check for null before comparing the contents. It is a valid bug. -Steve
Apr 01 2013
prev sibling next sibling parent =?UTF-8?B?Ikx1w61z?= Marques" <luismarques gmail.com> writes:
On Monday, 1 April 2013 at 23:56:08 UTC, Steven Schveighoffer 
wrote:
 No, AA's are not classes (which BTW have had that problem 
 fixed), they are pImpl structs.  The equals operator should 
 check for null before comparing the contents.  It is a valid 
 bug.

Baah, I had already closed the bug while cowering in shame! ;-)
Apr 01 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Luís Marques:

 Baah, I had already closed the bug while cowering in shame! ;-)

Don't be ashamed for mistakes like this. Bye, bearophile
Apr 01 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Apr 02, 2013 at 01:57:14AM +0200, digitalmars-d-bounces puremagic.com
wrote:
 On Monday, 1 April 2013 at 23:56:08 UTC, Steven Schveighoffer wrote:
No, AA's are not classes (which BTW have had that problem fixed),
they are pImpl structs.  The equals operator should check for null
before comparing the contents.  It is a valid bug.

Baah, I had already closed the bug while cowering in shame! ;-)

So reopen it. T -- Spaghetti code may be tangly, but lasagna code is just cheesy.
Apr 01 2013
prev sibling next sibling parent =?UTF-8?B?Ikx1w61z?= Marques" <luismarques gmail.com> writes:
On Tuesday, 2 April 2013 at 00:10:51 UTC, H. S. Teoh wrote:
 So reopen it.

bearophile already did. I just wanted the dust to settle, to see if there was consensus about it being a bug.
Apr 01 2013
prev sibling next sibling parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Monday, 1 April 2013 at 23:56:08 UTC, Steven Schveighoffer 
wrote:
 No, AA's are not classes (which BTW have had that problem 
 fixed), they are pImpl structs.  The equals operator should 
 check for null before comparing the contents.  It is a valid 
 bug.

 -Steve

This argument can be applied to classes too. I think it would be better to reject such code like in case with classes.
Apr 01 2013
prev sibling next sibling parent Timothee Cour <thelastmammoth gmail.com> writes:
can we officially use

assert(a);

instead of

assert(a !is null);

(likewise with if(...))

It seems to compile and work just fine, and is shorter.
Apr 01 2013
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Monday, April 01, 2013 23:44:43 Timothee Cour wrote:
 can we officially use
 
 assert(a);
 
 instead of
 
 assert(a !is null);
 
 (likewise with if(...))
 
 It seems to compile and work just fine, and is shorter.

That depends on what a is. If it's an AA as in the OP, then yes, they should be the same. The same goes for a pointers to built-in types and arrays, but for classes and pointers to structs, assert(a) checks for null and then calls the class' invariant rather than just checking for null. However, the invariant does not get called for if statements. - Jonathan M Davis
Apr 02 2013
prev sibling next sibling parent Timothee Cour <thelastmammoth gmail.com> writes:
thanks I didn't know... must've been buried in the specs somewhere...

On Tue, Apr 2, 2013 at 12:10 AM, Jonathan M Davis <jmdavisProg gmx.com> wrote:
 On Monday, April 01, 2013 23:44:43 Timothee Cour wrote:
 can we officially use

 assert(a);

 instead of

 assert(a !is null);

 (likewise with if(...))

 It seems to compile and work just fine, and is shorter.

That depends on what a is. If it's an AA as in the OP, then yes, they should be the same. The same goes for a pointers to built-in types and arrays, but for classes and pointers to structs, assert(a) checks for null and then calls the class' invariant rather than just checking for null. However, the invariant does not get called for if statements. - Jonathan M Davis

Apr 02 2013
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 02 Apr 2013 01:22:26 -0400, Maxim Fomin <maxim maxim-fomin.ru>  
wrote:

 On Monday, 1 April 2013 at 23:56:08 UTC, Steven Schveighoffer wrote:
 No, AA's are not classes (which BTW have had that problem fixed), they  
 are pImpl structs.  The equals operator should check for null before  
 comparing the contents.  It is a valid bug.

 -Steve

This argument can be applied to classes too. I think it would be better to reject such code like in case with classes.

If you are saying you think AA's should reject the code when comparing to null, then I don't agree. An AA is a struct, and a struct lives on the stack. It would be near impossible to make this work without arbitrary compiler help, and I don't see a reason to specifically add this. It's just as easy to check for null in opEquals. With classes there was NO way to intercept the comparison before the dereference, so the banning of == null was warranted (that situation has changed now that opEquals is a global runtime function, so this requirement is somewhat moot). -Steve
Apr 02 2013