{"id":5933,"date":"2007-02-06T17:12:00","date_gmt":"2007-02-06T17:12:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/vcblog\/2007\/02\/06\/digging-into-problems\/"},"modified":"2019-02-18T18:54:36","modified_gmt":"2019-02-18T18:54:36","slug":"digging-into-problems","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/cppblog\/digging-into-problems\/","title":{"rendered":"Digging Into Problems"},"content":{"rendered":"<p><span><\/p>\n<p class=\"MsoNormal\"><span>Hello my name is Steven Toscano, I am an SDET Tech Lead on the Visual C++ team.<span>&nbsp; <\/span>I am currently working in the IDE group focusing on improving our testing methodologies and expanding our library of tools.<span>&nbsp; <\/span>I&rsquo;ve been a member of many teams across Visual C++ during my 7 year career including front-end, back-end optimizers, libraries (MFC, ATL, CRT), and now IDE.<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\">\n<p><span><\/span><\/p>\n<p>&nbsp;<\/p>\n<p class=\"MsoNormal\"><span>One of the many pleasures I get from doing my job is the ability to diagnose a problem and discover its root cause.<span>&nbsp; <\/span>I love digging into things as deep as I can until the asm is staring me in the face exposing those nasty little bugs.<span>&nbsp; <\/span>Sometimes going that deep isn&rsquo;t necessary, sometimes you have to get creative about how to diagnose an issue.<span>&nbsp; <\/span>This is especially the case when you&rsquo;re dealing with complex multi-threading bugs.<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>One particular bug I looked into turned into a three day investigation.<span>&nbsp; <\/span>The net effect of the bug looked like this:<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>1. Open devenv<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>2. Load a solution that contains two C++ projects<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>3. Go to the Options dialog and set the &ldquo;maximum number of parallel project builds&rdquo; to 2 (I think this is the default if you&rsquo;ve installed VS on a dual-processor machine)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>4. Build the solution<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>Result is an Access Violation at <b>VCProjectEngine.dll!CBldFileRegEntry::ReleaseFRHRef()<\/b><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>That&rsquo;s right, the IDE just CRASHES!<span>&nbsp; <\/span>The worst possible behavior a customer could encounter (aside from data loss).<span>&nbsp; <\/span>And even better, this crash is not consistently reproducible; it might happen in 1 out of 100 times or not at all.<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>So the typical process is to get exact repro steps, a full callstack when the AV hits and to attach a dump to the bug.<span>&nbsp; <\/span>After some quick searching in our bug database I found a bug with a similar callstack logged by someone outside our team about one month prior.<span>&nbsp; <\/span>I was a bit concerned because this bug was resolved as No Repro and included full dump info!<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>Since I was encountering this problem on my multi-proc machine I decided to take a deeper look.<span>&nbsp; <\/span>First of all the callstack up to the AV looked a bit weird.<span>&nbsp; <\/span>Notice the function at the top of the stack.<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><b><span>&gt;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>0996f4f3()<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/p>\n<p><\/span><\/b><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;<\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>VCProjectEngine.dll!CBldFileRegEntry::ReleaseFRHRef<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>VCProjectEngine.dll!CBldFileRegistry::LookupFile<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;<\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>VCProjectEngine.dll!CVCBuildRegistryManipulator::LookupFile<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;<\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>VCProjectEngine.dll!GetFileFullPathI<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;<\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>VCProjectEngine.dll!GetFileFullPath<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;<\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>VCProjectEngine.dll!CBldIncludeEntry::FindFile<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;<\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>VCProjectEngine.dll!CVCToolImpl::ResolveIncludeDirectivesI<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;<\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>VCProjectEngine.dll!CVCToolImpl::ResolveIncludeDirectivesToPath<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;<\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>VCProjectEngine.dll!CLinkerLibrarianHelper::PickUpDeps<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;<\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>VCProjectEngine.dll!CLinkerLibrarianHelper::DoGetDependencies<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;<\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>VCProjectEngine.dll!CLinkerLibrarianHelper::DoGetAdditionalDependenciesInternal<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;<\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>VCProjectEngine.dll!CVCLinkerTool::GetAdditionalDependenciesInternal<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;<\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>VCProjectEngine.dll!CVCToolImpl::GetCommandLineOptions<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;<\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>VCProjectEngine.dll!CVCToolImpl::GetCommandLineOptions<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;<\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>VCProjectEngine.dll!CBldToolWrapper::GetCommandLineOptions<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;<\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>VCProjectEngine.dll!CBldAction::RefreshCommandOptions<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;<\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>VCProjectEngine.dll!CBldFileDepGraph::EnumerateBuildActionsI<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;<\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>VCProjectEngine.dll!CBldFileDepGraph::RetrieveBuildActions<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;<\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>VCProjectEngine.dll!CDynamicBuildEngine::DoBuild<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;<\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>VCProjectEngine.dll!CDynamicBuildEngine::DoBuild<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;<\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>VCProjectEngine.dll!CConfiguration::DoPreparedBuild<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;<\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>VCProjectEngine.dll!CConfiguration::TopLevelBuild<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;<\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>VCProjectEngine.dll!CVCBuildThread::BuildThread<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;<\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>kernel32.dll!BaseThreadStart<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p><font size=\"3\">&nbsp;<\/font><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>Doesn&rsquo;t resolve to symbol name and sure enough a check in the memory window shows this address is pointing into outer space.<span>&nbsp; <\/span>Here is the relevant source code at this point:<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p><font size=\"3\">&nbsp;<\/font><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>void<\/span><span> CBldFileRegEntry::ReleaseFRHRef()<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>{<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>\/\/ Prevent access to registry by other threads.<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>CritSectionT cs(g_sectionFileMap);<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>if<\/span> (m_nRefCount &lt;= 0)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>return<\/span>;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>m_nRefCount&#8211;;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>if<\/span> (m_nRefCount == 0)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&amp;nbsp\n;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>SafeDelete();<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>}<\/span><span><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p><font size=\"3\">&nbsp;<\/font><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>The AV occurred when the SafeDelete function was called.<span>&nbsp; <\/span>I hit this bug once and left the debug session open on my machine for the whole three days.<span>&nbsp; <\/span>Given the working set tax of debugging this was slowing down my machine for my normal day-to-day duties, but I had to leave it just in-case I couldn&rsquo;t repro it again.<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>Drilling into this mysterious AV at a callsite, I thought it was bad code gen, here is the relevant asm for the ReleaseFRHRef function:<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p><font size=\"3\">&nbsp;<\/font><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>if (m_nRefCount &lt;= 0)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>5B00B14A<span>&nbsp; <\/span>mov<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>eax,dword ptr [edi+18h] <\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>5B00B14D<span>&nbsp; <\/span>test<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>eax,eax <\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>return;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>5B00B14F<span>&nbsp; <\/span>jbe<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>CBldFileRegEntry::ReleaseFRHRef+32h (5B00B15Eh) <\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>m_nRefCount&#8211;;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>5B00B151<span>&nbsp; <\/span>dec<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>eax<span>&nbsp; <\/span><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>5B00B152<span>&nbsp; <\/span>mov<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>dword ptr [edi+18h],eax<\/span><span><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>if (m_nRefCount == 0)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>5B00B155<span>&nbsp; <\/span>jne<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>CBldFileRegEntry::ReleaseFRHRef+32h (5B00B15Eh) <\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>SafeDelete();<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>5B00B157<span>&nbsp; <\/span>mov<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>eax,dword ptr [edi] <\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>5B00B159<span>&nbsp; <\/span>mov<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>ecx,edi <\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>5B00B15B<span>&nbsp; <\/span>call<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>dword ptr [eax+8]<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p><font size=\"3\">&nbsp;<\/font><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>The last three instructions is the compiler generated code for a call through a vtable.<span>&nbsp; <\/span>Sure enough after debugging the code SafeDelete is the first virtual function call that we are making since we started executing code in this class.<span>&nbsp; <\/span>EDI is the this pointer, dereferencing that gives you the entry into the vtable.<span>&nbsp; <\/span>An offset of 8 on the vtable should give you back the address of the SafeDelete virtual function (since it&rsquo;s the third vfunction).<span>&nbsp; <\/span>But as we can see indirecting that address gives the access violation.<span>&nbsp; <\/span>So someone trashed the contents of our object including the vtable.<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>Now the question is who trashed our object?<span>&nbsp; <\/span>This was beginning to smell like a ref counting problem.<span>&nbsp; <\/span>I started to look at how the CBldFileRegEntry class was being used by looking at its implementation and where it is referenced.<span>&nbsp; <\/span>This class was retro-fitted to allow for simultaneous access through different threads.<span>&nbsp; <\/span>This was done through a shared reference or handle where\nuses of this handle were protected by Critical Sections sprinkled throughout the code.<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>After Everett shipped the Visual C++ team started to work on parallel project building for the Whidbey product (see this <a href=\"http:\/\/blogs.msdn.com\/peterhu\/archive\/2004\/06\/09\/151547.aspx\">blog<\/a> for details).<span>&nbsp; <\/span>This feature is great for multi-processor machines if you have a large solution with many leaf-node projects (i.e. projects that don&rsquo;t have intra-dependencies).<span>&nbsp; <\/span>The set of classes that are on this callstack are some of the ones that were modified to get this functionality enabled in Whidbey.<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>So all of this cool functionality but with random crashes?<span>&nbsp; <\/span>I had to take a deeper look at what was going on.<span>&nbsp; <\/span>The ref counting theory was beginning to make sense.<span>&nbsp; <\/span>If one thread had decremented the reference count too early another thread might think there are no references left to the shared object and delete it.<span>&nbsp; <\/span>While another thread is still using the object &ndash; and the next access to the object&rsquo;s contents results in an AV right in the middle of the code.<span>&nbsp; <\/span>The fact that we&rsquo;re seeing an AV is a good thing &ndash; Visual C++ 2005 will dirty the memory if you delete an object (filling it with sequences of 0xfeeefeee) imagine if that wasn&rsquo;t the case &ndash; you wouldn&rsquo;t see any crash just random incorrect behavior.<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>There wasn&rsquo;t much you could do with the information in the bug &ndash; if it was not easily reproducible you could not rerun the scenario and walk through the code.<span>&nbsp; <\/span>And with the dump that was attached you could only see the <b>*end*<\/b> result &ndash; the thread that did the damage is long gone.<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>So I took a different approach and extracted the relevant pieces of the code into my own simulation.<span>&nbsp; <\/span>This was easy since the class was pretty self-contained, any references or dependencies to things that weren&rsquo;t important I removed.<span>&nbsp; <\/span>Then I created a housing for the code &ndash; lifted straight off this MSDN <a href=\"http:\/\/msdn.microsoft.com\/library\/default.asp?url=\/library\/en-us\/dllproc\/base\/creating_threads.asp\">article<\/a>.<span>&nbsp; <\/span>It was a simple app that created threads through the CreateThread() Win32 API.<span>&nbsp; <\/span>I set the number of threads to 30.<span>&nbsp; <\/span>And in my ThreadProc I added the code that accesses the shared resource the same way as the CBldFileRegEntry code.<span>&nbsp; <\/span>Sure enough I hit the AV like once every other run.<span>&nbsp; <\/span>So now I had a very consistent repro!<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>With this little setup I was able to start closing in on the bug by using a binary search technique.<span>&nbsp; <\/span>I put a big Critical Section block around the first half of the code and left the rest as is.<span>&nbsp; <\/span>I ran the scenario and it didn&rsquo;t repro (since that whole piece of code was blocking all threads!).<span>&nbsp; <\/span>Since it didn&rsquo;t hit I tried the second half and it started to repro.<span>&nbsp; <\/span>Now that I had the right half I continued the process until I was down to a function level.<span>&nbsp; <\/span>Here was the suspect function:<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p><font size=\"3\">&nbsp;<\/font><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>BldFileRegHandle CBldFileRegFile::GetFileHandle(LPCOLESTR szFileName, BOOL bVerifyCase)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>{<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>CPathW path;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>LPCOLESTR szKey;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span style=\"mso-n\"><\/span><\/p>\n<p><\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hello my name is Steven Toscano, I am an SDET Tech Lead on the Visual C++ team.&nbsp; I am currently working in the IDE group focusing on improving our testing methodologies and expanding our library of tools.&nbsp; I&rsquo;ve been a member of many teams across Visual C++ during my 7 year career including front-end, back-end [&hellip;]<\/p>\n","protected":false},"author":289,"featured_media":35994,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-5933","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cplusplus"],"acf":[],"blog_post_summary":"<p>Hello my name is Steven Toscano, I am an SDET Tech Lead on the Visual C++ team.&nbsp; I am currently working in the IDE group focusing on improving our testing methodologies and expanding our library of tools.&nbsp; I&rsquo;ve been a member of many teams across Visual C++ during my 7 year career including front-end, back-end [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/5933","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/users\/289"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/comments?post=5933"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/5933\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media\/35994"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media?parent=5933"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/categories?post=5933"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/tags?post=5933"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}