Bug 26846

Summary: hidden visibility of static member in class derived from hash_map changes to default visibility
Product: gcc Reporter: Laszlo Szakony <laszlo.szakony>
Component: c++Assignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED DUPLICATE    
Severity: normal CC: aj, bkoz, braden, caolanm, debian-gcc, gcc-bugs, gcc, geoffk, hhinnant, hjl.tools, ismail, jwillemsen, lanius, laszlo.szakony, lothar, matz, mbeam, mmarcus, mmitchel, mueller, pawel_sikora, pedro.lamarao, pinskia, rhill, simon.strandman
Priority: P3 Keywords: visibility
Version: 4.0.2   
Target Milestone: ---   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed:
Attachments: Automke sources to reproduce/test the visibility change of static members
Simple test without automake files to test visibility changes of static members

Description Laszlo Szakony 2006-03-24 15:00:29 UTC
gcc (GCC) 4.0.2 20050901 (prerelease) (SUSE Linux)
SUSE Linux 10.0 i686

I don'know, if this is a gcc or elf bug. 
I use the following construct:

	Slib1 => Dlib1
	Slib1 + Dlib1 => Dlib2
	
	Test => dlopen/dlclose (Dlib2)
	
Slib1 is a static lib.
Dlib1 is a shared lib containing Slib1.
Dlib2 is a shared lib containing Dlib1 and Slib1.


After building the libraries with hidden visibility:

tmp/demo/lib/linuxrelease> readelf -s -W -D libdlib1.so | c++filt
...
   14  15: 00001a80     4  OBJECT GLOBAL DEFAULT  23 SLibC1::m_str
...

tmp/demo/lib/linuxrelease> readelf -s -W -D libdlib2.so | c++filt
...
   14  15: 00001ad8     4  OBJECT GLOBAL DEFAULT  23 SLibC1::m_str
...

Both Dso-s will have the static member SLibC1::m_str with DEFAULT visibility.
If you try to load / read symbol / close / load the Dso libdlib2.so, 
it will crash with the following error message:
*** glibc detected *** double free or corruption (fasttop): 0x0804b888 ***
If you set:
	export MALLOC_CHECK_=3
you can see in the debugger, 
that calling the global dtor in libdlib2.so at ~SLibC1::m_str() causes the crash.

If you change hash_map to map in the example below (comment the line #define BUG 1), 
the test is OK. In this case the visibility of SLibC1::m_str is hidden.

If this problem already known, does a workaround exist?


I will supply the automake files. Without them I could not reproduce bug(?).
I try to upload the whole configuration, but here are source files in the following tree:
(how can I upload an attachment?)

.
|-- AUTHORS   <= dummy
|-- COPYING   <= dummy
|-- ChangeLog <= dummy
|-- INSTALL   <= dummy
|-- NEWS      <= dummy
|-- README    <= dummy
|-- configure.ac
|-- dlib1
|   |-- dlib1_m1.cpp
|   `-- makefile.am
|-- dlib2
|   |-- dlib2_m1.cpp
|   `-- makefile.am
|-- lib
|-- makefile.am
`-- stlib1
    |-- makefile.am
    `-- stlib1_m1.cpp


>>>>>>> stlib1_m1.cpp
#include <string>

#define BUG 1

#ifdef BUG
#include <ext/hash_map>
class SLibC1 : public  __gnu_cxx::hash_map<int, int >
#else
#include <map>
class SLibC1 : public  std::map<int, int >
#endif

{
public:
	static const std::string m_str;
};

const std::string SLibC1::m_str = "SLibC1 1.0";
<<<<EOF>>>>
>>>>>>> dlib1_m1.cpp
struct __attribute__ ((visibility("default"))) Dlib1C1
{
	void Dlib1Func1() {}
};
<<<<EOF>>>>

>>>>>>> dlib2_m1.cpp
struct __attribute__ ((visibility("default"))) Dlib2C1
{
	void Dlib2Func1() {};
};
<<<<EOF>>>>

>>>>>>> configure.ac
_dnl Process this file with autoconf to produce a configure script.
AC_INIT([PSP],[pre])
AM_INIT_AUTOMAKE

dnl Checks for programs.
AC_PROG_LIBTOOL
#AC_PROG_RANLIB
AC_PROG_CXX
AC_PROG_CPP
AC_PROG_CC
AC_LANG(C++)

abs_top_srcdir=`pwd`
VERSION_INFO="-avoid-version"

AC_CONFIG_FILES([dlib1/makefile])
AC_CONFIG_FILES([dlib2/makefile])
AC_CONFIG_FILES([stlib1/makefile])

PRODNAME="linuxrelease"
CXXFLAGS=" -fvisibility=hidden -fvisibility-inlines-hidden -D_Linux "
CFLAGS=$CFLAGS" -fvisibility=hidden -D_Linux "
ALD_FLAGS=" -no-undefined"
SYSLIBS="-ldl"

AM_CONFIG_HEADER([config.h])
AC_CONFIG_FILES([makefile])

dnl Checks for libraries.

dnl Checks for header files.

dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_C_INLINE
AC_C_BIGENDIAN
AC_TYPE_SIZE_T

dnl Checks for library functions.

AC_SUBST(abs_top_srcdir)
AC_SUBST(PRODNAME)
AC_SUBST(AINC_PATH)
AC_SUBST(ALD_FLAGS)
AC_SUBST(SYSLIBS)
AC_SUBST(VERSION_INFO)
AC_OUTPUT([])
<<<<EOF>>>>

>>>>>>> ./makefile.am
SUBDIRS = stlib1 dlib1 dlib2 exe 
<<<<EOF>>>>

>>>>>>> stlib1/makefile.am
libdir = ${abs_top_srcdir}/lib/@PRODNAME@
lib_LTLIBRARIES = libstlib1.la
libstlib1_la_LDFLAGS = -all-static
libstlib1_la_LIBADD = 
libstlib1_la_SOURCES = stlib1_m1.cpp
libstlib1_la_CPPFLAGS = -D_LIB -I${top_srcdir}/inc @AINC_PATH@

install-exec-local:
	mkdir -p $(libdir)/.libs && \
	sed -e "1s/libstlib1.la/libstlib1_noi.la/;s/^old_library=.*/old_library='..\/libstlib1.a'/;s/^installed=.*/installed=no/;s/^libdir=.*/libdir=''/" libstlib1.la >$(libdir)/libstlib1_noi.la
<<<<EOF>>>>

>>>>>>> dlib1/makefile.am
libdir = ${abs_top_srcdir}/lib/@PRODNAME@
lib_LTLIBRARIES = libdlib1.la
libdlib1_la_LDFLAGS = @VERSION_INFO@ @ALD_FLAGS@ -L${abs_top_srcdir}/lib/@PRODNAME@
libdlib1_la_SOURCES = dlib1_m1.cpp
libdlib1_la_LIBADD = -lstlib1 @SYSLIBS@
libdlib1_la_CPPFLAGS = -D_USRDLL -DDLIB1_EXPORTS -I${top_srcdir}/stlib1 -I${top_srcdir}/inc @AINC_PATH@

install-exec-local:
	rm -f $(libdir)/libdlib1.a && \
	touch $(libdir)/_x.o && \
	ar cru $(libdir)/libdlib1.a $(libdir)/_x.o && \
	ranlib $(libdir)/libdlib1.a && \
	cp $(libdir)/libdlib1.a .libs/ && \
	rm -f $(libdir)/_x.o
<<<<EOF>>>>

>>>>>>> dlib2/makefile.am
libdir = ${abs_top_srcdir}/lib/@PRODNAME@
lib_LTLIBRARIES = libdlib2.la
libdlib2_la_LDFLAGS = @VERSION_INFO@ @ALD_FLAGS@ -L${abs_top_srcdir}/lib/@PRODNAME@
libdlib2_la_SOURCES = dlib2_m1.cpp
libdlib2_la_LIBADD = -ldlib1 -lstlib1 @SYSLIBS@
libdlib2_la_CPPFLAGS = -D_USRDLL -DDLIB2_EXPORTS -I${top_srcdir}/stlib1 -I${top_srcdir}/dlib1 -I${top_srcdir}/inc @AINC_PATH@

install-exec-local:
	rm -f $(libdir)/libdlib2.a && \
	touch $(libdir)/_x.o && \
	ar cru $(libdir)/libdlib2.a $(libdir)/_x.o && \
	ranlib $(libdir)/libdlib2.a && \
	cp $(libdir)/libdlib2.a .libs/ && \
	rm -f $(libdir)/_x.o
<<<<EOF>>>>


Installation:

go to the installation dir, and issue:

libtoolize --force
aclocal
autoheader
autoconf
automake --add-missing --warning=portability --warning=obsolete
./configure
make install
cd lib/linuxrelease
readelf -s -W -D libdlib1.so | c++filt
Comment 1 Laszlo Szakony 2006-03-24 15:06:41 UTC
Created attachment 11113 [details]
Automke sources to reproduce/test the visibility change of static members
Comment 2 Andrew Pinski 2006-04-11 17:25:25 UTC
Can you give some sources that don't use automake?  Because it is hard to follow what is wrong in this bug.
Comment 3 Laszlo Szakony 2006-04-20 14:52:39 UTC
Created attachment 11303 [details]
Simple test without automake files to test visibility changes of static members

To create the binaries and run the test:
>tar -xzf simpletest.tar.gz
>cd simpletest
>./build.sh

Actually the shared libs libdlib1.so and libdlib2.so should not export any symbols, but as you can see, both of them have the global symbol SLibC1::m_str.
But only in case of hash_map. With std::map works.
Comment 4 Laszlo Szakony 2006-04-21 07:49:05 UTC
(In reply to comment #2)
> Can you give some sources that don't use automake?  Because it is hard to
> follow what is wrong in this bug.

I have uploaded a simple test without automake files.
Actually this bug (if it is a bug) prevents me to use the "windows-like" visibility feature of gcc 4.0. A short explanation:
I have ported a project (one dll) from windows, that exports ca. 1200 symbols.
After porting to Linux without using the "windows-like" visibility (exporting all symbols on the IF) the number of visible symbols was ca. 75000.
I was really happy as I heard of the visibilty feature of gcc 4.0. 
I implemented that feature as described in http://gcc.gnu.org/wiki/Visibility.
The result: The number of exported symols was ca:70000. And the test crashed.
After several days I could identify the place of the crash, and I coud create this smaller example.
If this "bug" is fixed, is still a question for me:
Why is the big difference "1200-Windows" vs. "70000-Linux" in the exported symbols?
Comment 5 Andrew Pinski 2006-04-26 02:13:58 UTC
Oh, if you had put how you involved gcc in the comments instead of in build script, I would have seen what the problem is.


Anyways this is a dup of bug 19664.

The problem is the libstdc++'s headers don't have push/pop of the visibility.

*** This bug has been marked as a duplicate of 19664 ***