f



Invalid pointer dereference, or not?

Hi all,

I was quite baffled to see this (simplified) program run without
segfaults, and without valgrind complaining about invalid memory
reads.

<code>
#include <iostream>

using namespace std;

class A
{
public:
  A() { cout << "A()" << endl; }
  ~A() { cout << "~A()" << endl; }
  void print() const { cout << "Hello World" << endl; }
};

int main()
{
  A* a;
  a->print();   // Should segfault, shouldn't it?
  a = new A();
  a->print();
  delete a;
  a->print();   // Should segfault, shouldn't it?
  return 0;
}
</code>

Is this valid/correct C++? Any ideas?


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

0
loose (8)
4/18/2007 8:56:52 AM
comp.lang.c++.moderated 10738 articles. 1 followers. allnor (8509) is leader. Post Follow

9 Replies
465 Views

Similar Articles

[PageSpeed] 37

Hi

loose AT astron DOT nl wrote:
> int main()
> {
>   A* a;
>   a->print();   // Should segfault, shouldn't it?
>   a = new A();
>   a->print();
>   delete a;
>   a->print();   // Should segfault, shouldn't it?
>   return 0;
> }
> </code>
> 
> Is this valid/correct C++? Any ideas?

It is not valid, it invokes undefined behavior, but it will _likely_ not 
produce any errors. This is because the this pointer will probably be 
passed to the function "A::print()", but it will never be used for 
anything (because you do not access any members of A). As you never 
dereference the garbage pointer (other than calling print on it), 
neither will the program crash nor will valgrind be able to find any 
memory access errors.

But as I said, it's all undefined behavior, so it might just as well 
crash at any  time.

Markus

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

0
Markus
4/18/2007 10:46:00 AM
loose AT astron DOT nl <loose@astron.nl> writes:

> I was quite baffled to see this (simplified) program run without
> segfaults, and without valgrind complaining about invalid memory
> reads.

There is no invalid memory read that valgrind and similar tools could
detect.


> <code>
> #include <iostream>
>
> using namespace std;
>
> class A
> {
> public:
>   A() { cout << "A()" << endl; }
>   ~A() { cout << "~A()" << endl; }
>   void print() const { cout << "Hello World" << endl; }
> };
>
> int main()
> {
>   A* a;
>   a->print();   // Should segfault, shouldn't it?

The ISO C++ Standard doesn't define what a segmentation fault is and
when it should happen. What it does mention is "undefined behavior",
and reading an uninitialized variable is one of the situations that
cause a program to have undefined behavior.

What that means for a particular execution of the program is, well,
undefined. The program may seem to work, it can crash, the computer
can catch fire, etc.


>   a = new A();
>   a->print();
>   delete a;
>   a->print();   // Should segfault, shouldn't it?

Same thing here.


>   return 0;
> }
> </code>
>
> Is this valid/correct C++?

No.

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

0
Thomas
4/18/2007 10:46:10 AM
loose AT astron DOT nl wrote:
> Hi all,
> 
> I was quite baffled to see this (simplified) program run without
> segfaults, and without valgrind complaining about invalid memory
> reads.
> 
> <code>
> #include <iostream>
> 
> using namespace std;
> 
> class A
> {
> public:
>   A() { cout << "A()" << endl; }
>   ~A() { cout << "~A()" << endl; }
>   void print() const { cout << "Hello World" << endl; }
> };
> 
> int main()
> {
>   A* a;
>   a->print();   // Should segfault, shouldn't it?

Undefined behavior; in this case, it doesn't need to
dereference a (print is non-virtual), so it may well
"work" without generating an error.  A good compiler
could issue a diagnostic for this at compile time.

>   a = new A();
>   a->print();
>   delete a;
>   a->print();   // Should segfault, shouldn't it?

Undefined behavior; again, likely to "just work" but
it's allowed to do anything at all, including causing
a signal to be raised.

>   return 0;
> }
> </code>
> 
> Is this valid/correct C++? Any ideas?

No, it is not valid.  But no diagnostic is required,
either at compile time or runtime -- and some bad
libraries (such as MFC) rely on a compiler allowing
such poor code.

-- James

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

0
James
4/18/2007 10:46:23 AM
loose AT astron DOT nl <loose@astron.nl> wrote:
> int main()
> {
>   A* a;
>   a->print();   // Should segfault, shouldn't it?

I don't think there is anywhere in the C++ standard that it says in a given
scenario the program should segfault.

I believe the language rule that applies to this code is from section
9.3.1/2: "If a non-static member function of a class X is called for an
object that is not of type X, or of a type derived from X, the behavior is
undefined."

If the behavior is undefined that mean it may call A::print or core dump or
anything else. Its not defined and should not be relied to happen in any
given way.

-- 
--------------------
Ivan Novick
http://www.0x4849.net

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

0
ivan
4/18/2007 10:52:43 AM
loose AT astron DOT nl <loose@astron.nl> wrote:
> I was quite baffled to see this (simplified) program run without
> segfaults, and without valgrind complaining about invalid memory
> reads.
> 
> <code>
> #include <iostream>
> 
> using namespace std;
> 
> class A
> {
> public:
>  A() { cout << "A()" << endl; }
>  ~A() { cout << "~A()" << endl; }
>  void print() const { cout << "Hello World" << endl; }
> };
> 
> int main()
> {
>  A* a;
>  a->print();   // Should segfault, shouldn't it?
>  a = new A();
>  a->print();
>  delete a;
>  a->print();   // Should segfault, shouldn't it?
>  return 0;
> }
> </code>
> 
> Is this valid/correct C++? Any ideas?

No, your program has undefined behavior.  Since print() does not access
the "this" pointer of your A object, it appears to work.  However, if
you were to add a data member to A and try to access it in your
function, you most likely will get an error.  Do not rely on this
behavior, i.e., do not use pointers that do not point to a valid object.

-- 
Marcus Kwok
Replace 'invalid' with 'net' to reply

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

0
ricecake
4/18/2007 10:54:25 AM
loose AT astron DOT nl wrote:
> Hi all,
> 
> I was quite baffled to see this (simplified) program run without
> segfaults, and without valgrind complaining about invalid memory
> reads.
> 
> <code>
> #include <iostream>
> 
> using namespace std;
> 
> class A
> {
> public:
>   A() { cout << "A()" << endl; }
>   ~A() { cout << "~A()" << endl; }
>   void print() const { cout << "Hello World" << endl; }
> };
> 
> int main()
> {
>   A* a;
>   a->print();   // Should segfault, shouldn't it?

No. not necessarily.  You have undefined behavior.  UB can be anything, 
including performing "as expected" (whatever that is), segfaulting, 
reformatting your hard drive, calling NORAD and starting WWIII, or even 
killing the crew and locking the pod bay doors.

>   a = new A();
>   a->print();
>   delete a;
>   a->print();   // Should segfault, shouldn't it?

No. UB.  See above.

>   return 0;
> }
> </code>
> 
> Is this valid/correct C++? Any ideas?
It is syntactically correct C++. However, the program exhibits undefined 
behavior.

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

0
red
4/18/2007 11:06:39 AM
loose AT astron DOT nl wrote:

> class A
> {
> public:
>   A() { cout << "A()" << endl; }
>   ~A() { cout << "~A()" << endl; }
>   void print() const { cout << "Hello World" << endl; }
> };
> 
> int main()
> {
>   A* a;
>   a->print();   // Should segfault, shouldn't it?

Why should it? OK, you're calling the print method on a null pointer and
print is not a virtual method, OTOH, nothing in the print method references
anything in the object itself, so, no harm done...

>   a = new A();
>   a->print();
>   delete a;
>   a->print();   // Should segfault, shouldn't it?

Same thing...

> Is this valid/correct C++? Any ideas?

I'm unsure about a->x() on A* a = null. Although I can imagine that the
compiler does not do runtime checks so that might be the reason it passes.
So valid, yes, correct, looks like it. OTOH I can guarantee you it won't
keep working as soon as you make class A non-trivial... for example:

        class A
        {
        public:
          A() {}
          ~A() {}
          void print() const {cout << a << endl;}
        
        private:
          string a;
        };
        

-- 
Ruurd


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

0
R
4/18/2007 11:06:55 AM
loose AT astron DOT nl wrote:

> I was quite baffled to see this (simplified) program run without
> segfaults, and without valgrind complaining about invalid memory
> reads.
> 
> <code>
> #include <iostream>
> 
> using namespace std;
> 
> class A
> {
> public:
>   A() { cout << "A()" << endl; }
>   ~A() { cout << "~A()" << endl; }
>   void print() const { cout << "Hello World" << endl; }
> };
> 
> int main()
> {
>   A* a;
>   a->print();   // Should segfault, shouldn't it?

No, undefined behaviour. Note that "undefined" also includes that it 
might work fine.

>   a = new A();
>   a->print();
>   delete a;
>   a->print();   // Should segfault, shouldn't it?

No, see above. Undefined.

>   return 0;
> }
> </code>
> 
> Is this valid/correct C++? 

Definitely not. The reason why "it seems to work" is likely because
the "this" pointer is not required for the method print, thus the
code doesn't deference it. Note, however, that on a different compiler
the results might be different, and you cannot depend on what exactly
happens here. It's, as said, undefined.

So long,
	Thomas

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

0
Thomas
4/18/2007 11:09:50 AM
loose AT astron DOT nl wrote:
> I was quite baffled to see this (simplified) program run without
> segfaults, and without valgrind complaining about invalid memory
> reads.
>
> <code>
> #include <iostream>
>
> using namespace std;
>
> class A
> {
> public:
>  A() { cout << "A()" << endl; }
>  ~A() { cout << "~A()" << endl; }
>  void print() const { cout << "Hello World" << endl; }
> };
>
> int main()
> {
>  A* a;
>  a->print();   // Should segfault, shouldn't it?
>  a = new A();
>  a->print();
>  delete a;
>  a->print();   // Should segfault, shouldn't it?
>  return 0;
> }
> </code>
>
> Is this valid/correct C++? Any ideas?

The code is valid (well-formed), but has undefined behaviour.

As for why it doesn't segfault (whatever that means to you), there
is no requirement to do anything specific as far as undefined
behaivour goes.

Now, if I were to speculate as to why the program can actually run
(just like somebody might expect), the explanation is relatively
simple: the 'print' member function makes no attempt to access any
member data (there is no member data to access, actually), so no
dereferencing of the invalid pointer 'a' is actually performed.
But that's happening only on your system.  There is no guarantee
that the same behaviour would be observed on any other system, and
that's why the behaviour cannot be defined one way or another.

V
-- 
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask



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

0
Victor
4/18/2007 2:23:30 PM
Reply: