Это не проблема, которая обязательно решается путем изменения параметров конфигурации.
Изменение параметров конфигурации иногда оказывает положительное влияние, но оно может так же легко ухудшить ситуацию или вообще ничего не делать.
Природа ошибки такова:
#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).
Если вы поиграете с ужасным кодом, вы обнаружите, что не все эти явно неправильные операторы приводят к ошибке сегментации (фатальной ошибке завершения).
Я явно допустил эти ошибки в коде примера, но такие же виды ошибок очень легко случаются в управляемой памяти среде: если какой-то код не поддерживает правильный пересчет переменной (или другого символа) правильным образом Например, если он свободен, это слишком рано, другой фрагмент кода может прочитать из уже свободной памяти, если он каким-то образом хранит неправильный адрес, другой фрагмент кода может записать в недопустимую память, он может быть дважды освобожден. .
Это не те проблемы, которые можно отлаживать в PHP, они абсолютно требуют внимания разработчика внутренних компонентов.
Порядок действий должен быть:
- Открыть отчет об ошибке на http://bugs.php.net
- Если у вас есть segfault, попробуйте предоставить backtrace
- Включите столько информации о конфигурации, сколько кажется целесообразным, в частности, если вы используете opcache, включите уровень оптимизации.
- Продолжайте проверять отчет об ошибках на наличие обновлений, может потребоваться дополнительная информация.
- Если у вас загружен opcache, отключите оптимизацию
- Я не выбираю opcache, это здорово, но известно, что некоторые из его оптимизаций вызывали сбои.
- Если это не сработает, хотя ваш код может работать медленнее, попробуйте сначала выгрузить opcache.
- Если что-то из этого изменит или решит проблему, обновите сделанный вами отчет об ошибке.
- Отключить все ненужные расширения сразу.
- Начните активировать все свои расширения по отдельности, тщательно тестируя после каждого изменения конфигурации.
- Если вы найдете расширение проблемы, обновите свой отчет об ошибке с дополнительной информацией.
- Прибыль.
Там может не быть никакой прибыли ... Я сказал в начале, вы можете найти способ изменить ваши симптомы, путаясь с конфигурацией, но это очень удачно, и это не поможет в следующем если у вас одно и то же сообщение zend_mm_heap corrupted
, вариантов конфигурации слишком много.
Очень важно, что мы создаем отчеты об ошибках, когда мы находим ошибки, мы не можем предполагать, что следующий человек, который совершит ошибку, сделает это ... скорее всего, фактическое разрешение ни в коем случае не загадочное, Вы делаете правильных людей осведомленными о проблеме.
USE_ZEND_ALLOC
Если вы установите USE_ZEND_ALLOC=0
в среде, это отключит собственный менеджер памяти Zend; Диспетчер памяти Zend гарантирует, что каждый запрос имеет свою собственную кучу, что вся память освобождается в конце запроса, и оптимизирована для выделения кусков памяти, точно подходящего размера для PHP.
Отключение этой функции приведет к отключению этих оптимизаций, что более важно, вероятно, приведет к утечкам памяти, поскольку существует множество кода расширения, который полагается на Zend MM для освобождения памяти для них в конце запроса (tut, tut).
Он также может скрыть симптомы, но системная куча может быть повреждена точно так же, как куча Зенда.
Это может показаться более терпимым или менее терпимым, но устранить причину проблемы невозможно .
Возможность его вообще отключить, для блага внутренних разработчиков; Вы должны никогда развертывать PHP с отключенным Zend MM.