www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 4595] New: Accessing non-static member of a null reference compiles

reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=4595

           Summary: Accessing non-static member of a null reference
                    compiles
           Product: D
           Version: D2
          Platform: Other
        OS/Version: Windows
            Status: NEW
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: nobody puremagic.com
        ReportedBy: andrej.mitrovich gmail.com



17:02:48 PDT ---
This should not compile, DMD should detect that I'm trying to access a member
of a null reference (stated in TDPL):

class A 
{
    int x = 42;
}

unittest {
    A a;
    a.x = 5;
}

void main() 
{
}

Runtime error:
object.Error: Access Violation

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Aug 07 2010
next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=4595




17:05:41 PDT ---
And an additional example:

class A { int x; }

unittest {
    A a;
    assert(__traits(compiles, a.x = 5));
}

void main() { }

Compiles and runs succesfully. assert should fail.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Aug 07 2010
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=4595


nfxjfg gmail.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
                 CC|                            |nfxjfg gmail.com
         Resolution|                            |INVALID



You're obviously free to cause all access violation you want. dmd never
prevented that, and no non-nullable references feature is planned.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Aug 07 2010
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=4595


bearophile_hugs eml.cc changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |bearophile_hugs eml.cc



You are mostly right nfxjfg, but please don't be harsh with people that use
their time to submit problems in Bugzilla :-)

See enhancement request bug 4571 for a start of a proposal about non-null types
modifier in D. It needs more work, of course.

And even if D will never have non-null references in its type system, DMD is
already able to catch cases like this, if you compile it with -O:

class Foo { int x; }
void main() {
    Foo f;
    f.x = 5;
}


dmd 2.047 doesn't show a run-time sefault, it prints at compile-time:
test.d(4): Error: null dereference in function _Dmain

So adding few more logic to the compiler to catch other common cases of
uninitialized bugs is not inconceivable. The case shown in this bug reports are
well within the capabilities of a short analysis, good lint tools are able to
warn against far more complex cases. So I think this enhancement request should
be reopened.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Aug 07 2010
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=4595





 dmd 2.047 doesn't show a run-time sefault, it prints at compile-time:
 test.d(4): Error: null dereference in function _Dmain
I'd consider that a codegen bug. What if my program's semantics depend on the segfault? -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Aug 07 2010
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=4595


Jonathan M Davis <jmdavisProg gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |jmdavisProg gmail.com



20:37:32 PDT ---
No offense, but relying on a segfault seems rather silly. And if you really
need one, I'm sure that you could easily produce one which the compiler can't
catch (probably all it would take would be a function which returned null being
used to initialize the variable rather than just declaring the variable).

I think that it's perfectly reasonable for dmd to catch simple and obvious
cases where a null reference or pointer is going to be dereferenced. In other

to scream at you if do something like that and force you to initialize the
variable. D goes the route of default initialization to the closest thing to an
error value rather than forcing you to initialize variables before they're
used, but I think that it's perfectly reasonable for the compiler to catch
simple and obvious cases and scream at you about them. I believe that the main
reason that dmd doesn't do it in the general case is because it's too hard for
the compiler to accurately catch more complex cases without making the compiler
much more complex in its code flow analysis (and Walter doesn't want that kind
of complexity).

There's no question that you cannot rely on the compiler to catch all of the
references and pointers that you forgot to initialize, but I see nothing wrong
with it catching some of them.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Aug 07 2010
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=4595


bearophile_hugs eml.cc changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|RESOLVED                    |REOPENED
         Resolution|INVALID                     |
           Severity|normal                      |enhancement



 What if my program's semantics depend on the segfault?
That means relying on undefined or OS/machine-dependant behaviour. You are not programming in D any more. I reopen this, but as enhancement request, because while I don't think that Walter will implement this very soon, it's a legit feature request for a D compiler to catch at compile-time one more case of uninitialized object reference. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Aug 07 2010
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=4595





 That means relying on undefined or OS/machine-dependant behaviour. You are not
 programming in D any more.
Then what is supposed to happen on a null reference access in D according to your opinion? -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Aug 07 2010
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=4595




Generally the D program stops, some things happen deterministically inside the
GC and the D code and the underlying C runtime, some events happen to the
threads of your D code in a partially deterministic way, but then what exactly
happens is specified by the Operating System and Memory Management Unit of your
computer.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Aug 08 2010
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=4595




09:16:57 PDT ---
This is not a feature request. The TDPL specifically states that in *simple*
cases such as these, DMD should flag this as an error. Otherwise if it can't
figure out if it indeed is a null-reference, it will compile and let the user
handle it.

I usually compile with all warnings on. Thanks for the -O trick, bearophile. I
never thought adding optimizations can catch bugs like that. :)

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Aug 08 2010
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=4595




With -O -unittest DMD is already able to catch the first of the two shown cases
(it doesn't catch the case with __traits(compiles, a.x = 5).

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Aug 08 2010
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=4595




See also bug 4906

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Sep 21 2010
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=4595


Andrei Alexandrescu <andrei metalanguage.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |andrei metalanguage.com
            Summary|Accessing non-static member |[tdpl] Accessing non-static
                   |of a null reference         |member of a null reference
                   |compiles                    |compiles



20:20:09 PST ---
Failing unittest in TDPL:

unittest
{
  class A { int x; }
  A a;
  assert(!__traits(compiles, a.x = 5));
}

Such programs must be statically rejected, guaranteed if there's no intervening
flow in between definition and first use. We can work on improving that later,
but for now let's get the obvious case out of the way.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Dec 18 2011
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=4595




12:54:33 PDT ---

 Failing unittest in TDPL:
 
 unittest
 {
   class A { int x; }
   A a;
   assert(!__traits(compiles, a.x = 5));
 }
 
 Such programs must be statically rejected, guaranteed if there's no intervening
 flow in between definition and first use. We can work on improving that later,
 but for now let's get the obvious case out of the way.
After a few years of D use, I actually find the above will create problems. We often use traits like these to check whether something is compilable, even if the object is left uninitialized. For example if you want to check whether method "foo" of object "c" is callable with an int type: static assert(__traits(compiles, c.foo(1))); Making this fail now because of flow analysis could hurt code that does unittesting. I think a runtime exception is sufficient right now, and the OP feature could be part of some specialized flow-analysis tool. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 17 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=4595




---

 After a few years of D use, I actually find the above will create problems. We
 often use traits like these to check whether something is compilable, even if
 the object is left uninitialized. 
Today, code flow analysis for class ctor call (super(...) and this(...)) behaves as follows. class Foo { this(int) {} } class Bar : Foo { this() { static assert(is(typeof(super(0)))); static if (is(typeof(super(0)))) {} // inside typeof(), code flow analysis never works. super(1); // OK static assert(is(typeof(super(0)))); static if (is(typeof(super(0)))) {} // also OK super(2); // Error: multiple constructor call } this(int) { static assert( __traits(compiles, super(1))); // inside __traits(compiles), code flow analysis is enabled. super(1); // Error: multiple constructor call static assert(!__traits(compiles, super(2))); // The _second_ super call makes error. super(3); // Error: multiple constructor call } } This is expected behavior, from my compiler-internal knowledge. - `is(typeof(exp))` tests that the exp has valid type or not. For type calculation, the code flow analysis and its validation result is just unnecessary. - `__traits(compiles, exp)` tests the exact validness of `exp` at there. In other words, `__traits(compiles)` converts the error occurrence on the `exp` semantic analysis to the compile-time boolean value. In there, code flow analysis is enabled, and the errors will be counted normally. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 19 2013
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=4595




03:52:35 PDT ---

 - `is(typeof(exp))` tests that the exp has valid type or not. For type
 calculation, the code flow analysis and its validation result is just
 unnecessary.
 
 - `__traits(compiles, exp)` tests the exact validness of `exp` at there. In
 other words, `__traits(compiles)` converts the error occurrence on the `exp`
 semantic analysis to the compile-time boolean value. In there, code flow
 analysis is enabled, and the errors will be counted normally.
Well that explains why sometimes is(typeof()) works where __traits(compiles) doesn't. But as far as I know none of this is properly documented, and it's probably why people file bugs when a difference in behavior is found. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 19 2013