C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Why is NULL->foo() working?
Goto page 1, 2  Next
 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
vl106
Guest





PostPosted: Sun Oct 03, 2004 2:41 am    Post subject: Why is NULL->foo() working? Reply with quote



Again my compiler took me by surprise. The following code did
*not* lead to an access violation (complete listing at bottom):

C* pC = 0;
pC->getD ();

Looking at the assembly code I understand that member functions
(somewhat mangled) are global functions and actually don't
invoke the instance pointer at all:

// class C* pC = 0;
00416E5E mov dword ptr [pC],0

// D* pD = pC->getD ();
00416E65 mov ecx,dword ptr [pC]
00416E68 call C::getD (415A96h)
00416E6D mov dword ptr [pD],eax

Why do compilers (both MSVC and g++) allow such an invocation?
Is this specified in any way?

Thanks for your help.


// PtrTest.cpp

#include <iostream>

class D;

class C {
public:
D* getD () const;
};

D* C::getD () const {
if (0 == this)
std::cout << "I don't exist!" << std::endl;
else
std::cout << "I do exist!" << std::endl;
return (0);
}

class D {
private:
int d_;
};

int main () {
C* pC = 0;
D* pD = pC->getD (); // WORKS!
return (0);
}



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Balog Pal
Guest





PostPosted: Sun Oct 03, 2004 10:31 am    Post subject: Re: Why is NULL->foo() working? Reply with quote



"vl106" <vl106 (AT) hotmail (DOT) com> wrote


Quote:
Again my compiler took me by surprise. The following code did
*not* lead to an access violation (complete listing at bottom):

C* pC = 0;
pC->getD ();

Here you dereference a null pointer -- behavior is undefined from here.
Whatever could happen, on your particular run that whatever is just calling
getD and it runs. On some other run you could cee some other behavior. If
getD actually read or wrote instance data, or it was a virtual function
you'd get access violation with high chance, but whatever you actually see
doesn;t really count, UB is UB.

Quote:
Why do compilers (both MSVC and g++) allow such an invocation?

Why wouldn't it? It is the programmer's responsibility to use pointers by
the rules, never use an invalid pointer, and never dereference the special
valid pointers he shouldn't.

The compiler could detect your actual case, but what would be the point
besides showing off? In real practice it can't tell what value the pointer
will have at runtime, and you get the value from some other function ot use
as param.

Quote:
D* C::getD () const {
if (0 == this)
std::cout << "I don't exist!" << std::endl;

That is a pointless check. this can not be 0 unless you already invoked UB
in the program. So the compiler is allowed to treat the test as always
false. Just like checking the address of a reference.

Paul



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Ruslan Abdikeev
Guest





PostPosted: Sun Oct 03, 2004 10:32 am    Post subject: Re: Why is NULL->foo() working? Reply with quote



"vl106" <vl106 (AT) hotmail (DOT) com> wrote

Quote:
Again my compiler took me by surprise. The following code did
*not* lead to an access violation (complete listing at bottom):

C* pC = 0;
pC->getD ();

This code causes an undefined behaviour.
Undefined behaviour is undefined - it may work as excepted, it may fail to
work, it may even format your harddrive.

Quote:
Why do compilers (both MSVC and g++) allow such an invocation?
Is this specified in any way?

Yes. It is said that "foo->bar()" is equivalent of "(*foo).bar()", and
dereferencing a null pointer is an undefined behaviour.

Hope it helps,
Ruslan Abdikeev.



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
David
Guest





PostPosted: Sun Oct 03, 2004 10:33 am    Post subject: Re: Why is NULL->foo() working? Reply with quote

This 'works' because of how your particular implementation works.
Presumably C::getD() is called with the object pointer (0) as a
value. Since C::getD() doesn't contain any memory references
based on the (0) object address, no exception occurs.

A more realistic example with a more complicated class would
fail. There are probably times when the about code could fail.
For instance, if C::getD() was a virtual method and looked up
as part of a vtable, that lookup would cause an exception.

David

On Sun, 3 Oct 2004 02:41:17 UTC, "vl106" <vl106 (AT) hotmail (DOT) com> wrote:

Quote:
Again my compiler took me by surprise. The following code did
*not* lead to an access violation (complete listing at bottom):

C* pC = 0;
pC->getD ();

Looking at the assembly code I understand that member functions
(somewhat mangled) are global functions and actually don't
invoke the instance pointer at all:

// class C* pC = 0;
00416E5E mov dword ptr [pC],0

// D* pD = pC->getD ();
00416E65 mov ecx,dword ptr [pC]
00416E68 call C::getD (415A96h)
00416E6D mov dword ptr [pD],eax

Why do compilers (both MSVC and g++) allow such an invocation?
Is this specified in any way?

Thanks for your help.


// PtrTest.cpp

#include <iostream

class D;

class C {
public:
D* getD () const;
};

D* C::getD () const {
if (0 == this)
std::cout << "I don't exist!" << std::endl;
else
std::cout << "I do exist!" << std::endl;
return (0);
}

class D {
private:
int d_;
};

int main () {
C* pC = 0;
D* pD = pC->getD (); // WORKS!
return (0);
}

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Alberto Barbati
Guest





PostPosted: Sun Oct 03, 2004 1:11 pm    Post subject: Re: Why is NULL->foo() working? Reply with quote

vl106 wrote:
Quote:

Why do compilers (both MSVC and g++) allow such an invocation?
Is this specified in any way?

It's specified: it's unspecified behaviour Wink. Anything can happen in

this case, including that it works or that it reformats your HD.

Anyway why should a compiler disallow the invocation? As the pointer
value may only be known at runtime, you would need a runtime check on
every member function call and that would impact the performances.

If you are suggesting that, in your specific example, the compiler knows
at compile time that the pointer is null and so it should reject the
code upon such knowledge, I would say that you are asking too much to
the compiler, IMHO. There are static code analyzers that may detect
these kind of issues, if you're interested.

Regards,

Alberto

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Antoun Kanawati
Guest





PostPosted: Mon Oct 04, 2004 5:57 am    Post subject: Re: Why is NULL->foo() working? Reply with quote

vl106 wrote:
Quote:
Again my compiler took me by surprise. The following code did
*not* lead to an access violation (complete listing at bottom):

C* pC = 0;
pC->getD ();

Looking at the assembly code I understand that member functions
(somewhat mangled) are global functions and actually don't
invoke the instance pointer at all:
....

Yes, that is generally the case for non-virtual functions: the compiler
knows precisely which function to call at compile time, and need not
access the object state to call the function, effectively reducing
the non-virtual call p->foo() to something like foo__mangled(p).
Of course, as soon as you attempt to access the state of the object
during such an invocation, your program will do something bad.

A long time ago, before we had static functions in C++, some
people used this "trick" to implement the concept of static
member functions.

This does not work for virtual functions; in the simplest form,
a virtual call p->vmf() is equivalent to something like
(*(p->_vtbl[vmf_index]))(p), i.e.: requires access to the object
state to locate the function pointer, which requires that the
pointer be valid, and that the pointed-to object also be valid.

Speaking pedantically, the behavior is "undefined", which means: if
you do it, you're on your own; your compiler and runtime need not
bother detcting it, it may or may not fail, and when it fails
the failure may or may not be observable/detectable/catchable etc...

To get an idea of how these things work, it's a good idea to read
"The C++ Object Model" (Lippmann, if I recall correctly). Back in
the old days, we had 'cfront', and we could look at the C code and
figure out exactly what was going on. I don't know whether Cfront
is still around.
--
A. Kanawati
[email]NO.antounk.SPAM (AT) comcast (DOT) net[/email]

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
vl106
Guest





PostPosted: Mon Oct 04, 2004 6:00 am    Post subject: Re: Why is NULL->foo() working? Reply with quote

Thanks for your help. This is actually what I expected. I was just taken by
surprise because a check like
if(this == NULL) ...
is included in the MFC source code. So MS in the MFC is strongly relying
on the UB of its compiler ;-)

"Balog Pal" <pasa (AT) lib (DOT) hu> wrote

Quote:
"vl106" <vl106 (AT) hotmail (DOT) com> wrote in message
news:415ed593$0$11983$9b622d9e (AT) news (DOT) freenet.de...

Again my compiler took me by surprise. The following code did
*not* lead to an access violation (complete listing at bottom):

C* pC = 0;
pC->getD ();

Here you dereference a null pointer -- behavior is undefined from here.
Whatever could happen, on your particular run that whatever is just
calling
getD and it runs. On some other run you could cee some other behavior. If
getD actually read or wrote instance data, or it was a virtual function
you'd get access violation with high chance, but whatever you actually see
doesn;t really count, UB is UB.

Why do compilers (both MSVC and g++) allow such an invocation?

Why wouldn't it? It is the programmer's responsibility to use pointers by
the rules, never use an invalid pointer, and never dereference the special
valid pointers he shouldn't.

The compiler could detect your actual case, but what would be the point
besides showing off? In real practice it can't tell what value the pointer
will have at runtime, and you get the value from some other function ot
use
as param.

D* C::getD () const {
if (0 == this)
std::cout << "I don't exist!" << std::endl;

That is a pointless check. this can not be 0 unless you already invoked UB
in the program. So the compiler is allowed to treat the test as always
false. Just like checking the address of a reference.



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Chris Theis
Guest





PostPosted: Mon Oct 04, 2004 6:05 pm    Post subject: Re: Why is NULL->foo() working? Reply with quote


"vl106" <vl106 (AT) hotmail (DOT) com> schrieb im Newsbeitrag
news:4160411b$0$18985$9b622d9e (AT) news (DOT) freenet.de...
Quote:
Thanks for your help. This is actually what I expected. I was just taken
by
surprise because a check like
if(this == NULL) ...
is included in the MFC source code. So MS in the MFC is strongly relying
on the UB of its compiler ;-)


It's undefined by the means of the standard. However, they should know what
it is doing, although the practice naturally remains arguable.

Cheers
Chris



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Tokyo Tomy
Guest





PostPosted: Mon Oct 04, 2004 6:05 pm    Post subject: Re: Why is NULL->foo() working? Reply with quote

"vl106" <vl106 (AT) hotmail (DOT) com> wrote

Quote:
Again my compiler took me by surprise. The following code did
*not* lead to an access violation (complete listing at bottom):

C* pC = 0;
pC->getD ();

...

The problem is whether this code causes a undefined behavior or not.
Ruslan Abdikeev, Paul, and Alberto argue that the behavior is
undefined. David say that it is defined.

I am on the side of David. The pointer has a singular value, but its
behavior of the pointer is specified.
C* pC = 0; // C*pC = (C*)0;
pC->getD ();b// ok

Since there is no instance at the address 0, use of data members and
vtable causes a run-time error at best or a destructive behavior at
worst depending on your complier and your enviroment: the behavior of
the pointer is defined, but the result of the behavior is destructive
in the case of using data member or vtable.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Frank Birbacher
Guest





PostPosted: Mon Oct 04, 2004 6:07 pm    Post subject: Re: Why is NULL->foo() working? Reply with quote

Hi!

vl106 wrote:
Quote:
Thanks for your help. This is actually what I expected. I was just taken by
surprise because a check like
if(this == NULL) ...
is included in the MFC source code. So MS in the MFC is strongly relying
on the UB of its compiler Wink

yeah, haha, not a good example to teach C++ Smile
Of course MS wrote their own compiler and may have extended its
behaviour as they like. If they defined NULL->foo(), they can
rely on it.

Frank


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Craig Henderson
Guest





PostPosted: Mon Oct 04, 2004 6:20 pm    Post subject: Re: Why is NULL->foo() working? Reply with quote


"vl106" <vl106 (AT) hotmail (DOT) com> wrote

Quote:
Thanks for your help. This is actually what I expected. I was just taken
by
surprise because a check like
if(this == NULL) ...
is included in the MFC source code. So MS in the MFC is strongly relying
on the UB of its compiler ;-)


UB is in respect of the Standard. In MFC, MS are exploiting their knowledge
of how the compiler is implemented. It is no longer undefined behaviour, MS
have defined their implementation of the Standard's UB, and now use that.

Craig



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Bronek Kozicki
Guest





PostPosted: Mon Oct 04, 2004 7:22 pm    Post subject: Re: Why is NULL->foo() working? Reply with quote

vl106 wrote:
Quote:
Thanks for your help. This is actually what I expected. I was just
taken by surprise because a check like
if(this == NULL) ...
is included in the MFC source code. So MS in the MFC is strongly
relying
on the UB of its compiler Wink

Undefined behaviour actually can be defined by implementation, however
it makes code extremely nonportable and fragile. Above code is one of
many reasons why I strongly discourage others (especially novices) from
using MFC


B.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Balog Pal
Guest





PostPosted: Tue Oct 05, 2004 6:07 am    Post subject: Re: Why is NULL->foo() working? Reply with quote

"Tokyo Tomy" <hosoda (AT) jtec (DOT) or.jp> wrote


Quote:
C* pC = 0;
pC->getD ();
The problem is whether this code causes a undefined behavior or not.
Ruslan Abdikeev, Paul, and Alberto argue that the behavior is
undefined. David say that it is defined.

I couldn't find in David's post saying it is defined. In standard terms
the others were speaking about. He described whay is likely happens on the
particular implementation.

Quote:
I am on the side of David. The pointer has a singular value, but its
behavior of the pointer is specified.
C* pC = 0; // C*pC = (C*)0;

Thi shall initialise object pC with a null poiner value for type C*.

Quote:
pC->getD ();b// ok

This shall dereference the null pointer value for what no behavior is
defined in the standard. (And it's even mentioned explicitelty.)

Quote:
Since there is no instance at the address 0, use of data members and
vtable causes a run-time error at best or a destructive behavior at
worst depending on your complier and your enviroment: the behavior of
the pointer is defined

What do you mean by behavior of the pointer? A pointer is just a pointer.

What is undefined here is the outcome of operator -> used with the actual
value of the pointer (which will be null). The standard only defines
behavior if the pointer is valid and points to an object (ie. is not null
and not points one past end of an array).

If you disagree please refer the relevant parts of the standard.

Paul



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Tokyo Tomy
Guest





PostPosted: Tue Oct 05, 2004 6:08 am    Post subject: Re: Why is NULL->foo() working? Reply with quote

[email]hosoda (AT) jtec (DOT) or.jp[/email] (Tokyo Tomy) wrote in message news:<49c1da0b.0410032143.48c5d05e (AT) posting (DOT) google.com>...
Quote:
"vl106" <vl106 (AT) hotmail (DOT) com> wrote

Again my compiler took me by surprise. The following code did
*not* lead to an access violation (complete listing at bottom):

C* pC = 0;
pC->getD ();

...

The problem is whether this code causes a undefined behavior or not.
Ruslan Abdikeev, Paul, and Alberto argue that the behavior is
undefined. David say that it is defined.

I am on the side of David. The pointer has a singular value, but its
behavior of the pointer is specified.
C* pC = 0; // C*pC = (C*)0;
pC->getD ();b// ok

Since there is no instance at the address 0, use of data members and
vtable causes a run-time error at best or a destructive behavior at
worst depending on your complier and your enviroment: the behavior of
the pointer is defined, but the result of the behavior is destructive
in the case of using data member or vtable.
....

I failed to withdraw my previous post. Please forget about it. It
included an fatal error.

Tokyo Tomy

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Balog Pal
Guest





PostPosted: Tue Oct 05, 2004 6:08 am    Post subject: Re: Why is NULL->foo() working? Reply with quote

"Bronek Kozicki" <brok (AT) rubikon (DOT) pl> wrote


Quote:
vl106 wrote:
Thanks for your help. This is actually what I expected. I was just
taken by surprise because a check like
if(this == NULL) ...
is included in the MFC source code. So MS in the MFC is strongly
relying
on the UB of its compiler ;-)

Undefined behaviour actually can be defined by implementation,

Yes. For the particular example I couldn't locate any kind of documentation
in the MSDN. So MFC, which can be treated as part of the implementation may
use it for good, but MSVC user is better not think much about it. As the
behavior can be changed say in the next release or patch of the compiler.
(Without ntice on observable behavior if MFC is modified in sync.)

Quote:
however it makes code extremely nonportable and fragile.

Yeah, I once dragged the CList to a hitachi platform and it fall flat.
Until I discovered it uses the above thing, and calls member of CNode on a
null pointer sometimes. For no really good reason too. :-(

Quote:
Above code is one of
many reasons why I strongly discourage others (especially novices) from
using MFC

But this argument is strange -- use of the MFC mean you use the public
interface of classes. Not reading the implementation code, especially to
learn good coding practices.

The design of MFC has a plenty of problems (most inherited from 1.0 in
effort to keep compatibility) but that is another story.

Paul



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.