Search code examples
c++crashole

How can a simple string comparison cause an OleException?


I have this piece of C++ code:

static CString timeout(_T("TIMEOUT"));
if(strError.Left(7).CompareNoCase(timeout) == 0) return TRUE;

In my immediate windows, I see following value for strError:

? strError
L""
ATL::CSimpleStringT<wchar_t,1>: L""

I'm getting following exception (I'm debugging a crash dump):

Unhandled exception at 0x74B4A9F2 in CRASH.DMP: Microsoft C++ exception: 
COleException at memory location 0x01BFFD14. occurred

My call stack is the following:

   KERNELBASE.dll!_RaiseException@16()  Unknown
   msvcr110.dll!_CxxThrowException(void * pExceptionObject, const _s__ThrowInfo * pThrowInfo) Line 152  C++
   mfc110u.dll!AfxThrowOleException(long)   Unknown
   mfc110u.dll!ATL::AtlThrowImpl(long)  Unknown
   mfc110u.dll!ATL::CStringT<wchar_t,class StrTraitMFC_DLL<wchar_t,class ATL::ChTraitsCRT<wchar_t> > >::CompareNoCase(wchar_t const *)  Unknown
>  <Application>.exe!<Own_Class>::<Own_Function>(const ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t> > > & strError) Line 106 C++

As I was having a crash while checking .Left(7) of an empty string, I immediately assumed this was the course of the issue. However I've realised that this piece of code generally is working fine (I just double-checked this), and while having a second look, I see that the exception if not an access violation or a nullpointerexception, but an Ole related exception. In the meanwhile I've understood that the issue's not within the strError.Left(7) part: it seems to be the CompareNoCase() method, going wrong, but how?

Can anybody enlighten me what's doing wrong in my code?

As far as strError is concerned, it gets created as follows:

CString strError;
...
strError = <function>();

where <function>() is something like:

CString <function>(){
...
  return _T("fix string"); // or:
  return <Complicated_function_handling>();

In this particular case, I have no idea how strError has been created (I know it's empty, as clearly seen in the immediate window, but I only have the crash dump, so I can read current values, but I don't know their history).

One thing, which might be helpful: I've asked for the memory address of strError, and I've looked at the data within memory (using Visual Studio Memory debug window), and I get following data:

5c 18 9c 71 38 d9 ca 00 03 00 00 00 cc 3d c2 00 70 fe bf 01 94 13 b3 00 39 00 00 00 80 fe bf 01 be 58 aa 00 b0 3d c2 00 10 0c cd 00 44 03 00 00 01 00 00 00 d3 5f ac 00 8a 40 1d 72 8e f2 d6 73

Thanks in advance


Solution

  • Working my thru the source for MFC, the exception is being thrown because timeOut is a NULL string. Common ways that this can happen are if it has not been constructed yet, or it has been destroyed. The error code stored within the COleException is E_FAIL.

    The call sequence goes something like this:

    • CompareNoCase calls AtlIsValidString (which will return false in your case if timeOut, when converted to a const char *, is NULL).
    • Since AtlIsValidString returns false, the code associated with the ATLENSURE macro calls AtlThrow(E_FAIL) (AtlThrow is a macro that is defined as ATL::AtlThrowImpl.
    • AtlThrowImpl calls AfxThrowOleException since the error code is not E_OUTOFMEMORY.