“zend_mm_heap损坏”是什么意思USE_ZEND_ALLOC

2022-08-30 07:00:49

突然之间,我的应用程序遇到了以前从未遇到过的问题。我决定检查Apache的错误日志,我发现一条错误消息“zend_mm_heap损坏”。这是什么意思。

OS: Fedora Core 8 Apache: 2.2.9 PHP: 5.2.6


答案 1

经过反复试验,我发现如果我增加php.ini文件中的值,这个错误就会消失。output_buffering


答案 2

这不是一个必须通过更改配置选项解决的问题。

更改配置选项有时会产生积极影响,但它很容易使事情变得更糟,或者什么都不做。

错误的性质是这样的:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(void) {
    void **mem = malloc(sizeof(char)*3);
    void *ptr;

    /* read past end */
    ptr = (char*) mem[5];   

    /* write past end */
    memcpy(mem[5], "whatever", sizeof("whatever"));

    /* free invalid pointer */
    free((void*) mem[3]);

    return 0;
}

上面的代码可以编译为:

gcc -g -o corrupt corrupt.c

使用valgrind执行代码,您可以看到许多内存错误,最终导致分段错误:

krakjoe@fiji:/usr/src/php-src$ valgrind ./corrupt
==9749== Memcheck, a memory error detector
==9749== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==9749== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==9749== Command: ./corrupt
==9749== 
==9749== Invalid read of size 8
==9749==    at 0x4005F7: main (an.c:10)
==9749==  Address 0x51fc068 is 24 bytes after a block of size 16 in arena "client"
==9749== 
==9749== Invalid read of size 8
==9749==    at 0x400607: main (an.c:13)
==9749==  Address 0x51fc068 is 24 bytes after a block of size 16 in arena "client"
==9749== 
==9749== Invalid write of size 2
==9749==    at 0x4C2F7E3: memcpy@@GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9749==    by 0x40061B: main (an.c:13)
==9749==  Address 0x50 is not stack'd, malloc'd or (recently) free'd
==9749== 
==9749== 
==9749== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==9749==  Access not within mapped region at address 0x50
==9749==    at 0x4C2F7E3: memcpy@@GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9749==    by 0x40061B: main (an.c:13)
==9749==  If you believe this happened as a result of a stack
==9749==  overflow in your program's main thread (unlikely but
==9749==  possible), you can try to increase the size of the
==9749==  main thread stack using the --main-stacksize= flag.
==9749==  The main thread stack size used in this run was 8388608.
==9749== 
==9749== HEAP SUMMARY:
==9749==     in use at exit: 3 bytes in 1 blocks
==9749==   total heap usage: 1 allocs, 0 frees, 3 bytes allocated
==9749== 
==9749== LEAK SUMMARY:
==9749==    definitely lost: 0 bytes in 0 blocks
==9749==    indirectly lost: 0 bytes in 0 blocks
==9749==      possibly lost: 0 bytes in 0 blocks
==9749==    still reachable: 3 bytes in 1 blocks
==9749==         suppressed: 0 bytes in 0 blocks
==9749== Rerun with --leak-check=full to see details of leaked memory
==9749== 
==9749== For counts of detected and suppressed errors, rerun with: -v
==9749== ERROR SUMMARY: 4 errors from 3 contexts (suppressed: 0 from 0)
Segmentation fault

如果您不知道,您已经知道这是堆分配的内存;堆是指程序在运行时可用的内存区域,因为程序显式请求它(在我们的示例中使用malloc)。mem

如果你玩弄可怕的代码,你会发现并非所有那些明显不正确的语句都会导致分段错误(致命的终止错误)。

我在示例代码中明确地犯了这些错误,但是在内存管理的环境中,同样的错误很容易发生:如果某些代码没有以正确的方式维护变量(或其他一些符号)的引用计数,例如,如果它过早地释放了它,另一段代码可能会从已经释放的内存中读取, 如果它以某种方式存储了错误的地址,另一段代码可能会写入无效的内存,它可能会被释放两次......

这些不是可以在PHP中调试的问题,它们绝对需要内部开发人员的注意。

行动方针应是:

  1. http://bugs.php.net 上打开错误报告
    • 如果您有 segfault,请尝试提供回溯跟踪
    • 包括尽可能多的配置信息,特别是,如果你使用opcache包括优化级别。
    • 继续检查错误报告以获取更新,可能会要求您提供更多信息。
  2. 如果您已加载 opcache,请禁用优化
    • 我不是在挑剔opcache,它很棒,但是它的一些优化已经知道会导致错误。
    • 如果这不起作用,即使您的代码可能较慢,也请尝试先卸载 opcache。
    • 如果其中任何更改或修复了问题,请更新您所做的错误报告。
  3. 一次禁用所有不必要的扩展名。
    • 开始单独启用所有扩展,并在每次配置更改后进行全面测试。
    • 如果找到问题扩展,请使用更多信息更新错误报告。
  4. 利润。

可能没有任何利润...我在一开始就说过,你也许能够通过搞乱配置来找到一种方法来改变你的症状,但这是非常打击和错过的,并且下次你有相同的消息时无济于事,只有这么多的配置选项。zend_mm_heap corrupted

当我们发现错误时,我们创建错误报告非常重要,我们不能假设下一个击中错误的人会这样做......更有可能的是,如果你让合适的人意识到这个问题,实际的解决方案绝不是神秘的。

USE_ZEND_ALLOC

如果您在环境中设置,这将禁用Zend自己的内存管理器;Zend的内存管理器确保每个请求都有自己的堆,在请求结束时释放所有内存,并针对分配与PHP大小恰到好处的内存块进行了优化。USE_ZEND_ALLOC=0

禁用它将禁用这些优化,更重要的是它可能会产生内存泄漏,因为有很多扩展代码依赖于Zend MM在请求结束时为它们释放内存(tut,tut)。

它也可能隐藏症状,但系统堆的损坏方式可能与Zend的堆完全相同。

它可能看起来更宽容或更不宽容,但解决问题的根本原因,它不能

完全禁用它的能力是为了内部开发人员的利益;您永远不应该在禁用 Zend MM 的情况下部署 PHP。


推荐