Skip to content

Cory Foy

Organizational agility through intersecting business and technology

Menu
  • FASTER Fridays
  • Mapping Mondays
  • Player Embed
  • Search Videos
  • User Dashboard
  • User Videos
  • Video Category
  • Video Form
  • Video Tag
Menu

Exceptions in Constructors: How Reflection Helped Workaround an Oracle Bug

Posted on June 16, 2009 by Cory Foy

Our application supports both SQL and Oracle users. To do this, there are certain things that we need present at runtime – like an Oracle Provider. But, in our case, we require a certain version or higher due to the API calls we need to make.

During testing for our upcoming release, we found a bug where if someone tried to create a connection to an Oracle database, and didn’t have the Oracle Client tools, the app would crash – at some random time. Sometimes it was right after they tried the test from our app. Sometimes it wasn’t until they closed the app. But all points showed exactly where and why it was happening – sort of.

Firing up my trusty WinDBG and connecting to our app, I saw that when it crashed, we got the following CLR exception:

(9e4.bc0): CLR exception - code e0434f4d (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00c0f524 ebx=e0434f4d ecx=00000000 edx=7c8285ec esi=00c0f5b0 edi=0016dd50
eip=77e4bee7 esp=00c0f520 ebp=00c0f574 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
KERNEL32!RaiseException+0x53:
77e4bee7 5e              pop     esi

0:002> !printexception
Exception object: 0bb1e114
Exception type: System.TypeInitializationException
Message: The type initializer for 'Oracle.DataAccess.Client.OracleConnection' threw an exception.
InnerException: Oracle.DataAccess.Client.OracleException, use !PrintException 0bb169cc to see more
StackTrace (generated):

StackTraceString:

HResult: 80131534

0:002> !clrstack
OS Thread Id: 0xbc0 (2)
ESP       EIP    
00c0f628 77e4bee7 [GCFrame: 00c0f628]
00c0fc10 77e4bee7 [PrestubMethodFrame: 00c0fc10] Oracle.DataAccess.Client.OracleConnection.Dispose(Boolean)
00c0fc20 7a572eb5 System.ComponentModel.Component.Finalize()

The interesting part of the above is that last line. The exception just before the crash is happening on the Dispose method which is being called by the Finalizer. Recall that in .NET 2.0 and higher, unhandled exceptions on the finalizer thread kill the thread, taking down the runtime with it, since there is no longer a thread to handle garbage collection finalization.

Our app was basically just doing a return new OracleConnection(); so that meant that the exception was in the Oracle API itself. And sure enough, here’s what happens in the constructor of OracleConnection (according to Reflector):

public OracleConnection()
{
    if (!OracleInit.bSetDllDirectoryInvoked)
    {
        OracleInit.Initialize();
    }
    if (!OraTrace.m_RegistryRead)
    {
        OraTrace.GetRegistryTraceInfo();
    }
    if (OraTrace.m_TraceLevel != 0)
    {
        OraTrace.Trace(1, new string[] { " (ENTRY) OracleConnection::OracleConnection(1)\n" });
    }
    this.Initialize();
    if (OraTrace.m_TraceLevel != 0)
    {
        OraTrace.Trace(1, new string[] { " (EXIT)  OracleConnection::OracleConnection(1)\n" });
    }
}

Peeking at the exceptions that get thrown when we try to test the connection, I can see that OpsInit.CheckVersionCompatability throws a TypeInitializerException, which gets caught by the Initialize method, which then turns around and throws an OracleException. Which then caused the constructor to throw an exception, and the object not to get created.

But there’s something subtle there. To my app, the OracleConnection object was never created. In fact, the return value is null. But, what do we see on the Heap?

0:002> !dumpheap -type Oracle
Address       MT     Size    
0bb153e0 084b7e10      112    
0bb169cc 084b8318       76    
0bb16b14 084b87c4       24    
0bb16b2c 084b89a4       32    
total 4 objects
Statistics:
      MT    Count    TotalSize Class Name
084b87c4        1           24 Oracle.DataAccess.Client.OracleErrorCollection
084b89a4        1           32 Oracle.DataAccess.Client.OracleError
084b8318        1           76 Oracle.DataAccess.Client.OracleException
084b7e10        1          112 Oracle.DataAccess.Client.OracleConnection
Total 4 objects

There, on the heap, is an Oracle.DataAccess.Client.OracleConnection. Which means that at some point, the Garbage Collector will clean it up, and in doing so, call the Dispose() method. But the object hasn’t cleaned itself up properly, so it throws an exception in Dispose.

The problem at this point is 3-fold

  1. If you are going to throw an exception in your constructor, you must ensure that you’ve cleaned yourself up properly
  2. An unhandled exception on the Finalizer thread takes down the runtime, and because the object isn’t following number 1, this will happen
  3. Because the exception is in the constructor, we never get a handle to the object, and thus can’t do anything

The problem is further compounded by OracleConnection being sealed, so we can’t just subclass it. It seems like at this point we are just stuck. Or are we?

We know from Reflector that the exception happens on the call to OracleInit.Initialize(). So perhaps we could just call that, and if it throws an exception, we know that the Oracle Client isn’t set up properly, and thus we don’t try to construct an OracleConnection object. But OracleInit is an internal class. So how do we get around that?

Reflection.

public static bool Oracle102OrHigherIsInstalled()
{
    try
    {
        Assembly oracleAssembly = Assembly.LoadWithPartialName("Oracle.DataAccess");
        if (oracleAssembly == null) { return false; }

        Type oracleInit = oracleAssembly.GetType("Oracle.DataAccess.Client.OracleInit");
        if (oracleInit == null) { return false; }

        MethodInfo initialize = oracleInit.GetMethod("Initialize", BindingFlags.Public | BindingFlags.Static);
        if (initialize == null) { return false; }

        initial
ize.Invoke(null, null);

    }
    catch (Exception ex)
    {
        return false;
    }
    return true;
}

Internal or not, we can use reflection to get to that class. And since Initialize is a static method, we don’t even have to deal with getting an instance. We simply follow the same path that the OracleConnection constructor does, and if it fails, we know to not even try creating an instance of it.

The takeaway really is to make sure you are cleaning yourself up, and to absolutely ensure that Dispose never throws an unhandled exception. But even when you are dealing with third parties who don’t have that, you can still use tools like WinDBG, Reflector and .NET Reflection to find a workaround.

1 thought on “Exceptions in Constructors: How Reflection Helped Workaround an Oracle Bug”

  1. Pingback: Should Dispose throw exceptions? | out >> m_Conscientia();

Comments are closed.

© 2025 Cory Foy | Powered by Superbs Personal Blog theme