Closed
Description
As initially reported by George Greer to p5p, building with sanitize=address
shows that this commit causes reads of uninitialized memory, for example when a sort block exits with an explicit return:
==3168==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61c000000018 at pc 0x560bb1fe782a bp 0x7ffcd34f9a10 sp 0x7ffcd34f9a00
READ of size 1 at 0x61c000000018 thread T0
#0 0x560bb1fe7829 in Perl_pp_return /src/perl/git/pp_ctl.c:2575
#1 0x560bb1ee2642 in Perl_runops_standard /src/perl/git/run.c:41
#2 0x560bb211eb85 in S_sortcv /src/perl/git/pp_sort.c:1066
#3 0x560bb2145825 in dynprep /src/perl/git/pp_sort.c:188
#4 0x560bb2145825 in S_sortsv_flags_impl /src/perl/git/pp_sort.c:358
#5 0x560bb2145825 in Perl_sortsv_flags /src/perl/git/pp_sort.c:556
#6 0x560bb2147f6b in Perl_pp_sort /src/perl/git/pp_sort.c:909
#7 0x560bb1ee2642 in Perl_runops_standard /src/perl/git/run.c:41
#8 0x560bb1cdd700 in S_run_body /src/perl/git/perl.c:2738
#9 0x560bb1cdd700 in perl_run /src/perl/git/perl.c:2666
#10 0x560bb1c57636 in main /src/perl/git/miniperlmain.c:116
#11 0x7f6ef677abf6 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21bf6)
#12 0x560bb1c576d9 in _start (/src/perl/git/miniperl+0xe06d9)
0x61c000000018 is located 104 bytes to the left of 1872-byte region [0x61c000000080,0x61c0000007d0)
allocated by thread T0 here:
#0 0x7f6ef741db40 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb40)
#1 0x560bb1e66c82 in Perl_safesysmalloc /src/perl/git/util.c:161
SUMMARY: AddressSanitizer: heap-buffer-overflow /src/perl/git/pp_ctl.c:2575 in Perl_pp_return
Shadow bytes around the buggy address:
0x0c387fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c387fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c387fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c387fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c387fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c387fff8000: fa fa fa[fa]fa fa fa fa fa fa fa fa fa fa fa fa
0x0c387fff8010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c387fff8020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c387fff8030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c387fff8040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c387fff8050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==3168==ABORTING
This occurs at least when the cxix
found at the start of pp_return()
is negative, and during a normal build causes lib/unicore/mktables
to fail.
The diff below is sufficient to get make minitest
to pass, but it isn't clear if it fully solves the problem: for example, other code in pp_return()
also checks for cxix < cxstack_ix
. It seems likely to me that the whole CxTRY
test should probably be moved later in the function.
@leonerd suggests we apply this diff; @tonycoz or @iabyn could you check it over?
Hugo
diff --git a/pp_ctl.c b/pp_ctl.c
index 9e440dcd9b..6ef2ba17bb 100644
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -2487,11 +2487,13 @@ PP(pp_return)
I32 cxix = dopopto_cursub();
again:
- cx = &cxstack[cxix];
- if(CxTRY(cx)) {
- /* This was a try {}. keep going */
- cxix = dopoptosub_at(cxstack, cxix - 1);
- goto again;
+ if (cxix >= 0) {
+ cx = &cxstack[cxix];
+ if (CxTRY(cx)) {
+ /* This was a try {}. keep going */
+ cxix = dopoptosub_at(cxstack, cxix - 1);
+ goto again;
+ }
}
assert(cxstack_ix >= 0);