Topic: Adding 0 to the null pointer


Author: =?ISO-8859-1?Q?Joaqu=EDn_M_L=F3pez_Mu=F1oz?= <joaquin@tid.es>
Date: Tue, 26 May 2009 10:37:43 CST
Raw View
Hello,

Is the following a legal C++ program (note we're passing 0 as
the third argument to std::copy)?

   #include <algorithm>

   int main()
   {
     int x,*p=&x;
     std::copy(p,p,(int*)0);
   }

The (C++03) standard does not say whether result in
std::copy(first,last,result)  must be a valid pointer, and only
states that the algorithm returns result+ (last-first), which in
our particular case (first==last) is result+0. Regarding this
latter expression, 5.7/8 [expr.add] says:

   "If the value 0 is added to or subtracted from a pointer value,
   the result compares equal to the original pointer value [...]"

without regard to whether the pointer being added or
subtracted 0 is the null pointer or not. So, it seems to me that
result+0 is indeed valid and yields result, i.e. the null value of
int*.

To summarize, I think the program above is indeed valid, but
some stdlib implementers dissent: the implementation of
std::copy for MSVC 9.0 has roughly the following checking code
(when parameter debugging is activated):

   _DEBUG_RANGE(first, last);
   if (first != last)
     _DEBUG_POINTER(result);

which accepts the program above as valid, whereas the
implementer changed her mind in MSVC 10.0 and modified
the checking code as

   _DEBUG_RANGE(first, last);
   _DEBUG_POINTER(result);

where  _DEBUG_POINTER triggers and assertion when
result is a null pointer, thus failing on the program above.

So, who's right, I (and MSVC 9.0) or MSVC 10.0?

Thank you,

Joaqu   n M L   pez Mu   oz
Telef   nica, Investigaci   n y Desarrollo


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: daniel.kruegler@googlemail.com
Date: Tue, 26 May 2009 16:47:50 CST
Raw View
On 26 Mai, 18:37, Joaqu  n M L  pez Mu  oz <joaq...@tid.es> wrote:
> Is the following a legal C++ program (note we're passing 0 as
> the third argument to std::copy)?
>
>    #include <algorithm>
>
>    int main()
>    {
>      int x,*p=&x;
>      std::copy(p,p,(int*)0);
>    }
>

I think whether the program is well-formed and well-
defined, depends on a gray zone in the standard, see
below.

> The (C++03) standard does not say whether result in
> std::copy(first,last,result)  must be a valid pointer,

I don't agree with this general statement. An invalid
pointer may have different reasons. If e.g. the third
argument of std::copy in your example above would
be /indeterminate/, it would not be copyable and
this could legally be checked by any implementation
where the OS supports this kind of detection.

In regard to a null pointer value this problem does not
exist in *exactly* the same way. But the gray-zone
argument that may hit you here is the term /singular/
pointer value. As of 24.2 [iterator.concepts]/6 (N2857):

"[..] Iterators can also have singular values that are
not associated with any container. [ Example: After
the declaration of an uninitialized pointer x (as with
int* x;), x must always be assumed to have a singular
value of a pointer.   end example ] Results of most
expressions are undefined for singular values; the
only exceptions are destroying an iterator that holds
a singular value and the assignment of a non-singular
value to an iterator that holds a singular value. In
this case the singular value is overwritten the same
way as any other value.[..]"

I think for some reasonable definition of "container"
we both agree that a null pointer value does not have
an associated container. So, if the algorithm may
use a single operation except for a writing assignment
using an non-singular value or destruction your are lost ;-)

Funnily we have a single type of operation here from
all Output iterator operations that std::copy may use
without violating the spec and this is either copy-
constructing or copy-assigning the value. By the exact
wording of the currently written standard, you are
running into undefined behavior here, even though, when
we look from a different angle (e.g. from the position
that the output iterator actually was a built-in pointer
and that we can copy a null pointer value at our will), the
operation would be well-defined.

> and only
> states that the algorithm returns result+ (last-first), which in
> our particular case (first==last) is result+0. Regarding this
> latter expression, 5.7/8 [expr.add] says:
>
>    "If the value 0 is added to or subtracted from a pointer value,
>    the result compares equal to the original pointer value [...]"
>
> without regard to whether the pointer being added or
> subtracted 0 is the null pointer or not. So, it seems to me that
> result+0 is indeed valid and yields result, i.e. the null value of
> int*.

Unfortunately this rule is over-ruled (at least according to my
own reading) by the undefined-behavior straw man argument
shown above.

> To summarize, I think the program above is indeed valid, but
> some stdlib implementers dissent: the implementation of
> std::copy for MSVC 9.0 has roughly the following checking code
> (when parameter debugging is activated):
>
>    _DEBUG_RANGE(first, last);
>    if (first != last)
>      _DEBUG_POINTER(result);
>
> which accepts the program above as valid, whereas the
> implementer changed her mind in MSVC 10.0 and modified
> the checking code as
>
>    _DEBUG_RANGE(first, last);
>    _DEBUG_POINTER(result);
>
> where  _DEBUG_POINTER triggers and assertion when
> result is a null pointer, thus failing on the program above.
>
> So, who's right, I (and MSVC 9.0) or MSVC 10.0?

It seems to me that the latter obeys the standard
by exact reading, because your code produces
undefined behavior and the run-time can perform
anything it likes.

Greetings from Bremen,

Daniel


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: =?ISO-8859-1?Q?Joaqu=EDn_M_L=F3pez_Mu=F1oz?= <joaquin@tid.es>
Date: Wed, 27 May 2009 10:37:33 CST
Raw View
On 27 mayo, 00:47, daniel.krueg...@googlemail.com wrote:
> On 26 Mai, 18:37, Joaqu  n M L  pez Mu  oz <joaq...@tid.es> wrote:
>
> > The (C++03) standard does not say whether result in
> > std::copy(first,last,result)  must be a valid pointer,
>
> I don't agree with this general statement. An invalid
> pointer may have different reasons. If e.g. the third
> argument of std::copy in your example above would
> be /indeterminate/, it would not be copyable and
> this could legally be checked by any implementation
> where the OS supports this kind of detection.
>
> In regard to a null pointer value this problem does not
> exist in *exactly* the same way. But the gray-zone
> argument that may hit you here is the term /singular/
> pointer value. As of 24.2 [iterator.concepts]/6 (N2857):
>
> "[..] Iterators can also have singular values that are
> not associated with any container. [ Example: After
> the declaration of an uninitialized pointer x (as with
> int* x;), x must always be assumed to have a singular
> value of a pointer.   end example ] Results of most
> expressions are undefined for singular values; the
> only exceptions are destroying an iterator that holds
> a singular value and the assignment of a non-singular
> value to an iterator that holds a singular value. In
> this case the singular value is overwritten the same
> way as any other value.[..]"
>
> I think for some reasonable definition of "container"
> we both agree that a null pointer value does not have
> an associated container. So, if the algorithm may
> use a single operation except for a writing assignment
> using an non-singular value or destruction your are lost ;-)
>
> Funnily we have a single type of operation here from
> all Output iterator operations that std::copy may use
> without violating the spec and this is either copy-
> constructing or copy-assigning the value. By the exact
> wording of the currently written standard, you are
> running into undefined behavior here, even though, when
> we look from a different angle (e.g. from the position
> that the output iterator actually was a built-in pointer
> and that we can copy a null pointer value at our will), the
> operation would be well-defined.
>

OK, so your stance is that null pointers are singular. I
don't think so: null pointers can be passed around,
copied, tested for equality, etc., none of which operations
are allowed for singular values.

The whole null->singular issue is a little murky and badly
dealt with in the standard text. Resolution of issue 208:

http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#208

replaces the statement

   Dereferenceable and past-the-end values are always non-singular.

with the laxer

   Dereferenceable values are always non-singular.

so as to allow null pointers to serve as past-the-end iterators.
It even explicit states in the rationale  "Null pointers are
singular".
The problem with that is that singular iterators cannot be
moved around or tested for equality, which is clearly required
from past-the-end iterators. I smell a DR here. Your opinions
on this are much appreciated,

Joaqu  n M L  pez Mu  oz
Telef  nica, Investigaci  n y Desarrollo


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: daniel.kruegler@googlemail.com
Date: Wed, 27 May 2009 20:56:43 CST
Raw View
On 27 Mai, 18:37, Joaqu   n M L   pez Mu   oz <joaq...@tid.es> wrote:
> On 27 mayo, 00:47, daniel.krueg...@googlemail.com wrote:
>
> > On 26 Mai, 18:37, Joaqu   n M L   pez Mu   oz <joaq...@tid.es> wrote:
>
> > > The (C++03) standard does not say whether result in
> > > std::copy(first,last,result)  must be a valid pointer,
>
> > I don't agree with this general statement. An invalid
> > pointer may have different reasons. If e.g. the third
> > argument of std::copy in your example above would
> > be /indeterminate/, it would not be copyable and
> > this could legally be checked by any implementation
> > where the OS supports this kind of detection.
>
> > In regard to a null pointer value this problem does not
> > exist in *exactly* the same way. But the gray-zone
> > argument that may hit you here is the term /singular/
> > pointer value. As of 24.2 [iterator.concepts]/6 (N2857):
>
> > "[..] Iterators can also have singular values that are
> > not associated with any container. [ Example: After
> > the declaration of an uninitialized pointer x (as with
> > int* x;), x must always be assumed to have a singular
> > value of a pointer.    end example ] Results of most
> > expressions are undefined for singular values; the
> > only exceptions are destroying an iterator that holds
> > a singular value and the assignment of a non-singular
> > value to an iterator that holds a singular value. In
> > this case the singular value is overwritten the same
> > way as any other value.[..]"
>
> > I think for some reasonable definition of "container"
> > we both agree that a null pointer value does not have
> > an associated container. So, if the algorithm may
> > use a single operation except for a writing assignment
> > using an non-singular value or destruction your are lost ;-)
>
> > Funnily we have a single type of operation here from
> > all Output iterator operations that std::copy may use
> > without violating the spec and this is either copy-
> > constructing or copy-assigning the value. By the exact
> > wording of the currently written standard, you are
> > running into undefined behavior here, even though, when
> > we look from a different angle (e.g. from the position
> > that the output iterator actually was a built-in pointer
> > and that we can copy a null pointer value at our will), the
> > operation would be well-defined.
>
> OK, so your stance is that null pointers are singular. I
> don't think so: null pointers can be passed around,
> copied, tested for equality, etc., none of which operations
> are allowed for singular values.

IMO the standard can be read this way - in fact it is the
way I'm reading it. The problem is IMO that the term singular
is not properly defined in the standard and general purpose
interpretation wouldn't help us here.

> The whole null->singular issue is a little murky and badly
> dealt with in the standard text. Resolution of issue 208:
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#208
>
> replaces the statement
>
>    Dereferenceable and past-the-end values are always non-singular.
>
> with the laxer
>
>    Dereferenceable values are always non-singular.
>
> so as to allow null pointers to serve as past-the-end iterators.
> It even explicit states in the rationale  "Null pointers are
> singular".
> The problem with that is that singular iterators cannot be
> moved around or tested for equality, which is clearly required
> from past-the-end iterators. I smell a DR here. Your opinions
> on this are much appreciated,

I wasn't influenced by this issue because it was not on
my radar [so thanks for bringing that to my attention], so
my reading was completely free from any "mental model"
thinking ;-)

Of-course I completely agree with your interpretation that
a null pointer should not be considered as a singular
pointer, but for me the saying "values that are not associated
with any container" looks near to definition and I cannot
see a reasonable way to associate a null pointer value
to a container. It would be probably better, if the term
"indeterminate" value would have been used instead of
singular because this is the description that the standard
uses in several other places. I agree with your opinion
that an issue report should be created.

Greetings from Bremen,

Daniel



--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]