Use of a deleted pointer address - c++

(*) As far as I know the Standard allows an implementation to modify the operand of the delete operator, however most implementations do not do that.
int* ptr = new int(0);
delete ptr; //delete is allowed to modify ptr, for example set it to 0
std::cout << ptr; // UB?
Acknowledging (*), is the reading of ptr (in the form of printing it) well-defined?
If delete does modify ptr, is it allowed to set a trap value, which would make reading ptr UB?

In C++14 this is implementation-defined behaviour, [basic.stc.dynamic.deallocation]/4:
If the argument given to a deallocation function in the standard library is a pointer that is not the null pointer value, the deallocation function shall deallocate the storage referenced by the pointer, rendering invalid all pointers referring to any part of the deallocated storage.
Indirection through an invalid pointer value and passing an invalid pointer value to a deallocation function have undefined behavior. Any other use of an invalid pointer value has implementation-defined behavior.
There is a footnote:
Some implementations might define that copying an invalid pointer value causes a system-generated runtime fault.
This changed since C++11 where the bolded text said "undefined behaviour" and there was no footnote.
So to answer your question, delete ptr; is allowed to set a trap value that would cause a runtime fault for std::cout << ptr. The compiler documentation must specify the behaviour. This is a narrower restriction than UB in which case any unstable behaviour would be permissible.

In this example, std::cout << ptr is NOT undefined behavior by default, because ptr is not being dereferenced at all, so it doesn't matter what its value is actually set to.
By default, the STL does not define an operator<< for int* pointers. It defines:
an operator<< for (signed|unsignd) char*, used for printing null-terminated text.
a generic operator<< for void*, which simply prints the memory address itself that the pointer is set to, not the data that is being pointed at.
Since int* is implicitly convertible to void*, calling std::cin << ptr is actually calling operator<<(std::cin, (void*)ptr), and so prints the memory address as-is that ptr holds.
The code would have undefined behavior only if your app defines its own operator<< for int* and then tries to dereference the pointer after it has been deleted.

Related

Memory leaks when using pointer arithmetic

Will such code cause a memory leak?
unsigned char *ptr = new unsigned char[2];
ptr++; //pointer now points to the second member of array
delete [] ptr;
According to the standard (e.g. this online draft version), the behaviour of delete-ing a pointer, which has not been obtained previously by new, is undefined:
3.7.4.2 Deallocation functions
(3) If a deallocation function terminates by throwing an exception, the
behavior is undefined. The value of the first argument supplied to a
deallocation function may be a null pointer value; if so, and if the
deallocation function is one supplied in the standard library, the
call has no effect. Otherwise, the behavior is undefined if the value
supplied to operator delete(void*) in the standard library is not one
of the values returned by a previous invocation of either operator
new(std::size_t) or operator new(std::size_t, const std::nothrow_t&)
in the standard library, and the behavior is undefined if the value
supplied to operator delete in the standard library is not
one of the values returned by a previous invocation of either operator
new or operator new[](std::size_t, const
std::nothrow_t&) in the standard library.
The value of ptr+1 is not the one returned by new[], and hence the call to delete[] (ptr+1) is UB. Anything can happen, including that it seems to work correctly; But it is for sure not guaranteed to work correctly.
It is undefined behavior as mentioned here
delete [] expression
expression must be a null pointer value or a pointer value previously
obtained by an array form of new-expression. If expression is anything
else, including if it's a pointer obtained by the non-array form of
new-expression, the behavior is undefined.
This makes sense as delete[] would expect to get some information about number of elements to be deleted from the pointer supplied, which it would not found if a different pointer is passed.

Deleting dynamically allocated variables setting pointer to 0 [duplicate]

This question already has answers here:
Is it good practice to NULL a pointer after deleting it?
(18 answers)
Closed 5 years ago.
I can't understand the end of this code (array = 0;):
#include <iostream>
int main()
{
std::cout << "Enter a positive integer: ";
int length;
std::cin >> length;
int *array = new int[length];
std::cout << "I just allocated an array of integers of length " << length << '\n';
array[0] = 5; // set element 0 to value 5
delete[] array; // use array delete to deallocate array
array = 0; // use nullptr instead of 0 in C++11
return 0;
}
At the end, a dynamically allocated array is deleted (returned to OS) and then assigned a value of 0.
Why is this done? After array has been returned to the OS, there is no need to assign it a value of 0, right?
Code from: http://www.learncpp.com/cpp-tutorial/6-9a-dynamically-allocating-arrays/
After array has been returned to the OS, there is no need to assign it a value of 0, right?
You're right it is not needed because the memory is freed (deallocated) by the operator delete. But think of a case where you may use the pointer in another place in your code (functions, loops, etc.) after you use delete[] on it.
The array variable still holds the address of the old allocation after the delete[] statement was called (dangling pointer). If you would access that address you would get undefined bahaviour (UB) because the memory is no longer yours, in most of the cases your program would crash.
To avoid that you do a null pointer check like:
if (array != nullptr)
{
/* access array */
...
}
which is checking the pointer against the address 0 which represents an invalid address.
To make that check possible you set the pointer to nullptr or NULL if C++11 is not available. The nullptr keyword introduces type safety because it acts like a pointer type and should be preferred over the C-like NULL. In pre C++11 NULL is defined as integer 0, since C++11 it's an alias to nullptr.
To define your own nullptr to use it for pre C++11 compiler look here: How to define our own nullptr in c++98?
An interesting fact about delete or delete[] is that it is safe to use it on a nullptr. It is written at point 2 on cppreference.com or at this SO answer.
operator delete, operator delete[]
2)
[...] The behavior of the standard library implementation of this function is undefined unless ptr is a null pointer or is a pointer previously obtained from the standard library implementation of operator new[](size_t) or operator new[](size_t, std::nothrow_t).
We are setting pointers to NULL (0) to avoid dangling pointers (pointer is still pointing to same memory which is no longer yours). In case of local variables it is not that useful if function doesnt continue after delete (so its obvious pointer won't be reused). In case of global/member poitners its good practice to avoid bugs.
Accessing already deleted pointer may lead to overwriting/reading random memory (it might be more dangerous than crash) and causes undefined behavior, while accessing NULL pointer will immediatelly crash.
Since c++11 you should use nullptr because its defined as pointer type while NULL is more int type and improves type safety + resolves ambiguous situations.
In case of double deleting pointer, its safe to use delete on nullptr and nothing happens but if you delete already deleted non-null pointer, it will cause undefined behavior and most likely program will crash.
In c++ you should avoid using pure pointers since there are STL containers (which frees their resources them self (RAII)) for this usage or smart pointers.
std::vector<int> array{1,2,3,4,5};
This is done so that the pointer is set to NULL (whether in C++, we prefer nullptr, since NULL and 0 may be different things).
This tactic eliminates the possibility of a dangling pointer, because the array may have been deleted, but that doesn't mean that it's set to NULL.
If we don't do that, we run the risk of checking whether the pointer is NULL or not (latter in our code), we will see that it's not NULL, wrongly believe that the pointer is OK to be accessed, and cause Undefined Behavior.
You assign to a value commonly known as "invalid address", i.e. NULL, 0 or the pointer type nullptr, because otherwise there is no way you can know whether you pointer points to an invalid address. In other words when you delete[] your array your pointer "doesn't know" that it is pointing to a no longer usable memory address.

Pointers in c++ after delete

After reading many posts about this, I want to clarify the next point:
A* a = new A();
A* b = a;
delete a;
A* c = a; //illegal - I know it (in c++ 11)
A* d = b; //I suppose it's legal, is it true?
So the question is about using the value of copy of deleted pointer.
I've read, that in c++ 11 reading the value of a leads to undefined behaviour - but what about reading the value of b?
Trying to read the value of the pointer (note: this is different to
dereferencing it) causes implementation-defined behaviour since C++14,
which may include generating a runtime fault. (In C++11 it was
undefined behaviour)
What happens to the pointer itself after delete?
Both:
A* c = a;
A* d = b;
are undefined in C++11 and implementation defined in C++14. This is because a and b are both "invalid pointer values" (as they point to deallocated storage space), and "using an invalid pointer value" is either undefined or implementation defined, depending on the C++ version. ("Using" includes "copying the value of").
The relevant section ([basic.stc.dynamic.deallocation]/4) in C++11 reads (emphasis added):
If the argument given to a deallocation function in the standard library is a pointer that is not the null pointer value (4.10), the deallocation function shall deallocate the storage referenced by the pointer, rendering invalid all pointers referring to any part of the deallocated storage. The effect of using an invalid pointer value (including passing it to a deallocation function) is undefined.
with a non-normative note stating:
On some implementations, it causes a system-generated runtime
In C++14 the same section reads:
If the argument given to a deallocation function in the standard library is a pointer that is not the null pointer value (4.10), the deallocation function shall deallocate the storage referenced by the pointer, rendering invalid all pointers referring to any part of the deallocated storage. Indirection through an invalid pointer value and passing an invalid pointer value to a deallocation function have undefined behavior. Any other use of an invalid pointer value has implementation-defined behavior.
with a non-normative note stating:
Some implementations might define that copying an invalid pointer value causes a system-generated runtime fault
These 2 lines do not have any difference (meaning legality for C++):
A* c = a; //illegal - I know it (in c++ 11)
A* d = b; //I suppose it's legal, is it true?
Your mistake (and it is pretty common) to think if you call delete on a it makes it any different than b. You should remember that when you call delete on a pointer you pass argument by value, so memory, where a points to after delete is not usable anymore, but that call does not make a any different than b in your example.
You should not use the pointer after delete. My below example with acessing a is based on implementation-defined behaviour.
(thanks to for M.M and Mankarse for pointing this)
I feel that it is not the variable a (or b, c, d) that is important here, but that the value (=the memory address of a deallocated block) which in some implementations can trigger a runtime fault when used in some 'pointer context'.
This value may be an rvalue/expression, not necessarily the value stored in a variable - so I do not believe the value of a ever changes (I am using the loose 'pointer context' to distinguish from using the same value, i.e. the same set of bits, in non-pointer related expressions - which will not cause a runtime fault).
------------My original post is below.---------------
Well, you are almost there with your experiment. Just add some cout's like here:
class A {};
A* a = new A();
A* b = a;
std::cout << a << std::endl; // <--- added here
delete a;
std::cout << a << std::endl; // <--- added here. Note 'a' can still be used!
A* c = a;
A* d = b;
Calling delete a does not do anything to the variable a. This is just a library call. The library that manages dynamic memory allocation keeps a list of allocated memory blocks and uses the value passed by variable a to mark one of the previously allocated blocks as freed.
While it is true what Mankarse cites from C++ documentation, about: "rendering invalid all pointers referring to any part of the deallocated storage" - note that the value of variable a remains untouched (you did not pass it by reference, but by value !).
So to sum up and to try to answer your question:
Variable a still exists in the scope after delete. The variable a still contains the same value, which is the address of the beginning of the memory block allocated (and now already deallocated) for an object of class A. This value of a technically can be used - you can e.g. print it like in my above example – however it is hard to find a more reasonable use for it than printing/logging the past...
What you should not do is trying to de-reference this value (which you also keep in variables b, c, and d) – as this value is not a valid memory pointer any longer.
You should never rely on the object being in the deallocated storage (while it is quite probable that it will remain there for some while, as C++ does not require to clear the storage freed after use) - you have no guarantees and no safe way to check this).

Address held by pointer changes after pointer is deleted

In the following code, why is the address held by pointer x changing after the delete? As I understand, the deletecall should free up allocated memory from heap, but it shouldn't change the pointer address.
using namespace std;
#include <iostream>
#include <cstdlib>
int main()
{
int* x = new int;
*x = 2;
cout << x << endl << *x << endl ;
delete x;
cout << x << endl;
system("Pause");
return 0;
}
OUTPUT:
01103ED8
2
00008123
Observations: I'm using Visual Studio 2013 and Windows 8. Reportedly this doesn't work the same in other compilers. Also, I understand this is bad practice and that I should just reassign the pointer to NULL after it's deletion, I'm simply trying to understand what is driving this weird behaviour.
As I understand, the deletecall should free up allocated memory from heap, but it shouldn't change the pointer address.
Well, why not? It's perfectly legal output -- reading a pointer after having deleted it leads to undefined behavior. And that includes the pointer's value changing. (In fact, that doesn't even need UB; a deleted pointer can really point anywhere.)
Having read relevant bits of both C++98 and C++11 [N3485], and all the stuff H2CO3 pointed to:
Neither edition of the standard adequately describes what an "invalid pointer" is, under what circumstances they are created, or what their semantics are. Therefore, it is unclear to me whether or not the OP's code was intended to provoke undefined behavior, but de facto it does (since anything that the standard does not clearly define is, tautologically, undefined). The text is improved in C++11 but is still inadequate.
As a matter of language design, the following program certainly does exhibit unspecified behavior as marked, which is fine. It may, but should not also exhibit undefined behavior as marked; in other words, to the extent that this program exhibits undefined behavior, that is IMNSHO a defect in the standard. Concretely, copying the value of an "invalid" pointer, and performing equality comparisons on such pointers, should not be UB. I specifically reject the argument to the contrary from hypothetical hardware that traps on merely loading a pointer to unmapped memory into a register. (Note: I cannot find text in C++11 corresponding to C11 6.5.2.3 footnote 95, regarding the legitimacy of writing one union member and reading another; this program assumes that the result of this operation is unspecified but not undefined (except insofar as it might involve a trap representation), as it is in C.)
#include <string.h>
#include <stdio.h>
union ptr {
int *val;
unsigned char repr[sizeof(int *)];
};
int main(void)
{
ptr a, b, c, d, e;
a.val = new int(0);
b.val = a.val;
memcpy(c.repr, a.repr, sizeof(int *));
delete a.val;
d.val = a.val; // copy may, but should not, provoke UB
memcpy(e.repr, a.repr, sizeof(int *));
// accesses to b.val and d.val may, but should not, provoke UB
// result of comparison is unspecified (may, but should not, be undefined)
printf("b %c= d\n", b.val == d.val ? '=' : '!');
// result of comparison is unspecified
printf("c %c= e\n", memcmp(c.repr, e.repr, sizeof(int *)) ? '!' : '=');
}
This is all of the relevant text from C++98:
[3.7.3.2p4] If the argument given to a deallocation function in the standard library
is a pointer that is not the null pointer value (4.10), the deallocation function
shall deallocate the storage referenced by the pointer, rendering invalid all
pointers referring to any part of the deallocated storage. The effect of using
an invalid pointer value (including passing it to a deallocation function) is
undefined. [footnote: On some implementations, it causes a system-generated
runtime fault.]
The problem is that there is no definition of "using an invalid pointer value", so we get to argue about what qualifies. There is a clue to the committee's intent in the discussion of iterators (a category which is defined to include bare pointers):
[24.1p5] ... 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; [sic]), x must always be assumed to have a singular value of a pointer.] Results of most expressions are undefined for singular values; the only exception is an 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. Dereferenceable and past-the-end values are always non-singular.
It seems at least plausible to assume that an "invalid pointer" is also meant to be an example of a "singular iterator", but there is no text to back this up; going in the opposite direction, there is no text confirming the (equally plausible) assumption that an uninitialized pointer value is meant to be an "invalid pointer" as well s a "singular iterator". So the hair-splitters among us might not accept "results of most expressions are undefined" as clarifying what qualifies as use of an invalid pointer.
C++11 has changed the text corresponding to 3.7.2.3p4 somewhat:
[3.7.4.2p4] ... Indirection through an invalid pointer value and passing an invalid pointer value to a deallocation function have undefined behavior. Any other use of an
invalid pointer value has implementation-defined behavior. [footnote: Some implementations might define that copying an invalid pointer value causes a system-generated runtime fault.]
(the text elided by the ellipsis is unchanged) We now have somewhat more clarity as to what is meant by "use of an invalid pointer value", and we can now say that the OP's code's semantics are definitely implementation-defined (but might be implementation-defined to be undefined). There is also a new paragraph in the discussion of iterators:
[24.2.1p10] An invalid iterator is an iterator that may be singular.
which confirms that "invalid pointer" and "singular iterator" are effectively the same thing. The remaining confusion in C++11 is largely about the exact circumstances that produce invalid/singular pointers/iterators; there should be a detailed chart of pointer/iterator lifecycle transitions (like there is for *values). And, as with C++98, the standard is defective to the extent it does not guarantee that copying-from and equality comparison upon such values are valid (not undefined).

dereferencing a pointer when passing by reference

what happens when you dereference a pointer when passing by reference to a function?
Here is a simple example
int& returnSame( int &example ) { return example; }
int main()
{
int inum = 3;
int *pinum = & inum;
std::cout << "inum: " << returnSame(*pinum) << std::endl;
return 0;
}
Is there a temporary object produced?
Dereferencing the pointer doesn't create a copy; it creates an lvalue that refers to the pointer's target. This can be bound to the lvalue reference argument, and so the function receives a reference to the object that the pointer points to, and returns a reference to the same. This behaviour is well-defined, and no temporary object is involved.
If it took the argument by value, then that would create a local copy, and returning a reference to that would be bad, giving undefined behaviour if it were accessed.
The Answer To Your Question As Written
No, this behavior is defined. No constructors are called when pointer types are dereferenced or reference types used, unless explicitly specified by the programmer, as with the following snippet, in which the new operator calls the default constructor for the int type.
int* variable = new int;
As for what is really happening, as written, returnSame(*pinum) is the same variable as inum. If you feel like verifying this yourself, you could use the following snippet:
returnSame(*pinum) = 10;
std::cout << "inum: " << inum << std::endl;
Further Analysis
I'll start by correcting your provided code, which it doesn't look like you tried to compile before posting it. After edits, the one remaining error is on the first line:
int& returnSame( int &example ) { return example; } // semi instead of colon
Pointers and References
Pointers and references are treated in the same way by the compiler, they differ in their use, not so much their implementation. Pointer types and reference types store, as their value, the location of something else. Pointer dereferencing (using the * or -> operators) instructs the compiler to produce code to follow the pointer and perform the operation on the location it refers to rather than the value itself. No new data is allocated when you dereference a pointer (no constructors are called).
Using references works in much the same way, except the compiler automatically assumes that you want the value at the location rather than the location itself. As a matter of fact, it is impossible to refer to the location specified by a reference in the same way pointers allow you to: once assigned, a reference cannot be reseated (changed) (that is, without relying on undefined behavior), however you can still get its value by using the & operator on it. It's even possible to have a NULL reference, though handling of these is especially tricky and I don't recommend using them.
Snippet analysis
int *pinum = & inum;
Creates a pointer pointing to an existing variable, inum. The value of the pointer is the memory address that inum is stored in. Creating and using pointers will NOT call a constructor for a pointed-to object implicitly, EVER. This task is left to the programmer.
*pinum
Dereferencing a pointer effectively produces a regular variable. This variable may conceptually occupy the same space that another named variable uses, or it may not. in this case, *pinum and inum are the same variable. When I say "produces", it's important to note than no constructors are called. This is why you MUST initialize pointers before using them: Pointer dereferencing will NEVER allocate storage.
returnSame(*pinum)
This function takes a reference and returns the same reference. It's helpful to realize that this function could be written with pointers as well, and behave exactly the same way. References do not perform any initialization either, in that they do not call constructors. However, it is illegal to have an uninitialized reference, so running into uninitialized memory through them is not as common a mistake as with pointers. Your function could be rewritten to use pointers in the following way:
int* returnSamePointer( int *example ) { return example; }
In this case, you would not need to dereference the pointer before passing it, but you would need to dereference the function's return value before printing it:
std::cout << "inum: " << *(returnSamePointer(pinum)) << std::endl;
NULL References
Declaring a NULL reference is dangerous, since attempting to use it will automatically attempt to dereference it, which will cause a segmentation fault. You can, however, safely check if a reference is a null reference. Again, I highly recommend not using these ever.
int& nullRef = *((int *) NULL); // creates a reference to nothing
bool isRefNull = (&nullRef == NULL); // true
Summary
Pointer and Reference types are two different ways to accomplish the same thing
Most of the gotchas that apply to one apply to the other
Neither pointers nor references will call constructors or destructors for referenced values implicitly under any circumstances
Declaring a reference to a dereferenced pointer is perfectly legal, as long as the pointer is initialized properly
A compiler doesn't "call" anything. It just generates code. Dereferencing a pointer would at the most basic level correspond to some sort of load instruction, but in the present code the compiler can easily optimize this away and just print the value directly, or perhaps shortcut directly to loading inum.
Concerning your "temporary object": Dereferencing a pointer always gives an lvalue.
Perhaps there's a more interesting question hidden in your question, though: How does the compiler implement passing function arguments as references?