How to tell if a pointer is valid

Started by
15 comments, last by Matsen 21 years, 10 months ago
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&ltC*>(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]
Advertisement
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
If that's not the help you're after then you're going to have to explain the problem better than what you have. - joanusdmentia

My Page davepermen.net | My Music on Bandcamp and on Soundcloud

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]
"after many years of singularity, i'm still searching on the event horizon"
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]
Kippesoep
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 2Watcher<Derived>::Size(); // the answer is 1		Watcher<Base>::IsLegal(&one + 1) ); // Answer: False	Watcher<Derived>::IsLegal(&two); // Answer: True - &two is a valid Derived pointerWatcher<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
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.
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.

This topic is closed to new replies.

Advertisement