bug-sprint #2114, 2 comments

I have 2 major comment on the updated patch. Consider following snippet from gcc.hpp: #if __GNUC__ >= 4 && !defined(__MINGW32__) && !defined(__CYGWIN__) # define BOOST_SYMBOL_EXPORT __attribute__((visibility("default"))) # define BOOST_SYMBOL_HIDE __attribute__((visibility("hidden"))) # define BOOST_SYMBOL_IMPORT BOOST_SYMBOL_EXPORT ...And assume following scenario: Someone is writing shared library (let's name it foo) with 'visilibility=hidden' option. Library foo is using e.g. boost_filesystem. In this case, all the symbols marked with BOOST_FILESYSTEM_DECL will be exported from foo library. This could easily break foo library's ABI (in case of migration to the newest boost version etc.), so BOOST_SYMBOL_IMPORT should be defined for gcc as empty macro: # define BOOST_SYMBOL_IMPORT. The second comment: BOOST_EXCEPTION_EXPORT/IMPORT are intended for re-exporting exceptions from shared library. So, they should be defined for gcc as: # define BOOST_EXCEPTION_EXPORT BOOST_SYMBOL_EXPORT # define BOOST_EXCEPTION_IMPORT BOOST_SYMBOL_EXPORT and not as: # define BOOST_EXCEPTION_EXPORT BOOST_SYMBOL_EXPORT # define BOOST_EXCEPTION_IMPORT BOOST_SYMBOL_IMPORT Note: for the current patch version this part works as expected, since BOOST_SYMBOL_EXPORT == BOOST_SYMBOL_IMPORT for gcc. See also this thread (search for exception): http://lists.boost.org/Archives/boost/2008/12/146068.php Regards

Alexander Arhipenko wrote:
I have 2 major comment on the updated patch. Consider following snippet from gcc.hpp: #if __GNUC__ >= 4 && !defined(__MINGW32__) && !defined(__CYGWIN__) # define BOOST_SYMBOL_EXPORT __attribute__((visibility("default"))) # define BOOST_SYMBOL_HIDE __attribute__((visibility("hidden"))) # define BOOST_SYMBOL_IMPORT BOOST_SYMBOL_EXPORT
...And assume following scenario: Someone is writing shared library (let's name it foo) with 'visilibility=hidden' option. Library foo is using e.g. boost_filesystem. In this case, all the symbols marked with BOOST_FILESYSTEM_DECL will be exported from foo library. This could easily break foo library's ABI (in case of migration to the newest boost version etc.), so BOOST_SYMBOL_IMPORT should be defined for gcc as empty macro: # define BOOST_SYMBOL_IMPORT.
The second comment: BOOST_EXCEPTION_EXPORT/IMPORT are intended for re-exporting exceptions from shared library. So, they should be defined for gcc as:
# define BOOST_EXCEPTION_EXPORT BOOST_SYMBOL_EXPORT # define BOOST_EXCEPTION_IMPORT BOOST_SYMBOL_EXPORT
and not as:
# define BOOST_EXCEPTION_EXPORT BOOST_SYMBOL_EXPORT # define BOOST_EXCEPTION_IMPORT BOOST_SYMBOL_IMPORT
Oh, now I am confused. How exactly those symbols are to be used? Say, I declare an exception class in a header -- what modifiers should I use? Do we need BOOST_WHATEVER_EXCEPTION_DECL? Maybe you can write up some guidance for library authors? - Volodya

Hi ! On Tuesday 09 June 2009 19:15:15 Vladimir Prus wrote:
Alexander Arhipenko wrote:
I have 2 major comment on the updated patch.
In this case, all the symbols marked with BOOST_FILESYSTEM_DECL will be exported from foo library. This could easily break foo library's ABI (in case of migration to the newest boost version etc.), so BOOST_SYMBOL_IMPORT should be defined for gcc as empty macro: # define BOOST_SYMBOL_IMPORT.
Oh, I've simply copied this from our own project settings. I've checked against Qt-4.5 and they use an empty symbol import macro, too. I'll attach an updated patch to the ticket this evening.
The second comment: BOOST_EXCEPTION_EXPORT/IMPORT are intended for re-exporting exceptions from shared library. So, they should be defined for gcc as:
# define BOOST_EXCEPTION_EXPORT BOOST_SYMBOL_EXPORT # define BOOST_EXCEPTION_IMPORT BOOST_SYMBOL_EXPORT
and not as:
# define BOOST_EXCEPTION_EXPORT BOOST_SYMBOL_EXPORT # define BOOST_EXCEPTION_IMPORT BOOST_SYMBOL_IMPORT
That means "__attribute__((visibility("default")))", right ? Okay, I'll add change the patch accordingly.
Oh, now I am confused. How exactly those symbols are to be used? Say, I declare an exception class in a header -- what modifiers should I use? Do we need BOOST_WHATEVER_EXCEPTION_DECL? Maybe you can write up some guidance for library authors?
Yeah, me too ;-)) That whole exception export thing is quite a miracle. Yours, Jürgen -- * Dipl.-Math. Jürgen Hunold ! Ingenieurgesellschaft für * voice: ++49 511 262926 57 ! Verkehrs- und Eisenbahnwesen mbH * fax : ++49 511 262926 99 ! Lister Straße 15 * juergen.hunold@ivembh.de ! www.ivembh.de * * Geschäftsführer: ! Sitz des Unternehmens: Hannover * Prof. Dr.-Ing. Thomas Siefer ! Amtsgericht Hannover, HRB 56965 * PD Dr.-Ing. Alfons Radtke !

On Wed, Jun 10, 2009 at 11:04 AM, Juergen Hunold<juergen.hunold@ivembh.de> wrote:
[snip]
That means "__attribute__((visibility("default")))", right ? Yes, exactly
[snip]
Oh, now I am confused. How exactly those symbols are to be used? Say, I declare an exception class in a header -- what modifiers should I use? Do we need BOOST_WHATEVER_EXCEPTION_DECL? Maybe you can write up some guidance for library authors?
Yeah, me too ;-)) That whole exception export thing is quite a miracle.
In response to above: I have written down 2 sample configuration files for the 'foo' library. #if !defined BOOST_FOO_DETAIL_CONFIG_HPP #define BOOST_FOO_DETAIL_CONFIG_HPP #if defined BOOST_FOO_BUILD_SHLIB # define BOOST_FOO_DECL BOOST_SYMBOL_EXPORT # define BOOST_FOO_EXCEPTION_DECL BOOST_EXCEPTION_EXPORT #elif defined BOOST_FOO_USE_SHLIB # define BOOST_FOO_DECL BOOST_SYMBOL_IMPORT # define BOOST_FOO_EXCEPTION_DECL BOOST_EXCEPTION_IMPORT #else # define BOOST_FOO_DECL # define BOOST_FOO_EXCEPTION_DECL #endif #endif Configuration file above will re-export all the exceptions marked with BOOST_FOO_EXCEPTION_DECL from shared library foo. So, if I write library 'bar', it will contain all the symbols exported by 'bar' and also all the exceptions from 'foo' library'. This is intended for the following scenario: exe test : main.cpp bar ; main.cpp: #include <bar.hpp> #include <foo/error.hpp> int main() { try { bar::function();//could potentially throw foo's exception } catch(const foo::error& e) { std::cerr<<"error occured: "<<e.what()<<'\n'; } return 0; } In case if 'bar' reexports exceptions from 'foo', the code above will succeed. Otherwise it will be aborted, since foo::error won't be caught. But, all these could be not enough for the sophisticated user. Assume, library 'bar' will use library 'foo' as an implementation detail and also will catch all the foo's exceptions. So, bar's maintainer doesn't want to re-export foo's stuff from his library. As a result, foo's maintainer should provide more sophisticated configuration file (I marked changes with '+'): #if !defined BOOST_FOO_DETAIL_CONFIG_HPP #define BOOST_FOO_DETAIL_CONFIG_HPP #if defined BOOST_FOO_BUILD_SHLIB # define BOOST_FOO_DECL BOOST_SYMBOL_EXPORT # define BOOST_FOO_EXCEPTION_DECL BOOST_EXCEPTION_EXPORT #elif defined BOOST_FOO_USE_SHLIB # define BOOST_FOO_DECL BOOST_SYMBOL_IMPORT +# if defined BOOST_FOO_EXCEPTION_REEXPORT # define BOOST_FOO_EXCEPTION_DECL BOOST_EXCEPTION_IMPORT +# else +# define BOOST_FOO_EXCEPTION_DECL BOOST_SYMBOL_IMPORT +# endif #else # define BOOST_FOO_DECL # define BOOST_FOO_EXCEPTION_DECL #endif #endif So, now bar library maintener have a choice: 1. Re-export foo's exceptions and let them left the bar library's boundaries 2. Catch all the foo's exceptions, process and do not re-export P.S. I've attached minimal bbv2 project that reproduce the problem with uncaught exception. To eliminate it, you can do the following: a) Replace FOO_DECL with FOO_EXCEPTION_DECL in Error class declaration b) Uncomment ~Error() declaration (foo/error.hpp) and definition (foo/foo.cpp)

Hi Alexander, On Wednesday 10 June 2009 14:03:43 Alexander Arhipenko wrote:
On Wed, Jun 10, 2009 at 11:04 AM, Juergen Hunold<juergen.hunold@ivembh.de> wrote:
[snip]
That means "__attribute__((visibility("default")))", right ?
Okay. I've done some short experimenting and found some issues with BOOST_SYMPOL_IMPORT expand to nothing in our code. It seems necessary to declare some templated classes with 'visibility "default"' when they are imported. I'll have to do some more research on this. (and I lost the start of the thread due to human error, so no quotes ;-))
In response to above: I have written down 2 sample configuration files for the 'foo' library.
Yes, looks good. [snip]
But, all these could be not enough for the sophisticated user. Assume, library 'bar' will use library 'foo' as an implementation detail and also will catch all the foo's exceptions. So, bar's maintainer doesn't want to re-export foo's stuff from his library.
This is the gcc case, right ? With msvc, you have to "re-export" the used symbols anyway (by marking them "__dllimport". So why do you want to hide the symbols with gcc ?
I've attached minimal bbv2 project that reproduce the problem with uncaught exception. To eliminate it, you can do the following: a) Replace FOO_DECL with FOO_EXCEPTION_DECL in Error class declaration b) Uncomment ~Error() declaration (foo/error.hpp) and definition (foo/foo.cpp)
I'll take a look at it. Please be patient... Yours, Jürgen -- * Dipl.-Math. Jürgen Hunold ! Ingenieurgesellschaft für * voice: ++49 511 262926 57 ! Verkehrs- und Eisenbahnwesen mbH * fax : ++49 511 262926 99 ! Lister Straße 15 * juergen.hunold@ivembh.de ! www.ivembh.de * * Geschäftsführer: ! Sitz des Unternehmens: Hannover * Prof. Dr.-Ing. Thomas Siefer ! Amtsgericht Hannover, HRB 56965 * PD Dr.-Ing. Alfons Radtke !

Hi Juergen, On Wed, Jun 10, 2009 at 3:15 PM, Juergen Hunold<juergen.hunold@ivembh.de> wrote:
[snip]
But, all these could be not enough for the sophisticated user. Assume, library 'bar' will use library 'foo' as an implementation detail and also will catch all the foo's exceptions. So, bar's maintainer doesn't want to re-export foo's stuff from his library.
This is the gcc case, right ? With msvc, you have to "re-export" the used symbols anyway (by marking them "__dllimport". So why do you want to hide the symbols with gcc ?
I guess, I was not clear and typed too many words ;). Consider the following: foo: [foo::function, foo::Error] bar: [bar::function,] ('[]' - means list of exported symbols) In case, when 'bar' depends on 'foo' and foo::Error is not re-exported: bar: [bar::function]. So, bar only exports bar::function symbol. This is the same for gcc and msvc (I've rechecked msvc's case with dumpbin utility). In case, when foo::Error is re-exported (i.e., foo:Error always have 'default' visibility): bar: [bar::function, foo::Error]. This only relates to gcc.
So why do you want to hide the symbols with gcc ? The reason could be binary compatibility.
Regards

Hi Alexander On Thursday 11 June 2009 08:58:24 Alexander Arhipenko wrote:
Hi Juergen,
So, bar only exports bar::function symbol. This is the same for gcc and msvc (I've rechecked msvc's case with dumpbin utility).
Point taken. But msvc will add an _import_ reference to "foo::Error" and thus add a dependency to "foo".
In case, when foo::Error is re-exported (i.e., foo:Error always have 'default' visibility): bar: [bar::function, foo::Error]. This only relates to gcc.
Of course.
So why do you want to hide the symbols with gcc ?
The reason could be binary compatibility.
This is a weak point and no concern in my opinion. I think you can't "hide" a symbol from a 3rd library this way. It definitely won't work cross platform as at least msvc adds an explicit import reference. And guaranteeing binary compatibility implies a lot more than simply using symbol visibility. I've searched the current KDE trunk and found: #ifdef __KDE_HAVE_GCC_VISIBILITY #define KDE_NO_EXPORT __attribute__ ((visibility("hidden"))) #define KDE_EXPORT __attribute__ ((visibility("default"))) #define KDE_IMPORT __attribute__ ((visibility("default"))) so at least KDE uses default visibility for all imported symbols, too. Lacking more time to do further research, I'd like to add more visibility. We can try and remove "visibility default" from the import macros once we have the Boost.Build support up and running and get this thing tested across all platform. So I think we should take my original patch. Yours, Jürgen -- * Dipl.-Math. Jürgen Hunold ! Ingenieurgesellschaft für * voice: ++49 511 262926 57 ! Verkehrs- und Eisenbahnwesen mbH * fax : ++49 511 262926 99 ! Lister Straße 15 * juergen.hunold@ivembh.de ! www.ivembh.de * * Geschäftsführer: ! Sitz des Unternehmens: Hannover * Prof. Dr.-Ing. Thomas Siefer ! Amtsgericht Hannover, HRB 56965 * PD Dr.-Ing. Alfons Radtke !

Alexander Arhipenko wrote:
[snip] I have written down 2 sample configuration files for the 'foo' library.
#if !defined BOOST_FOO_DETAIL_CONFIG_HPP #define BOOST_FOO_DETAIL_CONFIG_HPP
#if defined BOOST_FOO_BUILD_SHLIB
Should be named BOOST_FOO_SOURCE.
# define BOOST_FOO_DECL BOOST_SYMBOL_EXPORT # define BOOST_FOO_EXCEPTION_DECL BOOST_EXCEPTION_EXPORT #elif defined BOOST_FOO_USE_SHLIB
Just #else should be enough, see the 'Supporting Windows Dll's' section at http://www.boost.org/development/separate_compilation.html
# define BOOST_FOO_DECL BOOST_SYMBOL_IMPORT # define BOOST_FOO_EXCEPTION_DECL BOOST_EXCEPTION_IMPORT #else # define BOOST_FOO_DECL # define BOOST_FOO_EXCEPTION_DECL #endif
#endif
Configuration file above will re-export all the exceptions marked with BOOST_FOO_EXCEPTION_DECL from shared library foo. So, if I write library 'bar', it will contain all the symbols exported by 'bar' and also all the exceptions from 'foo' library'. This is intended for the following scenario:
exe test : main.cpp bar ;
main.cpp:
#include <bar.hpp> #include <foo/error.hpp>
int main() { try { bar::function();//could potentially throw foo's exception } catch(const foo::error& e) { std::cerr<<"error occured: "<<e.what()<<'\n'; }
return 0; }
In case if 'bar' reexports exceptions from 'foo', the code above will succeed. Otherwise it will be aborted, since foo::error won't be caught.
But, all these could be not enough for the sophisticated user. Assume, library 'bar' will use library 'foo' as an implementation detail and also will catch all the foo's exceptions. So, bar's maintainer doesn't want to re-export foo's stuff from his library. As a result, foo's maintainer should provide more sophisticated configuration file (I marked changes with '+'):
#if !defined BOOST_FOO_DETAIL_CONFIG_HPP #define BOOST_FOO_DETAIL_CONFIG_HPP
#if defined BOOST_FOO_BUILD_SHLIB # define BOOST_FOO_DECL BOOST_SYMBOL_EXPORT # define BOOST_FOO_EXCEPTION_DECL BOOST_EXCEPTION_EXPORT #elif defined BOOST_FOO_USE_SHLIB # define BOOST_FOO_DECL BOOST_SYMBOL_IMPORT +# if defined BOOST_FOO_EXCEPTION_REEXPORT
Exceptions should be re-exported by default, IMHO.
# define BOOST_FOO_EXCEPTION_DECL BOOST_EXCEPTION_IMPORT +# else +# define BOOST_FOO_EXCEPTION_DECL BOOST_SYMBOL_IMPORT +# endif #else # define BOOST_FOO_DECL # define BOOST_FOO_EXCEPTION_DECL #endif
#endif
So, now bar library maintener have a choice: 1. Re-export foo's exceptions and let them left the bar library's boundaries 2. Catch all the foo's exceptions, process and do not re-export
P.S. I've attached minimal bbv2 project that reproduce the problem with uncaught exception. To eliminate it, you can do the following: a) Replace FOO_DECL with FOO_EXCEPTION_DECL in Error class declaration b) Uncomment ~Error() declaration (foo/error.hpp) and definition (foo/foo.cpp)
------------------------------------------------------------------------
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Ilya Sokolov wrote:
#if !defined BOOST_FOO_DETAIL_CONFIG_HPP #define BOOST_FOO_DETAIL_CONFIG_HPP
#if defined BOOST_FOO_BUILD_SHLIB # define BOOST_FOO_DECL BOOST_SYMBOL_EXPORT # define BOOST_FOO_EXCEPTION_DECL BOOST_EXCEPTION_EXPORT #elif defined BOOST_FOO_USE_SHLIB # define BOOST_FOO_DECL BOOST_SYMBOL_IMPORT +# if defined BOOST_FOO_EXCEPTION_REEXPORT
Exceptions should be re-exported by default, IMHO.
Probably so. If I have a library that users headers from another library (maybe even header-only), then the default behaviour should be to export all exceptions. Requiring that I explicitly list the libraries whose exceptions I might throw sounds extremely risky. - Volodya
participants (4)
-
Alexander Arhipenko
-
Ilya Sokolov
-
Juergen Hunold
-
Vladimir Prus