Topic: Invalid pointer values


Author: alfps@start.no (Alf P. Steinbach)
Date: Sun, 9 Oct 2005 07:41:18 GMT
Raw View
Can it be proven from the standard that the following code is Undefined
Behavior, or alternatively, can a convincing half-formal case be made?

#include    <iostream>          // std::cout
#include    <ostream>           // <<, std::endl

int* wrongAnswer()
{
    int x = 43;
    return &x;
}

int main()
{
    int*    p   = wrongAnswer();
    std::cout << *p << std::endl;           // Not necessarily 43...
}

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Sun, 9 Oct 2005 16:10:53 GMT
Raw View
Alf P. Steinbach wrote:
> Can it be proven from the standard that the following code is Undefined
> Behavior, or alternatively, can a convincing half-formal case be made?
>
> #include    <iostream>          // std::cout
> #include    <ostream>           // <<, std::endl
>
> int* wrongAnswer()
> {
>     int x = 43;
>     return &x;
> }
>
> int main()
> {
>     int*    p   = wrongAnswer();
>     std::cout << *p << std::endl;           // Not necessarily 43...
> }
>

If I interpret the standard correctly, the standard specify that this is
UB because of:

3.7.2/1 The storage for [local objects with automatic static duration]
lasts until the block in which they are created exits.

3.8/1 The lifetime of an object of type T ends when [...] the storage
which the object occupies is reused or released.

3.8/3 The properties ascribed to objects throughout this International
Standard apply for a given object only during its lifetime.

So the expression *p would refer to an l-value whose lifetime has ended
but any use of it is not covered by the standard (and that's practically
the definition of UB).

Ganesh

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Peter Dimov" <pdimov@gmail.com>
Date: Sun, 9 Oct 2005 11:11:34 CST
Raw View
Alf P. Steinbach wrote:
> Can it be proven from the standard that the following code is Undefined
> Behavior, or alternatively, can a convincing half-formal case be made?
>
> #include    <iostream>          // std::cout
> #include    <ostream>           // <<, std::endl
>
> int* wrongAnswer()
> {
>     int x = 43;
>     return &x;
> }
>
> int main()
> {
>     int*    p   = wrongAnswer();

Half-formal case: the pointer value that is returned from wrongAnswer
refers to storage that no longer "lasts" (3.7.2/1). This strongly
suggests that this pointer value is invalid.

Pointer values that refer to "deallocated" storage (3.7.3.2/4) are
invalid and "The effect of using an invalid pointer value is undefined
(footnote: On some implementations, it causes a system-generated
runtime fault.)"

>     std::cout << *p << std::endl;           // Not necessarily 43...

90% proven: The lifetime of *p has ended and the lvalue to rvalue
conversion is undefined behavior (3.8/6).

> }

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Greg Herlihy" <greghe@pacbell.net>
Date: Sun, 9 Oct 2005 16:59:21 CST
Raw View
Alf P. Steinbach wrote:
> Can it be proven from the standard that the following code is Undefined
> Behavior, or alternatively, can a convincing half-formal case be made?
>
> #include    <iostream>          // std::cout
> #include    <ostream>           // <<, std::endl
>
> int* wrongAnswer()
> {
>     int x = 43;
>     return &x;
> }
>
> int main()
> {
>     int*    p   = wrongAnswer();
>     std::cout << *p << std::endl;           // Not necessarily 43...
> }

If "the standard" includes the C language standard, then the answer is
unambiguous: "If an object is referred to outside of its
lifetime, the behavior is undefined." 6.2.4/2 (ISO/IEC 9899:TC2). Of
course the sample program is not a C, but a C++ program - but how much
of a difference does that really make? After all, wrongAnswer could
just as easily be a C function, and, name mangling aside, would it
compile any differently in C than in C++?

C++, I believe, retains compatibility with C's memory model, but also
further extends and refines it, adding dynamic allocations of class
types in particular. As a consequence, C's blanket statement about
accesses and object lifetimes and undefined behavior no longer holds in
all cases in C++. But none of the exceptions that the C++ standard
cites (which seem to pertain to only non-POD types) would appear to
have any relevance to the sample program above. So I would conclude
that behavior of the program after deferencing p in the second line of
main, is not defined.

Greg

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kuyper@wizard.net
Date: Mon, 10 Oct 2005 10:31:14 CST
Raw View
Greg Herlihy wrote:
> Alf P. Steinbach wrote:
> > Can it be proven from the standard that the following code is Undefined
> > Behavior, or alternatively, can a convincing half-formal case be made?
> >
> > #include    <iostream>          // std::cout
> > #include    <ostream>           // <<, std::endl
> >
> > int* wrongAnswer()
> > {
> >     int x = 43;
> >     return &x;
> > }
> >
> > int main()
> > {
> >     int*    p   = wrongAnswer();
> >     std::cout << *p << std::endl;           // Not necessarily 43...
> > }
>
> If "the standard" includes the C language standard, then the answer is
> unambiguous: "If an object is referred to outside of its
> lifetime, the behavior is undefined." 6.2.4/2 (ISO/IEC 9899:TC2). Of
> course the sample program is not a C, but a C++ program - but how much
> of a difference does that really make?

A lot. The C++ standard incorporates the C standard by reference, but
not wholesale; only parts of it are so incorporated. The main part so
incorporated is the C standard library, but even there it's
incorporated with modifications that are detailed in section C.2. For
the language itself, the description provided in the C++ standard is
intended to be basically complete; if the C standard says something
that the C++ standard does not, what the C standard says has nothing to
do with what the code means when interpreted by an implementation of
C++.

In this particular case, C++ has chosen a different way of saying this
than the C standard; I won't go into the details, since Peter Dimov has
already provided them.

> ... After all, wrongAnswer could
> just as easily be a C function, and, name mangling aside, would it
> compile any differently in C than in C++?

In general, yes, - see section C.1 of the C++ standard for a list of
differences between the two languages.

Keep in mind that since the behavior of this particular code is
undefined according to either standard, the result of using a C
implementation to translate this code could be the same as the result
of using a C++ implementation; it could also be quite different. In
particular, it could be the same using an implementation of Fortran, or
Lisp, or Java.

> C++, I believe, retains compatibility with C's memory model,

That's essentially true, but it's true only insofar as the C++ standard
actually says so; if you can't find text supporting a given assertion
in the C++ standard, finding relevant text in the C standard merely
serves to point out a difference between the two languages; it doesn't
make that assertion true for programs translated by an implementation
of C++.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]