Questo non è un problema che è necessariamente risolvibile modificando le opzioni di configurazione.
La modifica delle opzioni di configurazione a volte avrà un impatto positivo, ma può altrettanto facilmente peggiorare le cose o non fare nulla.
La natura dell'errore è questa:
#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;
}
Il codice sopra può essere compilato con:
gcc -g -o corrupt corrupt.c
Eseguendo il codice con valgrind puoi vedere molti errori di memoria, che culminano in un errore di segmentazione:
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
Se non lo sapevi, hai già capito che mem
è la memoria allocata in heap; L'heap si riferisce alla regione di memoria disponibile per il programma in fase di esecuzione, perché il programma lo ha esplicitamente richiesto (con malloc nel nostro caso).
Se giochi con il codice terribile, scoprirai che non tutte quelle dichiarazioni ovviamente errate provocano un errore di segmentazione (un errore fatale di terminazione).
Ho fatto esplicitamente quegli errori nel codice di esempio, ma gli stessi tipi di errori si verificano molto facilmente in un ambiente gestito dalla memoria: se un codice non mantiene il conteggio di una variabile (o qualche altro simbolo) nel modo corretto, ad esempio se è libero è troppo presto, un altro pezzo di codice potrebbe leggere dalla memoria già libera, se in qualche modo memorizza l'indirizzo sbagliato, un altro pezzo di codice potrebbe scrivere nella memoria non valida, potrebbe essere libero due volte ...
Questi non sono problemi che possono essere sottoposti a debug in PHP, richiedono assolutamente l'attenzione di uno sviluppatore interno.
Il corso di azione dovrebbe essere:
- Apri una segnalazione di bug su http://bugs.php.net
- Se hai un segfault, prova a fornire un backtrace
- Includi tutte le informazioni di configurazione che sembrano appropriate, in particolare se stai utilizzando opcache includi il livello di ottimizzazione.
- Continua a controllare la segnalazione di bug per gli aggiornamenti, potrebbero essere richieste ulteriori informazioni.
- Se hai opcache caricato, disabilita le ottimizzazioni
- Non sto scegliendo Opcache, è fantastico, ma alcune delle sue ottimizzazioni sono state conosciute per causare errori.
- Se non funziona, anche se il tuo codice potrebbe essere più lento, prova prima a scaricare opcache.
- Se una di queste modifiche o risolve il problema, aggiorna la segnalazione di bug che hai effettuato.
- Disabilita tutte le estensioni non necessarie contemporaneamente.
- Inizia ad abilitare tutte le tue estensioni individualmente, testando accuratamente dopo ogni modifica della configurazione.
- Se trovi l'estensione del problema, aggiorna la tua segnalazione bug con maggiori informazioni.
- Profitto.
Potrebbe non esserci alcun profitto ... Ho detto all'inizio, potresti essere in grado di trovare un modo per cambiare i sintomi facendo confusione con la configurazione, ma questo è estremamente incostante, e non aiuta la prossima volta che hai lo stesso zend_mm_heap corrupted
messaggio, ci sono solo tante opzioni di configurazione.
È davvero importante creare report di bug quando troviamo bug, non possiamo presumere che la prossima persona a colpirlo lo farà ... molto probabilmente, la risoluzione effettiva non è in alcun modo misteriosa, se rendi il persone giuste consapevoli del problema.
USE_ZEND_ALLOC
Se impostato USE_ZEND_ALLOC=0
nell'ambiente, questo disabilita il gestore della memoria di Zend; Il gestore della memoria di Zend assicura che ogni richiesta abbia il proprio heap, che tutta la memoria sia libera alla fine di una richiesta ed è ottimizzata per l'allocazione di blocchi di memoria delle dimensioni giuste per PHP.
Disabilitarlo disabiliterà quelle ottimizzazioni, cosa ancora più importante probabilmente creerà perdite di memoria, poiché esiste un sacco di codice di estensione che si basa su Zend MM per liberare memoria per loro alla fine di una richiesta (tut, tut).
Potrebbe anche nascondere i sintomi, ma l'heap di sistema può essere danneggiato esattamente allo stesso modo dell'heap di Zend.
Può sembrare di essere più tolleranti o meno tolleranti, ma correggere la causa principale del problema, non ci riesce .
La possibilità di disabilitarlo affatto, è a beneficio degli sviluppatori interni; Non si dovrebbe mai distribuire PHP con Zend MM disabilitato.
USE_ZEND_ALLOC=0
per ottenere lo stacktrace nel registro degli errori/usr/sbin/httpd: corrupted double-linked list
e ho trovato il bug , ho scoperto che commentando haopcache.fast_shutdown=1
funzionato per me.