C ++ unallocated memory access

I have this piece of code:

try
{
    int* myTestArray = new int[2];

    myTestArray[4] = 54;

    cout << "Should throw ex "  << myTestArray[4] + 1 << endl;
}
catch (exception& exception)
{ 
    cout << "Exception content: " << exception.what() << endl;
}

      

What is really curious to me is why the exception is not being thrown here since it was referenced by an index that was not allocated ... and why does 55 print? Does this mean that C ++ has automatically increased the size of the array?

+3


source to share


6 answers


Access to unallocated memory is not guaranteed to throw exceptions.

It doesn't actually guarantee anything, since this behavior is undefined. Anything could happen. Beware of the nasal demons.



It prints 55 because you just saved 54, returned it, and printed 54 + 1. This does not guarantee 55 is printed, although it often happens in practice. This time it worked.

+9


source


There are vague and incorrect assumptions here. This assumption is that C ++ doesn't really give a damn about what you do with memory. C ++, like its C ancestors, has a completely untested memory model. What you have here is classically called a buffer overflow and is the source of countless bugs, including some dire security flaws.

This is what your code says:

  • myTestArray

    is the name of a location in memory large enough to hold the address int

    .

  • There are two memory values ​​allocated for it on the heap int

    . [And this addreress is put in location myTestArray

    . Doesn't matter, but it probably makes it clearer.] (Along with probably 16 bytes of overhead, but we don't care for now.)

  • then you insert the value 54

    into memory location 4 int

    from the address contained in myTestArray

    .

  • looking at that location, adding 1 and printing the result.



You are demonstrating that C (++) really just doesn't care.

Now, in most cases, the underlying memory and runtime management system won't let you deal with it; you break his assumptions and get a segmentation fault or something similar. But in this case, you haven't reached the boundary yet, most likely because you are using a data structure that malloc uses under the covers to manage the heap. You handle this because nothing happens to the heap for the rest of the program. But for a good time, write a small loop that runs this code, freeing myTestArray

and reallocating it. I would waste long chances that it won't run more than 10 iterations before the program blows up and may not do two.

+10


source


You can write a range of arrays, but it is not guaranteed to work, and the data is not guaranteed to persist there, as something else might overwrite it.

It's just not a good idea, and since there is no exception, it is potentially difficult to find the error.

When you read this memory, you will be pulling out some random garbage that was left from some other program or something else that was used in memory before, so it really could be something.

+1


source


As others have said, this behavior is undefined, but I thought a little more information might help. myTestArray

is not an "array" in the sense of a type, with special operators, and so on. It's just a pointer to a memory location. The expression is myTestArray[4]

just short for *(myTestArray+4)

- it returns a reference to the memory location 4 * sizeof(int)

minus myTestArray

. If you need bounds checking you will need to use std::vector<int>::at()

.

+1


source


It is very difficult to know for sure what is going on here. But I can give you a general idea.

Most operating systems have a minimum size for memory allocation. On Unix, this is the native page size. On x86 and amd64 systems, this is 4KB. On Windows it is 64KB (I think).

The memory allocator used by malloc

and new

receives memory from the operating system in chunks of this size. It creates data structures (often a linked list, sometimes a bitmap or tree) and produces small chunks of the required sizes.

Another confusion is that before your program even starts running main()

, it ran completely different code and allocated memory. For std::cout

other static and global objects, and for linking a shared library.

But suppose when you call new

, your program first gets a 4KB chunk and gives a pointer to 8 bytes (two integers). Your program has all 4KB allocated and you can write there without crashing. However, what happens if you call again new

? It is highly likely that the memory allocator wrote some important tracking information somewhere in this 4KB. The next bytes can be the size of the next block. Writing 54 to it can make him think she has more or less memory than she does. Or those bytes could be a pointer to the next block of free memory, and your 54 will fail in the next memory allocation.

+1


source


Array access out of range is undefined behavior. Thus, 55 is one of many possible outcomes, and there is nothing surprising here.

C ++ Standard n3337 Β§ 5.7 Additive operators

5) When an expression with integral type is added to or subtracted from a pointer, the result is of the type of the pointer operand. If the pointer operand points to an element of the array object, and the array is large enough, the result indicates the offset of the element from the original element such that the difference between the indices of the resulting and original elements of the array is equal to the integral expression. In other words, if the expression P points to the i-th element of the array, the expressions (P) + N (equivalently, N + (P)) and (P) -N (where N is n) indicate i + n-th and i are the nth elements of the array, if they exist. Moreover, if the expression P points to the last element of the array object, the expression (P) +1 points one after the last element of the array object, and if the expression Q points to the object one after the last element of the array,expression (Q) -1 points to the last element of the object array. If both the pointer operand and the result point to elements of the same array object, or one object after the last element of the array, the evaluation should not overflow;otherwise, the behavior is undefined .

0


source







All Articles