[cfe-dev] clang, -fvisibility=hidden, static class method

Narinder Claire narinder.claire at gmail.com
Tue Jul 26 13:48:33 PDT 2011


Hello,
I am seeing some unexpected (unwanted) behaviour from clang concerning
-fvisibility=hidden and static class method. When I build a shared
library with  -fvisibility=hidden consisting of a function with a
static variable as expected the static variable is NOT exported.
However if I build the same library with  -fvisibility=hidden but
modified so that the same function is now  a static method method is a
method of a class, the static variable IS exported. I am NOT
decorating anything with :
__attribute__ ((visibility("default")))

To better illustrate I have pasted the code below

My dev environment has the following components:

OS
-----
Ubuntu 11.04 x64

g++
------
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro
4.5.2-8ubuntu4'
--with-bugurl=file:///usr/share/doc/gcc-4.5/README.Bugs
--enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr
--program-suffix=-4.5 --enable-shared --enable-multiarch
--with-multiarch-defaults=x86_64-linux-gnu --enable-linker-build-id
--with-system-zlib --libexecdir=/usr/lib/x86_64-linux-gnu
--without-included-gettext --enable-threads=posix
--with-gxx-include-dir=/usr/include/c++/4.5
--libdir=/usr/lib/x86_64-linux-gnu --enable-nls --with-sysroot=/
--enable-clocale=gnu --enable-libstdcxx-debug
--enable-libstdcxx-time=yes --enable-plugin --enable-gold
--enable-ld=default --with-plugin-ld=ld.gold --enable-objc-gc
--disable-werror --with-arch-32=i686 --with-tune=generic
--enable-checking=release --build=x86_64-linux-gnu
--host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4)


clang
---------
clang version 2.8 (branches/release_28)
Target: x86_64-pc-linux-gnu
Thread model: posix


The source code an makefile are shown below:


makefile
------------
CXX = clang++

VISIBILITY = -fvisibility=hidden

MODE = AS_NAMESPACE

all: clean
	$(CXX)  -D$(MODE) $(VISIBILITY) dll.cpp   -I./  -fPIC -shared -o libdll.so
	$(CXX)  -D$(MODE) $(VISIBILITY) main.cpp  -I./  -fPIC  -ldl -o main

clean:
	rm -fr *.so *.o main	




klass.h
----------
#ifndef KLASS_HEADER_GUARD
#define KLASS_HEADER_GUARD
#include<string>
#include<set>

typedef std::set<std::string>::const_iterator  const_iterator ;

#ifdef AS_CLASS

class scope
{

public:
	static
#else
namespace scope
{
#endif
	std::set<std::string>& Instance()
	{
		static std::set<std::string> inst;
		return inst;
	}
}
#ifdef AS_CLASS
;
#endif

struct Insert
{
	Insert(const std::string & x)
	{
		scope::Instance().insert(x);
	}

};
#endif




dll.cpp
---------
#include"klass.h"
namespace
{
	Insert x("SHOULD NOT SEE THIS INSERTION");
}



main.cpp
-------------
#include<iostream>
#include<dlfcn.h>
#include"klass.h"

using namespace std;
typedef const_iterator Iterator;

int main()
{
	void* D = dlopen("libdll.so",RTLD_LOCAL|RTLD_LAZY);
	if(!D)
	{
		throw("Cannot load DLL\n");
	}

	if(scope::Instance().empty())
	{
		cout << "Set is empty\n";
	}
	else
	{
		cout << "CONTENTS OF SET\n";
		for(Iterator theIterator = scope::Instance().begin();
			theIterator != scope::Instance().end();
			theIterator++)
		{
			cout << *theIterator << "\n";
		}
	}
}



-------------------------------------------------------------------------------------------------------------------

To see the unexpected behaviour we first set LD_LIBRARY_PATH

export LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH

and then 'make' the exectuable with the following variations:

Test 1:
``````````
make MODE=AS_NAMESPACE

output is from the executable is:
Set is empty


make CXX=g++ MODE=AS_NAMESPACE

output is from the executable is:
Set is empty


As expected ( and wanted) the output between clang and g++ is consistent.



Test 2
`````````
make MODE=AS_CLASS

output is from the executable is:
CONTENTS OF SET
SHOULD NOT SEE THIS INSERTION


make CXX=g++ MODE=AS_CLASS

output is from the executable is:
Set is empty


Unexpected (and unwanted) the output is inconsistent between clang and
g++. The behaviour from g++ appears correct whereas the behaviour from
clang appears incorrect since it seems to be exporting a static
variable inside a static method of a class that was never designated
to have default visibility.


I have seen one other email from a few months ago concerning
unexpected behaviour of clang concerning visibility but from what I
understand it doesn't look the same.  Any help or explanation would be
appreciated.


Regards
Narinder



More information about the cfe-dev mailing list