Bug 301204 - infinite loop in canonicaliseSymtab with ifunc symbol
Summary: infinite loop in canonicaliseSymtab with ifunc symbol
Status: RESOLVED FIXED
Alias: None
Product: valgrind
Classification: Developer tools
Component: memcheck (show other bugs)
Version: 3.7.0
Platform: Debian testing Linux
: NOR critical
Target Milestone: ---
Assignee: Julian Seward
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-06-05 10:58 UTC by Chantry Xavier
Modified: 2012-07-05 10:08 UTC (History)
2 users (show)

See Also:
Latest Commit:
Version Fixed In:


Attachments
testcase (259 bytes, text/x-csrc)
2012-06-05 10:59 UTC, Chantry Xavier
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Chantry Xavier 2012-06-05 10:58:30 UTC
Running valgrind on a binary using gcc ifunc attribute result in an infinite loop.
When running valgrind --trace-syscalls=yes --trace-symtab=yes ./a.out , the following is printed endlessly:

canonicaliseSymtab: 0 symbols merged
overlapping address ranges in symbol table
            1:  TI 0x  400568 .. 0x  400572 (11)      test
            2:  T- 0x  400568 .. 0x  400572 (11)      resolve_test

Reproducible: Always

Steps to Reproduce:
Build the attached sample program and run it inside valgrind.
Comment 1 Chantry Xavier 2012-06-05 10:59:43 UTC
Created attachment 71599 [details]
testcase
Comment 2 Chantry Xavier 2012-06-05 11:06:15 UTC
If I build with -Wl,-x , valgrind works fine on the resulting binary.

Binary linked with -Wl,-x :
% readelf -Ws ./a.out | grep test
    20: 0000000000400568    11 IFUNC   GLOBAL DEFAULT   14 test

Binary linked with default ldflags :
% readelf -Ws ./a.out | grep test 
    11: 0000000000400544    36 FUNC    LOCAL  DEFAULT   14 mytest
    12: 0000000000400568    11 FUNC    LOCAL  DEFAULT   14 resolve_test
    37: 0000000000400568    11 IFUNC   GLOBAL DEFAULT   14 test

Versions used:
valgrind-3.7.0
gcc (Debian 4.6.3-1) 4.6.3 
GNU gold (GNU Binutils for Debian 2.22) 1.11
Comment 3 Florian Krohm 2012-07-03 20:46:57 UTC
Thanks for the testcase.
I've looked at it and the issue is that in coregrind/m_debuginfo/storage.c:1466 there is the belief that the code @ cleanup_more will merge the symbols that have the same address and size. 
But the code @ cleanup_more will only do so only if they agree in their ifunc'ness. Which in this case they do not. Hence, the infinite loop.
This patch fixes the issue but I'm not at all sure it's the right thing.

Index: coregrind/m_debuginfo/storage.c
===================================================================
--- coregrind/m_debuginfo/storage.c	(revision 12704)
+++ coregrind/m_debuginfo/storage.c	(working copy)
@@ -1370,7 +1370,7 @@
          if (   di->symtab[w].addr      == di->symtab[r].addr
              && di->symtab[w].size      == di->symtab[r].size
              && !!di->symtab[w].isText  == !!di->symtab[r].isText
-             && !!di->symtab[w].isIFunc == !!di->symtab[r].isIFunc) {
+             && 1) {
             /* merge the two into one */
             n_merged++;
             /* Add r names to w if r has secondary names
Comment 4 Julian Seward 2012-07-05 08:48:21 UTC
We need somebody who understands ifunc stuff to tell us the significance of 
an address which has both normal and ifunc symbol.  TomH, or JakubJ ?
Comment 5 Tom Hughes 2012-07-05 09:40:43 UTC
It seems to be normal, at least if you follow the details in the gcc documentation on how to declare an ifunc. The ifunc symbol, and the normal symbol for the underlying resolver function, will be at the same address.

Obviously glibc is doing something different, as the ifunc routines in glibc don't seem to have a visible symbol for the underlying resolver.
Comment 6 Tom Hughes 2012-07-05 10:08:12 UTC
I've committed a change (r12711) that allows an IFunc symbol to be merged with a non-IFunc symbol, which should fix this.