'How to check c++ pointer pointing to invalid memory address?
Is there anyone show me how to check my pointer is pointing to an invalid memory address.
#include<iostream>
class Node{
public:
int data;
Node * next , * prev;
};
// Driver Code
int main () {
Node * node = new Node{ 3 , nullptr , nullptr };
Node * ptr = node;
delete node;
// here node gets deleted from memory and ptr pointing to invalid memory address
if(ptr == nullptr)
std::cout << "ptr is null \n";
else std::cout << "ptr is not null !\n";
return 0;
}
// OUTPUT : ptr is not null !
Here I have very simple code In which ' node ' is allocating memory in heap and pointer ' ptr ' points to the node after this I delete ' node ' and ' ptr ' is still pointing to 'node'. so the question is how I can check ' ptr ' is pointing to an invalid memory address.
Solution 1:[1]
I end up with this solution It may help someone who runs into the same problem
#include<iostream>
class Node{
public:
int data;
Node * next , * prev;
};
template<class T>
void DeletePtr (T*** ptr) {
T** auxiliary = &(**ptr);
delete *auxiliary;
**ptr = nullptr;
*ptr = nullptr;
}
// Driver Code
int main () {
Node * node = new Node{ 3 , nullptr , nullptr };
Node ** ptr = &node;
DeletePtr(&ptr);
if(ptr == nullptr && node == nullptr)
std::cout << "ptr is null \n";
else std::cout << "ptr is not null !\n";
return 0;
}
Solution 2:[2]
A debugger on Windows will use ReadProcessMemory and WriteProcessMemory functions to access memory of the debugged program in a safe way. Those functions do not crash if memory is not accessible, but instead return an error.
Using ReadProcessMemory
outside of a debugger has a lot of drawbacks:
- Extremely bad programming design.
- Not sure it works for own process.
- Not portable, need to figure out for Linux and macOS.
- The function is orders of magnitude slower than a direct memory access. Your program may become slow as hell.
- The fact that memory is accessible does not mean pointer is valid. It can point to other completely random application data. You cannot trust what you read; displaying for debug is OK, using it for real not. And writing is very dangerous
Alternatively, what you might actually need is Address Sanitizer. Address Sanitizer is an extremely powerful debug tool for C++, made by Google and currently builtin in all major compilers: GCC, Clang and MSVC.
Address Sanitizer will automatically check the validity of every pointer value before dereferencing them. A valid pointer means pointing inside a previously allocated and not et deallocated block. If you have a bad pointer, the program stops with a nice diagnostics message.
Valgrind is a similar debugging tool, but I would recommend Address Sanitizer as it is much faster, uses less memory, and is available on all platforms.
Solution 3:[3]
I usually never call directly delete
, I use a template function to clean memory:
template < typename T > void destroy ( T*& p ) {
if (p)
delete p;
p = nullptr;
}
....
Anything* mypointer = new ..... ;
....
destroy(mypointer) ; // Implicit instanciation, mypointer is nullptr on exit.
This way, you never have a destroyed object with a invalid pointer remaining. Better, the call to destroy
is safe, you can call it on an already nullptr
pointer without any consequences.
Solution 4:[4]
As mentioned in the comments there is no canonical way to check whether a raw pointer points to a valid allocated memory. Any code trying to do so relying on underlying compiler specific semantics will produce brittle code.
Fortunately since C++11, the C++ standard library present us with 3 smart pointer types we can use to write safe code that can check the validity of memory. Look at the documentation for smart pointers.
The three smart pointer types are std::unique_ptr
, std::shared_ptr
and std::weak_ptr
.
unique_ptr
allows only a single ownership of the underlying allocated memory. This means that at any point during the program's execution, only oneunique_ptr
object can be used to access the memory. Once the ownership is transferred to anotherunique_ptr
object the old object can no longer be used to access the underlying memory. This kind of smart pointer is perfect for holding private state or for implementing move semantics API.shared_ptr
allows shared ownership of the memory. As long as there is at least oneshared_ptr
object holding access to the memory the memory will not be released. This is achieved using reference counting. Every time theshared_ptr
is copied the reference count is incremented. Every time ashared_ptr
object goes out of scope the reference count is decremented. Once the count reaches 0 the memory is released.weak_ptr
is also used for shared ownership of memory together withshared_ptr
. However holding aweak_ptr
object will not prevent the memory from being released (assigning aweak_ptr
will not increase the reference count`). You may wonder why this is a good thing? The most trivial example is a circular reference. It will be shown in the code below.
Actually a linked list like the one on the question should not use unique_ptr
(unless each node holds some private state) but rather shared_ptr
and weak_ptr
. In the sample code below I will show the use of all three types (the unique_ptr
will be used for the data - not the list).
#include <memory>
#include <iostream>
class List;
// A small sample ilustrating the use of smart pointer
class Node {
friend class List;
public:
typedef std::shared_ptr<Node> ptr;
~Node() = default; // No need to handle releasing memory ourselves - the smart pointer will take care of it
static ptr create_with_data(int data) {
return ptr(new Node(data));
}
ptr next() {
return next_;
}
ptr prev() {
return prev_.lock(); // We need to upgrade the weak_ptr to shared_ptr to actually be able to access the data
// If we don't have a previous element od if it was deleted we will return nullptr
}
int data() const {
return *data_;
}
private:
// We make the constructors private so we can only create shared pointers to Node
Node() = default;
Node(int data) {
data_.reset(new int);
*data_ = data;
}
// The data will be automatically released when Node is released.
// This is obviously not needed for int but if we were dealing with more complex data
// Then it would have come handy
std::unique_ptr<int> data_;
ptr next_; // Pointer to the next node in the list
// If we are released so will be the next node unless someone else is using it
std::weak_ptr<Node> prev_; // Pointer to the previous node in the list (We will however not prevent it from being released)
// If we were to hold a shared_ptr here we would have prevented the list from being freed.
// because the reference count of prev would never get to be 0
};
class List {
public:
typedef std::shared_ptr<List> ptr;
~List() = default; // Once List is deleted all the elements in the list will be dleted automatically
// If however someone is still holding an element of the list it will not be deleted until they are done
static ptr create() {
return ptr(new List());
}
void append(Node::ptr next) {
if(nullptr == head_) {
head_ = next;
}
else {
auto tail = head_;
while(tail->next_) {
tail = tail->next_;
}
tail->next_ = next;
next->prev_ = tail; // This will not increment the reference count of tail as prev_ is a weak_ptr
}
}
Node::ptr head() {
return head_;
}
long head_use_count() const {
return head_.use_count();
}
private:
Node::ptr head_;
};
int main(int, char const*[]) {
auto list = List::create(); // List will go out of scope when main returns and all the list will be released
auto node = Node::create_with_data(100); // This node will also live until the end of main.
std::cout << "node reference count: " << node.use_count() <<std::endl;
list->append(node); // node is now the head of the list and has a reference count of 2
std::cout << "node reference count: " << node.use_count() <<std::endl;
node.reset(); // Hey what is this? node is no longer valid in the scope of main but continues to live happily inside the list
// the head of the list has a reference count of 1
std::cout << "node reference count: " << node.use_count() <<std::endl;
if (nullptr != node) {
std::cout << node->data() << std::endl;
}
else {
std::cout << "node is released in this scope we can access the data using head()" << std::endl;
std::cout << "Head is: " << list->head()->data() << std::endl;
// You may thin that the below line should print 1. However since we requested
// a copy of the head using head() it is 2
std::cout << "Head reference count: " << list->head().use_count() << std::endl;
// To print the use count from the list we will use the function we created for this
// It will print 1 as expected
std::cout << "Head reference count: " << list->head_use_count() << std::endl;
}
// Lets add another node to the list and then release the but continue holding our node and see what happens
node = Node::create_with_data(200);
list->append(node);
// Did the reference count of the head changed? No because prev_ is weak_ptr
std::cout << "Head reference count: " << list->head_use_count() << std::endl;
auto prev = node->prev();
// Did the reference count of the head changed? Yes because the call to prev() locks the previous element for us
// And the previous of node is the head
std::cout << "Head reference count: " << list->head_use_count() << std::endl;
prev.reset(); // Let's release our holding of the head
std::cout << "Head reference count: " << list->head_use_count() << std::endl;
// Traverse the list
{
auto next = list->head();
while(next) {
std::cout << "List Item: " << next->data() << std::endl;
next = next->next();
}
}
// Here we still hold a reference to the second element of the list.
// Let's release the list and see what happens
list.reset();
if (nullptr != list) {
std::cout << "The head of the list is " << list->head()->data() << std::endl;
}
else {
// We will get here
std::cout << "The list is released" <<std::endl;
// So the list is released but we still have a reference to the second item - let's check this
if (nullptr != node) {
std::cout << "The data is " << node->data() << std::endl;
// What about the head - can we maybe access it using prev?
auto head = node->prev();
if (nullptr != head) { // We will not get here
std::cout << "The value of head is " << head->data() << std::endl;
}
else {
// We will get here
std::cout << "We are detached from the list" << std::endl;
}
}
else {
std::cout << "This is unexpected" << std::endl;
}
}
return 0;
}
Note The callse to reset()
you see in the code are just to illustrate what happens when you release the reference a shared_ptr
holds. In most cases you will not call reset()
directly.
Solution 5:[5]
I don't how to check invalid memory address but I have a solution for you're problem you can create your own Pointer. here's code
#include<iostream>
// Add this class in you're code
template<class T>
class Pointer {
public:
Pointer (T* node){
this->node = node;
}
// use obj.DeletePtr() instead of 'delete' keyword
void DeletePtr () {
delete node;
node = nullptr;
}
// compare to nullptr
bool operator == (nullptr_t ptr){
return node == ptr;
}
private:
T* node;
};
class Node{
public:
int data;
Node * next , * prev;
};
int main () {
Pointer ptr (new Node{3 , nullptr , nullptr}); // initialize pointer like this
ptr.DeletePtr();
if(ptr == nullptr)
std::cout << "ptr is null \n";
else
std::cout << "ptr is not null !\n";
return 0;
}
Solution 6:[6]
Yes, you can check if a pointer is pointing to an allocated memory of certain size.
But no, you can't check if it points to the "correct" object. But since this wasn't your question, I will assume you only care if dereferencing a pointer would cause a crash in your program.
bool wouldDereferencingCauseCrash(int* ptr); //checks if ptr points to sizeof(int)
//allocated on heap bytes
int* a = new(int);
int* b = a;
wouldDereferencingCauseCrash(b); //returns false - b points to memory alocated for a
free(a);
wouldDereferencingCauseCrash(b); //returns true - b points to freed memory chunk
int* c = new(int);
wouldDereferencingCauseCrash(b); //returns ???? - b points to either freed memory
// or memory allocated for c
Now how would we implement this mysterious function "wouldDereferencingCauseCrash"?
First, the basics. Let's assume you're using GCC compiler, and new() is actually just a malloc() in disguise (which is usually the case).
Heap is one contiguous block of memory. Malloc() returns a chunk of memory which for our purposes looks like this:
//this is a simplification but you can deduce all these parameters from the original
//struct contained in malloc.c
struct memory_chunk{
void* ptrToPreviousChunk; //we can deduce pointer to prev. allocated memory_chunk
void* ptrToNextChunk; //we can deduce pointer to next allocated memory_chunk
void* ptrToChunk; //this is what malloc() returns - usable memory.
int sizeOfChunk; //we can deduce if this holds sizeof(int) bytes
};
Now if we just iteratore through all the allocated chunks and find our pointer - we know it points to an allocated memory. If sizeOfChunk is also sizeof(int) - we know it holds an integer. Voila, dereferencing this pointer won't cause a crash. Great! But just to be safe, don't try to write to this memory, copy it first :).
Now the hard stuff:
1/ depending on your compiler, malloc() might work differently,
2/ malloc() sometimes doesn't allocate memory chunks on the heap, sometimes it maps them using mmap() (but usually only if they are very very big),
3/ new() might not be based on malloc() (not likely),
4/ I simplified this quite a bit, read sources if you're intrested in implementing any of this. I recommend using unique_ptr instead or tracking the allocations/deallocations in some kind of a map.
Good luck! :) I hope I don't see this nonsense anywhere near me though :)
Sources:
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | zain ul din |
Solution 2 | |
Solution 3 | Wisblade |
Solution 4 | |
Solution 5 | Ars |
Solution 6 | Jedrzej |