How to purposefully put an Assertion failure into Finalize() for debug builds using C++/CLI syntax?

  • Thread starter Thread starter Bern McCarty
  • Start date Start date
B

Bern McCarty

I am porting stuff from MEC++ syntax to the new C++/CLI syntax. Something
that we did in the old syntax that proved to be very valuable was to make
sure that the finalizer would purposefully generate an assertion failure
for unoptimized, debug builds. We did this to find and fix cases where we
were relying upon finalization rather than pro-active Dispose() calls.

For classes that introduced IDisposable() into the class hierarchy themselves
we would do this:

protected: ~ColorBookEnumerator()
{
#if !defined (NDEBUG)
System::Diagnostics::Debug::Assert(false, S"Neglected to call Dispose()
on object.");
#endif
this->Dispose(false);
}

For classes where IDisposable was already introduced into the class heirarchy
we would do this:


#if !defined (NDEBUG)
protected: ~ColorBookEnumerator()
{
System::Diagnostics::Debug::Assert(false, S"Neglected to call Dispose()
on object.");
this->Dispose(false);
}
#endif


This has been very useful in helping us to find places where we were relying
upon the finalizer thread only by accident. How do I accomplish this using
the new C++/CLI syntax?

-Bern McCart
 
To implement a finalization logic, write a function !T instead of ~T (where
T is the typename)

Marcus
 
Bern said:
That is not an answer to my question.

Marcus is right, the finalizer in C++/CLI is !T.

So to translate your old code to C++/CLI:

public: ~ColorBookEnumerator()
{
delete unmanaged_resources;
FinalizeMe();
}
protected: !ColorBookEnumerator()
{
#if !defined (NDEBUG)
System::Diagnostics::Debug::Assert(false,
"Neglected to call Dispose() on object.");
#endif
FinalizeMe();
}
private: void FinalizeMe()
{
delete managed_resources;
}

Tom
 
Thanks Tom :)

Bern McCarty, after rereading your post, I find your approach is a little
bit strange.

What is your intention to handle classes that introduce IDisposable diffrent
than classes derived from classes that introduce IDisposable?

If you want to avoid that two assertions are done, your approach does not
seem right. In this case it is sufficient to implement !T in the class that
first introduces a finalizer.

Marcus


If your class does not implement IDisposable, there is no need for a
finalizer
 
Those replying are failing to understand my question at all so I'll attempt
to clarify. Firstly, the reason I treat classes that introduce IDisposable
into the class heirarchy a little differently from those that derive from
something that has already introduced it into the class heirarchy, is because
you're supposed to. Go read up on the Dispose pattern in the Framework Design
Guidelines. When you derive from something that has already introduced IDisposable
into the heirarchy you don't really need a finalizer since chaining happens
through "virtual Dispose(bool)". So I add a finalizer anyway (only for non-retail
builds) just because I want a place for the assert.

The MEC++ code that I showed does exactly what I want in both cases. It
generates an assert in non-retail builds whenever finalization occurs on
my instances, but the assertions do NOT fail any other time - because that
code isn't even called during proactive Dispose() calls and then finalization
is supressed.

Yes, I know the C++/CLI syntax. Yes, I know about ~ and !. The problem is
the way that the compiler generates the code when you use ~ and !. It affords
me no place to put any code that will ONLY be run during finalization (and
not during proactive Dispose()). The code that I put into ~ is in fact called
during proactive Dispose() in addittion to finalization. Perhaps if I could
access the "disposing" boolean that is defined/used in the automatically
generated code, then I could do:

if (false==disposing)
System::Diagnostics::Debug::Assert(false, L"Neglected to call Dispose()
on object.");

....but I don't know how to get access to that instance bool at source level.
Is there a way?

There must be some way to do this in the new language. We have found the
practice very useful. It has definitely saved us from shipping code that
relied unnecessarily upon the finalizer thread.

-Bern
 
Bern McCarty wrote:

The problem
is the way that the compiler generates the code when you use ~ and !. It
affords me no place to put any code that will ONLY be run during
finalization

Yes it, does, !T().
The code that I put
into ~ is in fact called during proactive Dispose() in addittion to
finalization.

No. ~T() is called for Dispose() and only for that. !T() is called for
finalization and only for that.
Perhaps if I could access the "disposing" boolean that is
defined/used in the automatically generated code, then I could do:

if (false==disposing)

For the C++/CLI compiler, both the Dispose() and the Dispose(bool)
methods are inaccessible. But you don't need to access any of those
functions, when the language provides true destructor and finalizer.
Forget about the entire Dispose(bool) pattern. You don't need that
runtime disposing flag, when you have a way to separate your destruction
and finalization at compile time. The way C# is doing it is
overcomplicated -- why doing it runtime, when you can do it at compile time?

I'm positive that the code I posted works, regardless from where you
inherit from. It works when inheriting from existing C# classes, and it
also work when you don't inherit from any class at all. The compiler
automatically generates the SupressFinalize call, the Dispose() method,
everything that you need, but it absolutely disregards the Dispose(bool)
pattern, because it's an overkill and you don't need that.

The only case when my sample doesn't work is when you inherit from a
class implementing this pattern:

ref class Base
{
public:
~Base() { this->!Base(); }
protected:
!Base() { }
};

In this case ~T() calls !T(), which means you have nowhere to place your
assertion. But my pattern is different, I explicitly made sure that the
destructor doesn't call the finalizer.

Here's something to prove that !T() is not called when Dispose() is
called properly:

public ref class FSTest : public System::IO::FileStream
{
public:
FSTest() : System::IO::FileStream("test.out",
System::IO::FileMode::Create) { }
protected:
!FSTest()
{
#if !defined (NDEBUG)
System::Diagnostics::Debug::Assert(false,
"Neglected to call Dispose() on object.");
#endif
}
};

int main(array<String ^> ^args)
{
FSTest test1;
}

Tom
 
I think I understand better now. Does the below program use ~T and !T correctly
to deal with the managed and native resources of MyClass? If a type has native
resources then you have to make sure to free them from both !T and ~T. That
was the point that I was missing. Whenver you have more than a single native
resource to deal with you will obviously want to free all of them in a routine
that is called from both ~T and !T for ease of maintenance. We will face
this pattern over and over again. But what to call this other method? It
seems to me that the C++/CLI programmers of the world would do well to agree
to name that routine uniformly so that it is recognizeable immediately by
an C++/CLI programmer for what it is. Is there a convention for the naming
of this routine that has been agreed to to any extent? DisposeNativeResources()?

-Bern McCarty

---------------------------------------------------

#using <System.dll>
#using <System.Windows.Forms.dll>
namespace Test
{
using System::Windows::Forms::Form;

class MyNativeType
{
private: int fooint;
public: virtual ~MyNativeType() { System::Console::WriteLine(L"MyNativeType
destructor called"); }
};

ref class MyClass : System::IDisposable
{
private: MyNativeType* myNativeInstance;
private: Form^ myDisposableForm;

public: MyClass()
{
myNativeInstance = new MyNativeType;
myDisposableForm = gcnew Form();
}

public: !MyClass()
{
#if !defined (NDEBUG)
System::Diagnostics::Debug::Assert(false, L"Neglected to call Dispose()
on MyClass instance.");
#endif
delete myNativeInstance;
}

private: ~MyClass()
{
System::Console::WriteLine(L"MyClass Dispose() called");
delete myDisposableForm;
delete myNativeInstance;
}
};
}

int main(int argc, char* argv[])
{
Test::MyClass^ myClassInstance = gcnew Test::MyClass;
delete myClassInstance;
System::GC::Collect();
System::GC::WaitForPendingFinalizers();
return 0;
}
 
Bern said:
Does the below program use ~T and !T
correctly to deal with the managed and native resources of MyClass?

I think it's all correct.
If a
type has native resources then you have to make sure to free them from
both !T and ~T.

Yes, you did that right. Although I'm usually not very happy about
placing "naked" native pointers in any class, whether it's managed or
native. In a native application, I'd use boost::shared_ptr or
boost::scoped_ptr to guard that native object. I've worked out a similar
template for managed classes:

http://tweakbits.com/CliScopedPtr.h

Using this template you can ensure that the owned native objects are
deleted automatically, no matter what (if Dispose is not called, then
the finalizer will take care of it). Here's how to use it:

#include "CliScopedPtr.h"

ref class MyClass
{
public:
MyClass()
: native1(new MyNativeType),
native2(new MyNativeType2)
{ }
private:
CliScopedPtr<MyNativeType> native1;
CliScopedPtr<MyNativeType2> native2;
};

You don't even need to declare any destructor or finalizer (except for
your Assert, but not for resource management). The compiler will
automatically implement those, and will inherit from IDisposable too.
You'll never miss another delete. Of course MyClass is a resource now
(thanks to the CliScopedPtr members), so it is strongly recommended to
call Dispose on it (the compiler implicitly generates the Dispose() for
MyClass; in C++/CLI you call delete, in other languages you call Dispose()).

Note that CliScopedPtr holds a native pointer, never a managed object.

I'm not trying to force this on you at all; what you're doing is
perfectly fine. When I program in native C++, I certainly use smart
pointers. I may be overreacting here, but I prefer doing the same for
native resources inside managed classes. I'm aware that this adds a
little bit of an overhead to the code, therefore it is not always advisable.

Exception safety inside a constructor is not that important in managed
code, because when any exception is thrown from the constructor, the
destructor is still being called (unlike in ISO C++). So the importance
of CliScopedPtr is certainly much smaller than the importance of smart
pointers in native C++.
Is there a convention for the naming of this
routine that has been agreed to to any extent? DisposeNativeResources()?

That sounds good to me. I'm not aware of any naming the standard
recommends. The convention that others are using is this:

~T() { this->!T(); }

Which you can rule out if you want to place an Assert in your finalizer.
What you're doing is not a bad idea, but it will only work with your own
classes. There are commercial memory leak detectors that can point out
these problems, and even more. Nevertheless, the Assert may still be a
good idea in many cases, and it comes free.
ref class MyClass : System::IDisposable
{

It is not required that you inherit from IDisposable. If your ref class
declares a destructor, the compiler automatically makes the class an
IDisposable.

Tom
 
Hi Bern McCarty,

Even though you believe I am failing to understand your question, I think I
should add some facts here.

As I mentioned originally, !T implements a finalizer. This fializer is
sufficient for your concrete needs (Assertions)
As Tom mentioned, !T is aware of the Dispose pattern

As soon as you want to implement finalizers that do more than just
assertions, the situation gets really different. Apart from some high
availability issues that we can ignore in most cases, the code you suggest
has three issues:
a) There is a high danger of adding an ugly race condition to your code
b) In case of finalization, your referenced managed objects (the form and
all controls it contains) are held longer than necessary. This is called the
"graph promotion" problem
c) Your code may be exploitable via a so-called "handle recycling attack".

re a) make sure you call GC::KeepAlive(this) at the end of each function
that uses your native resource
re b) do not mix managed and native resources in a single class - write a
separate class that wraps only the native resource. Only this class should
contain finalization logic.
re c) this problem is difficult to solve manually, however, handle recycling
attacks are difficult to achieve in reality, so you may ignore them. If you
don't want to ignore them, read the MSDN documentation of
System::Runtime::InteropServices::SafeHandle.

Marcus

Bern McCarty said:
I think I understand better now. Does the below program use ~T and !T
correctly to deal with the managed and native resources of MyClass? If a
type has native resources then you have to make sure to free them from
both !T and ~T. That was the point that I was missing. Whenver you have
more than a single native resource to deal with you will obviously want to
free all of them in a routine that is called from both ~T and !T for ease
of maintenance. We will face this pattern over and over again. But what to
call this other method? It seems to me that the C++/CLI programmers of the
world would do well to agree to name that routine uniformly so that it is
recognizeable immediately by an C++/CLI programmer for what it is. Is
there a convention for the naming of this routine that has been agreed to
to any extent? DisposeNativeResources()?

-Bern McCarty

---------------------------------------------------

#using <System.dll>
#using <System.Windows.Forms.dll>
namespace Test
{
using System::Windows::Forms::Form;

class MyNativeType
{
private: int fooint;
public: virtual ~MyNativeType() {
System::Console::WriteLine(L"MyNativeType destructor called"); }
};

ref class MyClass : System::IDisposable
{
private: MyNativeType* myNativeInstance;
private: Form^ myDisposableForm;
public: MyClass()
{
myNativeInstance = new MyNativeType;
myDisposableForm = gcnew Form();
}

public: !MyClass()
{
#if !defined (NDEBUG)
System::Diagnostics::Debug::Assert(false, L"Neglected to call
Dispose() on MyClass instance.");
#endif
delete myNativeInstance;
}
private: ~MyClass()
{
System::Console::WriteLine(L"MyClass Dispose() called");
delete myDisposableForm;
delete myNativeInstance;
}
};
}

int main(int argc, char* argv[])
{
Test::MyClass^ myClassInstance = gcnew Test::MyClass;
delete myClassInstance;
System::GC::Collect();
System::GC::WaitForPendingFinalizers();
return 0;
}




Yes it, does, !T().

No. ~T() is called for Dispose() and only for that. !T() is called for
finalization and only for that.

For the C++/CLI compiler, both the Dispose() and the Dispose(bool)
methods are inaccessible. But you don't need to access any of those
functions, when the language provides true destructor and finalizer.
Forget about the entire Dispose(bool) pattern. You don't need that
runtime disposing flag, when you have a way to separate your
destruction and finalization at compile time. The way C# is doing it
is overcomplicated -- why doing it runtime, when you can do it at
compile time?

I'm positive that the code I posted works, regardless from where you
inherit from. It works when inheriting from existing C# classes, and
it also work when you don't inherit from any class at all. The
compiler automatically generates the SupressFinalize call, the
Dispose() method, everything that you need, but it absolutely
disregards the Dispose(bool) pattern, because it's an overkill and you
don't need that.

The only case when my sample doesn't work is when you inherit from a
class implementing this pattern:

ref class Base
{
public:
~Base() { this->!Base(); }
protected:
!Base() { }
};
In this case ~T() calls !T(), which means you have nowhere to place
your assertion. But my pattern is different, I explicitly made sure
that the destructor doesn't call the finalizer.

Here's something to prove that !T() is not called when Dispose() is
called properly:

public ref class FSTest : public System::IO::FileStream
{
public:
FSTest() : System::IO::FileStream("test.out",
System::IO::FileMode::Create) { }
protected:
!FSTest()
{
#if !defined (NDEBUG)
System::Diagnostics::Debug::Assert(false,
"Neglected to call Dispose() on object.");
#endif
}
};
int main(array<String ^> ^args)
{
FSTest test1;
}
Tom
 
Back
Top