Bug 1993976
| Summary: | valgrind finds Conditional jump or move depends on uninitialised value(s) in perl-XML-Parser | ||
|---|---|---|---|
| Product: | Red Hat Enterprise Linux 9 | Reporter: | Martin Kyral <mkyral> |
| Component: | valgrind | Assignee: | Mark Wielaard <mjw> |
| valgrind sub component: | system-version | QA Contact: | Jesus Checa <jchecahi> |
| Status: | CLOSED ERRATA | Docs Contact: | Jacob Taylor Valdez <jvaldez> |
| Severity: | unspecified | ||
| Priority: | unspecified | CC: | arnez, bugproxy, fweimer, jakub, jvaldez, mjw, mspacek, ohudlick, psklenar, wcohen |
| Version: | 9.0 | Keywords: | Triaged |
| Target Milestone: | beta | Flags: | pm-rhel:
mirror+
|
| Target Release: | --- | ||
| Hardware: | s390x | ||
| OS: | Unspecified | ||
| Whiteboard: | |||
| Fixed In Version: | valgrind-3.19.0-3.el9 | Doc Type: | Bug Fix |
| Doc Text: |
.Valgrind override of `glibc` `memmem` function installed on IBMz15 architecture
Previously, a missing valgrind override of the `glibc` `memmem` function lead to false positive warnings of:
----
Conditional jump or move depends on uninitialised value(s)
----
This update includes a valgrind override of the `glibc` `memmem` function and, as a result, there are no longer false positive warnings when using the `memmem` function in programs running under valgrind on the IBMz15 architecture.
|
Story Points: | --- |
| Clone Of: | Environment: | ||
| Last Closed: | 2022-11-15 10:16:30 UTC | Type: | Bug |
| Regression: | --- | Mount Type: | --- |
| Documentation: | --- | CRM: | |
| Verified Versions: | Category: | --- | |
| oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |
| Cloudforms Team: | --- | Target Upstream Version: | |
| Embargoed: | |||
| Deadline: | 2022-06-13 | ||
|
Description
Martin Kyral
2021-08-16 13:19:39 UTC
*** Bug 2052848 has been marked as a duplicate of this bug. *** After upgrade of valgrind to valgrind-3.18.1-9.el9 issue is still here. Test on components: valgrind-3.18.1-9.el9 perl-5.32.1-479.el9 perl-XML-Parser-2.46-9.el9 architecture: s390x Tested on rawhide and result is same. Components: perl-5.34.1-486.fc37.s390x perl-XML-Parser-2.46-10.fc36.s390x perl-XML-XPath-1.44-12.fc36.noarch valgrind-3.18.1-9.fc36.s390x This issue isn't related to perl-XML-Parser. Issue is with parsing of module name (require). Probably some length of module name. Still investigating. Reproducer: [root@s390x-kvm-002 test]# cat BarXXXXXXXXXXXXXXX.pm package BarXXXXXXXXXXXXXXX; 1; [root@s390x-kvm-002 test]# valgrind --error-exitcode=1 perl -e "use lib '.'; require BarXXXXXXXXXXXXXXX;" ==21978== Memcheck, a memory error detector ==21978== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==21978== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info ==21978== Command: perl -e use\ lib\ '.';\ require\ BarXXXXXXXXXXXXXXX; ==21978== ==21978== Conditional jump or move depends on uninitialised value(s) ==21978== at 0x4C38218: __memmem_arch13 (in /usr/lib64/libc.so.6) ==21978== by 0x49B5B0F: Perl_pp_require (in /usr/lib64/libperl.so.5.32.1) ==21978== by 0x4964611: Perl_runops_standard (in /usr/lib64/libperl.so.5.32.1) ==21978== by 0x48DA705: perl_run (in /usr/lib64/libperl.so.5.32.1) ==21978== by 0x108E57: main (in /usr/bin/perl) ==21978== ==21978== ==21978== HEAP SUMMARY: ==21978== in use at exit: 523,763 bytes in 2,004 blocks ==21978== total heap usage: 6,864 allocs, 4,860 frees, 1,063,483 bytes allocated ==21978== ==21978== LEAK SUMMARY: ==21978== definitely lost: 19,995 bytes in 29 blocks ==21978== indirectly lost: 52,556 bytes in 23 blocks ==21978== possibly lost: 450,848 bytes in 1,951 blocks ==21978== still reachable: 364 bytes in 1 blocks ==21978== of which reachable via heuristic: ==21978== newarray : 1,088 bytes in 34 blocks ==21978== suppressed: 0 bytes in 0 blocks ==21978== Rerun with --leak-check=full to see details of leaked memory ==21978== ==21978== Use --track-origins=yes to see where uninitialised values come from ==21978== For lists of detected and suppressed errors, rerun with: -s ==21978== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) Issue is present on last Fedora rawhide * glibc-2.35.9000-17.fc37.src.rpm * perl-5.34.1-486.fc37.src.rpm Tested on compiled perl 5.35.11 on same machine and still here. Affected on S390/arch14 only Sorry, i mean arch13 not arch14.(In reply to Michal Josef Spacek from comment #7) > Affected on S390/arch14 only Sorry, i mean S390/arch13 Could you install glibc debugging information and run the test under vgdb, with valgrind --vgdb-error=1 ? Then valgrind will print instructions to attach GDB, and you should be able to use that to extract the memmem arguments. We'll need both the memory contents there and the alignment. Thanks! (I'm reassigning to valgrind for awareness/further debugging. Also Cc:ing the IBM team.) (gdb) target remote | /usr/libexec/valgrind/../../bin/vgdb --pid=52142 Remote debugging using | /usr/libexec/valgrind/../../bin/vgdb --pid=52142 relaying data between gdb and process 52142 warning: remote target does not support file transfer, attempting to access files from local filesystem. Reading symbols from /usr/libexec/valgrind/vgpreload_core-s390x-linux.so... Reading symbols from /usr/libexec/valgrind/vgpreload_memcheck-s390x-linux.so... Reading symbols from /lib64/libperl.so.5.34... Reading symbols from /root/.cache/debuginfod_client/e4fb94a27875065be6e02943c56103e2c27a908d/debuginfo... Reading symbols from /lib64/libc.so.6... Reading symbols from /usr/lib/debug/usr/lib64/libc.so.6-2.35.9000-17.fc37.s390x.debug... Reading symbols from /lib64/libm.so.6... Reading symbols from /usr/lib/debug/usr/lib64/libm.so.6-2.35.9000-17.fc37.s390x.debug... Reading symbols from /lib64/libcrypt.so.2... Reading symbols from /root/.cache/debuginfod_client/8ca706b59fc1b92ed2d377a10bf07963c8e83744/debuginfo... Reading symbols from /lib/ld64.so.1... __memmem_arch13 () at ../sysdeps/s390/memmem-arch13.S:65 65 brc 9,.Lend_no_match /* Jump away if cc == 0 || cc == 3. */ (gdb) bt #0 __memmem_arch13 () at ../sysdeps/s390/memmem-arch13.S:65 #1 0x00000000049ba502 in S_require_file (sv=<optimized out>, my_perl=0x4e8f040) at pp_ctl.c:3969 #2 Perl_pp_require (my_perl=0x4e8f040) at pp_ctl.c:4394 #3 0x0000000004968812 in Perl_runops_standard (my_perl=0x4e8f040) at run.c:41 #4 0x00000000048df7f6 in S_run_body (oldscope=<optimized out>, my_perl=<optimized out>) at perl.c:2743 #5 perl_run (my_perl=0x4e8f040) at perl.c:2666 #6 0x00000000001093b8 in main (argc=<optimized out>, argv=<optimized out>, env=<optimized out>) at perlmain.c:110 Thanks. Is it possible to recover the arguments at the call site in S_require_file? And dump the memory at those locations using GDB? Is the reproducer: valgrind --error-exitcode=1 perl -e "use lib '.'; require BarXXXXXXXXXXXXXXX;" I assume __memmem_arch13 is a s390x optimized version of memmem. Is arch13 z15? If so, I assume it doesn't happen on z14? How exactly is memmem called from pp_ctl.c:3969 ? (In reply to Mark Wielaard from comment #14) > I assume __memmem_arch13 is a s390x optimized version of memmem. > > Is arch13 z15? If so, I assume it doesn't happen on z14? All correct. Replicated using valgrind --gdb-error=0 --error-exitcode=1 perl -e "use lib '.'; require BarXXXXXXXXXXXXXXX;"
And gdb target remote | vgdb
Dump of assembler code for function __memmem_arch13:
0x0000000004c30e40 <+0>: clgrjl %r3,%r5,0x4c30e9e <__memmem_arch13+94>
0x0000000004c30e46 <+6>: clgfi %r5,9
0x0000000004c30e4c <+12>: jgh 0x4cbf470 <__memmem_vx>
0x0000000004c30e52 <+18>: aghik %r0,%r5,-1
0x0000000004c30e58 <+24>: bl 0(%r14)
0x0000000004c30e5c <+28>: vll %v18,%r0,0(%r4)
0x0000000004c30e62 <+34>: vlvgb %v19,%r5,7
0x0000000004c30e68 <+40>: clgijh %r3,16,0x4c30ea4 <__memmem_arch13+100>
0x0000000004c30e6e <+46>: aghik %r0,%r3,-1
0x0000000004c30e74 <+52>: vll %v16,%r0,0(%r2)
0x0000000004c30e7a <+58>: sgr %r3,%r5
0x0000000004c30e7e <+62>: jl 0x4c30e9e <__memmem_arch13+94>
0x0000000004c30e82 <+66>: vstrsb %v20,%v16,%v18,%v19
=> 0x0000000004c30e88 <+72>: jnlh 0x4c30e9e <__memmem_arch13+94>
0x0000000004c30e8c <+76>: vlgvb %r1,%v20,7
0x0000000004c30e92 <+82>: clgrjh %r1,%r3,0x4c30e9e <__memmem_arch13+94>
0x0000000004c30e98 <+88>: la %r2,0(%r1,%r2)
0x0000000004c30e9c <+92>: br %r14
0x0000000004c30e9e <+94>: lghi %r2,0
0x0000000004c30ea2 <+98>: br %r14
Which is called as:
#1 0x00000000049b6b10 in S_require_file (sv=<optimized out>,
my_perl=0x4e9f040) at pp_ctl.c:3954
3954 if (ninstr(name, name + package_len, slashdot,
(gdb) list
3949 DIE(aTHX_ "Bareword in require maps to disallowed filename \"%" SVf "\"", sv);
3950 if (memchr(name, 0, package_len)) {
3951 /* diag_listed_as: Bareword in require contains "%s" */
3952 DIE(aTHX_ "Bareword in require contains \"\\0\"");
3953 }
3954 if (ninstr(name, name + package_len, slashdot,
3955 slashdot + sizeof(slashdot))) {
3956 /* diag_listed_as: Bareword in require contains "%s" */
3957 DIE(aTHX_ "Bareword in require contains \"/.\"");
3958 }
Where ninstr is defined as:
#ifdef HAS_MEMMEM
# define ninstr(big, bigend, little, lend) \
((char *) memmem((big), (bigend) - (big), \
(little), (lend) - (little)))
#else
# define ninstr(a,b,c,d) Perl_ninstr(a,b,c,d)
#endif
(gdb) print name
$1 = <optimized out>
(gdb) print package_len
$2 = 18
(gdb) print slashdot
$3 = "/."
3954 if (ninstr(name, name + package_len, slashdot,
0x00000000049b6afa <+6122>: lgdr %r2,%f11
0x00000000049b6afe <+6126>: lgr %r3,%r10
0x00000000049b6b02 <+6130>: lghi %r5,2
0x00000000049b6b06 <+6134>: la %r4,296(%r15)
0x00000000049b6b0a <+6138>: brasl %r14,0x48a9048 <memmem@plt>
=> 0x00000000049b6b10 <+6144>: cgijne %r2,0,0x49b767a <Perl_pp_require+9066>
3955 slashdot + sizeof(slashdot))) {
3956 /* diag_listed_as: Bareword in require contains "%s" */
3957 DIE(aTHX_ "Bareword in require contains \"/.\"");
0x00000000049b767a <+9066>: lgr %r2,%r11
0x00000000049b767e <+9070>: larl %r3,0x4ba9536
0x00000000049b7684 <+9076>: brasl %r14,0x48a96c8 <Perl_die@plt>
(gdb) print name $9 = 0x5009d20 "Bar", 'X' <repeats 15 times>, ".pm" (gdb) print package_len $10 = 18 (gdb) print slashdot $11 = "/." (In reply to Mark Wielaard from comment #16) > Replicated using valgrind --gdb-error=0 --error-exitcode=1 perl -e "use lib > '.'; require BarXXXXXXXXXXXXXXX;" > [...] Using the same method, I reproduced this as well. In my testing the "vector string search" instruction (vstrsb) yields the condition code which is then used for a conditional jump: 0x0000000004caabb0 <+64>: vstrsb %v20,%v16,%v18,%v19 => 0x0000000004caabb6 <+70>: jnlh 0x4caabcc <__memmem_arch13+92> The input operands to vstrsb are as follows: v16 = "XX.pm" (7 bytes defined) v18 = "./" (all defined) v19 = {[7] = 2} (only byte 7 defined) The reason for v16 to be partially defined is that it was loaded from the end of a malloc'd block and the last 9 bytes were outside that block. v19 is partially defined as well; that's OK because only byte 7 is used by the instruction. Now, unfortunately the conditional jump indeed depends on the undefined bytes in v16. If these bytes contained the pattern "./" (full match), the jump would not be taken, otherwise it is. It is possible that the function's end result is still independent from this jump being taken or not. If so, we'd probably have to add a suppression. (In reply to Andreas Arnez from comment #18) > Using the same method, I reproduced this as well. In my testing the "vector > string search" instruction (vstrsb) yields the condition code which is then > used for a conditional jump: > 0x0000000004caabb0 <+64>: vstrsb %v20,%v16,%v18,%v19 > => 0x0000000004caabb6 <+70>: jnlh 0x4caabcc <__memmem_arch13+92> > The input operands to vstrsb are as follows: > v16 = "XX.pm" (7 bytes defined) > v18 = "./" (all defined) > v19 = {[7] = 2} (only byte 7 defined) > The reason for v16 to be partially defined is that it was loaded from the > end of a malloc'd block and the last 9 bytes were outside that block. > v19 is partially defined as well; that's OK because only byte 7 is used by > the instruction. > Now, unfortunately the conditional jump indeed depends on the undefined > bytes in v16. If these bytes contained the pattern "./" (full match), the > jump would not be taken, otherwise it is. The glibc source code sysdeps/s390/memmem-arch13.S is nicely commented and I believe we end up here: .Lhaystack_smaller_16: sgr %r3,%r5 /* r3 = largest valid match-index. */ jl .Lend_no_match /* Haystack-len < needle-len? */ vstrs %v20,%v16,%v18,%v19,0,0 /* Vector string search without zero search where v20 will contain the index of a partial/full match or 16 (index is named k). cc=0 (no match; k=16): .Lend_no_match cc=1 (only available with zero-search): Ignore cc=2 (full match; k<16): Needle found, but could be beyond haystack! cc=3 (partial match; k<16): Always at end of v16 and thus beyond! */ brc 9,.Lend_no_match /* Jump away if cc == 0 || cc == 3. */ vlgvb %r1,%v20,7 /* Verify that the full-match (cc=2) is valid! */ clgrjh %r1,%r3,.Lend_no_match /* Jump away if match is beyond. */ la %r2,0(%r1,%r2) br %r14 .Lend_no_match: lghi %r2,0 br %r14 Assuming the code correctly checks the end of Haystack is indeed accessible then this seems correct since if the match was beyond the end then an extra check (that I don't think valgrind memcheck can know about) masks away the undefined bits. > It is possible that the function's end result is still independent from this > jump being taken or not. If so, we'd probably have to add a suppression. Maybe we could add a valgrind intercept for memmem in vg_replace_strmem.c just for s390x? (In reply to Mark Wielaard from comment #19) > [...] > Maybe we could add a valgrind intercept for memmem in vg_replace_strmem.c > just for s390x? Right, that might be the easiest way. I've opened an upstream Bug and attached a patch that does this: https://bugs.kde.org/show_bug.cgi?id=454040 Since the problem described in this bug report should be resolved in a recent advisory, it has been closed with a resolution of ERRATA. For information on the advisory (valgrind bug fix and enhancement update), and where to find the updated files, follow the link below. If the solution does not work for you, open a new bug report. https://access.redhat.com/errata/RHBA-2022:8066 |