Topic: Address of one-past-the-last element
Author: mseitz@yahoo.com (Matt Seitz)
Date: Wed, 6 Mar 2002 04:39:10 GMT Raw View
"P.J. Plauger" <pjp@dinkumware.com> wrote in message news:<3c7e81c8$0$7869$724ebb72@reader2.ash.ops.us.uu.net>...
> "Andrew Koenig" <ark@research.att.com> wrote in message news:yu99k7sx8uxo.fsf@europa.research.att.com...
> > Now, of course, the compiler should be able to figure out that as soon
> > as that pointer is dereferenced, it is immediately ``rereferenced''
> > again. In other words, &*p should be equivalent to p. But that's not
> > the way the standard is written.
> >
> > That's the problem.
>
> I'm no longer convinced it's such a problem. I've long been in the
> habit of writing &bar[bar_count] as a past-the-end pointer, on the
> assumption that any decent compiler should know that no dereferencing
> occurs. (After all, the C compilers I've written in the past were
> that smart.) But I recently added debug logic to a bunch of iterator
> definitions and found that this form rightly generates a diagnostic
> if bar is an iterator that is suitably fussy about its operator*().
>
> Maybe it's not such a bad thing that standards discourage this
> pleasant shorthand.
It seems the committee is aware of the issue, but there is no
consensus and no active discussion of the issue. Given that the
current C++ Standard conflicts with both the C99 Standard and with
TC++PL3rd, is this worthy of a defect report, so that it can be
"officially" discussed and resolved?
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: kanze@gabi-soft.de (James Kanze)
Date: Fri, 1 Mar 2002 18:31:49 GMT Raw View
Ron Natalie <ron@sensor.com> wrote in message
news:<3C7D0A61.58690C2@sensor.com>...
> Matt Seitz wrote:
> > I recently ran into a situation where I wanted to check whether a
> > pointer was going to write past the end of an array. My test was
> > essentially
> > bar_type bar[bar_count];
> > bar_type * foo;
> > //...
> > assert(foo < &bar[bar_count]);
> If you want to be sure that it's legal (as far as I know, the note
> on Bjarne's page is the current state, fixed in C99, not in C++).
> You can fix your assert to be legal via the letter of the standard
> by writing:
> assert(foo < bar + bar_count);
> The issue is not whether comparing one-past-the-end is legal (it
> is), but whether you can take the address of bar[bar_count] which is
> not an lvalue by the strict definition in the standard.
The standard clearly says that an expression of the type a[b]
(supposing built in operators) is an exact equivalent of *(a+b). And
that the result of the unary * is an lvalue. The problem is what Andy
pointed out -- the expression *(a+b) is illegal, because it
dereferences one past the end.
--
James Kanze mailto:kanze@gabi-soft.de
Beratung in objektorientierer Datenverarbeitung --
-- Conseils en informatique orient e objet
Ziegelh ttenweg 17a, 60598 Frankfurt, Germany, T l.: +49 (0)69 19 86 27
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: xleobx@qmailcomq.com
Date: Fri, 1 Mar 2002 21:25:12 GMT Raw View
P.J. Plauger <pjp@dinkumware.com> wrote:
> <xleobx@qmailcomq.com> wrote in message news:cyBf8.2724$T_.33057@iad-read.news.verio.net...
>> > There is no question that bar+bar_count is a legal expression, so
>> > you can write
>>
>> > assert(foo < bar+bar_count);
>>
>> Which will promptly fail for all values of foo if bar + bar_count == 0
>> because of an overflow.
>>
>> size_t bar_count = 65536;
>> char * bar = mmap(0xffff0000, bar_count, ....) ; // nothing prevents it
>> // from succeeding
> But that's not permitted. If size_t is 16 bits, then it's not big enough
> to count the bytes in a 65536-byte object. We did think about this way
No, size_t in this case is 32 bits. My point is that if the last byte
of a memory area is the last byte of addressable memory, then the "one-off"
pointer value may happen to coincide with NULL.
> back when we developed the C Standard. (char *)&x + sizeof (x) must be
> a representable pointer value for any object x.
Representable, yes. Such that it is greater than any pointer into x -
not necessarily.
Leo
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "P.J. Plauger" <pjp@dinkumware.com>
Date: Sat, 2 Mar 2002 00:05:16 GMT Raw View
<xleobx@qmailcomq.com> wrote in message news:vLPf8.2780$T_.34702@iad-read.news.verio.net...
> > But that's not permitted. If size_t is 16 bits, then it's not big enough
> > to count the bytes in a 65536-byte object. We did think about this way
>
> No, size_t in this case is 32 bits. My point is that if the last byte
> of a memory area is the last byte of addressable memory, then the "one-off"
> pointer value may happen to coincide with NULL.
And THAT's not permissible either. An implementation has to leave at least
one buffer byte before the edge of the world.
> > back when we developed the C Standard. (char *)&x + sizeof (x) must be
> > a representable pointer value for any object x.
>
> Representable, yes. Such that it is greater than any pointer into x -
> not necessarily.
I think necessarily.
P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: xleobx@qmailcomq.com
Date: Sat, 2 Mar 2002 19:25:54 GMT Raw View
P.J. Plauger <pjp@dinkumware.com> wrote:
> <xleobx@qmailcomq.com> wrote in message news:vLPf8.2780$T_.34702@iad-read.news.verio.net...
>> > But that's not permitted. If size_t is 16 bits, then it's not big enough
>> > to count the bytes in a 65536-byte object. We did think about this way
>>
>> No, size_t in this case is 32 bits. My point is that if the last byte
>> of a memory area is the last byte of addressable memory, then the "one-off"
>> pointer value may happen to coincide with NULL.
> And THAT's not permissible either. An implementation has to leave at least
> one buffer byte before the edge of the world.
An implementation of what? mmap() is not in C or C++ standard and I do not
see a reason why an OS kernel should care about a particular language.
>> > back when we developed the C Standard. (char *)&x + sizeof (x) must be
>> > a representable pointer value for any object x.
>>
>> Representable, yes. Such that it is greater than any pointer into x -
>> not necessarily.
> I think necessarily.
Could it be said that in size_t(&x) + sizeof(x) - 1 == MAX_SIZE_T, then
the behavior of (char *)&x + sizeof (x) is unspecified and shift the
burden from the implementation to the programmer?
By the way, as the only iterators that require ordering relation
are random access iterators,
it is OK to have container.end() to be equal to NULL, if
container's iterator category is not random access; and in this case it
would not matter whether end() is NULL by definition or just happens
to be NULL because of the address arithmetic overflow.
Leo
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "P.J. Plauger" <pjp@dinkumware.com>
Date: Sat, 2 Mar 2002 21:09:14 GMT Raw View
<xleobx@qmailcomq.com> wrote in message news:cmXf8.2803$T_.35173@iad-read.news.verio.net...
> > And THAT's not permissible either. An implementation has to leave at least
> > one buffer byte before the edge of the world.
>
> An implementation of what? mmap() is not in C or C++ standard and I do not
> see a reason why an OS kernel should care about a particular language.
Only if it wants to support an API to it that obeys its rules.
An OS COULD return a pointer to an object in the user address space
that happens to compare equal to a null pointer, but that violates
Nixon's Rule.
> Could it be said that in size_t(&x) + sizeof(x) - 1 == MAX_SIZE_T, then
> the behavior of (char *)&x + sizeof (x) is unspecified and shift the
> burden from the implementation to the programmer?
It could be said, but that has little or nothing to do with the C
Standard.
> By the way, as the only iterators that require ordering relation
> are random access iterators,
> it is OK to have container.end() to be equal to NULL, if
> container's iterator category is not random access; and in this case it
> would not matter whether end() is NULL by definition or just happens
> to be NULL because of the address arithmetic overflow.
True, but also not relevant to the constraints on one-past-the-end
addresses within a C object.
P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: mseitz@yahoo.com (Matt Seitz)
Date: Wed, 27 Feb 2002 16:11:44 GMT Raw View
I recently ran into a situation where I wanted to check whether a
pointer was going to write past the end of an array. My test was
essentially
bar_type bar[bar_count];
bar_type * foo;
//...
assert(foo < &bar[bar_count]);
I remembered that this was listed as an open issue on Dr. Stroustrup's
web site (http://www.research.att.com/~bs/3rd_issues.html). I decided
to check on the status of this issue, so I visited the Standard Core
Language Issue list (http://std.dkuug.dk/jtc1/sc22/wg21/docs/cwg_toc.html).
I skimmed the list and tried searching for "address" and "element",
but could not find an entry for this issue. What is the status of
this issue in the Standards Committee?
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Ron Natalie <ron@sensor.com>
Date: Wed, 27 Feb 2002 17:14:46 GMT Raw View
Matt Seitz wrote:
>
> I recently ran into a situation where I wanted to check whether a
> pointer was going to write past the end of an array. My test was
> essentially
>
> bar_type bar[bar_count];
> bar_type * foo;
> //...
> assert(foo < &bar[bar_count]);
If you want to be sure that it's legal (as far as I know, the note on
Bjarne's page is the current state, fixed in C99, not in C++). You
can fix your assert to be legal via the letter of the standard by
writing:
assert(foo < bar + bar_count);
The issue is not whether comparing one-past-the-end is legal (it is),
but whether you can take the address of bar[bar_count] which is not
an lvalue by the strict definition in the standard.
Note that the comparison is only defined if foo has a value between
bar and bar+bar_count (inclusive). If you do something like:
foo = &bar[bar_count-1]; // last element
foo++;
foo++;
assert(foo < foo + bar_count)
There is no guarantee that the expression will yield false.
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: mseitz@yahoo.com (Matt Seitz)
Date: Wed, 27 Feb 2002 23:08:31 GMT Raw View
Thanks for your reply. Apparently I did not ask my question clearly.
I am not looking for an alternative solution, nor whether my code was
legal according to the current Standard. Dr. Stroustrup's page
already answered those questions. I am asking what opinions the C++
Standards Committee currently holds regarding this issue.
Ron Natalie <ron@sensor.com> wrote in message news:<3C7D0A61.58690C2@sensor.com>...
> Matt Seitz wrote:
> >
> > I recently ran into a situation where I wanted to check whether a
> > pointer was going to write past the end of an array. My test was
> > essentially
> >
> > bar_type bar[bar_count];
> > bar_type * foo;
> > //...
> > assert(foo < &bar[bar_count]);
>
> If you want to be sure that it's legal (as far as I know, the note on
> Bjarne's page is the current state, fixed in C99, not in C++). You
> can fix your assert to be legal via the letter of the standard by
> writing:
> assert(foo < bar + bar_count);
>
> The issue is not whether comparing one-past-the-end is legal (it is),
> but whether you can take the address of bar[bar_count] which is not
> an lvalue by the strict definition in the standard.
>
> Note that the comparison is only defined if foo has a value between
> bar and bar+bar_count (inclusive). If you do something like:
>
> foo = &bar[bar_count-1]; // last element
> foo++;
> foo++;
> assert(foo < foo + bar_count)
>
> There is no guarantee that the expression will yield false.
>
> ---
> [ 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.research.att.com/~austern/csc/faq.html ]
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Andrew Koenig <ark@research.att.com>
Date: Thu, 28 Feb 2002 16:26:05 GMT Raw View
Matt> I recently ran into a situation where I wanted to check whether a
Matt> pointer was going to write past the end of an array. My test was
Matt> essentially
Matt> bar_type bar[bar_count];
Matt> bar_type * foo;
Matt> //...
Matt> assert(foo < &bar[bar_count]);
There is no question that bar+bar_count is a legal expression, so
you can write
assert(foo < bar+bar_count);
without fear (assuming, of course, that foo points to an element of
bar or one past the end of bar). The question, then is only about the
form
&bar[bar_count]
The reason that this form is a problem is that if p is a pointer and
i is an integer, p[i] is defined to be equivalent to *(p+i). Therefore,
by definition,
&bar[bar_count]
is equivalent to
&(*(bar+bar_count))
The sub-expression *(bar+bar_count) is illegal because it attempts to
dereference a pointer that does not point to an element.
Now, of course, the compiler should be able to figure out that as soon
as that pointer is dereferenced, it is immediately ``rereferenced''
again. In other words, &*p should be equivalent to p. But that's not
the way the standard is written.
That's the problem.
--
Andrew Koenig, ark@research.att.com, http://www.research.att.com/info/ark
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "P.J. Plauger" <pjp@dinkumware.com>
Date: Thu, 28 Feb 2002 19:18:15 GMT Raw View
"Andrew Koenig" <ark@research.att.com> wrote in message news:yu99k7sx8uxo.fsf@europa.research.att.com...
> There is no question that bar+bar_count is a legal expression, so
> you can write
>
> assert(foo < bar+bar_count);
>
> without fear (assuming, of course, that foo points to an element of
> bar or one past the end of bar). The question, then is only about the
> form
>
> &bar[bar_count]
>
> The reason that this form is a problem is that if p is a pointer and
> i is an integer, p[i] is defined to be equivalent to *(p+i). Therefore,
> by definition,
>
> &bar[bar_count]
>
> is equivalent to
>
> &(*(bar+bar_count))
>
> The sub-expression *(bar+bar_count) is illegal because it attempts to
> dereference a pointer that does not point to an element.
>
> Now, of course, the compiler should be able to figure out that as soon
> as that pointer is dereferenced, it is immediately ``rereferenced''
> again. In other words, &*p should be equivalent to p. But that's not
> the way the standard is written.
>
> That's the problem.
I'm no longer convinced it's such a problem. I've long been in the
habit of writing &bar[bar_count] as a past-the-end pointer, on the
assumption that any decent compiler should know that no dereferencing
occurs. (After all, the C compilers I've written in the past were
that smart.) But I recently added debug logic to a bunch of iterator
definitions and found that this form rightly generates a diagnostic
if bar is an iterator that is suitably fussy about its operator*().
Maybe it's not such a bad thing that standards discourage this
pleasant shorthand.
P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: xleobx@qmailcomq.com
Date: Fri, 1 Mar 2002 02:56:02 GMT Raw View
Andrew Koenig <ark@research.att.com> wrote:
> Matt> I recently ran into a situation where I wanted to check whether a
> Matt> pointer was going to write past the end of an array. My test was
> Matt> essentially
> Matt> bar_type bar[bar_count];
> Matt> bar_type * foo;
> Matt> //...
> Matt> assert(foo < &bar[bar_count]);
> There is no question that bar+bar_count is a legal expression, so
> you can write
> assert(foo < bar+bar_count);
Which will promptly fail for all values of foo if bar + bar_count == 0
because of an overflow.
size_t bar_count = 65536;
char * bar = mmap(0xffff0000, bar_count, ....) ; // nothing prevents it
// from succeeding
Leo
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "P.J. Plauger" <pjp@dinkumware.com>
Date: Fri, 1 Mar 2002 06:19:18 GMT Raw View
<xleobx@qmailcomq.com> wrote in message news:cyBf8.2724$T_.33057@iad-read.news.verio.net...
> > There is no question that bar+bar_count is a legal expression, so
> > you can write
>
> > assert(foo < bar+bar_count);
>
> Which will promptly fail for all values of foo if bar + bar_count == 0
> because of an overflow.
>
> size_t bar_count = 65536;
> char * bar = mmap(0xffff0000, bar_count, ....) ; // nothing prevents it
> // from succeeding
But that's not permitted. If size_t is 16 bits, then it's not big enough
to count the bytes in a 65536-byte object. We did think about this way
back when we developed the C Standard. (char *)&x + sizeof (x) must be
a representable pointer value for any object x.
P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
---
[ 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.research.att.com/~austern/csc/faq.html ]