From: Andrew on
Hi Oleg,
I managed to do use WinDbg with the debug version to track the refcnt
changes. And you are correct, as soon as it hits 0, there is an
exception. I have 606 access to the refcnt. But everything looks ok,
the refcnt just goes up and down - no-one is "trashing" the variable.
Obivously there is one more decrement than increment...just tracking
this will be quite a long process..nothing jumps out by inspection.

One problem is that I cannot set the break point before starting the
executable. How do I stop at the "entry point" before any access to the
the refcnt has ever been made.


7c901230 cc int 3
0:000> ba w4 0x03609ce8 "dd 0x03609ce8 L1;kb;g"
^ Unable to set breakpoint error
The system resets thread contexts after the process
breakpoint so hardware breakpoints cannot be set.
Go to the executable's entry point and set it then.
'ba w4 0x03609ce8 "dd 0x03609ce8 L1;kb;g"'


Andrew

From: Oleg Starodumov on

Hi Andrew,

> I managed to do use WinDbg with the debug version to track the refcnt
> changes. And you are correct, as soon as it hits 0, there is an
> exception. I have 606 access to the refcnt. But everything looks ok,
> the refcnt just goes up and down - no-one is "trashing" the variable.
> Obivously there is one more decrement than increment...just tracking
> this will be quite a long process..nothing jumps out by inspection.
>

Probably it makes sense to try to narrow down the scope a bit.
For example, try to return FALSE from InitInstance() - will the problem
happen then? If it does not happen, try to exit the application right after
its initialization has completed. And so on, until you find the place
where the problem starts happening. This might give you an idea what part
of the refcnt monitoring output to look at.

> One problem is that I cannot set the break point before starting the
> executable. How do I stop at the "entry point" before any access to the
> the refcnt has ever been made.
>
> 7c901230 cc int 3
> 0:000> ba w4 0x03609ce8 "dd 0x03609ce8 L1;kb;g"
> ^ Unable to set breakpoint error
> The system resets thread contexts after the process
> breakpoint so hardware breakpoints cannot be set.
> Go to the executable's entry point and set it then.
> 'ba w4 0x03609ce8 "dd 0x03609ce8 L1;kb;g"'
>

You can use 'bp mfc71d!_DllMainCRTStartup' to break at the entry point
of mfc71.dll. After the breakpoint was hit, remove it (otherwise it will be hit
again e.g. when a thread starts).

(If MFC is linked statically, you can use 'bp yourapp!WinMainCRTStartup' to set
breakpoint at the entry point of the application (or 'bp yourapp!wWinMainCRTStartup'
for Unicode builds))

Oleg



From: Andrew on
Hi Oleg,
Returning false from InitInstance has helped me narrowthis down a
lot.Initially I just returned from the first line in InitInstance. No
crash. So I moved the return FALSE; down my InitInstance until the
crash occured and I discovered I do NOT get the crash until I return
FALSE in InitInstance just after creating my MainFrame.

Now here is the weird part... I thought I would have this nailed so I
then set the break on the write to the refcnt. But you will see from
the debug output below, that it appears the refcnt goes from 3 to 0
without triggering the breakpoint???

0:000> bp mfc71d!_DllMainCRTStartup
0:000> g
Starting to track Class instances
ModLoad: 042a0000 0461f000 D:\Program
Files\Intel\MKL\8.0.1\ia32\bin\mkl_p4p.dll
ModLoad: 773d0000 774d2000
D:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.2180_x-ww_a84f1ff9\comctl32.dll
Breakpoint 0 hit
eax=01c8fa7c ebx=034d8120 ecx=00003687 edx=7c90eb94 esi=01c8fa04
edi=00000001
eip=034d8120 esp=01c8f9f4 ebp=01c8fa10 iopl=0 nv up ei pl nz na
pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000
efl=00200202
MFC71D!_DllMainCRTStartup:
034d8120 55 push ebp
0:000> ba w4 0x03609ce8 "dd 0x03609ce8 L1;kb;g"
0:000> g
03609ce8 00000002
ChildEBP RetAddr Args to Child
01c8f978 0350c30b 03609cd8 01c8f98c 0350c2ed
MFC71D!ATL::CNilStringData::CNilStringData+0x1a
01c8f984 0350c2ed 01c8f994 02351d48 01c8f9a4
MFC71D!CAfxStringMgr::CAfxStringMgr+0x1b
01c8f98c 02351d48 01c8f9a4 034d80a3 03603008
MFC71D!operator>><wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>
> >+0x18d
01c8f994 034d80a3 03603008 03603188 01c8f9f0 MSVCR71D!_initterm+0x18
01c8f9a4 034d81ba 03420000 00000001 01c8fd30 MFC71D!_CRT_INIT+0xa3
01c8f9f0 7c9011a7 03420000 00000001 01c8fd30
MFC71D!_DllMainCRTStartup+0x9a
01c8fa10 7c91cbab 034d8120 03420000 00000001
ntdll!LdrpCallInitRoutine+0x14
01c8fb18 7c92173e 01c8fd30 7fffe000 7ffff000
ntdll!LdrpRunInitializeRoutines+0x344
01c8fc94 7c921639 01c8fd30 7c900000 01c8fce0
ntdll!LdrpInitializeProcess+0x1131
01c8fd1c 7c90eac7 01c8fd30 7c900000 00000000
ntdll!_LdrpInitialize+0x183
00000000 00000000 00000000 00000000 00000000
ntdll!KiUserApcDispatcher+0x7
03609ce8 00000003
ChildEBP RetAddr Args to Child
01c8f908 0350bee2 03609cd8 01c8f924 0345a2ac
MFC71D!ATL::CStringData::AddRef+0x3e
01c8f914 0345a2ac 0360bbf4 01c8f928 01c8f934
MFC71D!CAfxStringMgr::GetNilString+0x12
01c8f924 0345b0c5 03609cd8 0360bbf4 01c8f94c
MFC71D!ATL::CSimpleStringT<char,1>::CSimpleStringT<char,1>+0x3c
01c8f934 0345eedf 0360bbec 01c8f960 035d9a63
MFC71D!ATL::CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<char> >
>::CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<char> > >+0x15
01c8f94c 0345f258 00000000 0360bbec 01c8f978
MFC71D!CSyncObject::CSyncObject+0x3f
01c8f96c 0357c301 0360bbd0 01c8f9e0 035dcc28
MFC71D!CCriticalSection::CCriticalSection+0x28
01c8f984 0358e9fd 01c8f994 02351d48 01c8f9a4
MFC71D!CSessionMapPtrToPtr::CSessionMapPtrToPtr+0x41
01c8f98c 02351d48 01c8f9a4 034d80a3 03603070
MFC71D!CGopherFileFind::GetRuntimeClass+0x1d
01c8f994 034d80a3 03603070 03603188 01c8f9f0 MSVCR71D!_initterm+0x18
01c8f9a4 034d81ba 03420000 00000001 01c8fd30 MFC71D!_CRT_INIT+0xa3
01c8f9f0 7c9011a7 03420000 00000001 01c8fd30
MFC71D!_DllMainCRTStartup+0x9a
01c8fa10 7c91cbab 034d8120 03420000 00000001
ntdll!LdrpCallInitRoutine+0x14
01c8fb18 7c92173e 01c8fd30 7fffe000 7ffff000
ntdll!LdrpRunInitializeRoutines+0x344
01c8fc94 7c921639 01c8fd30 7c900000 01c8fce0
ntdll!LdrpInitializeProcess+0x1131
01c8fd1c 7c90eac7 01c8fd30 7c900000 00000000
ntdll!_LdrpInitialize+0x183
00000000 00000000 00000000 00000000 00000000
ntdll!KiUserApcDispatcher+0x7
ModLoad: 5d360000 5d36e000 D:\WINDOWS\system32\MFC71ENU.DLL
ModLoad: 5ad70000 5ada8000 D:\WINDOWS\system32\uxtheme.dll
VA One Initializing ...ModLoad: 732e0000 732e5000
D:\WINDOWS\system32\RICHED32.DLL
ModLoad: 74e30000 74e9c000 D:\WINDOWS\system32\RICHED20.dll
ModLoad: 04ba0000 04d0f000 D:\WINDOWS\system32\nview.dll
ModLoad: 76bf0000 76bfb000 D:\WINDOWS\system32\PSAPI.DLL
ModLoad: 77690000 776b1000 D:\WINDOWS\system32\NTMARTA.DLL
ModLoad: 76f60000 76f8c000 D:\WINDOWS\system32\WLDAP32.dll
ModLoad: 71bf0000 71c03000 D:\WINDOWS\system32\SAMLIB.dll
ModLoad: 04d80000 04d95000 D:\WINDOWS\system32\nvwddi.dll
Warning: no shared menu for document template #129.
Warning: no shared menu for document template #129.
Warning: Destroying non-NULL m_pMainWnd
The number of objects in CGXCaptiveManager is: 0
HEAP[VAOne.exe]: Invalid Address specified to RtlValidateHeap(
03B40000, 03609CBC )
(580.ad8): Break instruction exception - code 80000003 (first chance)
eax=03609cb4 ebx=03609cb4 ecx=7c91eb05 edx=01c8faf6 esi=03b40000
edi=03b40000
eip=7c901230 esp=01c8fcfc ebp=01c8fd00 iopl=0 nv up ei pl nz na
pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000
efl=00000202
ntdll!DbgBreakPoint:
7c901230 cc int 3
*** WARNING: Unable to verify checksum for VAOne.exe
0:000> dd 0x03609ce8 L1
03609ce8 00000000

From: Oleg Starodumov on

> Now here is the weird part... I thought I would have this nailed so I
> then set the break on the write to the refcnt. But you will see from
> the debug output below, that it appears the refcnt goes from 3 to 0
> without triggering the breakpoint???
>

Most likely because I made a mistake referring you to mfc71d!_DllMainCRTStartup
only. The thread context will be reset after that, so you need one more breakpoint -
at yourapp!WinMainCRTStartup, and at that breakpoint you should run
'ba' command again to reenable the data breakpoint at the refcounter.

Oleg



From: Andrew on
Hi Oleg,
I found the bug!
It was in some third-party code ( Objective Toolkit), in a class
SECStatusBar that is a replacement for CStatusBar. They had code that
worked in prior versions of MFC, but causes the problem in MFC 7.

I cannot thank you enough for your help! I learnt how to use WinDbg,
which is a very useful tool.



BOOL SECStatusBar::AllocElements(int nElements, int cbElement)
{
// destruct old elements
AFX_STATUSPANE* pSBP = _GetPanePtr(0);
for (int i = 0; i < m_nCount; i++)
{
pSBP->strText.~CString();
++pSBP;
}

// allocate new elements
if (!SECControlBar::AllocElements(nElements, cbElement))
return FALSE;

/*
// OLD code that works in MFC prior to 7
// construct new elements
pSBP = _GetPanePtr(0);
CString emptyString("");
for (i = 0; i < m_nCount; i++)
{
memcpy(&pSBP->strText, &emptyString, sizeof(CString));
++pSBP;
}
*/
// construct new elements
pSBP = _GetPanePtr(0);
for (i = 0; i < m_nCount; i++)
{
#pragma push_macro("new")
#undef new
new( &pSBP->strText ) CString;
#pragma pop_macro("new")
++pSBP;
}

return TRUE;
}