Subject: | Memory corruption/Perl crash with ${^ENCODING} and decode callback |
Because encode_method() is asymmetrical (it treats HTMLCREF & XMLCREF as
if they were PERLQQ for decode but encode works fine), I tried making a
callback and Perl segfaulted. A reduced test case is below.
$ ./perl -I lib -V
Summary of my perl5 (revision 5 version 12 subversion 1) configuration:
Commit id: b85be81e3471288c8c432533cfaf3713e28157e9
[...]
$ ./perl -I lib -MEncode -le 'print $Encode::VERSION;'
2.39
$ ./perl -e 'print
"\xd5\xa5\xd5\xd5\xd1\xd1\xd1\xd5\xd1\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd1\xd5\xd1\xd1\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd1\xd1\xd1\xd5\xd5\xd5\xd5\xd5\xd5\xd1\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd1\xd1\xa5\x81\x9c\xd5\x81\x9c\xa5\xd5\xa5\xd0\xd0\xd5\xd5\n"'
Show quoted text
> /tmp/xin && valgrind ./perl -I lib -MEncode -le 'BEGIN { ${^ENCODING}
= $x = find_encoding("windows-1252"); } open my $fh, "<", shift or die;
binmode $fh, ":bytes"; while (<$fh>) { print $x->decode($_, sub {
sprintf "&#%u;", shift }); }' /tmp/xin
==25999== Memcheck, a memory error detector
==25999== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==25999== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==25999== Command: ./perl -I lib -MEncode -le BEGIN\ {\ ${^ENCODING}\ =\
$x\ =\ find_encoding("windows-1252");\ }\ open\ my\ $fh,\ "\<",\ shift\
or\ die;\ binmode\ $fh,\ ":bytes";\ while\ (\<$fh\>)\ {\ print\
$x-\>decode($_,\ sub\ {\ sprintf\ "&#%u;",\ shift\ });\ } /tmp/xin
==25999==
==25999== Invalid write of size 1
==25999== at 0xAEC2710: do_encode (encengine.c:119)
==25999== by 0xAEBD51B: encode_method (Encode.xs:125)
==25999== by 0xAEBF9A3: XS_Encode__XS_decode (Encode.xs:629)
==25999== by 0x4C2BAA: Perl_pp_entersub (pp_hot.c:2882)
==25999== by 0x496D22: Perl_runops_debug (dump.c:2049)
==25999== by 0x437340: perl_run (perl.c:2308)
==25999== by 0x41BDFB: main (perlmain.c:117)
==25999== Address 0x4ee4998 is 0 bytes after a block of size 248 alloc'd
==25999== at 0x4A05255: realloc (vg_replace_malloc.c:476)
==25999== by 0x4A71BD: Perl_safesysrealloc (util.c:180)
==25999== by 0x4E868B: Perl_sv_grow (sv.c:1555)
==25999== by 0x4F0C84: Perl_sv_utf8_upgrade_flags_grow (sv.c:3254)
==25999== by 0x4D3E4E: Perl_sv_catsv_flags (sv.c:4843)
==25999== by 0xAEBD87B: encode_method (Encode.xs:235)
==25999== by 0xAEBF9A3: XS_Encode__XS_decode (Encode.xs:629)
==25999== by 0x4C2BAA: Perl_pp_entersub (pp_hot.c:2882)
==25999== by 0x496D22: Perl_runops_debug (dump.c:2049)
==25999== by 0x437340: perl_run (perl.c:2308)
==25999== by 0x41BDFB: main (perlmain.c:117)
==25999==
Without Valgrind I get:
*** glibc detected *** perl: double free or corruption (!prev):
0x0840de78 ***
(My original code gets ${^ENCODING} from encoding::warnings.)