Bug 434764 - iconv_open causes ld.so v2.28 and later to execute optimised strncmp which confuses memcheck
Summary: iconv_open causes ld.so v2.28 and later to execute optimised strncmp which co...
Status: RESOLVED FIXED
Alias: None
Product: valgrind
Classification: Developer tools
Component: memcheck (show other bugs)
Version: unspecified
Platform: Other Linux
: NOR normal
Target Milestone: ---
Assignee: Julian Seward
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2021-03-22 11:58 UTC by Mike Crowe
Modified: 2022-05-16 14:10 UTC (History)
2 users (show)

See Also:
Latest Commit:
Version Fixed In:


Attachments
Patch (1.12 KB, patch)
2021-03-22 11:58 UTC, Mike Crowe
Details
iconv.c test code (277 bytes, text/plain)
2021-03-22 11:59 UTC, Mike Crowe
Details
Complete valgrind output (7.98 KB, text/plain)
2021-03-22 11:59 UTC, Mike Crowe
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Mike Crowe 2021-03-22 11:58:30 UTC
Created attachment 136941 [details]
Patch

I originally reported this problem in the thread at https://sourceforge.net/p/valgrind/mailman/valgrind-developers/thread/20190909131626.9633-1-mac%40mcrowe.com/#msg36759152 but I don't think it reached a conclusion. Some of what follows is based on information provided in that thread by Mark Wielaard.

STEPS TO REPRODUCE

Compile:
---8<---
#include <iconv.h>
#include <stdio.h>

int main()
{
    iconv_t descriptor = iconv_open("UCS-4BE", "euc-kr");
    if (descriptor == (iconv_t)(-1)) {
        fprintf(stderr, "Failed to get iconv\n");
        return 1;
    }

    fprintf(stderr, "Got iconv\n");

    return 0;
}
---8<---

and run with:

 valgrind --default-suppressions=no ./a.out

(For at least valgrind 3.16.1 and valgrind 3.17.0.)

Expected result:

 No complaints from valgrind.

Actual result:

==344358== Memcheck, a memory error detector                                                          
==344358== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==344358== Using Valgrind-3.17.0 and LibVEX; rerun with -h for copyright info
==344358== Command: ./a.out                                                                           
==344358==                                                                                            
==344358== Invalid read of size 8                                                                     
==344358==    at 0x401D54C: strncmp (strcmp.S:173)                                                    
==344358==    by 0x400604D: is_dst (dl-load.c:209)                                                    
==344358==    by 0x4008566: _dl_dst_count (dl-load.c:246)                
==344358==    by 0x4008757: expand_dynamic_string_token (dl-load.c:388)
==344358==    by 0x40088D1: fillin_rpath.isra.0 (dl-load.c:460)
==344358==    by 0x4008BE1: decompose_rpath (dl-load.c:631)              
==344358==    by 0x4009745: cache_rpath (dl-load.c:673)
==344358==    by 0x4009745: cache_rpath (dl-load.c:654)                                               
==344358==    by 0x4009745: _dl_map_object (dl-load.c:2074)                                           
==344358==    by 0x400DD90: openaux (dl-deps.c:64)                                                    
==344358==    by 0x499925F: _dl_catch_exception (dl-error-skeleton.c:208)
==344358==    by 0x400E108: _dl_map_object_deps (dl-deps.c:248)
==344358==    by 0x4013D7A: dl_open_worker (dl-open.c:571) 
==344358==    by 0x499925F: _dl_catch_exception (dl-error-skeleton.c:208)
==344358==  Address 0x4a29981 is 1 bytes inside a block of size 8 alloc'd
==344358==    at 0x483979B: malloc (vg_replace_malloc.c:380)
==344358==    by 0x401C0BA: strdup (strdup.c:42)  
==344358==    by 0x4008B74: decompose_rpath (dl-load.c:606)              
==344358==    by 0x4009745: cache_rpath (dl-load.c:673)        
==344358==    by 0x4009745: cache_rpath (dl-load.c:654)                   
==344358==    by 0x4009745: _dl_map_object (dl-load.c:2074)              
==344358==    by 0x400DD90: openaux (dl-deps.c:64)                                                    
==344358==    by 0x499925F: _dl_catch_exception (dl-error-skeleton.c:208)
==344358==    by 0x400E108: _dl_map_object_deps (dl-deps.c:248)
==344358==    by 0x4013D7A: dl_open_worker (dl-open.c:571)
==344358==    by 0x499925F: _dl_catch_exception (dl-error-skeleton.c:208)
==344358==    by 0x40138C9: _dl_open (dl-open.c:837)   
==344358==    by 0x49986DC: do_dlopen (dl-libc.c:96)                   
==344358==    by 0x499925F: _dl_catch_exception (dl-error-skeleton.c:208)

(and two more similar complaints in strncmp.)

(Note that the current Debian Testing valgrind v3.16.1 emits the errors even without "--default-suppressions=no".)

The attached patch fixes this problem for me by using valgrind's implementation of strncmp instead. In the previously mentioned email thread I claimed to have seen this when compiling for sufficiently modern x86 too, but I have not reproduced this recently.
Comment 1 Mike Crowe 2021-03-22 11:59:18 UTC
Created attachment 136942 [details]
iconv.c test code
Comment 2 Mike Crowe 2021-03-22 11:59:32 UTC
Created attachment 136943 [details]
Complete valgrind output
Comment 3 Mike Crowe 2021-03-22 12:19:37 UTC
I've been unable to reproduce this problem on AArch64 with the current Debian Testing (glibc 2.31 and valgrind 3.17.0.)
Comment 4 Mark Wielaard 2022-05-13 22:23:40 UTC
On some systems the default suppression would have caught this.
Specifically this one in glibc-2.X.supp.in:

{
   dl-hack4-64bit-addr-1
   Memcheck:Addr8
   obj:*/lib*/ld-@GLIBC_VERSION@*.so*
   obj:*/lib*/ld-@GLIBC_VERSION@*.so*
   obj:*/lib*/ld-@GLIBC_VERSION@*.so*
}

But this doesn't match anymore since glibc 2.34 which changed the (in-memory) paths of the glibc library names.
The paths were updated for some, but not all suppressions, see:

commit a1364805fc74b5690f763033c0c9b43f27613572
Author: Mark Wielaard <mark@klomp.org>
Date:   Fri Jul 16 15:47:08 2021 -0400

    Update helgrind and drd suppression libc and libpthread paths in glibc 2.34
[...]
    The same could be done for the glibc-2.X.supp.in file, but hasn't
    yet because it looks like most suppressions in that file are obsolete.

Instead of fixing up those suppressions I think it is better to go with Mike's intercepts.

I tried on arm64, armhf, s390x and ppc64le. None would trigger an issue (and none had suppressions).
Comment 5 Mark Wielaard 2022-05-13 22:56:21 UTC
commit 947388eb043ea1c44b37df94046e1eee790ad776 (HEAD -> master)
Author: Mike Crowe <mac@mcrowe.com>
Date:   Mon Sep 9 14:16:16 2019 +0100

    Intercept strncmp for glibc ld.so v2.28+
    
    In glibc 5aad5f617892e75d91d4c8fb7594ff35b610c042 (first released in
    v2.28) a call to strncmp was added to dl-load.c:is_dst. This causes
    valgrind to complain about glibc's highly-optimised strncmp performing
    sixteen-byte reads on short strings in ld.so. Let's intercept strncmp in
    ld.so too so we use valgrind's simple version to avoid this problem.