Ce n'est pas un problème qui peut nécessairement être résolu en modifiant les options de configuration.
Changer les options de configuration aura parfois un impact positif, mais cela peut tout aussi facilement aggraver les choses, ou ne rien faire du tout.
La nature de l'erreur est la suivante:
#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;
}
Le code ci-dessus peut être compilé avec:
gcc -g -o corrupt corrupt.c
En exécutant le code avec valgrind, vous pouvez voir de nombreuses erreurs de mémoire, aboutissant à une erreur de segmentation:
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
Si vous ne le saviez pas, vous avez déjà compris qu'il mem
s'agit de la mémoire allouée au tas; Le tas fait référence à la région de mémoire disponible pour le programme à l'exécution, car le programme l'a explicitement demandé (avec malloc dans notre cas).
Si vous jouez avec le terrible code, vous constaterez que toutes ces déclarations manifestement incorrectes ne provoquent pas une erreur de segmentation (une erreur de fin fatale).
J'ai explicitement fait ces erreurs dans l'exemple de code, mais les mêmes types d'erreurs se produisent très facilement dans un environnement géré en mémoire: si un code ne maintient pas le refcount d'une variable (ou d'un autre symbole) de la manière correcte, par exemple s'il est libre, c'est trop tôt, un autre morceau de code peut lire à partir de la mémoire déjà libérée, s'il stocke d'une manière ou d'une autre l'adresse incorrecte, un autre morceau de code peut écrire dans une mémoire invalide, il peut être libéré deux fois ...
Ce ne sont pas des problèmes qui peuvent être débogués en PHP, ils nécessitent absolument l'attention d'un développeur interne.
Le plan d'action devrait être:
- Ouvrez un rapport de bogue sur http://bugs.php.net
- Si vous avez un segfault, essayez de fournir un backtrace
- Incluez autant d'informations de configuration que vous le souhaitez, en particulier si vous utilisez opcache, incluez le niveau d'optimisation.
- Continuez à vérifier le rapport de bogue pour les mises à jour, plus d'informations peuvent être demandées.
- Si vous avez chargé opcache, désactivez les optimisations
- Je ne choisis pas opcache, c'est génial, mais certaines de ses optimisations sont connues pour causer des erreurs.
- Si cela ne fonctionne pas, même si votre code peut être plus lent, essayez d'abord de décharger opcache.
- Si l'un de ces changements ou corrige le problème, mettez à jour le rapport de bogue que vous avez effectué.
- Désactivez toutes les extensions inutiles à la fois.
- Commencez à activer toutes vos extensions individuellement, en effectuant des tests approfondis après chaque changement de configuration.
- Si vous trouvez l'extension du problème, mettez à jour votre rapport de bogue avec plus d'informations.
- Profit.
Il n'y a peut-être aucun profit ... J'ai dit au début, vous pourrez peut-être trouver un moyen de changer vos symptômes en jouant avec la configuration, mais c'est extrêmement hasardeux, et n'aide pas la prochaine fois que vous avez le même zend_mm_heap corrupted
message, il n'y a que tellement d'options de configuration.
Il est vraiment important que nous créions des rapports de bogues lorsque nous trouvons des bogues, nous ne pouvons pas supposer que la prochaine personne à frapper le bogue va le faire ... plus probable qu'autrement, la résolution réelle n'est en aucun cas mystérieuse, si vous faites le les bonnes personnes conscientes du problème.
USE_ZEND_ALLOC
Si vous définissez USE_ZEND_ALLOC=0
dans l'environnement, cela désactive le propre gestionnaire de mémoire de Zend; Le gestionnaire de mémoire de Zend garantit que chaque requête a son propre tas, que toute la mémoire est libérée à la fin d'une requête et est optimisé pour l'allocation de blocs de mémoire de la bonne taille pour PHP.
Le désactiver désactivera ces optimisations, plus important encore, cela créera probablement des fuites de mémoire, car il y a beaucoup de code d'extension qui s'appuie sur le Zend MM pour libérer de la mémoire pour eux à la fin d'une requête (tut, tut).
Cela peut également masquer les symptômes, mais le tas système peut être corrompu exactement de la même manière que le tas de Zend.
Cela peut sembler plus ou moins tolérant, mais il ne peut pas résoudre la cause profonde du problème .
La possibilité de le désactiver du tout, est au profit des développeurs internes; Vous ne devez jamais déployer PHP avec Zend MM désactivé.
USE_ZEND_ALLOC=0
d'obtenir le stacktrace dans le journal des erreurs Et/usr/sbin/httpd: corrupted double-linked list
j'ai trouvé le bogue , j'ai découvert que commenter leopcache.fast_shutdown=1
fonctionnait pour moi.