[boost.intrusive] Assertion failure with SunCC
The following simple program crashes with assertion failure when compiled under
Solaris 11 with SunCC: Sun C++ 5.8 Patch 121018-10 2007/02/21
Assertion failed: node_algorithms::unique(to_insert),
file boost/boost/intrusive/list.hpp, line 168
I'm using the latest Boost.Intrusive from CVS (snapshot taken 2007-06-03).
I have tracked the problem, but I don't know wheter it's the code or compiler
problem; see below the code for cause.
== Begin code
// Program to demonstrate a bug with SunCC and member hooks.
#include
Hi Zeljko, Zeljko Vrba wrote:
The following simple program crashes with assertion failure when compiled under Solaris 11 with SunCC: Sun C++ 5.8 Patch 121018-10 2007/02/21
Assertion failed: node_algorithms::unique(to_insert), file boost/boost/intrusive/list.hpp, line 168
I'm using the latest Boost.Intrusive from CVS (snapshot taken 2007-06-03). I have tracked the problem, but I don't know wheter it's the code or compiler problem; see below the code for cause.
Now I must confess it: Boost.Intrusive uses a non-standard and
non-portable hack to make member hooks as small as base hooks. This hack
uses the fact that for a member stored in a class or in a superclass
without any virtual inheritance relationship a pointer to member is just
the offset of that member in the class. This offset is encoded
differently for different compilers. If you see the file
boost/intrusive/detail/parent_from_member.hpp you have the following
function:
template
On Mon, Jun 04, 2007 at 05:10:31PM +0200, Ion Gaztañaga wrote:
Since I don't have access to a SunCC compiler you will need to help me discover how SunCC implements pointer to data members. I will need for
It's downloadable for free, both for Linux and Solaris :)
example the size of a pointer to data member (a simple sizeof(ptr_to_member) would be enough), and what the binary value of of that pointer to member for different layouts, say:
The program at the bottom prints the following for NN=10 and NN=20:
4 45
4 85
Do you need more information?
==
#include <iostream>
#include
Zeljko Vrba wrote:
On Mon, Jun 04, 2007 at 05:10:31PM +0200, Ion Gaztañaga wrote:
Since I don't have access to a SunCC compiler you will need to help me discover how SunCC implements pointer to data members. I will need for
It's downloadable for free, both for Linux and Solaris :)
I've just started downloading Solaris Express for Developers, but it's taking a while ;-)
The program at the bottom prints the following for NN=10 and NN=20:
4 45 4 85
I'm a bit puzzled, because it seems odd that the hook is not aligned to 4 bytes even if you have a char between data and the hook. The compiler might be reordering things a bit. Could you check the real distance between klass and hook_? Something like: int main(void) { using std::cout; using std::endl; klass k; cout << ((char*)k.hook_ - (char*)k)sizeof(ptr) << endl; return 0; } If the distance is exactly 45 and 85 then you can try to add sunCC detection in the first part of the parent from member function and see if everything goes well. If the real distance is something different, we'll need to try something new. Thanks for the help, Ion
On Mon, Jun 04, 2007 at 08:54:03PM +0200, Ion Gaztañaga wrote:
I'm a bit puzzled, because it seems odd that the hook is not aligned to 4 bytes even if you have a char between data and the hook. The compiler might be reordering things a bit.
No, the data stored in the pointer-to-member is *not* the "real" offset, contrary to your assumption :) When checking in the debugger, the hook is aligned properly.
Could you check the real distance between klass and hook_? Something like:
The statement (after adding 'klass k' in the local scope of main())
cout << (char*)&k.hook_ - (char*)&k << endl;
prints out 84.
Furthermore, given the following program:
==
#include
Zeljko Vrba wrote:
No, the data stored in the pointer-to-member is *not* the "real" offset, contrary to your assumption :) When checking in the debugger, the hook is aligned properly.
I just realized about this just after sending my previous mail. SunCC seems to use the classical cfront approach encoding a pointer to member as offset + 1. So it seems that parent_from_member detection is correct for SunCC.
Could you check the real distance between klass and hook_? Something like:
The statement (after adding 'klass k' in the local scope of main())
cout << (char*)&k.hook_ - (char*)&k << endl;
prints out 84.
Thanks. Really useful information.
Furthermore, given the following program: [snip]
int main(void) { Gl.push_back(Gd); return 0; } [snip] So, the "to_insert" does not point to the hook address, but to the very beginning of the structure.
So the problem lies in ValueTraits::to_node_ptr() which just should use the pointer to member template to get the address of the hook. But for some reason, it does not work. The real logic for the conversion is boost/intrusive/detail/utilities.hpp in the member_value_traits class: static node_ptr to_node_ptr(reference value) { MemberHookType* result = &(value.*P); return result->to_node_ptr(); } So I'm a bit puzzled this does not work (we are not using the non-standard hack here). If you can debug it further, let me know. Meanwhile, I will download the SunCC version for Linux to see what happens. Thanks again for your help, Ion
On Tue, Jun 05, 2007 at 04:35:16PM +0200, Ion Gaztañaga wrote:
I just realized about this just after sending my previous mail. SunCC seems to use the classical cfront approach encoding a pointer to member as offset + 1. So it seems that parent_from_member detection is correct for SunCC.
Slightly off-topic, but: do you know the background WHY did they decide to implement ptr-to-member as offset +1?
boost/intrusive/detail/utilities.hpp in the member_value_traits class:
static node_ptr to_node_ptr(reference value) { MemberHookType* result = &(value.*P); return result->to_node_ptr(); }
I have tracked the conversion to here myself. I wondered whether this was
a compiler bug, but the following simple program works, ie. it does NOT
raise an assertion failure. I hope I managed to reproduce correctly the
usage pattern of ptr-to-member..
==
#include
Zeljko Vrba wrote:
On Tue, Jun 05, 2007 at 04:35:16PM +0200, Ion Gaztañaga wrote:
I just realized about this just after sending my previous mail. SunCC seems to use the classical cfront approach encoding a pointer to member as offset + 1. So it seems that parent_from_member detection is correct for SunCC.
Slightly off-topic, but: do you know the background WHY did they decide to implement ptr-to-member as offset +1?
Because you need to represent a null pointer to data member. So they choose to represent a null pointer to member as 0 (which is a valid offset inside the object) and add 1 to the valid offset to represent a valid offset. The offset + 1 approach is shared by more implementations (CW for windows and Digital Mars, for example). This was the historical presentation C-front chose, so I think many compilers implement it like that because of this historical heritage. Other implementations used another encoding. For example, the Itanium C++ ABI says (http://www.codesourcery.com/cxx-abi/abi.html#member-pointers): "A pointer to data member is an offset from the base address of the class object containing it, represented as a ptrdiff_t. It has the size and alignment attributes of a ptrdiff_t. A NULL pointer is represented as -1."
I have tracked the conversion to here myself. I wondered whether this was a compiler bug, but the following simple program works, ie. it does NOT raise an assertion failure. I hope I managed to reproduce correctly the usage pattern of ptr-to-member..
[snip]
I'm kinda clueless as how to proceed from here. If it _is_ a genuine compiler bug, we need a more complex test-case, which I'm unable to produce myself (as I don't know how many intermediate instantiation steps there are in the intrusive library).
This seems a strange issue. I'll try to investigate it when I install the Sun compiler. Thanks for your effort! Ion
Ion Gaztanaga wrote:
P.S.: I'm not sure if EDG-based compilers and HP compiler work because I don't have such compilers. If someone wants to help on those, I would be glad.
Below are the results on HP-UX/ia64 in 32- and 64-bit pointer mode using
the program posted by Zeljko Vrba.
The compiler on HP-UX/ia64 is EDG-based so checking both __HP_aCC and
__EDG_VERSION__ in boost/intrusive/detail/parent_from_member.hpp is
reduntant.
bash-2.03$ aCC -V
aCC: HP C/aC++ B3910B A.06.14 [Feb 22 2007]
bash-2.03$ aCC -I./boost -DNN=10 x.cpp && a.out
4 44
bash-2.03$ aCC -I./boost -DNN=20 x.cpp && a.out
4 84
bash-2.03$ aCC -I./boost -DNN=10 +DD64 x.cpp && a.out
8 88
bash-2.03$ aCC -I./boost -DNN=20 +DD64 x.cpp && a.out
8 168
bash-2.03$
x.cpp
-----
#include <iostream>
#include
Hi Zeljko,
Zeljko Vrba wrote:
The following simple program crashes with assertion failure when compiled under Solaris 11 with SunCC: Sun C++ 5.8 Patch 121018-10 2007/02/21
Assertion failed: node_algorithms::unique(to_insert), file boost/boost/intrusive/list.hpp, line 168
I'm using the latest Boost.Intrusive from CVS (snapshot taken 2007-06-03). I have tracked the problem, but I don't know wheter it's the code or compiler problem; see below the code for cause.
Now I must confess it: Boost.Intrusive uses a non-standard and non-portable hack to make member hooks as small as base hooks. This hack uses the fact that for a member stored in a class or in a superclass without any virtual inheritance relationship a pointer to member is just the offset of that member in the class. This offset is encoded differently for different compilers. If you see the file boost/intrusive/detail/parent_from_member.hpp you have the following function:
template
std::size_t offset_from_pointer_to_member(const Member Parent::* ptr_to_member) { //The implementation of a pointer to member is compiler dependent. #if defined(BOOST_MSVC) || defined(__GNUC__) || \ defined(BOOST_INTEL) || defined(__HP_aCC) || \ defined(__EDG_VERSION__) //This works with gcc, msvc, edg, ac++ return *(const std::size_t*)(const void*)&ptr_to_member; #else //This is the traditional C-front approach: CW 9.4, dmc return *(const std::size_t*)(const void*)&ptr_to_member - 1; #endif } This function takes a pointer to member and tries to guess the offset between the class that owns the member and the member. As you can see, for Visual, Intel and GCC a pointer to data member it's just the offset. For compilers like DMC and CW is the offset minus 1.
Since I don't have access to a SunCC compiler you will need to help me discover how SunCC implements pointer to data members. I will need for example the size of a pointer to data member (a simple sizeof(ptr_to_member) would be enough), and what the binary value of of that pointer to member for different layouts, say:
struct klass {
void *data_klass[N];
boost::intrusive::list_member_hook<> hook_;
typedef boost::intrusive::list<
boost::intrusive::list_member_hook<>::value_traits<
klass, &klass::hook_>,
false> list;
};
changing the value of N. Willing to help?
Regards,
Ion
P.S.: I'm not sure if EDG-based compilers and HP compiler work because I don't have such compilers. If someone wants to help on those, I would be glad. _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Boris Gubenko wrote:
Ion Gaztanaga wrote:
P.S.: I'm not sure if EDG-based compilers and HP compiler work because I don't have such compilers. If someone wants to help on those, I would be glad.
Below are the results on HP-UX/ia64 in 32- and 64-bit pointer mode using the program posted by Zeljko Vrba.
The compiler on HP-UX/ia64 is EDG-based so checking both __HP_aCC and __EDG_VERSION__ in boost/intrusive/detail/parent_from_member.hpp is reduntant.
bash-2.03$ aCC -V aCC: HP C/aC++ B3910B A.06.14 [Feb 22 2007] bash-2.03$ aCC -I./boost -DNN=10 x.cpp && a.out 4 44 bash-2.03$ aCC -I./boost -DNN=20 x.cpp && a.out 4 84 bash-2.03$ aCC -I./boost -DNN=10 +DD64 x.cpp && a.out 8 88 bash-2.03$ aCC -I./boost -DNN=20 +DD64 x.cpp && a.out 8 168 bash-2.03$
So it seems that the compiler aligns the hook to 4 bytes: void *data_[NN]; //4*NN bytes char ch_; //1 byte plus alignment so the trick used to extract the offset in parent_from_member function is adequate. But the regression tests for Intrusive with HP aCC: http://engineering.meta-comm.com/boost-regression/CVS-HEAD/developer/intrusi... seems to fail in tests using member hooks. A bit strange. Can you check the real distance between members with something like: int main(void) { using std::cout; using std::endl; klass k; cout << ((char*)k.hook_ - (char*)k) << endl; return 0; } If the distance is equal to the raw values extracted from the pointer to data member, then regression test failures might be provoked by another library bug. Regards, Ion
Ion Gaztanaga wrote:
If the distance is equal to the raw values ...
It is equal:
bash-2.03$ aCC -I./boost -DNN=10 x.cpp && a.out
4 44
44
bash-2.03$ aCC -I./boost -DNN=20 x.cpp && a.out
4 84
84
bash-2.03$ aCC -I./boost -DNN=10 +DD64 x.cpp && a.out
8 88
88
bash-2.03$ aCC -I./boost -DNN=20 +DD64 x.cpp && a.out
8 168
168
bash-2.03$
x.cpp
-----
#include <iostream>
#include
Boris Gubenko wrote:
Ion Gaztanaga wrote:
P.S.: I'm not sure if EDG-based compilers and HP compiler work because I don't have such compilers. If someone wants to help on those, I would be glad.
Below are the results on HP-UX/ia64 in 32- and 64-bit pointer mode using the program posted by Zeljko Vrba.
The compiler on HP-UX/ia64 is EDG-based so checking both __HP_aCC and __EDG_VERSION__ in boost/intrusive/detail/parent_from_member.hpp is reduntant.
bash-2.03$ aCC -V aCC: HP C/aC++ B3910B A.06.14 [Feb 22 2007] bash-2.03$ aCC -I./boost -DNN=10 x.cpp && a.out 4 44 bash-2.03$ aCC -I./boost -DNN=20 x.cpp && a.out 4 84 bash-2.03$ aCC -I./boost -DNN=10 +DD64 x.cpp && a.out 8 88 bash-2.03$ aCC -I./boost -DNN=20 +DD64 x.cpp && a.out 8 168 bash-2.03$
So it seems that the compiler aligns the hook to 4 bytes:
void *data_[NN]; //4*NN bytes char ch_; //1 byte plus alignment
so the trick used to extract the offset in parent_from_member function is adequate. But the regression tests for Intrusive with HP aCC:
http://engineering.meta-comm.com/boost-regression/CVS-HEAD/developer/intrusi...
seems to fail in tests using member hooks. A bit strange. Can you check the real distance between members with something like:
int main(void) { using std::cout; using std::endl; klass k; cout << ((char*)k.hook_ - (char*)k) << endl; return 0; }
If the distance is equal to the raw values extracted from the pointer to data member, then regression test failures might be provoked by another library bug.
Regards,
Ion _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Boris Gubenko wrote:
Ion Gaztanaga wrote:
If the distance is equal to the raw values ...
It is equal:
Thanks for your info. So aCC pointer to member is really the offset. This means that parent_from_member function is correctly configured for aCC but for some other reason regression tests fail. Regards, Ion
Hi,
On 6/4/07, Ion Gaztañaga
P.S.: I'm not sure if EDG-based compilers and HP compiler work because I don't have such compilers. If someone wants to help on those, I would be glad.
For HP development environment, you can create an account at: http://www.testdrive.hp.com/ They offer free accounts on a whole range of HP operating systems and architectures. with best regards, dhruva -- Dhruva Krishnamurthy Contents reflect my personal views only!
dhruva wrote:
For HP development environment, you can create an account at: http://www.testdrive.hp.com/ They offer free accounts on a whole range of HP operating systems and architectures.
Thanks! I tried the sourceforge compiler farm but they shut it down. Glad to know there is still hope. Regards, Ion
participants (5)
-
Boris Gubenko
-
dhruva
-
Ion Gaztañaga
-
Zeljko Vrba
-
Zeljko Vrba