Це не проблема, яку обов'язково можна вирішити, змінивши параметри конфігурації.
Зміна параметрів конфігурації іноді матиме позитивний вплив, але це може так само легко погіршити ситуацію або взагалі нічого не зробити.
Характер помилки такий:
#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
- Якщо у вас є сегмент за замовчуванням, спробуйте створити зворотній шлях
- Включіть стільки інформації про конфігурацію, скільки здається доцільною, зокрема, якщо ви використовуєте opcache, включайте рівень оптимізації.
- Продовжуйте перевіряти звіт про помилку щодо оновлень, більше інформації може знадобитися.
- Якщо у вас завантажений опкаш, вимкніть оптимізацію
- Я не вибираю на оптике, це чудово, але деякі оптимізації, як відомо, спричиняють помилки.
- Якщо це не працює, хоча ваш код може бути повільнішим, спробуйте спочатку розвантажити опкаш.
- Якщо щось із цього зміниться або виправить проблему, оновіть зроблений вами звіт про помилку.
- Вимкніть одразу всі непотрібні розширення.
- Почніть активувати всі розширення окремо, ретельно протестуючи після кожної зміни конфігурації.
- Якщо ви знайдете розширення проблеми, оновіть звіт про помилку, отримавши більше інформації.
- Прибуток.
Можливо, прибутку не буде ... Я сказав, що на початку ви, можливо, зможете знайти спосіб змінити свої симптоми, змішавшись із конфігурацією, але це надзвичайно вражає і пропускає, і це не допоможе наступного разу, коли у вас буде те саме zend_mm_heap corrupted
повідомлення, існує лише стільки варіантів конфігурації.
Дійсно важливо, що ми створюємо звіти про помилки, коли знаходимо помилки, ми не можемо припустити, що наступна людина, яка потрапила на помилку, це зробить ... скоріше, ніж ні, фактичне рішення ні в якому разі не таємниче, якщо ви зробите потрібні люди, обізнані про проблему.
USE_ZEND_ALLOC
Якщо ви встановите USE_ZEND_ALLOC=0
в оточенні, це відключає власний диспетчер пам'яті Зенда; Менеджер пам’яті Zend гарантує, що кожен запит має власну купу, що вся пам'ять вільна, в кінці запиту, і оптимізована для розподілу шматочків пам'яті саме потрібного розміру для PHP.
Якщо вимкнути його, вимкніть ці оптимізації, що ще важливіше, це, швидше за все, створить витоки пам’яті, оскільки існує дуже багато коду розширення, який покладається на Zend MM для звільнення для них пам’яті в кінці запиту (tut, tut).
Це також може приховати симптоми, але системна купа може бути пошкоджена точно так само, як і купа Зенда.
Це може здатися більш толерантним або менш толерантним, але виправити першопричину проблеми вона не може .
Можливість взагалі відключити це - на благо розробників внутрішніх справ; Ніколи не слід розгортати PHP з відключеним Zend MM.
USE_ZEND_ALLOC=0
трак стека в журналі помилок. І знайшов помилку/usr/sbin/httpd: corrupted double-linked list
, я виявив, що коментуючи працюючеopcache.fast_shutdown=1
для мене.