使用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 的粗心大意。这段代码可以作为纠错的一个范例。

使用Appverifier 查找堆损坏

时间: 2024-10-24 17:09:27

使用Appverifier 查找堆损坏的相关文章

解决堆损坏的一点心得

问题描述 之前在实现水印提取的过程中,遇到了一个诡异的异常.为了较好的说明出现问题的情况,假定我运行的函数为f(),其代码如下: f() { code A;//该段代码在读取一个文件中的记录 for(int i = 0; i < 3; i ++) { code B; } } 程序在运行时出现中断,中断信息为:Windows已在ApplicationGUI.exe中触发一个断点.其原因可能是堆被损坏,这说明ApplicationGUI.exe中或它所加载的任何DLL中有Bug. 点击中断信息框中的

SOS.dll(SOS 调试扩展)

SecAnnotate.exe(.NET 安全批注器工具) SignTool.exe(签名工具) Sn.exe(强名称工具) SOS.dll(SOS 调试扩展) SqlMetal.exe(代码生成工具) Storeadm.exe(独立存储工具) Tlbexp.exe(类型库导出程序) Tlbimp.exe(类型库导入程序) Winmdexp.exe(Windows 运行时元数据导出工具) Winmdexp.exe 错误消息 Winres.exe(Windows 窗体资源编辑器) 此文章由人工翻译

讨论SQLite数据库损坏与修复

昨晚,朋友和我反馈SQLite数据库发生损坏有没有办法恢复.大致的情况是这样的,当数据库在使用时不小心用了新的文件覆盖数据库,导致了SQLite数据库出现了损坏,打开的时候出现要输入密码,而且不能把SQL语句dump下来.所以,文章这里整理SQLite数据库出现损坏的所有情况,以及如何修复损坏的SQLite数据库文件. SQLite算是非常稳定的数据库,不容易出现损坏,就算应用程序崩溃,或者操作系统崩溃,甚至是执行事务时出现断电,都能在下一次使用数据库时自动修复.但是,还是不能避免不出现损坏的情

内存损坏问题的演示样例及分析

原文以演示样例代码系统的讲述了三种内存损坏的情况: 全局内存.栈损坏及堆损坏, 以及它们产生的原因. 粗略整理例如以下. Global Memory Corruption 即全局变量的内存使用出了问题,主要还是越界. 例如以下代码: #include <stdio.h> #define MAX 6 int arrdata[MAX]; int endval; int main() { int i = 0; endval = 12; for (i = MAX; (endval) &&

数据结构--堆的实现之深入分析

一,介绍 以前在学习堆时,写了两篇文章:数据结构--堆的实现(上)   和   数据结构--堆的实现(下),  感觉对堆的认识还是不够.本文主要分析数据结构 堆(讨论小顶堆)的基本操作的一些细节,比如 insert(插入)操作 和 deleteMin(删除堆顶元素)操作的实现细节.分析建堆的时间复杂度.堆的优缺点及二叉堆的不足. 二,堆的实现分析 堆的物理存储结构是一维数组,逻辑存储结构是完全二叉树.堆的基本操作有:insert--向堆中插入一个元素:deleteMin--删除堆顶元素 故堆的类

内存损坏问题的示例及分析

原文以示例代码系统的讲述了三种内存损坏的情况: 全局内存.栈损坏及堆损坏, 以及它们产生的原因.粗略整理如下. Global Memory Corruption 即全局变量的内存使用出了问题,主要还是越界.如下代码: #include <stdio.h> #define MAX 6 int arrdata[MAX]; int endval; int main() { int i = 0; endval = 12; for (i = MAX; (endval) && (i >

《软件调试的艺术》学习笔记——GDB使用技巧摘要

<软件调试的艺术>学习笔记——GDB使用技巧摘要 <软件调试的艺术>,因为名是The Art of Debugging with GDB, DDD, and Eclipse. 作者是美国的Norman Matloff和Peter Jay Salzman,中文版由张云翻译.是人邮出版社图灵程序设计丛书初版.这里称为"艺术",个人觉得有点过了,但是其中关于gdb以及在gdb基础之上集成的DDD和Eclipse调试技巧的整理确实是做的很好,对于Linux/开源社区下的

使用devpartner的blockchecker检查c++内存错误

在仿写stl的过程中,被一处内存错误卡了很久.当内存池需要多次malloc时会出现堆损坏的错误,初步判断是数组越界,但总是检查不出来.一开始用Dr.Memory检查不出来,就试了一下devpartner.官网链接 http://www.borland.com/zh-CN/Products/Software-Testing/Automated-Testing/Devpartner-Studio devpartner安装完后会自动在vs上装插件,但是那个插件好像没什么用.我是直接在安装目录下找到bl

你所不知道的SQL Server数据库启动过程(用户数据库加载过程的疑难杂症)

前言 本篇主要是上一篇文章的补充篇,上一篇我们介绍了SQL Server服务启动过程所遇到的一些问题和解决方法,可点击查看,我们此篇主要介绍的是SQL Server启动过程中关于用户数据库加载的流程,并且根据加载过程中所遇到的一系列问题提供解决方案. 其实SQL Server作为微软的一款优秀RDBMS,它启动的过程中,本身所带的那些系统库发生问题的情况相对还是很少的,我们在平常使用中,出问题的大部分集中于我们自己建立的用户数据库. 而且,相对于侧重面而言,其实我们更关注的是我们自己建立的用户数