Compare boost::system::error_category
The following comparison fails for an error whom outputs "asio.misc" for errorCode.category().name() and "end of file" for errorCode.message() If it claims to be in category asio.misc, then why does the if condition of (errorCode.category() == boost::asio::error::misc_category ) evaluate to false? Googling says that a boost::system::error_code can have the same value in more than one category, so I assume that in order to get the proper message and meaning we must compare boost::system::error_category as well as boost::system::error_code::value. How do we properly compare the category if this fails to work? Code in question: //-------------------------------------------------------------------------------------------------- std::string ClientSocketASIO::ErrorCodeToString(const boost::system::error_code & errorCode) { std::ostringstream debugMsg; debugMsg << " Error Category: " << errorCode.category().name() << ". " << " Error Message: " << errorCode.message() << ". "; if( errorCode.category() == boost::asio::error::misc_category ) { switch (errorCode.value()) { case boost::asio::error::eof: debugMsg << ". Server has disconnected."; break; case boost::asio::error::connection_refused: debugMsg << ". Connection Refused"; break; default: debugMsg << ". Unknown Error."; break; } } else { debugMsg << ". Unknown Error category."; } return debugMsg.str(); } -- View this message in context: http://boost.2283326.n4.nabble.com/Compare-boost-system-error-category-tp469... Sent from the Boost - Users mailing list archive at Nabble.com.
On 24/03/2017 09:26, Christopher Pisz wrote:
The following comparison fails for an error whom outputs "asio.misc" for errorCode.category().name() and "end of file" for errorCode.message()
If it claims to be in category asio.misc, then why does the if condition of (errorCode.category() == boost::asio::error::misc_category ) evaluate to false?
Googling says that a boost::system::error_code can have the same value in more than one category, so I assume that in order to get the proper message and meaning we must compare boost::system::error_category as well as boost::system::error_code::value.
How do we properly compare the category if this fails to work?
If they appear to have equal value but aren't equal, you might have a problem with multiple definitions. The most common problem is where you're using some shared libraries (DLL or SO) and trying to pass errors across the boundary. This works as expected only when you ensure that the dependencies of both sides also use the Boost libraries (esp. ASIO and System) as shared libraries, not as static libraries. When you're linking your Boost-using application with Boost-using shared libraries (and when the Boost types are used in the API between them), it's generally best to ensure that the shared libraries are used. On Linux, this generally just happens (as long as the shared libraries have been compiled and are in the same or earlier library path as the static libraries), but on Windows you should also define BOOST_ALL_DYN_LINK on both sides.
Sounds like that could solve my problem. However, I am using the Nuget boost package and it seem to set up linking automatically? I don't see anything in the project settings for include directories or additional library directories. When I define BOOST_ALL_DYN_LINK the process runs without the dll being copied to the output directory, so I suspect it is ignoring it. So, might be OT here, but going to have to track down some insight on how to dynamically link boost with the Nuget package. -- View this message in context: http://boost.2283326.n4.nabble.com/Compare-boost-system-error-category-tp469... Sent from the Boost - Users mailing list archive at Nabble.com.
(MSVS Specific) So I've edited all the target files for the public Nuget packages for all the boost libraries I am using to look like: <?xml version="1.0" encoding="utf-8"?> <Project ToolVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemDefinitionGroup Condition="'$(Platform)'=='Win32'"> <ClCompile> <PreprocessorDefinitions>BOOST_ALL_DYN_LINK;%(PreprocessorDefinitions)</PreprocessorDefinitions> </ClCompile> <Link> <AdditionalLibraryDirectories>$(MSBuildThisFileDirectory)..\..\lib\native\address-model-32\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Platform)'=='x64'"> <ClCompile> <PreprocessorDefinitions>BOOST_ALL_DYN_LINK;%(PreprocessorDefinitions)</PreprocessorDefinitions> </ClCompile> <Link> <AdditionalLibraryDirectories>$(MSBuildThisFileDirectory)..\..\lib\native\address-model-64\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> </Link> </ItemDefinitionGroup> <ItemGroup /> <Target Name="CopyBoostAtomicDll" BeforeTargets="PrepareForBuild"> <Copy SourceFiles="$(MSBuildThisFileDirectory)..\..\lib\native\address-model-32\lib\boost_atomic-vc100-mt-1_62.dll" DestinationFolder="$(OutDir)" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" /> <Copy SourceFiles="$(MSBuildThisFileDirectory)..\..\lib\native\address-model-32\lib\boost_atomic-vc100-mt-gd-1_62.dll" DestinationFolder="$(OutDir)" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" /> </Target> </Project> (General) So, now I am dynamically linking to all boost libraries and if I use the following code, I get the expected results. If I statically link, all the if conditions evaluate to false. This seems like a very big problem to me and very unexpected. //-------------------------------------------------------------------------------------------------- std::string ClientSocketASIO::ErrorCodeToString(const boost::system::error_code & errorCode) { std::ostringstream debugMsg; debugMsg << " Error Category: " << errorCode.category().name() << ". " << " Error Message: " << errorCode.message() << ". "; // IMPORTANT - These comparisons only work if you dynamically link boost libraries // Because boost chose to implement boost::system::error_category::operator == by comparing addresses // The addresses are different in one library and the other when statically linking. // // We use make_error_code macro to make the correct category as well as error code value. // Error code value is not unique and can be duplicated in more than one category. if (errorCode == make_error_code(boost::asio::error::connection_refused)) { debugMsg << ". Connection Refused"; } else if (errorCode == make_error_code(boost::asio::error::eof)) { debugMsg << ". Server has disconnected."; } else { debugMsg << ". boost::system::error_code has not been mapped to a meaningful message."; } return debugMsg.str(); } Why would the authors use address comparison for the boost::system::error_category and leave us getting different results if we statically link vs dynamically link? Also, is my error_code comparison now the proper and correct way to compare error codes? -- View this message in context: http://boost.2283326.n4.nabble.com/Compare-boost-system-error-category-tp469... Sent from the Boost - Users mailing list archive at Nabble.com.
This is the same issue I reported here: https://svn.boost.org/trac/boost/ticket/11989 and passed it on to GCC as well: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69789 On 3/24/17 4:34 PM, Christopher Pisz via Boost-users wrote:
(MSVS Specific)
So I've edited all the target files for the public Nuget packages for all the boost libraries I am using to look like:
<?xml version="1.0" encoding="utf-8"?> <Project ToolVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemDefinitionGroup Condition="'$(Platform)'=='Win32'"> <ClCompile>
<PreprocessorDefinitions>BOOST_ALL_DYN_LINK;%(PreprocessorDefinitions)</PreprocessorDefinitions> </ClCompile> <Link>
<AdditionalLibraryDirectories>$(MSBuildThisFileDirectory)..\..\lib\native\address-model-32\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Platform)'=='x64'"> <ClCompile>
<PreprocessorDefinitions>BOOST_ALL_DYN_LINK;%(PreprocessorDefinitions)</PreprocessorDefinitions> </ClCompile> <Link>
<AdditionalLibraryDirectories>$(MSBuildThisFileDirectory)..\..\lib\native\address-model-64\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> </Link> </ItemDefinitionGroup> <ItemGroup />
<Target Name="CopyBoostAtomicDll" BeforeTargets="PrepareForBuild"> <Copy SourceFiles="$(MSBuildThisFileDirectory)..\..\lib\native\address-model-32\lib\boost_atomic-vc100-mt-1_62.dll" DestinationFolder="$(OutDir)" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" /> <Copy SourceFiles="$(MSBuildThisFileDirectory)..\..\lib\native\address-model-32\lib\boost_atomic-vc100-mt-gd-1_62.dll" DestinationFolder="$(OutDir)" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" /> </Target>
</Project>
(General)
So, now I am dynamically linking to all boost libraries and if I use the following code, I get the expected results. If I statically link, all the if conditions evaluate to false. This seems like a very big problem to me and very unexpected.
//-------------------------------------------------------------------------------------------------- std::string ClientSocketASIO::ErrorCodeToString(const boost::system::error_code & errorCode) { std::ostringstream debugMsg; debugMsg << " Error Category: " << errorCode.category().name() << ". " << " Error Message: " << errorCode.message() << ". ";
// IMPORTANT - These comparisons only work if you dynamically link boost libraries // Because boost chose to implement boost::system::error_category::operator == by comparing addresses // The addresses are different in one library and the other when statically linking. // // We use make_error_code macro to make the correct category as well as error code value. // Error code value is not unique and can be duplicated in more than one category. if (errorCode == make_error_code(boost::asio::error::connection_refused)) { debugMsg << ". Connection Refused"; } else if (errorCode == make_error_code(boost::asio::error::eof)) { debugMsg << ". Server has disconnected."; } else { debugMsg << ". boost::system::error_code has not been mapped to a meaningful message."; }
return debugMsg.str(); }
Why would the authors use address comparison for the boost::system::error_category and leave us getting different results if we statically link vs dynamically link?
Also, is my error_code comparison now the proper and correct way to compare error codes?
-- View this message in context: http://boost.2283326.n4.nabble.com/Compare-boost-system-error-category-tp469... Sent from the Boost - Users mailing list archive at Nabble.com. _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
On 23/03/2017 20:26, Christopher Pisz via Boost-users wrote:
The following comparison fails for an error whom outputs "asio.misc" for errorCode.category().name() and "end of file" for errorCode.message()
The C++ 11 standard implies that each error category instance shall have a globally unique address and comparisons of equality shall use that address to compare. Unfortunately, this is not reliable in portable code, only the Dinkumware STL implements true address uniqueness anywhere in the process and it adds a full memory barrier to achieve that i.e. it's expensive. Boost's quality of implementation is the same as libstdc++ or libc++, you can get multiple instantiations in certain circumstances and those can have differing addresses. In my own code, I do the comparison operator first, and if that fails I do a strcmp() of the category's name(). To date, this has not bitten me. I would personally consider this aspect of error categories to be a defect in the standard, as specified it forces non-header-only implementation if you want it to be conforming, and even that doesn't cover RTLD_LOCAL which means you need to fall back onto named shared memory or some hack. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/
On 03/25/2017 12:32 AM, Niall Douglas via Boost-users wrote:
Boost's quality of implementation is the same as libstdc++ or libc++, you can get multiple instantiations in certain circumstances and those can have differing addresses.
The various error categories are implemented (for header-only libraries) as inlined Meyer singletons. Does that mean that we have a general problem with such singletons?
On 3/25/17 7:12 AM, Bjorn Reese via Boost-users wrote:
On 03/25/2017 12:32 AM, Niall Douglas via Boost-users wrote:
Boost's quality of implementation is the same as libstdc++ or libc++, you can get multiple instantiations in certain circumstances and those can have differing addresses.
The various error categories are implemented (for header-only libraries) as inlined Meyer singletons. Does that mean that we have a general problem with such singletons?
I think the issue is that for C++ versions prior to C++11, it isn't guaranteed to be thread safe, as C++ had no concept of threads (which sort of makes anything you do with threads problematical). With C++11, if fully implemented, it should be thread safe as the standard now requires the compiler to implement the required thread safety, the issue is that there may be implementation that don't fully provide that as it can be a bit expensive in some cases. -- Richard Damon
I have run into boost issues even when dynamically linking everything. http://stackoverflow.com/questions/39948997/use-of-boost-log-and-boost-asio-... It's actually quite concerning. James On Saturday, March 25, 2017, Richard Damon via Boost-users < boost-users@lists.boost.org> wrote:
On 3/25/17 7:12 AM, Bjorn Reese via Boost-users wrote:
On 03/25/2017 12:32 AM, Niall Douglas via Boost-users wrote:
Boost's quality of implementation is the same as libstdc++ or libc++,
you can get multiple instantiations in certain circumstances and those can have differing addresses.
The various error categories are implemented (for header-only libraries) as inlined Meyer singletons. Does that mean that we have a general problem with such singletons?
I think the issue is that for C++ versions prior to C++11, it isn't guaranteed to be thread safe, as C++ had no concept of threads (which sort of makes anything you do with threads problematical). With C++11, if fully implemented, it should be thread safe as the standard now requires the compiler to implement the required thread safety, the issue is that there may be implementation that don't fully provide that as it can be a bit expensive in some cases.
-- Richard Damon
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
On 25/03/2017 12:44, james via Boost-users wrote:
I have run into boost issues even when dynamically linking everything.
http://stackoverflow.com/questions/39948997/use-of-boost-log-and-boost-asio-...
It's actually quite concerning.
There are very long standing ABI issues with Boost, but before C++ 11 it was hard to do something about it which wasn't disruptive to end users. I've proposed the scheme described at https://ned14.github.io/boost.outcome/md_doc_md_07-faq.html, but it has not gained traction with the Boost community. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/
On 25/03/2017 12:01, Richard Damon via Boost-users wrote:
Boost's quality of implementation is the same as libstdc++ or libc++, you can get multiple instantiations in certain circumstances and those can have differing addresses.
The various error categories are implemented (for header-only libraries) as inlined Meyer singletons. Does that mean that we have a general problem with such singletons?
I think the issue is that for C++ versions prior to C++11, it isn't guaranteed to be thread safe, as C++ had no concept of threads (which sort of makes anything you do with threads problematical). With C++11, if fully implemented, it should be thread safe as the standard now requires the compiler to implement the required thread safety, the issue is that there may be implementation that don't fully provide that as it can be a bit expensive in some cases.
I know of no linker based method to bypass multiple category instances occurring in ELF if a library is loaded via RTLD_LOCAL. You need to fall back onto named memory maps in that situation. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/
Boost's quality of implementation is the same as libstdc++ or libc++, you can get multiple instantiations in certain circumstances and those can have differing addresses.
The various error categories are implemented (for header-only libraries) as inlined Meyer singletons. Does that mean that we have a general problem with such singletons?
The short answer is yes, the error category comparison operators are unreliable on all major STLs apart from Dinkumware's and in Boost. The longer answer is that the hack of strcmp()ing the name() works surprisingly well in practice, and it might be wise if Boost's error categories implemented that, followed by libstdc++ and libc++. I expect after Charley Bay bangs the drum on this stuff at C++ Now followed very shortly thereafter by me banging the drum at ACCU that we might draw some attention to this problem by the STL maintainers. The only one who really gets the problem is Stephan, but his solution for Dinkumware does bring in an atomic fence which he himself admits is a bit heavy. It certainly causes a lot of code bloat when using Outcome with the Dinkumware STL, as every possible error code construction point requires an atomic fence. I've done some remedial evil hackery in Outcome to bypass Stephan's atomic fence some of the time on VS. It's the best I can do given the constraints. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/
On 03/25/2017 01:45 PM, Niall Douglas via Boost-users wrote:
Boost's quality of implementation is the same as libstdc++ or libc++, you can get multiple instantiations in certain circumstances and those can have differing addresses.
The various error categories are implemented (for header-only libraries) as inlined Meyer singletons. Does that mean that we have a general problem with such singletons?
The short answer is yes, the error category comparison operators are unreliable on all major STLs apart from Dinkumware's and in Boost.
Can you elaborate on what the core problem is? You have mentioned both memory barriers and RTLD_LOCAL which seem to imply different problems (concurrency versus relocation of weak symbols.) Please notice that I am interested in singletons in general, not only error categories.
Boost's quality of implementation is the same as libstdc++ or libc++, you can get multiple instantiations in certain circumstances and those can have differing addresses.
The various error categories are implemented (for header-only libraries) as inlined Meyer singletons. Does that mean that we have a general problem with such singletons?
The short answer is yes, the error category comparison operators are unreliable on all major STLs apart from Dinkumware's and in Boost.
Can you elaborate on what the core problem is?
To generate ELF object A using header only library X which defines a custom error category, the linker chooses any one of the implementations of that error category in the object files linked as it is marked weak due to being inline. Due to use of -fvisibility=hidden, symbol for custom error category is not exported. To generate ELF object B using header only library X which defines a custom error category, the linker chooses any one of the implementations of that error category in the object files linked as it is marked weak due to being inline. Due to use of -fvisibility=hidden, symbol for custom error category is not exported. Program C links against ELF object A and ELF object B. There are now two instances of the same category object, and their addresses will not equal. Possible solution: Mark custom error category retrieval function with default visibility? That will work with RTLD_GLOBAL. But what if a SO is loaded with RTLD_LOCAL? That establishes multiple global symbol tables, and once again two instances of the same error category appear. The exact same problem applies to the RTTI used to catch exception throws. The problem was fixed on libstdc++ by using string comparison to compare RTTI if address comparison failed. libc++ used to noisily take a stand against string comparison and insist on address comparison, but they may since have buckled under the constant bugs about exceptions not being caught.
You have mentioned both memory barriers and RTLD_LOCAL which seem to imply different problems (concurrency versus relocation of weak symbols.)
MSVC has the advantage of controlling its ABI. They invented a thing called _Immortalize which gets specially treated by the linker to instantiate exactly one of the thing ever in a process. As the VS2015 source file says, /* MAGIC */. Because multiple threads could reach the instantiation concurrently, it needs to be a memory barrier so one gets chosen and the others wait.
Please notice that I am interested in singletons in general, not only error categories.
PE and MachO are the least affected by this problem because their creators thought of symbol encapsulation in advance. ELF is severely affected by it. The fault is in the ELF spec which assumes a globally visible unique symbol table. I have tried raising this problem with those responsible for ELF on a number of occasions in the past, it was considered not a problem for the linker and ELF folk, they felt it was a C++ problem. Attempting to explain this was not a problem in PE nor MachO nor many other binary formats got me nowhere. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/
What would be so wrong with category being an actual number to compare against? I don't know anyone whom creates classes and operator == using the address of that class. You guys talk about the standard and what not, and admittedly I've never looked inside how they implement things, but I've never had such problems using the STL either. On Sat, Mar 25, 2017 at 5:58 PM, Boost - Users mailing list [via Boost] < ml-node+s2283326n4692952h86@n4.nabble.com> wrote:
Boost's quality of implementation is the same as libstdc++ or libc++, you can get multiple instantiations in certain circumstances and those can have differing addresses.
The various error categories are implemented (for header-only libraries) as inlined Meyer singletons. Does that mean that we have a general problem with such singletons?
The short answer is yes, the error category comparison operators are unreliable on all major STLs apart from Dinkumware's and in Boost.
Can you elaborate on what the core problem is?
To generate ELF object A using header only library X which defines a custom error category, the linker chooses any one of the implementations of that error category in the object files linked as it is marked weak due to being inline. Due to use of -fvisibility=hidden, symbol for custom error category is not exported.
To generate ELF object B using header only library X which defines a custom error category, the linker chooses any one of the implementations of that error category in the object files linked as it is marked weak due to being inline. Due to use of -fvisibility=hidden, symbol for custom error category is not exported.
Program C links against ELF object A and ELF object B. There are now two instances of the same category object, and their addresses will not equal. Possible solution: Mark custom error category retrieval function with default visibility?
That will work with RTLD_GLOBAL. But what if a SO is loaded with RTLD_LOCAL? That establishes multiple global symbol tables, and once again two instances of the same error category appear.
The exact same problem applies to the RTTI used to catch exception throws. The problem was fixed on libstdc++ by using string comparison to compare RTTI if address comparison failed. libc++ used to noisily take a stand against string comparison and insist on address comparison, but they may since have buckled under the constant bugs about exceptions not being caught.
You have mentioned both memory barriers and RTLD_LOCAL which seem to imply different problems (concurrency versus relocation of weak symbols.)
MSVC has the advantage of controlling its ABI. They invented a thing called _Immortalize which gets specially treated by the linker to instantiate exactly one of the thing ever in a process. As the VS2015 source file says, /* MAGIC */. Because multiple threads could reach the instantiation concurrently, it needs to be a memory barrier so one gets chosen and the others wait.
Please notice that I am interested in singletons in general, not only error categories.
PE and MachO are the least affected by this problem because their creators thought of symbol encapsulation in advance. ELF is severely affected by it. The fault is in the ELF spec which assumes a globally visible unique symbol table. I have tried raising this problem with those responsible for ELF on a number of occasions in the past, it was considered not a problem for the linker and ELF folk, they felt it was a C++ problem. Attempting to explain this was not a problem in PE nor MachO nor many other binary formats got me nowhere.
Niall
-- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/
_______________________________________________ Boost-users mailing list [hidden email] http:///user/SendEmail.jtp?type=node&node=4692952&i=0 http://lists.boost.org/mailman/listinfo.cgi/boost-users
------------------------------ If you reply to this email, your message will be added to the discussion below: http://boost.2283326.n4.nabble.com/Compare-boost-system-error-category- tp4692861p4692952.html To unsubscribe from Compare boost::system::error_category, click here http://boost.2283326.n4.nabble.com/template/NamlServlet.jtp?macro=unsubscribe_by_code&node=4692861&code=Y2hyaXN0b3BoZXJwaXN6QGdtYWlsLmNvbXw0NjkyODYxfC04ODIyNjQ5NzI= . NAML http://boost.2283326.n4.nabble.com/template/NamlServlet.jtp?macro=macro_viewer&id=instant_html%21nabble%3Aemail.naml&base=nabble.naml.namespaces.BasicNamespace-nabble.view.web.template.NabbleNamespace-nabble.view.web.template.NodeNamespace&breadcrumbs=notify_subscribers%21nabble%3Aemail.naml-instant_emails%21nabble%3Aemail.naml-send_instant_email%21nabble%3Aemail.naml
-- View this message in context: http://boost.2283326.n4.nabble.com/Compare-boost-system-error-category-tp469... Sent from the Boost - Users mailing list archive at Nabble.com.
On 25/03/2017 23:05, Christopher Pisz via Boost-users wrote:
What would be so wrong with category being an actual number to compare against?
I don't know anyone whom creates classes and operator == using the address of that class. You guys talk about the standard and what not, and admittedly I've never looked inside how they implement things, but I've never had such problems using the STL either.
C++ 14 standard subsection 19.5.1.1: "error_category objects are passed by reference, and two such objects are equal if they have the same address. This means that applications using custom error_category types should create a single object of each such type." Indeed subsection 19.5.1.3 explicitly says that the comparison operator returns (this == &rhs). That puts standard library implementators in a bind. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/
On 3/25/17 7:24 PM, Niall Douglas via Boost-users wrote:
On 25/03/2017 23:05, Christopher Pisz via Boost-users wrote:
What would be so wrong with category being an actual number to compare against?
I don't know anyone whom creates classes and operator == using the address of that class. You guys talk about the standard and what not, and admittedly I've never looked inside how they implement things, but I've never had such problems using the STL either. C++ 14 standard subsection 19.5.1.1:
"error_category objects are passed by reference, and two such objects are equal if they have the same address. This means that applications using custom error_category types should create a single object of each such type."
Indeed subsection 19.5.1.3 explicitly says that the comparison operator returns (this == &rhs). That puts standard library implementators in a bind.
Niall
My guess is that the creators of the standard expect that implementers, and library creators will take the effort to explicitly create their error objects to allow them to really be unique. I think this means that in the presence of things like DLLs in windows and the like, a header only library doesn't work without special help from the linker, as you really need to move such objects into a special DLL to keep them unique, or the library loader needs to be given the references to this object and it picks one of them to satisfy all the references, ignoring the other definitions. For the standard library, this isn't as much of an issue, as it already needs a compiled module, so there is a spot to put them, it just says that if you might have troubles staticly linking to parts of the standard library if you are building such a loadable module, all loadable modules need to refer to the standard library via a loadable module to keep things unique. The issue becomes for library creators who want to try to build a 'header only' library. -- Richard Damon
On 03/26/2017 12:24 AM, Niall Douglas via Boost-users wrote:
Indeed subsection 19.5.1.3 explicitly says that the comparison operator returns (this == &rhs). That puts standard library implementators in a bind.
It does. You should consider submitting a defect to LWG with the excellent description to wrote in your earlier reply.
Indeed subsection 19.5.1.3 explicitly says that the comparison operator returns (this == &rhs). That puts standard library implementators in a bind.
It does. You should consider submitting a defect to LWG with the excellent description to wrote in your earlier reply.
Sorry, probably I wasn't clear: I *have* raised this with the committee already, albeit informally. They are well aware of the problems introduced by the use of shared objects on ELF in practice. The problem is that C++ says nothing about shared object binaries. Implicit throughout the standard is the assumption that monolithic binaries are the sole thing ever produced by a linker, period, and in that use case the standard mandated behaviour works perfectly. If you do anything with C++ that is not generating a monolithic executable, you are officially in UB land where monsters such as the problem described lurk. You are *on your own*, and this is despite most C++ programmers are in this UB land on a daily basis. It is unfortunate that the Modules TS intentionally says absolutely nothing about shared binaries. It could have been an opportunity to fix these issues. But objections to that part of earlier proposals was objected to very early, and they got dropped swiftly. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/
On 3/26/17 5:38 PM, Niall Douglas via Boost-users wrote:
Indeed subsection 19.5.1.3 explicitly says that the comparison operator returns (this == &rhs). That puts standard library implementators in a bind. It does. You should consider submitting a defect to LWG with the excellent description to wrote in your earlier reply. Sorry, probably I wasn't clear: I *have* raised this with the committee already, albeit informally. They are well aware of the problems introduced by the use of shared objects on ELF in practice.
The problem is that C++ says nothing about shared object binaries. Implicit throughout the standard is the assumption that monolithic binaries are the sole thing ever produced by a linker, period, and in that use case the standard mandated behaviour works perfectly. If you do anything with C++ that is not generating a monolithic executable, you are officially in UB land where monsters such as the problem described lurk. You are *on your own*, and this is despite most C++ programmers are in this UB land on a daily basis.
It is unfortunate that the Modules TS intentionally says absolutely nothing about shared binaries. It could have been an opportunity to fix these issues. But objections to that part of earlier proposals was objected to very early, and they got dropped swiftly.
Niall
There is nothing about a shared binary environment that says you are by definition in the Undefined Behavior territory. The question becomes is the implementation (fully) conforming when generating programs in this form. (It can't be UB, as you can generate the problems with a strictly conforming program, which by definition can't have undefined behavior) There definitely are challenges to being conforming in this environment, and the cost to be conforming may be higher than is desired. One solution to the issue is that if your shared library include code that came about by a 'weak' definition (one that multiple definitions are allowed to be generated, but only one placed in the final output), then the library needs to be broken into several smaller libraries, were each group of weak symbols gets moved into its own shared library, in a way the this piece can be match with the same definition from another shared library that also was possibly put into its own shared library. -- Richard Damon
On 03/26/2017 12:05 AM, Christopher Pisz via Boost-users wrote:
What would be so wrong with category being an actual number to compare against?
The challenge is to select a number for a category that is globally unique across translation units. The error equality operators use the address of a singleton as this unique number.
participants (7)
-
Bjorn Reese
-
Christopher Pisz
-
Gavin Lambert
-
james
-
Niall Douglas
-
Richard Damon
-
Thomas Markwalder