2011-01-16 35 views
24

Ho visto molti depositi fondamentali nella mia vita, ma questo mi ha lasciato perplesso.Dump nucleo "inspiegabile"

Contesto:

  • multi-threaded programma/Linux x86_64 in esecuzione su un cluster di AMD Barcelona CPU
  • il codice che si blocca viene eseguito un sacco
  • esecuzione 1000 istanze del programma (la esatto stesso binario ottimizzato) sotto carico produce 1-2 arresti all'ora
  • gli arresti anomali si verificano su macchine diverse (ma le macchine stesse sono piuttosto identiche)
  • il crash tutti hanno lo stesso aspetto (stesso indirizzo esatto, lo stesso stack di chiamate)

Ecco i dettagli del disastro:

Program terminated with signal 11, Segmentation fault. 
#0 0x00000000017bd9fd in Foo() 
(gdb) x/i $pc 
=> 0x17bd9fd <_Z3Foov+349>: rex.RB orb $0x8d,(%r15) 

(gdb) x/6i $pc-12 
0x17bd9f1 <_Z3Foov+337>: mov (%rbx),%eax 
0x17bd9f3 <_Z3Foov+339>: mov %rbx,%rdi 
0x17bd9f6 <_Z3Foov+342>: callq *0x70(%rax) 
0x17bd9f9 <_Z3Foov+345>: cmp %eax,%r12d 
0x17bd9fc <_Z3Foov+348>: mov %eax,-0x80(%rbp) 
0x17bd9ff <_Z3Foov+351>: jge 0x17bd97e <_Z3Foov+222> 

Si noterà che l'incidente è accaduto nel mezzo di istruzioni a 0x17bd9fc, che è dopo il ritorno da una chiamata a 0x17bd9f6 a una funzione virtuale.

Quando esamino la tabella virtuale, vedo che non sia danneggiato in alcun modo:

(gdb) x/a $rbx 
0x2ab094951f80: 0x3f8c550 <_ZTI4Foo1+16> 
(gdb) x/a 0x3f8c550+0x70 
0x3f8c5c0 <_ZTI4Foo1+128>: 0x2d3d7b0 <_ZN4Foo13GetEv> 

e che punti a questa funzione banale (come previsto dalla guardando il sorgente):

(gdb) disas 0x2d3d7b0 
Dump of assembler code for function _ZN4Foo13GetEv: 
    0x0000000002d3d7b0 <+0>: push %rbp 
    0x0000000002d3d7b1 <+1>: mov 0x70(%rdi),%eax 
    0x0000000002d3d7b4 <+4>: mov %rsp,%rbp 
    0x0000000002d3d7b7 <+7>: leaveq 
    0x0000000002d3d7b8 <+8>: retq 
End of assembler dump. 

Inoltre, quando guardo l'indirizzo del mittente che Foo1::Get() dovrebbe hanno fatto ritorno a:

(gdb) x/a $rsp-8 
0x2afa55602048: 0x17bd9f9 <_Z3Foov+345> 

Vedo che punti alle istruzioni destra, quindi è come se durante il ritorno da Foo1::Get(), alcuni gremlin è arrivato e ha incrementato %rip per 4.

spiegazioni plausibili?

+0

Hai mai scoperto cosa ha causato questo? Se è così, sarei molto interessato a sapere cos'era! – us2012

+1

@ us2012 Credo che abbiamo trovato la causa. Vedi la mia risposta. –

risposta

27

Quindi, per quanto possa sembrare improbabile, sembra che abbiamo riscontrato un vero bug della CPU in buona fede.

http://support.amd.com/us/Processor_TechDocs/41322_10h_Rev_Gd.pdf ha erratum # 721:

721 processore potrebbe erroneamente Aggiornamento Stack Pointer

Descrizione

Under a highly specific and detailed set of internal timing conditions, 
the processor may incorrectly update the stack pointer after a long series 
of push and/or near-call instructions, or a long series of pop 
and/or near-return instructions. The processor must be in 64-bit mode for 
this erratum to occur. 

potenziale effetto sul sistema

The stack pointer value jumps by a value of approximately 1024, either in 
the positive or negative direction. 
This incorrect stack pointer causes unpredictable program or system behavior, 
usually observed as a program exception or crash (for example, a #GP or #UD). 
+0

Ouch. In realtà è una condizione "altamente specifica" - cioè, hai risolto il problema modificando leggermente il codice prodotto nel punto problematico? – us2012

+8

@ us2012 Il nostro codice e i nostri compilatori cambiano continuamente, e il problema è scomparso all'improvviso come appariva ... solo per accadere di nuovo 2 anni dopo in un eseguibile completamente non correlato. –

3

ho visto una volta un incidente "codice operativo illegale" proprio nel bel mezzo di un'istruzione. Stavo lavorando su una porta Linux. Per farla breve, Linux sottrae dal puntatore dell'istruzione per riavviare un syscall, e nel mio caso ciò accadeva due volte (se due segnali arrivavano alla stessa ora).

Ecco, questo è un possibile colpevole: il kernel giocherellando con il puntatore all'istruzione. Potrebbe esserci qualche altra causa nel tuo caso.

Tenere presente che a volte il processore capirà i dati che sta elaborando come un'istruzione, anche quando non dovrebbe essere. Quindi il processore potrebbe aver eseguito la "istruzione" a 0x17bd9fa e poi spostato su 0x17bd9fd e quindi generato un'eccezione di opcode non valida. (Ho appena fatto quel numero, ma sperimentare con un disassemblatore può mostrarti dove il processore potrebbe aver "inserito" il flusso di istruzioni.)

Buon debug!

+0

Ho considerato i segnali, ma ci sono diversi "avvertimenti" contro di loro che sono la causa: 1. notare che non ci sono chiamate di sistema da nessuna parte attorno a questo codice; 2. questa discussione non dovrebbe ricevere alcun segnale asincrono; 3. Se un segnale lo stava causando, come spieghi l'incidente che si verifica su * esattamente * lo stesso indirizzo in tutti i programmi bloccati? –

+0

Non ho suggerito che il tuo problema potrebbe essere un segnale. (Questo era solo il bug nella porta che era dietro il mio problema.) Il mio punto era che fattori completamente esterni al tuo programma - come un bug del kernel - potrebbero causare questo problema. Un'altra cosa che può compromettere il puntatore delle istruzioni è la gestione delle eccezioni. – Artelius

Problemi correlati