Archived

This topic is now archived and is closed to further replies.

Matsen

How to tell if a pointer is valid

Recommended Posts

Hi Is it possible to determine if a pointer is valid and if it''s not, maybe throw an exception? Here is what I mean: Lets say I have a class... class MyClass { public: void function(); } Now, somewhere, someone does this to a pointer, pointing on an instance of the class above... ptrMyClass = 1; ...and later on, when trying to access function() if (ptrMyClass != NULL) ptrMyClass->function(); .. crash Is there a way to tell that ptrMyClass isn''t a valid pointer? NULL doesn''t help much, and I think I''ve read here somewhere that using NULL as a guarantee for non-valid pointers isn''t the best way. What is the best (or correct) way? Best regards Mats

Share this post


Link to post
Share on other sites
Well, there''s only so much you can do. If you initialize your pointers to NULL, then checking for NULL will work in most cases. Of course, if you''re creating something, then deleting it an not setting the pointer back to NULL, or if someone else is pointing to the same data, there''s nothing you can do.

Share this post


Link to post
Share on other sites
You could do a dynamic_downcast surrounded by a try { } catch (...) block, but that''s really overkill. If somebody does that to a pointer to your class, you''re entitled to crash :-)

Share this post


Link to post
Share on other sites
if someone does that then they are being mailicious.

what about overloading the assignment operator? slightly related, i remember reading an article where a class that was returned from a function by value would log an error if it wasn''t assigned to another object.

maybe you could prevent someone assigning an integer to an object pointer.

any ideas anyone?

Share this post


Link to post
Share on other sites
quote:
Original post by Matsen
Now, somewhere, someone does this to a pointer, pointing on an instance of the class above...

ptrMyClass = 1;

That''s not actually going to compile. The only means of converting an integral expression to a pointer is via a reinterpret_cast, which would most likely represent malicious (or very stupid) intent.
quote:

Is there a way to tell that ptrMyClass isn''t a valid pointer?

Not in the sense that you are thinking, but you might like to learn a little about smart pointers which may be useful in some of the pointer-related headaches you are bound to encounter.


[ C++ FAQ Lite | ACCU | Boost | Python | Agile Manifesto! ]

Share this post


Link to post
Share on other sites
quote:
Original post by SabreMan
That''s not actually going to compile. The only means of converting an integral expression to a pointer is via a reinterpret_cast, which would most likely represent malicious (or very stupid) intent.



No, it didn''t (ptrMyClass = (MyClass*)1);

The example might not have been the best, but you understood what I meant. I was just curious to know if it was possible, and the conclusion is that it''s not, at least not without using os specific functions.

Thanks

Regards Mats

Share this post


Link to post
Share on other sites
quote:
Original post by SabreMan
The only means of converting an integral expression to a pointer is via a reinterpret_cast, which would most likely represent malicious (or very stupid) intent.



Real-mode memory-mapped IO, or driver implementations which require absolute addresses. (OK, I''ll admit it''s a bit outside the scope of these forums )


Documents [ GDNet | MSDN | STL | OpenGL | Formats | RTFM | Asking Smart Questions ]
C++ Stuff [ MinGW | Loki | SDL | Boost. | STLport | FLTK | ACCU Recommended Books ]

Share this post


Link to post
Share on other sites
quote:
Original post by Fruny
Real-mode memory-mapped IO, or driver implementations which require absolute addresses. (OK, I''ll admit it''s a bit outside the scope of these forums )

Which is why I said "most likely". I did, of course, leave out the "least likely" interpretation, which is that the person genuinely knows what they are doing.

Share this post


Link to post
Share on other sites
quote:
Original post by Matsen
The example might not have been the best, but you understood what I meant.

Not meaning to have a go, but the "you know what I meant" attitude is a real pet-hate of mine. I can only know what you said.

I thought your question was about how to avoid seemingly innocuous constructs like:

class C
{};

C *pc = new C;
pc = 1;

//...


With the answer being that you can't do that. I think that's a different question to how to avoid this:


class C
{};

C *pc = new C;
pc = reinterpret_cast<C*>(1);

//...


Since, in the 2nd case, the coder has to go out of their way to do something malicious. You shouldn't worry about it too much, since you cannot prevent malicious intent.

[edited by - SabreMan on June 10, 2002 2:53:38 PM]

Share this post


Link to post
Share on other sites
you _can_ prevent the bad pointer... but this bad pointer was PLANNED from the programmer so.. if he wants to stress you he can simply write while(1);
catching this is rather difficult

"take a look around" - limp bizkit
www.google.com

Share this post


Link to post
Share on other sites
quote:
Original post by Matsen
...
ptrMyClass = 1;




Try this (a quick hack, not the safest):


        
class MyClass
{
public:
MyClass() : _validId(0x12345678) { }
~MyClass() { _validId = 0; }
void SomeFunc();

private:
void TestLegal()
{
if (_validId == 0x12345678)
throw "An invalid MyClass object function called.";
}

private:
unsigned long _validId;
};

void MyClass::SomeFunc()
{
TestLegal();
// do ur stuff here

}

int main()
{
try
{
...
MyClass *pMyClass = (MyClass*) 1;
pMyClass->SomeFunc(); // will throw exception

...
}
catch(const char *msg)
{
cerr << "Error: " << msg << endl;
return 1;
}
catch(...)
{
cerr << "Unknown exception caught." << endl;
return 3;
}
return 0;
}


When you call the function of an invalid object of class MyClass, it will throw an exception... indicating the intended error. But remember to set the _validId in every constructor you got.

**Note: Not necessarily an exception of type char* will be thrown.

[edit] Added destructor so that pointing to a deleted (but forgot NULLing) MyClass object will also throw.

[edited by - DerekSaw on June 10, 2002 12:27:33 AM]

[edited by - DerekSaw on June 10, 2002 12:31:08 AM]

Share this post


Link to post
Share on other sites
If the pointer to the class is invalid, dereferencing it to get the _validId member will still cause the same problem. (Unless you catch the error, which you do in main, but to be really safe, it should happen in TestLegal).




[edited by - Kippesoep on June 11, 2002 8:30:54 AM]

Share this post


Link to post
Share on other sites
You could make things more safe if you are willing to pay the price. Introduce your own pointer safety by using something like a singleton to register your class instances with.

Give or take typing mistakes


  
template <class T> class Watcher
{
static set<T *> instanceList;

// Prevent other instances of this class

Watcher()
{

}

Watcher(const Watcher &)
{

}
public:

static void Register(T* instance)
{
Watcher<T>::instanceList.insert(instance);
// cout << "Registering" << endl;

}


static void Unregister(T* instance)
{
Watcher<T>::instanceList.erase(instance);
// cout << "Unregistering" << endl;

}

static bool IsLegal(T* instance)
{
return (Watcher<T>::instanceList.count(instance) == 1) ? true : false;
}

static T *GetLegal(T* instance)
{
if( IsLegal(instance) == true )
return instance;
else
return NULL;
}

static int Size()
{
return Watcher<T>::instanceList.size();
}
};


Then you just bung


  
class Base
{
public:
Base()
{
Watcher<Base>::Register(this);
}

~Base()
{
Watcher<Base>::Unregister(this);
}
};

class Derived : public Base
{
public:
Derived()
{
Watcher<Derived>::Register(this);
}
~Derived()
{
Watcher<Derived>::Unregister(this);
}
};

int main(int argc, char* argv[])
{
Base one;
Derived two;

Watcher<Base>::Size(); // the answer is 2

Watcher<Derived>::Size(); // the answer is 1


Watcher<Base>::IsLegal(&one + 1) ); // Answer: False

Watcher<Derived>::IsLegal(&two); // Answer: True - &two is a valid Derived pointer

Watcher<Base>::IsLegal(&two); // Answer: True - &two is a valid Base pointer

return 0;
}



I wrote a little test program and it does compile and do what I think you want. I may have missed an issue or two here it''s off the top of my head.

There are various adaptations you could make to this - eg not registering etc class in a seperate instanceList. Maybe you want a Register class to inherit from or similar - which checks that the pointer is valid but not if the type conversion is.

I guess this is some form of homebrew RTTI.

There was something else too...but I''ve forgotten it.

Oh well hoped that helped,

Chris

Share this post


Link to post
Share on other sites
quote:
Original post by chrisflatley
Introduce your own pointer safety by using something like a singleton to register your class instances with.

I don''t see how that is any "safer" than not doing anything specific, as it is still open to abuse, and actually requires more discipline from the programmer.

Share this post


Link to post
Share on other sites
I agree that it''s not bullet proof but if I put system in my classes and then I check in my code when passed a pointer from the client code:


  
void GiveMeAClass(MyClass *p)
{
if( Watcher<MyClass *>::IsLegal(p) == false)
{
throw "Bad MyClass pointer";
}

// else do your stuff


}


In order to get past this, say you want to call with p = 1, then you are going to have to Register a MyClass at 1. Easily done with a cast I know - but you have to actually do it.

I''ll admit that no matter what you do there''s some way around it but if do want to check if a pointer valid then you could do it this way.

If you hide the implementation of your constructors/destructors, then the "evil coder" is going to have to do some work before he''ll find out what to call - at which point nothing is going to stop him from ruining your code however safe you attempt to make it.

Share this post


Link to post
Share on other sites