首页 > 代码库 > 使用Appverifier 查找堆损坏

使用Appverifier 查找堆损坏

我们先看下面的代码

 

void ui::wnd::CDesktopWnd::Exe2Shortcut( LPCWSTR strFullPath, LPCWSTR strFileName, LPCWSTR shelllink_path) 

{

  CString strDescName = strFileName;

  if(strDescName == _T("iexplore.exe")) 

  {

  strDescName = _T("Internet Explorer");

  }

  PathRenameExtension(strDescName.GetBuffer(0), _T("")); 

   CString strFileNameTmp = strFileName;

  CString strLnk = GetLnkPath();

  PathRenameExtension(strFileNameTmp.GetBuffer(0), DESKTOPWND_SHORTCUT_EXT); 

  CString strLnkFileTxt = strLnk + _T("\\") + strFileNameTmp; 

  strFileNameTmp = strFileName;

  PathRenameExtension(strFileNameTmp.GetBuffer(0), _T(".bmp")); //和上述同样问题

  CString strIcoPath = strLnk + _T("\\") + strFileNameTmp;

 // CIconSnap is;

 // is.GetIcon(strFullPath);

  CIconSnap iconsnap;

  if(FALSE == iconsnap.Save(strFullPath, strIcoPath))

  {

    SIMPLE_TRACE(L"提取图标失败!");

    //::MessageBox(m_hWnd, _T("提取图标失败!"), _T("消息"), 0);

  }

  else

  {

    AppLogicalContainer iconContainer;

    BOOL bAddSuc = TRUE;

    if(shelllink_path==0)

    {

     if (strDescName != _T("Internet Explorer"))

     {

    bAddSuc = iconContainer.AddApp(strFullPath,strIcoPath,strDescName, shelllink_path); 

     }

     if (bAddSuc)

     {

    CString strSkinPath = GetSkinPath();

    m_IconListView.AddButtonEx( strDescName, strFullPath , m_hWnd, HandlerParam(this, OnBtnMessage),

     strIcoPath, strSkinPath + _T("\\tools\\desktop_icon_back3.png"), strSkinPath + _T("\\tools\\desktop_icon_back1.png"));

   }

     

    }

    else if (shelllink_path)

    {

     CString strSkinPath = GetSkinPath();

     m_IconListView.AddButtonEx( strDescName, shelllink_path , m_hWnd, HandlerParam(this, OnBtnMessage),

   strIcoPath, strSkinPath + _T("\\tools\\desktop_icon_back3.png"), strSkinPath + _T("\\tools\\desktop_icon_back1.png"));

    }

  }

}

 


 

这段代码是有问题的,跟踪调试出现在内存释放的时候,下面是栈

PathRenameExtension (str.GetBuffer
 THREAD fffffa8002791b60 Cid 0ab0.0ad8 Teb: 000007fffff8e000 Win32Thread: fffff900c22cf600 WAIT: (UserRequest) UserMode Non-Alertable
            fffffa800291c5b0 ProcessObject
            fffffa80038d2e90 NotificationEvent
        Not impersonating
        DeviceMap fffff8a000f67550
        Owning Process fffffa8002777060 Image: SandBoxMgr.exe
        Attached Process N/A Image: N/A
        Wait Start TickCount 36688 Ticks: 8719 (0:00:02:16.017)
        Context Switch Count 1282 LargeStack
        UserTime 00:00:00.124
        KernelTime 00:00:00.374
        Win32 Start Address SandboxMgr!_threadstartex (0x000000013f35a670)
        Stack Init fffff88003c62d70 Current fffff88003c61f90
        Base fffff88003c63000 Limit fffff88003c51000 Call 0
        Priority 12 BasePriority 8 UnusualBoost 0 ForegroundBoost 2 IoPriority 2 PagePriority 5
        Kernel stack not resident.
        Child-SP RetAddr Call Site
        fffff880`03c61fd0 fffff800`03ed0052 nt!KiSwapContext+0x7a
        fffff880`03c62110 fffff800`03ecc54b nt!KiCommitThreadWait+0x1d2
        fffff880`03c621a0 fffff800`041c1bcf nt!KeWaitForMultipleObjects+0x271
        fffff880`03c62450 fffff800`041c24d6 nt!ObpWaitForMultipleObjects+0x294
        fffff880`03c62920 fffff800`03ec8153 nt!NtWaitForMultipleObjects+0xe5
        fffff880`03c62b70 00000000`7749046a nt!KiSystemServiceCopyEnd+0x13 (TrapFrame @ fffff880`03c62be0)
        00000000`04b9cac8 000007fe`fd6213a6 ntdll!NtWaitForMultipleObjects+0xa
        00000000`04b9cad0 00000000`77243143 KERNELBASE!WaitForMultipleObjectsEx+0xe8
        00000000`04b9cbd0 00000000`772b9025 kernel32!WaitForMultipleObjectsExImplementation+0xb3
        00000000`04b9cc60 00000000`772b91a7 kernel32!WerpReportFaultInternal+0x215
        00000000`04b9cd00 00000000`772b91ff kernel32!WerpReportFault+0x77
        00000000`04b9cd30 00000000`772b941c kernel32!BasepReportFault+0x1f
        00000000`04b9cd60 00000000`774d573c kernel32!UnhandledExceptionFilter+0x1fc
        00000000`04b9ce40 00000000`77455148 ntdll! ?? ::FNODOBFM::`string‘+0x2365
        00000000`04b9ce70 00000000`7747554d ntdll!_C_specific_handler+0x8c
        00000000`04b9cee0 00000000`77455d1c ntdll!RtlpExecuteHandlerForException+0xd
        00000000`04b9cf10 00000000`7748fe48 ntdll!RtlDispatchException+0x3cb
        00000000`04b9d5f0 00000000`77491da0 ntdll!KiUserExceptionDispatcher+0x2e (TrapFrame @ 00000000`04b9da18)
        00000000`04b9dbb0 000007fe`fbd6254a ntdll!RtlFreeHeap+0xd0
        00000000`04b9dc30 000007fe`f6cd13ca FLTLIB!FilterConnectCommunicationPort+0x1da
        00000000`04b9dd30 000007fe`f6cd4033 EstSbFile!EstSbFileManager+0x6a [e:\ronggf\work\branches\minsheng\client_windows\src\estsbfile08\devicectrol.cpp @ 345]
        00000000`04b9dda0 00000001`3f1c43d1 EstSbFile!EstLogInformationPrint+0x103 [e:\ronggf\work\branches\minsheng\client_windows\src\estsbfile08\estsbfile.cpp @ 1684]
        00000000`04b9de20 00000001`3f1c4545 SandboxMgr!myout::print+0x31 [e:\ronggf\work\branches\minsheng\client_windows\src\include\misc\myout.h @ 100]
        00000000`04b9de50 00000001`3f1fa789 SandboxMgr!global::trace::output_trace+0x165 [e:\ronggf\work\branches\minsheng\client_windows\src\include\misc\trace.h @ 18]
        00000000`04b9ef40 00000001`3f1f27c9 SandboxMgr!CIconSnap::Save+0x109 [e:\ronggf\work\branches\minsheng\client_windows\src\sandboxmgr\iconsnap.cpp @ 122]
        00000000`04b9f2b0 00000001`3f1f6782 SandboxMgr!ui::wnd::CDesktopWnd::Exe2Shortcut+0x1c9 [e:\ronggf\work\branches\minsheng\client_windows\src\sandboxmgr\desktopwnd.cpp @ 579]
        00000000`04b9f430 00000001`3f1f06e0 SandboxMgr!ui::wnd::CDesktopWnd::OnRecvOpenDialogData+0x42 [e:\ronggf\work\branches\minsheng\client_windows\src\sandboxmgr\desktopwnd.cpp @ 1574]
        00000000`04b9f480 00000001`3f1f9f96 SandboxMgr!ui::w
nd::CDesktopWnd::ProcessWindowMessage+0x4c0 [e:\ronggf\work\branches\minsheng\client_windows\src\sandboxmgr\desktopwnd.h @ 130]
        00000000`04b9f4d0 00000000`7735c3c1 SandboxMgr!ATL::CWindowImplBaseT<ATL::CWindow,ATL::CWinTraits<1442840576,0> >::WindowProc+0xc6 [c:\program files (x86)\microsoft visual studio 9.0\vc\atlmfc\include\atlwin.h @ 3081]
        00000000`04b9f590 00000000`7735c60a USER32!UserCallWinProcCheckWow+0x1ad
        00000000`04b9f650 00000001`3f208478 USER32!DispatchMessageWorker+0x3b5
        00000000`04b9f6d0 00000001`3f35a65b SandboxMgr!CVirtualDesktop::NewDesktopRunLoop+0x478 [e:\ronggf\work\branches\minsheng\client_windows\src\sandboxmgr\virtualdesktop.cpp @ 328]
        00000000`04b9fac0 00000001`3f35a70f SandboxMgr!_callthreadstartex+0x17 [f:\dd\vctools\crt_bld\self_64_amd64\crt\src\threadex.c @ 348]
        00000000`04b9faf0 00000000`7723f56d SandboxMgr!_threadstartex+0x9f [f:\dd\vctools\crt_bld\self_64_amd64\crt\src\threadex.c @ 326]
        00000000`04b9fb20 00000000`77473281 kernel32!BaseThreadInitThunk+0xd
        00000000`04b9fb50 00000000`00000000 ntdll!RtlUserThreadStart+0x1d
 
在RtlFreeHeap 中出现问题了。
这个时候怎么办呢?从现场来看一定是堆出问题胃,那FLB 或者ntdll 上查找是找不出头绪的。这个时候想到了AppVerifier 和gflags 都可以用来进行堆的分配验证,释放验证。AppVerifier 使用比较方便,因此就使用AppVerifier 了。
 
使用AppVerifier后,果然出现了问题,提示在PathRenameExtension处出现问题了。
直接说结果吧:
因为CString 的 GetBuffer 直接传0,没有分配多余的空间导致PathRenameExtension 在后面追加了.txt四个字节,导致写内存超出了分配的内存范围,然后在释放内存的时候,内存管理检查到堆结构边界被破坏了,检查了出来。而原来的崩溃,是因为写的几个字节破坏了堆分配表,而应声而崩。
 
再看看上面的代码有下面的问题(浅析了),还有什么问题请大家补充。
 
void ui::wnd::CDesktopWnd::Exe2Shortcut( LPCWSTR strFullPath, LPCWSTR strFileName, LPCWSTR shelllink_path) 
{
  CString strDescName = strFileName;
  if(strDescName == _T("iexplore.exe"))
    //不严谨
  {
  strDescName = _T("Internet Explorer");
  }
  PathRenameExtension(strDescName.GetBuffer(0), _T(""));
  //上述条件成立的时候不是必须的
 
  CString strFileNameTmp = strFileName;
  CString strLnk = GetLnkPath();
  PathRenameExtension(strFileNameTmp.GetBuffer(0), DESKTOPWND_SHORTCUT_EXT);
  //有问题代码,因为
    //CString::GetBuffer 没有增大内存导致当strFileName 的扩展名没有或者比替换的扩展名长度小的时候,会出现向未分配的内存写数据
  CString strLnkFileTxt = strLnk + _T("\\") + strFileNameTmp;
    //效率很低,两个临时变量,两次析构
  strFileNameTmp = strFileName;
  PathRenameExtension(strFileNameTmp.GetBuffer(0), _T(".bmp"));
 //和上述同样问题
  CString strIcoPath = strLnk + _T("\\") + strFileNameTmp;
 // CIconSnap is;
 // is.GetIcon(strFullPath);
  CIconSnap iconsnap;
  if(FALSE == iconsnap.Save(strFullPath, strIcoPath))
  {
    SIMPLE_TRACE(L"提取图标失败!");
    //::MessageBox(m_hWnd, _T("提取图标失败!"), _T("消息"), 0);
  }
  else
  {
    AppLogicalContainer iconContainer;
    BOOL bAddSuc = TRUE;
    if(shelllink_path==0)
    {
     if (strDescName != _T("Internet Explorer"))
     {
    bAddSuc = iconContainer.AddApp(strFullPath,strIcoPath,strDescName, shelllink_path);	 
     }
     if (bAddSuc)
     {
    CString strSkinPath = GetSkinPath();
    m_IconListView.AddButtonEx( strDescName, strFullPath , m_hWnd, HandlerParam(this, OnBtnMessage),
     strIcoPath, strSkinPath + _T("\\tools\\desktop_icon_back3.png"), strSkinPath + _T("\\tools\\desktop_icon_back1.png"));
   }
     
    }
    else if (shelllink_path)
    {
     CString strSkinPath = GetSkinPath();
     m_IconListView.AddButtonEx( strDescName, shelllink_path , m_hWnd, HandlerParam(this, OnBtnMessage),
   strIcoPath, strSkinPath + _T("\\tools\\desktop_icon_back3.png"), strSkinPath + _T("\\tools\\desktop_icon_back1.png"));
    }
  }
}

经上分析,这个编写者没有掌握好CString 的用法和对API PathRenameExtension 的粗心大意。这段代码可以作为纠错的一个范例。