HelllllloW everybody!!!
Finally I am back, after 7 months, from a crazy trip in South America! Where I got robbed at gun-point, and denied access to USA (wanted to consult there), saw amazing views and creatures, among other stories, but it’s not the place to talk about them :) Maybe if you insist I will post once about it.
<geek warning>
Honestly, I freaked out in the trip without a computer (bits/assembly/compiler), so all I could do was reading and following many blogs and stuff.
</geek warning>
I even learned that my post about the kernel DoS in XPSP3 about the desktop wallpaper weakness became a CVE. It seems MS has fixed it already, yey.
And now I need to warm up a bit, and I decided to dive into C++ with an interesting and very useful example. Cleaning resources automatically when they go out of scope. I think that not many people are aware to the simplicity of writing such a feature in C++ (or any other language that supports templates).
The whole issue is about how you destroy resources, I will use Win32 resources for the sake of example. I already talked once about this issue in C.
Suppose we have the following snippet:
HBITMAP h = LoadBitmap(...);
if (h == NULL) return 0;
HBITMAP h2 = Loadbitmap(...);
if (h2 == NULL) {
DeleteObject(h);
return 0;
}
char* p = (char*)malloc(1000);
if (p == NULL) {
DeleteObject(h2);
DeleteObject(h);
return 0;
}
And so on, every failure handling in the if statements we have to clean more and more resources. And you know what, even today people forget to clean all resources, and it might even lead to security problems. But that was C times, and now we are all cool and know C++, so why not use it? One book which talks about these issues is Effective C++, recommended.
Also, another problem with the above code is while an exception is being thrown in the middle or afterward, you still have to clean those resources and copy/paste some lines, which makes it prone to errors.
Basically, all we need is a nice small class which will be called AutoResource that holds the object itself and will manage it. Personally, it reminds me auto_ptr class, but it’s way less permissive. You will be only able to initialize and use the object. Of course, it will be destroyed automatically when it goes out of scope.
How about this code now:
AutoResource<HBITMAP> h(LoadBitmap(...));
AutoResource<HBITMAP> h2(LoadBitmap(...));
char* p = new char[1000]; // If an exception is thrown, all objects initialized prior to this line are automatically cleaned.
Now you can move on and be totally free of ugly failure testing code and not worry about leaking objects, etc. Let’s get into details. What we really need is a special class that we can change the behavior of the CleanUp() method according to its object’s type, that’s easily possible in C++ by using a method specialization technique. We will not let to copy or assign to the class. We want a total control over the object, therefore we will let the user to get() it too. And as a type of defense programming, we will force the coder to implement a specialized CleanUp() in a case he uses the class for new types and forgets to implement the new CleanUp code; By using compile time assertion (I used this trick from Boost). Also, there might be a case where the constructor input is NULL, and therefore the constructor will have to inform the caller by throwing an exception, download and check out the complete code later.
template <class T> class AutoResource {
public:
AutoResource(T t) : m_obj(t) { }
void CleanUp()
{
// WARNING:
// If the assertion occurred you will have to specialize the CleanUp with the new type.
BOOST_STATIC_ASSERT(0);
}
~AutoResource()
{
CleanUp();
m_obj = NULL;
}
T get() const
{
return m_obj;
}
private:
T m_obj;
};
//Here we specialize the CleanUp() for the HICON resource.
template<> void AutoResource<HICON>::CleanUp()
{
DestroyIcon(AutoResource<HICON>::m_obj);
}
You can easily add new types and enjoy the class. If you have any suggestions/fixes please leave a comment!
Download complete code: AutoResource.cpp.
Thanks to Yan Michalevsky for helping with the code!
P.S – While compiling this stuff, I found a crash in the Optimization Compiler of VS2008 :) lol.