2014-05-09 11 views
6

Devo aver fatto perl molto turbato perché mi sta dando un messaggio di errore che non è documentato in perldiag:Che cosa significa "PmmREFCNT_dec: REFCNT decrementato sotto 0" significa?

PmmREFCNT_dec: RefCnt decrementato di sotto di 0 per 53a6930 !.

A seconda della sua stato d'animo, a volte questo è seguito da:

*** glibc rilevato ***/usr/bin/perl: doppio libero o la corruzione (prec!): 0x0000000004e58a60 *

... o più chiaramente da:

Segmentation fault

Questo, chiaramente, è fatale, ma l'ho anche testato per essere intercettabile. Quando utilizzo Try::Tiny, rileverò sempre l'errore nello stesso punto, ma quando non lo utilizzo, vengono eseguite ulteriori istruzioni prima che si verifichi l'arresto anomalo. Inoltre, anche se il mio modulo è completamente determinista e sono abbastanza sicuro che tutte le dipendenze siano uguali, l'errore non si verifica tutte le volte.

Sfortunatamente, il modulo che mi sta dando questo problema è enorme, con molte dipendenze e non sono stato in grado di replicare il problema su un esempio più piccolo. Quindi, non posso chiedere aiuto per il debug, ma se qualcuno ha familiarità con gli interni di Perl sa in quali circostanze si verifica questo errore, questo può aiutare me (o chiunque altro vedrà mai questo messaggio) a trovare la fonte del problema e/o una soluzione.

Nel caso sia utile, l'idea generale è questa. Ho due classi, chiamiamole Thing e SetOfThings. SetOfThings ha un attributo che è un insieme di istanze Thing. Entrambi classe ha anche un metodo explode che fa qualcosa di simile:

# SetOfThings 
sub explode { 
    my $self = shift; 
    my $new = dclone $self; 
    delete $new->{'some_attribute'}; 
    $new->set_of_things(map { $_->explode } $self->constraints); 
    return $new; 
} 

# Thing 
sub explode { 
    my $self = shift; 
    return map { new Thing(do_something_fancy) } keys %$self; 
} 

L'errore di solito sembra verificarsi quando si chiama SetOfThings::explode o quando si chiama SetOfThings::set_of_things come un getter.

Edit: Backtrace

Non credo io sono abbastanza competente per interpretarlo, ma ho ottenuto un backtrace da gdb:

#0 0x00007ffff70a6094 in ??() from /lib/x86_64-linux-gnu/libc.so.6 
#1 0x00007ffff70a76a8 in ??() from /lib/x86_64-linux-gnu/libc.so.6 
#2 0x00007ffff70aab1c in free() from /lib/x86_64-linux-gnu/libc.so.6 
#3 0x00007ffff7b0869b in Perl_hv_undef_flags() from /usr/lib/libperl.so.5.14 
#4 0x00007ffff7b1ae66 in Perl_sv_clear() from /usr/lib/libperl.so.5.14 
#5 0x00007ffff7b1b292 in Perl_sv_free2() from /usr/lib/libperl.so.5.14 
#6 0x00007ffff7b04bc3 in Perl_hv_free_ent() from /usr/lib/libperl.so.5.14 
#7 0x00007ffff7b04e6e in ??() from /usr/lib/libperl.so.5.14 
#8 0x00007ffff7b08683 in Perl_hv_undef_flags() from /usr/lib/libperl.so.5.14 
#9 0x00007ffff7b1ae66 in Perl_sv_clear() from /usr/lib/libperl.so.5.14 
#10 0x00007ffff7b1b292 in Perl_sv_free2() from /usr/lib/libperl.so.5.14 
#11 0x00007ffff7b42cef in Perl_leave_scope() from /usr/lib/libperl.so.5.14 
#12 0x00007ffff7b11112 in Perl_pp_leave() from /usr/lib/libperl.so.5.14 
#13 0x00007ffff7b0bce6 in Perl_runops_standard() from /usr/lib/libperl.so.5.14 
#14 0x00007ffff7aad815 in perl_run() from /usr/lib/libperl.so.5.14 
#15 0x0000000000400f89 in main() 

Edit 2: Valgrind backtrace

Questo è quello che ho ottenuto dall'esecuzione di valgrind. Anche se non sono ancora sicuro di quello che sta succedendo, almeno ora so chi dare la colpa.:-)

==27226== Invalid free()/delete/delete[]/realloc() 
==27226== at 0x4C27D4E: free (vg_replace_malloc.c:427) 
==27226== by 0xA138F42: PmmREFCNT_dec (in /usr/lib/perl5/auto/XML/LibXML/LibXML.so) 
==27226== by 0xA11D3FA: XS_XML__LibXML__Node_DESTROY (in /usr/lib/perl5/auto/XML/LibXML/LibXML.so) 
==27226== by 0x4EE770B: Perl_pp_entersub (in /usr/lib/libperl.so.5.14.2) 
==27226== by 0x4E7AB90: Perl_call_sv (in /usr/lib/libperl.so.5.14.2) 
==27226== by 0x4EEDBD8: Perl_sv_clear (in /usr/lib/libperl.so.5.14.2) 
==27226== by 0x4EEE291: Perl_sv_free2 (in /usr/lib/libperl.so.5.14.2) 
==27226== by 0x4ED7BC2: Perl_hv_free_ent (in /usr/lib/libperl.so.5.14.2) 
==27226== by 0x4ED7E6D: ??? (in /usr/lib/libperl.so.5.14.2) 
==27226== by 0x4EDB682: Perl_hv_undef_flags (in /usr/lib/libperl.so.5.14.2) 
==27226== by 0x4EEDE65: Perl_sv_clear (in /usr/lib/libperl.so.5.14.2) 
==27226== by 0x4EEE291: Perl_sv_free2 (in /usr/lib/libperl.so.5.14.2) 
==27226== Address 0x17d0b710 is 0 bytes inside a block of size 32 free'd 
==27226== at 0x4C27D4E: free (vg_replace_malloc.c:427) 
==27226== by 0xA138F42: PmmREFCNT_dec (in /usr/lib/perl5/auto/XML/LibXML/LibXML.so) 
==27226== by 0xA11D3FA: XS_XML__LibXML__Node_DESTROY (in /usr/lib/perl5/auto/XML/LibXML/LibXML.so) 
==27226== by 0x4EE770B: Perl_pp_entersub (in /usr/lib/libperl.so.5.14.2) 
==27226== by 0x4E7AB90: Perl_call_sv (in /usr/lib/libperl.so.5.14.2) 
==27226== by 0x4EEDBD8: Perl_sv_clear (in /usr/lib/libperl.so.5.14.2) 
==27226== by 0x4EEE291: Perl_sv_free2 (in /usr/lib/libperl.so.5.14.2) 
==27226== by 0x4ED7BC2: Perl_hv_free_ent (in /usr/lib/libperl.so.5.14.2) 
==27226== by 0x4EDA919: Perl_hv_common (in /usr/lib/libperl.so.5.14.2) 
==27226== by 0x4F0EEC7: Perl_pp_delete (in /usr/lib/libperl.so.5.14.2) 
==27226== by 0x4EDECE5: Perl_runops_standard (in /usr/lib/libperl.so.5.14.2) 
==27226== by 0x4E80814: perl_run (in /usr/lib/libperl.so.5.14.2) 
+6

È un errore in Perl o in un modulo XS. Una variabile deve essere liberata quando il suo conteggio dei riferimenti raggiunge lo zero, ma qualcosa ha tentato di decrementare il conteggio dei riferimenti di una variabile quando era già zero. – ikegami

+2

'valgrind' può essere utile utile. Una traccia stack da 'gdb' su segfault può essere utile. – ikegami

+0

Hai avuto ragione, come al solito, grazie! Non sono abbastanza bravo in un programmatore C per capire cosa sta succedendo qui, ma 'valgrind' è stato in grado di dire quale sia il modulo XS da incolpare. – scozy

risposta

3

Citando commento ikegami s' perché non riuscivo a formulare meglio:

Si tratta di un bug in Perl o in un modulo XS. Una variabile deve essere liberata quando il suo conteggio dei riferimenti raggiunge lo zero, ma qualcosa ha tentato di decrementare il conteggio dei riferimenti di una variabile quando era già zero.

come uscita del valgrind spettacoli, nel caso specifico, il problema è in XML::LibXML.

Suppongo che l'aggiornamento XML::LibXML, come suggerito da Sinan Ünür non appena il problema verrà compreso e risolto sia la strada da percorrere. Sfortunatamente, l'aggiornamento da 2.0001 (versione stabile di Debian) a 2.0116 (versione CPAN) non lo ha risolto.

Che cosa ha fatto risolvere il problema, infine, è stato quello di modificare SetOfThings::explode in modo da creare una nuova istanza e copia gli attributi di cui ha bisogno, piuttosto che clonare l'istanza corrente e l'eliminazione degli attributi è non ha bisogno:

sub explode { 
    my $self = shift; 
    my $new = __PACKAGE__->new; 
    $new->some_attribute('whatever'); 
    $new->set_of_things(map { $_->explode } $self->constraints); 
    return $new; 
} 

Uno degli attributi dell'oggetto SetOfThings che è stato clonato e quindi eliminato era un DOM, che chiaramente XML::LibXML ha ottenuto non. Grazie a questa conoscenza e dei commenti inseriti, sono stato finalmente in grado di riprodurre il mio problema molto in un piccolo script e inviare un bug report:

#!/usr/bin/perl 

use strict; 
use warnings; 

use Clone 'clone'; 
use XML::LibXML; 

my $dom1 = new XML::LibXML::Document; 
my $dom2 = clone $dom1; 

Come sottolineato da Ikegami, clonando la variabile Perl non copia il underlying C structure usato dalla biblioteca. Ma XML::LibXML fornisce un metodo cloneNode, cambiando quindi l'ultima linea di

my $dom2 = $dom1->cloneNode(1) 

dà il risultato desiderato.

+2

La clonazione dell'oggetto Perl non clona l'oggetto C++ sottostante. Esistono metodi XML :: LibXML in grado di fornire che istruisca 'clone' su come clonare il suo oggetto (e similmente, penso, per' dclone'), ma non deve fornire quelli. – ikegami

+2

Si dovrebbe usare '$ newnode = $ nodo-> cloneNode ($ profondo);' – ikegami

Problemi correlati