“zend_mm_heap corrupted”는 무엇을 의미합니까?

갑자기 전에 없던 앱에 문제가 생겼어요.Apache 오류 로그를 확인해보니 “zend_mm_heap corrupted”라는 오류 메시지가 나타납니다.이게 무슨 뜻이죠?

OS: Fedora Core 8 Apache: 2.2.9 PHP: 5.2.6



질문에 대한 답변



많은 시행착오 끝에, 만약 내가 더 많은 것을 한다면output_bufferingphp.ini 파일의 값은 이 오류가 사라집니다.




이 문제는 구성 옵션을 변경하여 반드시 해결할 수 있는 문제는 아닙니다.

구성 옵션을 변경하면 긍정적인 영향을 미칠 수 있지만, 상황을 쉽게 악화시키거나 전혀 도움이 되지 않을 수 있습니다.

에러의 성질은 다음과 같습니다.

#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 

몰랐다면 이미 알아냈을 거야mem히프가 할당된 메모리입니다.힙은 프로그램이 명시적으로 요청했기 때문에 실행 시 프로그램에서 사용할 수 있는 메모리 영역을 나타냅니다(이 경우 malloc 포함).

이 끔찍한 코드를 가지고 장난을 치면 명백히 잘못된 문장이 모두 세그멘테이션 장애(치명적인 종단 오류)로 이어지는 것은 아니라는 것을 알게 됩니다.

샘플 코드에서 이러한 에러를 분명히 했습니다만, 메모리 관리 환경에서는 같은 종류의 에러가 매우 쉽게 발생합니다.일부 코드가 변수(또는 다른 심볼)의 리카운트를 올바른 방법으로 유지하지 않는 경우(예를 들어 너무 이른 경우), 다른 코드 조각은 이미 free’d 메모리에서 읽을 수 있습니다.주소가 잘못되었을 경우, 다른 코드 조각이 무효 메모리에 쓸 수 있으며, 두 번 비어 있을 수 있습니다.

이것들은 PHP로 디버깅할 수 있는 문제가 아닙니다.이것은 반드시 내부 개발자의 주의가 필요합니다.

행동 방침은 다음과 같습니다.

  1. http://bugs.php.net에서 버그 보고서를 엽니다.
    • seg fault가 있는 경우 백트레이스를 제공하려고 합니다.
    • 특히 opcache를 사용하는 경우 최적화 수준을 포함하여 필요한 만큼의 구성 정보를 포함합니다.
    • 업데이트에 대한 버그 보고서를 계속 확인하십시오. 더 많은 정보가 필요할 수 있습니다.
  2. opcache가 로드된 경우 최적화를 사용하지 않도록 설정합니다.
    • opcache를 이용하는 것은 아니지만, 일부 opcache의 최적화로 인해 장애가 발생하는 것으로 알려져 있습니다.
    • 이 방법으로 동작하지 않는 경우는, 코드가 늦어도, 우선 opcache를 언로드해 보겠습니다.
    • 이 중 하나라도 문제가 변경 또는 수정되면 작성한 버그 보고서를 갱신합니다.
  3. 불필요한 확장을 한 번에 모두 사용하지 않도록 설정합니다.
    • 모든 내선번호를 개별적으로 이니블로 하여 설정 변경 후 테스트를 철저히 실시합니다.
    • 문제의 확장이 발견되면 버그 보고서를 업데이트하여 자세한 정보를 얻습니다.
  4. 이익.

이익이 없을지도 모른다…처음에 구성을 망치는 것으로 증상을 바꿀 수 있을 것이라고 말했지만, 이것은 매우 히트 앤 미스이며, 다음 번과 같은 상태가 되어도 도움이 되지 않습니다.zend_mm_heap corrupted설정 옵션은 한정되어 있습니다.

버그를 발견했을 때 버그 리포트를 작성하는 것은 매우 중요합니다.다음 버그를 발견한 사람이 버그 보고서를 작성한다고 가정할 수 없습니다.적절한 사람에게 문제를 인식시키면 실제 문제 해결은 전혀 수수께끼가 되지 않습니다.

USE_ZEND_ALLOC

설정했을 경우USE_ZEND_ALLOC=0이로 인해 Zend의 메모리 매니저가 비활성화됩니다.Zend의 메모리 매니저는 각 요청에 자체 힙이 있는지, 요청 끝에 모든 메모리가 비어 있는지 확인하고 PHP에 적합한 크기의 메모리 청크를 할당하도록 최적화되어 있습니다.

이러한 최적화를 디세블로 하면, 보다 중요한 것은, 요구의 마지막에 메모리를 해방하기 위해서 Zend MM 에 의존하는 많은 확장 코드가 존재하기 때문에, 이러한 최적화가 디세블이 됩니다(tut, tut).

증상을 숨길 수도 있지만 시스템 힙은 Zend의 힙과 동일한 방식으로 손상될 수 있습니다.

더 관용적이거나 덜 관용적인 것처럼 보일 수 있지만 문제의 근본 원인을 해결할 수는 없습니다.

이 기능을 사용하지 않도록 설정하는 것은 내부 개발자를 위한 것입니다. Zend MM을 사용하지 않도록 설정한 상태에서 PHP를 배포해서는 안 됩니다.




PHP 5.5에서도 같은 에러가 발생하고 있어 출력 버퍼링을 늘려도 도움이 되지 않습니다.나도 APC를 운영하지 않았기 때문에 그것은 문제가 되지 않았다.마지막으로 opcache까지 추적했습니다. CLI에서 비활성화만 하면 되었습니다.여기에는 다음과 같은 특정 설정이 있습니다.

opcache.enable_cli=0 

스위치를 켜면 zend_mm_heap 파손 오류가 사라집니다.




Linux 의 경우는, 커맨드 라인에서 시험해 주세요.

export USE_ZEND_ALLOC=0 



확인하다unset()s. 하지 않도록 주의해 주세요.unset()에 대한 참조$this파괴자(또는 이에 상당하는 것) 및 그unset()destructor의 s는 같은 오브젝트에 대한 참조 카운트를 0으로 떨어뜨리지 않습니다.제가 조사를 좀 해봤는데 그게 보통 더미의 손상을 일으키는 원인이라는 걸 알아냈어요.

zend_mm_heap 파손 오류에 대한 PHP 버그 보고서가 있습니다.코멘트를 참조[2011-08-31 07:49 UTC] f dot ardelian at gmail dot com예를 들어 재생산하는 방법에 대해 설명하겠습니다.

다른 모든 ‘해결책'(변화)이php.ini더 적은 모듈로 소스에서 PHP를 컴파일하는 등) 문제를 숨깁니다.