代码之家  ›  专栏  ›  技术社区  ›  goldenmean

内存覆盖问题

  •  1
  • goldenmean  · 技术社区  · 16 年前

    我有一个C代码应用程序。我用MS-VS2005构建的。我有一个输出数据缓冲区,它是使用malloc动态分配的。

    对于一些测试用例,malloc的内存大小比实际生成的输出大小(以字节为单位)要小。较大的输出被写入较小的缓冲区,导致缓冲区溢出。结果,测试运行崩溃,MSVS-2005显示一个窗口“堆损坏….”。

    我知道这与一些动态内存分配有关,但是我花了很长时间才找到根本原因,因为我不怀疑内存分配,因为我分配的内存足够大,足以支持输出。但是有一个特定的测试用例产生的输出比我计算的要多,因此导致了崩溃。

    我的问题是:

    1.)我可以使用什么工具来检测这种动态内存缓冲区溢出情况。它们还可以帮助检测任何缓冲区溢出情况吗(不管缓冲区/数组是否位于堆、堆栈、全局内存区域)?

    2.)内存泄漏工具(如purify)或代码分析工具(如lint、klocworks)在特定情况下会有帮助吗?我相信它们必须是运行时分析工具。

    谢谢您。

    广告。

    4 回复  |  直到 15 年前
        1
  •  1
  •   Heath Hunnicutt    16 年前

    我在书中第一次遇到的解决方案 Writing Solid Code ,是要“包装”的 malloc() 带诊断代码的API。

    首先,诊断 马尔洛() 安排为尾随的sentinel分配额外的字节。例如,在分配的内存之后的另外四个字节是保留的,并且包含字符“fine”。

    稍后,当指针从 马尔洛() 传递给 free() ,对应的诊断版本 自由() 被称为。在调用 自由() 而放弃记忆,尾随的哨兵就被验证了;它应该是未被修改的。如果修改了sentinel,则块指针在从诊断返回后的某个时间点被误用。 马尔洛() .

    使用内存保护保护保护页而不是sentinel模式检测缓冲区溢出是有好处的。特别是,使用基于模式的方法,只有在事实发生后才检测到非法内存访问。Sentinel模式方法只检测到非法写入。内存保护方法捕获非法的读和写,并在它们发生时立即检测到它们。

    的诊断包装函数 马尔洛() 也可以解决其他滥用 马尔洛() ,例如多次调用 免费() 对于相同的内存块。也, realloc() 可以修改为在调试环境中执行时始终移动块,以测试的调用方 RealLoad() .

    特别是,诊断包装器可以记录所有分配和释放的块,并在程序退出时报告内存泄漏。内存泄漏是由程序执行期间未释放而分配的块。

    包装时 马尔洛() API,必须包装所有相关函数,包括 calloc(), realloc(), strdup() .

    包装这些函数的典型方法是通过预处理器宏:

    #define malloc(s)   diagnostic_malloc(s, __FILE__, __LINE__)
    /* etc.... */
    

    如果需要对标准实现的调用进行编码(例如,分配的块将传递给第三方、仅限二进制的库,该库希望使用标准释放块 自由() 实现时,可以使用 (malloc)(s) --也就是说,在函数名周围加上括号。

        2
  •  1
  •   Andrei Pokrovsky    16 年前

    您可以尝试使用virtuaalloc分配足够的页面+1,使用virtualprotect和上一页的page_readonly_page_guard标志,然后对齐可疑的分配,使对象的结尾接近受保护页的开头。如果一切正常,那么在访问保护页时,应该会出现访问冲突。如果您大致知道哪个分配被覆盖,这将有所帮助。否则,它需要覆盖可能需要大量额外内存的所有分配(每个分配至少2页)。我在这里命名为“统计页面保护”的这种技术的一个变化是,仅以这种方式随机分配内存以获得相对较小的分配百分比,以避免小对象出现大的膨胀。在大量的执行运行中,您应该能够命中错误。在这种情况下,随机数生成器必须以类似时间的方式播种。类似地,如果怀疑在较低的地址覆盖,可以在对象前面分配保护页(不能同时执行这两项操作,但也可能随机混淆)。

    更新:原来gflags.exe(以前是pageheap.exe)微软实用程序已经支持“统计页面保护”,所以我重新设计了控制盘:)你只需要运行gflags.exe/p/enable[/random 0-100]你的application.exe并运行你的应用程序。如果在堆分配中使用自定义堆或自定义保护,那么您可以简单地切换到使用heapalloc,至少是为了捕获错误,然后切换回。gflgs.exe是支持工具包的一部分,可以从Microsoft下载中心下载,只需在那里搜索即可。

        3
  •  0
  •   Simeon Pilgrim    16 年前

    电脑线头可能会遇到一些形式的malloc/新的尺寸问题,但我不确定它是否会找到你的。

    VS2005在调试模式下(在函数末尾运行)对堆栈对象具有良好的缓冲区溢出检查功能。它会定期检查堆。

    至于它帮助跟踪问题发生的位置,我倾向于从这里开始使用宏来转储所有分配,以便稍后(在检测到损坏的内存时)与之匹配。

    痛苦的过程,所以我也渴望学习更好的方法。

        4
  •  0
  •   Ira Baxter    15 年前

    考虑我们 Memory Safety Check . 我想它会抓住你描述的所有错误。是的,它是运行时检查 每一个 访问,有相当大的开销(不像我们认为的valgrind那么糟糕),有利于诊断第一个错误的程序操作。