Description
It seems that since Perl 5.34 (probably commit 399fef9 or ce9f3c9) there is a bug in av.c:Perl_av_extend_guts() which may cause the underlying array of an AV to have uninitialized (non zeroed) data. This leads to segfaults (or possible other errors depending on the data) if the uninitialized data is accessed.
Steps to Reproduce
I mostly debugged this issue with OpenBSD 7.3 (since they switched in 7.3 from Perl 5.32.1 to 5.36.0), but also verified the crash in manually build Perl versions 5.34.0, 5.38.0 and blead. Additionally I reproduced it on an Ubuntu 22.04.1 system which runs perl 5.34.0.
The following code should be able to reproduce the issue (sometimes it took up to 10 tries to crash).
#!/usr/bin/perl use strict; use warnings; use Data::Dumper; use Devel::Peek; my $x = []; print STDERR "$x\n"; Dump $x; # ARRAY = 0x0 # FILL = -1 # MAX = -1 $x->[0] ||= []; print STDERR "set 0\n"; Dump$x; # ARRAY = 0x26d4ca951a0 # FILL = 0 # MAX = 3 shift @$x; print STDERR "shift 1\n"; Dump$x; # ARRAY = 0x26d4ca951a8 (offset=1) # ALLOC = 0x26d4ca951a0 # FILL = -1 # MAX = 2 $x->[22] = []; print STDERR "set 22\n"; Dump$x; # ARRAY = 0x26d4ca84a30 # FILL = 22 # MAX = 25 shift @$x for 1 .. 5; print STDERR "shift 5\n"; Dump$x; # ARRAY = 0x26d4ca84a58 (offset=5) # ALLOC = 0x26d4ca84a30 # FILL = 17 # MAX = 20 $x->[19] ||= []; print STDERR "set 19\n"; Dump$x; # ARRAY = 0x26d4ca84a58 (offset=5) # ALLOC = 0x26d4ca84a30 # FILL = 19 # MAX = 20 print Dumper$x;
I found it easy to use Data::Dumper to reproduce the issue but Perl may also crash while just iterating over the array or even doing "nothing" (crash on exit in Perl_sv_clear()).
Besides segfaults I also observed errors like "Attempt to free unreferenced scalar: SV 0x563787eab3f0, Perl interpreter: 0x563787d5a2a0.".
More observations
I included some of the Devel::Peek output above because I used it to reproduce the issue. There seems to be a very specific code path where the data is not zeroed correctly.
I build Perl with debug output and it seems that the array gets "corrupted" when it is extended to 22/25. Inspecting the array at that time shows that while Zero() is called in Perl_av_extend_guts(), the last two elements in the array are not actually zeroed. I assume that either the logic in that code path is incorrect so the arguments to Zero() are wrong or that some of the internal data (like MAX) has to be adjusted at some point.
Let me know if I can be of any more help or if there are any issues with this report. I don't know how the internal AV data structures should work in the above case so I can't really propose a fix for this issue.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4