5

If it is legal to take the address one past the end of an array, how would I do this if the last element of array's address is 0xFFFFFFFF?

How would this code work:

for (vector<char>::iterator it = vector_.begin(), it != vector_.end(); ++it)
{
}

Edit:

I read here that it is legal before making this question: May I take the address of the one-past-the-end element of an array?

Community
  • 1
  • 1
Marlon
  • 19,924
  • 12
  • 70
  • 101
  • What makes you think `0xFFFFFFFF` is the largest possible element? What about 64-bit architectures? – Chris Eberle Dec 04 '11 at 22:45
  • 3
    It is *not* legal to access one-past-the-end pointers. It is only legal to create those, not dereference them. – Xeo Dec 04 '11 at 22:46
  • @Chris That's what I wanted to know, if I am making any invalid assumptions that you could possibly clear up. And let's just say 32-bit only. – Marlon Dec 04 '11 at 22:46
  • If you had a `vector` for instance, wouldn't it calculate `end()` by adding the size to the base, so that `end()` would be the address `0` because of overflow? If so, it should work fine because your iterator will also overflow to `0` and stop properly. – Seth Carnegie Dec 04 '11 at 22:56
  • @SethCarnegie: `end()` returns an iterator, not a pointer, and therefore it can't return a null pointer. There's no direct equivalent "null iterator". – MSalters Dec 05 '11 at 08:18

7 Answers7

9

If this situation is a problem for a particular architecture (it may or may not be), then the compiler and runtime can be expected to arrange that allocated arrays never end at 0xFFFFFFFF. If they were to fail to do this, and something breaks when an array does end there, then they would not conform to the C++ standard.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • In "normal" architectures this will not even be a problem either I think, because the stack is above the heap which is where `vector` stores its contents. – Seth Carnegie Dec 04 '11 at 23:00
  • @GregHewgill Thanks, this is what I thought and you answered my question! – Marlon Dec 05 '11 at 04:59
3

Accessing out of the array boundaries is undefined behavior. You shouldn't be surprised if a demon flies out of your nose (or something like that)

What might actually happen would be an overflow in the address which could lead to you reading address zero and hence segmentation fault.

If you are always within the array range, and you do the last ++it which goes out of the array and you compare it against _vector.end(), then you are not really accessing anything and there should not be a problem.

Shahbaz
  • 46,337
  • 19
  • 116
  • 182
  • The standard guarantees that it's legal to obtain a pointer to an element past the end of the array (of course it's *not* legal to dereference it). – Matteo Italia Dec 04 '11 at 22:57
  • @MatteoItalia hence the "_then you are not really accessing anything and there should not be a problem._" but thanks for stressing that out – Shahbaz Dec 04 '11 at 23:31
  • Correct, I was stressing it out again just because the first sentence seemed to give the wrong idea about it. – Matteo Italia Dec 04 '11 at 23:36
1
  • It's not legal to access one past the end of an array
  • that code doesn't actually access that address.
  • and you will never get an address like that on a real system for you objects.
Karoly Horvath
  • 94,607
  • 11
  • 117
  • 176
1

I think there is a good argument for suggesting that a conformant C implementation cannot allow an array to end at (e.g.) 0xFFFFFFFF.

Let p be a pointer to one-element-off-the-end-of-the-array: if buffer is declared as char buffer[BUFFSIZE], then p = buffer+BUFFSIZE, or p = &buffer[BUFFSIZE]. (The latter means the same thing, and its validity was made explicit in the C99 standard document.)

We then expect the ordinary rules of pointer comparison to work, since the initialization of p was an ordinary bit of pointer arithmetic. (You cannot compare arbitrary pointers in standard C, but you can compare them if they are both based in a single array, memory buffer, or struct.) But if buffer ended at 0xFFFFFFFF, then p would be 0x00000000, and we would have the unlikely situation that p < buffer!

This would break a lot of existing code which assumes that, in valid pointer arithmetic done relative to an array base, the intuitive address-ordering property holds.

librik
  • 3,738
  • 1
  • 19
  • 20
  • 3
    A conforming C implementation could use an internal pointer representation that does not map directly to memory addresses. For example, it might decide that memory address `N` is represented by the pointer value `N-1`. Such an implementation gains the ability to access byte 0xFFFFFFFF by sacrificing the ability to access bytes 1. Win32s worked this way (except that the bias was not 1 but rather around 4MB.) – Raymond Chen Dec 09 '11 at 00:54
0

The difference is between dereferencing that element and taking its address. In your example the element past the end wont be dereferenced and so it is a valid. Although this was not really clear in the early days of C++ it is clear now. Also the value you pass to subscript does not really matter.

pmr
  • 58,701
  • 10
  • 113
  • 156
0

Sometimes the best thing you can do about corner cases is forbid them. I saw this class of problem with some bit field extraction instructions of the NS32032 in which the hardware would load 32 bits starting at the byte address and extract from that datum. So even single-bit fields anywhere in the last 3 bytes of mapped memory would fail. The solution was to never allow the last 4 bytes of memory to be available for allocation.

phunctor
  • 599
  • 3
  • 9
0

Quite a few architectures that would be affected by this solve the problem by reserving offset 0xFFFFFFFF (and a bit more) for the OS.

MSalters
  • 173,980
  • 10
  • 155
  • 350