Jump to content
  • Advertisement
Sign in to follow this  
KodeWarrior

Pointers out of bounds legal???

This topic is 4226 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Someone who thinks it's bad. Edit: del My code that dereferences NULL. Actually, code that uses what I think is a bad pointer. Make sure optimizations are off, volatile used just in case. My asm was unoptimized when I checked it.
  volatile int arr[1] = {99};
  volatile int offset = (int)arr;
  volatile char *ptr = 0;
  volatile int x = ptr[offset];




Asm:
  volatile int arr[1] = {99};
0083233F  mov         dword ptr [arr],63h 
  volatile int offset = (int)arr;
00832346  lea         eax,[arr] 
00832349  mov         dword ptr [offset],eax 
  volatile char *ptr = 0;
0083234C  mov         dword ptr [ptr],0 
  volatile int x = ptr[offset];
00832353  mov         eax,dword ptr [ptr] 
00832356  add         eax,dword ptr [offset] 
00832359  movsx       ecx,byte ptr [eax] 
0083235C  mov         dword ptr [x],ecx 




The above code executed just fine (x will == 99). Is there another address I can't dereference? Question: Is this ok to do on a Windows 32bit OS, any CPU brand, compiled as protected mode exe? Bonus is, does this work on other devices like handhelds, 64bit, etc?

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by KodeWarrior
My code that dereferences NULL.

Your code doesn't dereference NULL. Its behaviour is undefined, though.

Share this post


Link to post
Share on other sites
Is it undefined tho?
the final line is just like writing
x = *(0 + arr);
Also if I remember correctly the address and the index are interchangeable
so that :

int i =0;
i[arr] and arr are the same

Share this post


Link to post
Share on other sites
It is undefined. It will likely crash if you tried to dereference x. It might not, because that's the nature of undefined behavior: you can't be too sure about what will happen.

i[arr] would require a cast. It is also undefined, but has I tenancy to work.

Remember also that at compile time, a null pointer does not necessarily hold a value equal to an integer representation of zero.

Share this post


Link to post
Share on other sites
offset is being cast between a pointer type and an integral type. While this will tend to work on current 32-bit platforms, it's certainly not well-defined in general, and absolutely a very bad idea.

This code, unlike that in the OP, actually does dereference NULL, and it crashes on every platform I have access to at the moment (Win32, an old ia32 Linux, and an ancient PalmOS build):

int* p = NULL;
*p = 42;



Either way, dereferencing NULL isn't really the issue at hand here, but rather accessing out of defined array boundaries. The linked FAQ is absolutely correct.


int* array = new int[100];
array[101] = 0;


This code also has undefined behaviour; it may work, or it may blow up, or it may cause demons to fly out of your printer and assail you with loud, drunken renditions of I've Been Working on the Railroad while beating you about the head with a rubber balloon.

Pointer voodoo is, in general, a bad idea, and should be avoided as much as possible; if nothing else it is to be done with exceeding care. If you even begin to suspect that you may be wandering into Undefined Land, bail out as soon as possible.

Share this post


Link to post
Share on other sites
Looks like perfectly valid C to me and no pointers are being dereference out of bounds. The link is correct in that you can get wraparound which leads to undefined behavior.
Example:

int arr0[100];
int* ptrA = &arr0[100];
int* ptrB = &arr0[-1];
ptrA[-1] = 0;
ptrB[1] = 2;

C will generate the same address for all these statements:
ptr[offset] = 0[offset] = offset[0] = arr[0];
But if the pointer type was different from the offset type then you get undefined behavior.

Dereferencing is another problem which may lead to an undefined result. It depends on the type/size of offset pointer and pointer type. This leads to nasty casting which are generally not a good ideal.

To that point, you're only storing the first byte of 'arr' in x since you're dereferencing a 'char' pointer when it needs to be an int pointer.

Should look like this:

volatile int x = *(reinterpret_cast<int*>(&ptr[offset]));


[Edit]

[Edited by - Jack Sotac on March 26, 2007 9:25:57 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by ApochPiQ
This code also has undefined behaviour; it may work, or it may blow up, or it may cause demons to fly out of your printer and assail you with loud, drunken renditions of I've Been Working on the Railroad while beating you about the head with a rubber balloon.


[lol]

I don't think this would be such a problem if compiler writers bothered to use the bounds instruction [1], but they don't. My guess is that they would have if a bounds violation threw int 3 instead of int 5.

Share this post


Link to post
Share on other sites
Quote:

i[arr] would require a cast. It is also undefined, but has I tenancy to work.


I don't have access to any books at the moment, but why would it require a cast? Was I wrong to assume the address and index are interchangeable?

[edit]It seems Jack Sotac's post confirms what I thought.

Share this post


Link to post
Share on other sites
Quote:
Original post by Jack Sotac
Looks like perfectly valid C to me and no pointers are being dereference out of bounds.

It might be valid, but it isn't defined. Pointers are being dereferenced out of bounds, and that's why it's undefined.
Quote:

C will generate the same address for all these statements:
ptr[offset] = 0[offset] = offset[0] = arr[0];

1. ptr[offset] is *(ptr + offset).

The value of offset is not defined. There is no guarantee that, if cast back to int*, it would point at the same object. For example, a 64-pointer can't reliably be converted to a 32-bit int and back. Real systems exist with such data types.

Furthermore, the value of ptr is not defined. It's possible that the null pointer might actually point at the last addressable byte of memory, not the first. (i.e. it might have the integer value ~0.) This might be the case on a platform where the data at byte 0 needs to be accessible.

On x86 systems the interrupt table is stored starting from byte 0, so for system software a pointer to byte 0 is a reasonable pointer upon which pointer arithmetic should have defined results. However, the standard requires that a null pointer not compare equal to any other valid pointer, including a pointer to byte 0.

Even if offset does contain the offset of the array from ptr, pointer arithmetic is only defined for pointers into an array (or one-past-the-end of an array), which the null pointer is not.

2. 0[offset] and offset[0]

These are invalid. One argument must have pointer type.
Quote:

Dereferencing is the only problem which may lead to an undefined result.

This is so wrong I'm sure you can't possibly mean what you seem to mean. C and C++ have tons of undefined behaviour that doesn't involve dereferencing.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!