[LLVMbugs] [Bug 20322] New: invalid symbol type in a shared library with -fvisibility=hidden when using a custom allocator in std::basic_string

bugzilla-daemon at llvm.org bugzilla-daemon at llvm.org
Wed Jul 16 08:04:33 PDT 2014


http://llvm.org/bugs/show_bug.cgi?id=20322

            Bug ID: 20322
           Summary: invalid symbol type in a shared library with
                    -fvisibility=hidden when using a custom allocator in
                    std::basic_string
           Product: clang
           Version: 3.4
          Hardware: PC
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P
         Component: C++
          Assignee: unassignedclangbugs at nondot.org
          Reporter: georgid at outlook.com
                CC: dgregor at apple.com, llvmbugs at cs.uiuc.edu
    Classification: Unclassified

Created attachment 12775
  --> http://llvm.org/bugs/attachment.cgi?id=12775&action=edit
The source files and the build script to reproduce the issue.

I am trying to assign a value to std::basic_string with a custom Allocator
across a shared library boundaries and the code generated causes a crash when
compiling with -fvisibility=hidden.

Here are files used:

% cat SecureAllocator.h
#pragma once

#ifndef SECURE_ALLOCATOR_H_
#define SECURE_ALLOCATOR_H_

#include <memory>
#include <algorithm>

namespace Runtime {


template <class T>
class SecureAllocator : public std::allocator<T> {
   typedef std::allocator<T> base_type;

public:
    template<class U> struct rebind { typedef SecureAllocator<U> other; };

    SecureAllocator() throw() {}
    SecureAllocator(const SecureAllocator&) throw() : base_type() { }
    template <class U>
    SecureAllocator(const SecureAllocator<U>&) throw() : base_type() { }

    void deallocate(typename base_type::pointer p,
                    typename base_type::size_type n) {
        std::fill_n((volatile char*)p, n * sizeof(T), 0);
        base_type::deallocate(p, n);
    }
};


} // namespace Runtime

#endif // SECURE_ALLOCATOR_H_



% cat Value.h
#pragma once

#ifndef VALUE_H_
#define VALUE_H_

#include <string>
#include "SecureAllocator.h"


namespace Runtime {

typedef std::basic_string<char,
                          std::char_traits<char>,
                          SecureAllocator<char> > SecretString;

class Value {
public:
   template<typename T>
   static void Get(T& out);

};

} // namespace Runtime

#endif // VALUE_H_


% cat Value.cpp
#include "Value.h"

namespace Runtime {


template<>
__attribute__ ((visibility ("default"))) void
Value::Get<SecretString>(SecretString& out)
{
   out = SecretString("something");
}


} // namespace Runtime

% cat main.cpp

#include "Value.h"

using namespace Runtime;

int main()
{
   SecretString tmp;
   Value::Get(tmp);
}

The file Value.cpp is build into the libvalue.so and then main.cpp is linked
into an executable against libvalue.so

% cat build-lite.sh
#!/bin/sh

SH=/bin/sh
BLD_DIR=build
CXX=${CXX:=clang++}

CXXFLAGS="-fPIC -fvisibility=hidden -pipe"
LDFLAGS=

echo "CXX = $CXX"
echo "CXXFLAGS = $CXXFLAGS"
echo "LDFLAGS = $LDFLAGS"

mkdir $BLD_DIR

# compile the files
$CXX -c -v -o $BLD_DIR/Value.o $CXXFLAGS Value.cpp
$CXX -c -v -o $BLD_DIR/main.o $CXXFLAGS main.cpp

# link the shared lib
$CXX -v -shared -o $BLD_DIR/libvalue.so $LDFLAGS $BLD_DIR/Value.o

# link the executable
$CXX -o $BLD_DIR/a.out $LDFLAGS $BLD_DIR/main.o $BLD_DIR/libvalue.so


Here is the output from the above script:

% ./build-lite.sh
CXX = clang++
CXXFLAGS = -fPIC -fvisibility=hidden -pipe
LDFLAGS =

clang version 3.4 (http://llvm.org/git/clang
48eff6c3512fd6c768072b05ab4c287c7719072b) (http://llvm.org/git/llvm
8240ef04108620fef51219e9495a6e71e95ccd75)
Target: x86_64-unknown-linux-gnu
Thread model: posix
 "/dbc/dbc101/georgid/sysroot/bin/clang" -cc1 -triple x86_64-unknown-linux-gnu
-emit-obj -mrelax-all -disable-free -main-file-name Value.cpp
-mrelocation-model pic -pic-level 2 -mdisable-fp-elim -fmath-errno
-masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64
-target-linker-version 2.20.51.0.2 -v -coverage-file
/dbc/dbc101/georgid/tmp/clang_bugs/clang-secure-alloc/runtime/build/Value.o
-resource-dir /dbc/dbc101/georgid/sysroot/bin/../lib/clang/3.4
-internal-isystem
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7
-internal-isystem
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/x86_64-redhat-linux
-internal-isystem
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/backward
-internal-isystem
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/x86_64-redhat-linux/c++/4.4.7
-internal-isystem /usr/local/include -internal-isystem
/dbc/dbc101/georgid/sysroot/bin/../lib/clang/3.4/include
-internal-externc-isystem /include -internal-externc-isystem /usr/include
-fdeprecated-macro -fdebug-compilation-dir
/dbc/dbc101/georgid/tmp/clang_bugs/clang-secure-alloc/runtime -ferror-limit 19
-fmessage-length 229 -fvisibility hidden -mstackrealign -fobjc-runtime=gcc
-fobjc-default-synthesize-properties -fcxx-exceptions -fexceptions
-fdiagnostics-show-option -fcolor-diagnostics -backend-option -vectorize-loops
-o build/Value.o -x c++ Value.cpp
clang -cc1 version 3.4 based upon LLVM 3.4svn default target
x86_64-unknown-linux-gnu
ignoring nonexistent directory
"/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/x86_64-redhat-linux/c++/4.4.7"
ignoring nonexistent directory "/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7

/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/x86_64-redhat-linux
 /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/backward
 /usr/local/include
 /dbc/dbc101/georgid/sysroot/bin/../lib/clang/3.4/include
 /usr/include
End of search list.
clang version 3.4 (http://llvm.org/git/clang
48eff6c3512fd6c768072b05ab4c287c7719072b) (http://llvm.org/git/llvm
8240ef04108620fef51219e9495a6e71e95ccd75)
Target: x86_64-unknown-linux-gnu
Thread model: posix
 "/dbc/dbc101/georgid/sysroot/bin/clang" -cc1 -triple x86_64-unknown-linux-gnu
-emit-obj -mrelax-all -disable-free -main-file-name main.cpp -mrelocation-model
pic -pic-level 2 -mdisable-fp-elim -fmath-errno -masm-verbose
-mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-linker-version
2.20.51.0.2 -v -coverage-file
/dbc/dbc101/georgid/tmp/clang_bugs/clang-secure-alloc/runtime/build/main.o
-resource-dir /dbc/dbc101/georgid/sysroot/bin/../lib/clang/3.4
-internal-isystem
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7
-internal-isystem
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/x86_64-redhat-linux
-internal-isystem
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/backward
-internal-isystem
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/x86_64-redhat-linux/c++/4.4.7
-internal-isystem /usr/local/include -internal-isystem
/dbc/dbc101/georgid/sysroot/bin/../lib/clang/3.4/include
-internal-externc-isystem /include -internal-externc-isystem /usr/include
-fdeprecated-macro -fdebug-compilation-dir
/dbc/dbc101/georgid/tmp/clang_bugs/clang-secure-alloc/runtime -ferror-limit 19
-fmessage-length 229 -fvisibility hidden -mstackrealign -fobjc-runtime=gcc
-fobjc-default-synthesize-properties -fcxx-exceptions -fexceptions
-fdiagnostics-show-option -fcolor-diagnostics -backend-option -vectorize-loops
-o build/main.o -x c++ main.cpp
clang -cc1 version 3.4 based upon LLVM 3.4svn default target
x86_64-unknown-linux-gnu
ignoring nonexistent directory
"/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/x86_64-redhat-linux/c++/4.4.7"
ignoring nonexistent directory "/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7

/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/x86_64-redhat-linux
 /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/backward
 /usr/local/include
 /dbc/dbc101/georgid/sysroot/bin/../lib/clang/3.4/include
 /usr/include
End of search list.
clang version 3.4 (http://llvm.org/git/clang
48eff6c3512fd6c768072b05ab4c287c7719072b) (http://llvm.org/git/llvm
8240ef04108620fef51219e9495a6e71e95ccd75)
Target: x86_64-unknown-linux-gnu
Thread model: posix
 "/usr/bin/ld" --eh-frame-hdr -m elf_x86_64 -shared -o build/libvalue.so
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64/crti.o
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/crtbeginS.o
-L/usr/lib/gcc/x86_64-redhat-linux/4.4.7
-L/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64 -L/lib/../lib64
-L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../.. -L/lib
-L/usr/lib build/Value.o -lstdc++ -lm -lgcc_s -lc -lgcc_s
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/crtendS.o
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64/crtn.o



When I try to run the above binary I get:

% ./build/a.out
*** glibc detected *** ./build/a.out: free(): invalid pointer:
0x0000000000601c40 ***
======= Backtrace: =========
/lib64/libc.so.6[0x38a1276126]
./build/a.out(_ZN9__gnu_cxx13new_allocatorIcE10deallocateEPcm+0x1d)[0x40104d]
build/libvalue.so(+0x194b)[0x7feb11d1d94b]
build/libvalue.so(+0x1884)[0x7feb11d1d884]
build/libvalue.so(+0x17da)[0x7feb11d1d7da]
build/libvalue.so(+0x1615)[0x7feb11d1d615]
build/libvalue.so(+0x149d)[0x7feb11d1d49d]
build/libvalue.so(_ZN7Runtime5Value3GetISbIcSt11char_traitsIcENS_15SecureAllocatorIcEEEEEvRT_+0x46)[0x7feb11d1d2b6]
./build/a.out[0x400b11]
/lib64/libc.so.6(__libc_start_main+0xfd)[0x38a121ecdd]
./build/a.out[0x400a29]
======= Memory map: ========
00400000-00402000 r-xp 00000000 fd:00 322571941                         
/dbc/dbc101/georgid/tmp/clang_bugs/clang-secure-alloc/runtime/build/a.out
00601000-00602000 rw-p 00001000 fd:00 322571941                         
/dbc/dbc101/georgid/tmp/clang_bugs/clang-secure-alloc/runtime/build/a.out
00e1e000-00e3f000 rw-p 00000000 00:00 0                                  [heap]
312a800000-312a8e8000 r-xp 00000000 08:03 26478803                      
/usr/lib64/libstdc++.so.6.0.13
312a8e8000-312aae8000 ---p 000e8000 08:03 26478803                      
/usr/lib64/libstdc++.so.6.0.13
312aae8000-312aaef000 r--p 000e8000 08:03 26478803                      
/usr/lib64/libstdc++.so.6.0.13
312aaef000-312aaf1000 rw-p 000ef000 08:03 26478803                      
/usr/lib64/libstdc++.so.6.0.13
312aaf1000-312ab06000 rw-p 00000000 00:00 0
3728800000-3728816000 r-xp 00000000 08:03 524495                        
/lib64/libgcc_s-4.4.7-20120601.so.1
3728816000-3728a15000 ---p 00016000 08:03 524495                        
/lib64/libgcc_s-4.4.7-20120601.so.1
3728a15000-3728a16000 rw-p 00015000 08:03 524495                        
/lib64/libgcc_s-4.4.7-20120601.so.1
38a0a00000-38a0a20000 r-xp 00000000 08:03 524290                        
/lib64/ld-2.12.so
38a0c1f000-38a0c20000 r--p 0001f000 08:03 524290                        
/lib64/ld-2.12.so
38a0c20000-38a0c21000 rw-p 00020000 08:03 524290                        
/lib64/ld-2.12.so
38a0c21000-38a0c22000 rw-p 00000000 00:00 0
38a1200000-38a138a000 r-xp 00000000 08:03 524295                        
/lib64/libc-2.12.so
38a138a000-38a1589000 ---p 0018a000 08:03 524295                        
/lib64/libc-2.12.so
38a1589000-38a158d000 r--p 00189000 08:03 524295                        
/lib64/libc-2.12.so
38a158d000-38a158e000 rw-p 0018d000 08:03 524295                        
/lib64/libc-2.12.so
38a158e000-38a1593000 rw-p 00000000 00:00 0
38a1e00000-38a1e83000 r-xp 00000000 08:03 524301                        
/lib64/libm-2.12.so
38a1e83000-38a2082000 ---p 00083000 08:03 524301                        
/lib64/libm-2.12.so
38a2082000-38a2083000 r--p 00082000 08:03 524301                        
/lib64/libm-2.12.so
38a2083000-38a2084000 rw-p 00083000 08:03 524301                        
/lib64/libm-2.12.so
7feb11d07000-7feb11d0d000 rw-p 00000000 00:00 0
7feb11d1b000-7feb11d1c000 rw-p 00000000 00:00 0
7feb11d1c000-7feb11d20000 r-xp 00000000 fd:00 322571940                 
/dbc/dbc101/georgid/tmp/clang_bugs/clang-secure-alloc/runtime/build/libvalue.so
7feb11d20000-7feb11f1f000 ---p 00004000 fd:00 322571940                 
/dbc/dbc101/georgid/tmp/clang_bugs/clang-secure-alloc/runtime/build/libvalue.so
7feb11f1f000-7feb11f20000 rw-p 00003000 fd:00 322571940                 
/dbc/dbc101/georgid/tmp/clang_bugs/clang-secure-alloc/runtime/build/libvalue.so
7feb11f20000-7feb11f21000 rw-p 00000000 00:00 0
7fff0964b000-7fff09661000 rw-p 00000000 00:00 0                         
[stack]
7fff097ff000-7fff09800000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                 
[vsyscall]
[3]    64804 abort (core dumped)  ./build/a.out




In GDB the backtrace looks like this:

(gdb) bt
#0  0x00000038a12328e5 in raise (sig=6) at
../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1  0x00000038a12340c5 in abort () at abort.c:92
#2  0x00000038a12707f7 in __libc_message (do_abort=2, fmt=0x38a1357fc0 "***
glibc detected *** %s: %s: 0x%s ***\n") at
../sysdeps/unix/sysv/linux/libc_fatal.c:198
#3  0x00000038a1276126 in malloc_printerr (action=3, str=0x38a13560af "free():
invalid pointer", ptr=<value optimized out>) at malloc.c:6311
#4  0x000000000040104d in __gnu_cxx::new_allocator<char>::deallocate(char*,
unsigned long) ()
#5  0x00007ffff7dfa94b in Runtime::SecureAllocator<char>::deallocate(char*,
unsigned long) () from build/libvalue.so
#6  0x00007ffff7dfa884 in std::basic_string<char, std::char_traits<char>,
Runtime::SecureAllocator<char>
>::_Rep::_M_destroy(Runtime::SecureAllocator<char> const&) () from
build/libvalue.so
#7  0x00007ffff7dfa7da in std::basic_string<char, std::char_traits<char>,
Runtime::SecureAllocator<char>
>::_Rep::_M_dispose(Runtime::SecureAllocator<char> const&) () from
build/libvalue.so
#8  0x00007ffff7dfa615 in std::basic_string<char, std::char_traits<char>,
Runtime::SecureAllocator<char> >::assign(std::basic_string<char,
std::char_traits<char>, Runtime::SecureAllocator<char> > const&) () from
build/libvalue.so
#9  0x00007ffff7dfa49d in std::basic_string<char, std::char_traits<char>,
Runtime::SecureAllocator<char> >::operator=(std::basic_string<char,
std::char_traits<char>, Runtime::SecureAllocator<char> > const&) () from
build/libvalue.so
#10 0x00007ffff7dfa2b6 in void Runtime::Value::Get<std::basic_string<char,
std::char_traits<char>, Runtime::SecureAllocator<char> >
>(std::basic_string<char, std::char_traits<char>,
Runtime::SecureAllocator<char> >&) () from build/libvalue.so
#11 0x0000000000400b11 in main ()


The issue is that the code attempts to delete the buffer used for empty string
which should not happen.


The exact same code works fine which clang 3.2 and gcc 4.4.3 and above (I have
not tested with older versions)

It is also working with clang 3.4 when -fvisibility=hidden is not set.


As far as I can see the problem is with the 

std::basic_string<char, std::char_traits<char>, Runtime::SecureAllocator<char>
>::_Rep::_S_empty_rep_storage symbol which is used for the "empty string" case.

The code generated by gcc is: (Working)

% nm -a -C build_gcc/a.out |grep empty
0000000000401310 W std::basic_string<char, std::char_traits<char>,
Runtime::SecureAllocator<char> >::_S_empty_rep()
0000000000401426 W std::basic_string<char, std::char_traits<char>,
Runtime::SecureAllocator<char> >::_Rep::_S_empty_rep()
0000000000602040 u std::basic_string<char, std::char_traits<char>,
Runtime::SecureAllocator<char> >::_Rep::_S_empty_rep_storage

% nm -a -C build_gcc/libvalue.so |grep empty
0000000000002fa6 W std::basic_string<char, std::char_traits<char>,
Runtime::SecureAllocator<char> >::_S_empty_rep()
0000000000002b71 W std::basic_string<char, std::char_traits<char>,
Runtime::SecureAllocator<char> >::_Rep::_S_empty_rep()
0000000000205040 u std::basic_string<char, std::char_traits<char>,
Runtime::SecureAllocator<char> >::_Rep::_S_empty_rep_storage


The code generated by Clang 3.2 is:  (Working)

% nm -a -C build_clang32/a.out |grep empty
0000000000401820 W std::basic_string<char, std::char_traits<char>,
Runtime::SecureAllocator<char> >::_S_empty_rep()
0000000000401560 W std::basic_string<char, std::char_traits<char>,
Runtime::SecureAllocator<char> >::_Rep::_S_empty_rep()
0000000000603020 V std::basic_string<char, std::char_traits<char>,
Runtime::SecureAllocator<char> >::_Rep::_S_empty_rep_storage

% nm -a -C build_clang32/libvalue.so |grep empty
00000000000037e0 W std::basic_string<char, std::char_traits<char>,
Runtime::SecureAllocator<char> >::_S_empty_rep()
0000000000002c10 W std::basic_string<char, std::char_traits<char>,
Runtime::SecureAllocator<char> >::_Rep::_S_empty_rep()
0000000000205020 V std::basic_string<char, std::char_traits<char>,
Runtime::SecureAllocator<char> >::_Rep::_S_empty_rep_storage


The code generated by Clang 3.4 is: (Crash)

% nm -a -C build_clang34/a.out |grep empty
00000000004011c0 W std::basic_string<char, std::char_traits<char>,
Runtime::SecureAllocator<char> >::_S_empty_rep()
0000000000400f00 W std::basic_string<char, std::char_traits<char>,
Runtime::SecureAllocator<char> >::_Rep::_S_empty_rep()
0000000000602020 V std::basic_string<char, std::char_traits<char>,
Runtime::SecureAllocator<char> >::_Rep::_S_empty_rep_storage

% nm -a -C build_clang34/libvalue.so |grep empty
0000000000002430 t std::basic_string<char, std::char_traits<char>,
Runtime::SecureAllocator<char> >::_S_empty_rep()
0000000000001840 t std::basic_string<char, std::char_traits<char>,
Runtime::SecureAllocator<char> >::_Rep::_S_empty_rep()
0000000000204020 b std::basic_string<char, std::char_traits<char>,
Runtime::SecureAllocator<char> >::_Rep::_S_empty_rep_storage

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20140716/433a3238/attachment.html>


More information about the llvm-bugs mailing list