$ g++ -v
Using built-in specs.
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu
4.3.3-5ubuntu4' --with-bugurl=file:///usr/share/doc/gcc-4.3/README.Bugs
--enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr
--enable-shared --with-system-zlib --libexecdir=/usr/lib
--without-included-gettext --enable-threads=posix --enable-nls
--with-gxx-include-dir=/usr/include/c++/4.3 --program-suffix=-4.3
--enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc
--enable-mpfr --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.3.3 (Ubuntu 4.3.3-5ubuntu4)
Results so far:
The default configuration (just ./configure) passes make check.
With CXXFLAGS="-g -DNDEBUG -DGTEST_HAS_RTTI=0 -DGOOGLE_PROTOBUF_NO_RTTI
-fno-rtti" PROTOBUF_OPT_FLAG="-O2": make check hangs on the
CustomOptions.OptionLocations test. The stack trace looks like this:
> (gdb) where
> #0 0x00002b85e53005cb in pthread_once () from /lib/libpthread.so.0
> #1 0x0000000000426431 in google::protobuf::GoogleOnceInit (once=0xa7b148, init_func=0x726bfd <protobuf_unittest::protobuf_AssignDesc_google_2fprotobuf_2funittest_5fcustom_5foptions_2eproto()>)
> at ./google/protobuf/stubs/once.h:115
> #2 0x000000000071c3c0 in protobuf_AssignDescriptorsOnce () at google/protobuf/unittest_custom_options.pb.cc:342
> #3 0x000000000071c4c9 in protobuf_unittest::ComplexOpt6::GetMetadata (this=0x262e320) at google/protobuf/unittest_custom_options.pb.cc:3796
> #4 0x00002b85e3ffb67a in google::protobuf::internal::ReflectionOps::Merge (from=@0x262e320, to=0x268f0e0) at ./google/protobuf/message.h:311
> #5 0x000000000071dc4a in protobuf_unittest::ComplexOpt6::MergeFrom (this=0x268f0e0, from=@0x262e320) at google/protobuf/unittest_custom_options.pb.cc:3753
> #6 0x00002b85e3fa844e in google::protobuf::internal::ExtensionSet::MergeFrom (this=0x268f048, other=<value optimized out>) at google/protobuf/extension_set.cc:644
> #7 0x00002b85e3fdf191 in google::protobuf::MessageOptions::MergeFrom (this=0x268f040, from=@0x268a530) at google/protobuf/descriptor.pb.cc:4732
> #8 0x00002b85e3fcebf3 in google::protobuf::DescriptorBuilder::AllocateOptionsImpl<google::protobuf::Descriptor> (this=0x7fffc6d68730, name_scope=@0x268ef40, element_name=@0x268ef40,
> orig_options=@0x268a530, descriptor=0x2687820) at google/protobuf/descriptor.cc:2648
> #9 0x00002b85e3fc6fcb in google::protobuf::DescriptorBuilder::BuildMessage (this=0x7fffc6d68730, proto=@0x268a370, parent=0x0, result=0x2687820) at google/protobuf/descriptor.cc:2625
> #10 0x00002b85e3fc7a86 in google::protobuf::DescriptorBuilder::BuildFile (this=0x7fffc6d68730, proto=@0x7fffc6d687b0) at google/protobuf/descriptor.cc:2814
> #11 0x00002b85e3fc8c5f in google::protobuf::DescriptorPool::BuildFileFromDatabase (this=0x25b6c90, proto=@0x7fffc6d687b0) at google/protobuf/descriptor.cc:2197
> #12 0x00002b85e3fc9c53 in google::protobuf::DescriptorPool::TryFindFileInFallbackDatabase (this=0x25b6c90, name=@0x7fffc6d68ac0) at google/protobuf/descriptor.cc:1230
> #13 0x00002b85e3fc9d40 in google::protobuf::DescriptorPool::FindFileByName (this=0x25b6c90, name=@0x7fffc6d68ac0) at google/protobuf/descriptor.cc:875
> #14 0x0000000000726c3c in protobuf_unittest::protobuf_AssignDesc_google_2fprotobuf_2funittest_5fcustom_5foptions_2eproto () at google/protobuf/unittest_custom_options.pb.cc:79
> #15 0x00002b85e53005d3 in pthread_once () from /lib/libpthread.so.0
> #16 0x0000000000426431 in google::protobuf::GoogleOnceInit (once=0xa7b148, init_func=0x726bfd <protobuf_unittest::protobuf_AssignDesc_google_2fprotobuf_2funittest_5fcustom_5foptions_2eproto()>)
> at ./google/protobuf/stubs/once.h:115
> #17 0x000000000071c3c0 in protobuf_AssignDescriptorsOnce () at google/protobuf/unittest_custom_options.pb.cc:342
> #18 0x000000000071ca01 in protobuf_unittest::TestMessageWithCustomOptions::descriptor () at google/protobuf/unittest_custom_options.pb.cc:766
> #19 0x0000000000479d88 in google::protobuf::descriptor_unittest::CustomOptions_OptionLocations_Test::TestBody (this=0x262eab0) at google/protobuf/descriptor_unittest.cc:1956
> #20 0x00002b85e44ec225 in testing::Test::Run (this=0x262eab0) at src/gtest.cc:2135
> #21 0x00002b85e44f14de in testing::internal::TestInfoImpl::Run (this=0x260e980) at src/gtest.cc:2355
> #22 0x00002b85e44f9716 in testing::internal::TestInfoImpl::RunTest (test_info=0x260e960) at ./src/gtest-internal-inl.h:496
> #23 0x00002b85e44f22be in testing::internal::Vector<testing::TestInfo*>::ForEach<void (*)(testing::TestInfo*)> (this=0x260eb40,
> functor=0x2b85e44f96f9 <testing::internal::TestInfoImpl::RunTest(testing::TestInfo*)>) at ./src/gtest-internal-inl.h:344
> #24 0x00002b85e44f13c9 in testing::internal::TestCase::Run (this=0x260eaf0) at src/gtest.cc:2455
> #25 0x00002b85e44f96f7 in testing::internal::TestCase::RunTestCase (test_case=0x260eaf0) at ./include/gtest/gtest.h:703
> #26 0x00002b85e44f1f56 in testing::internal::Vector<testing::internal::TestCase*>::ForEach<void (*)(testing::internal::TestCase*)> (this=0x25c8a20,
> functor=0x2b85e44f96e2 <testing::internal::TestCase::RunTestCase(testing::internal::TestCase*)>) at ./src/gtest-internal-inl.h:344
> #27 0x00002b85e44f1214 in testing::internal::UnitTestImpl::RunAllTests (this=0x25c89a0) at src/gtest.cc:3814
> #28 0x00002b85e44f132d in testing::UnitTest::Run (this=0x2b85e4714fd0) at src/gtest.cc:3544
> #29 0x00002b85e4716a5d in main (argc=1, argv=0x7fffc6d69148) at src/gtest_main.cc:38
> #30 0x00002b85e552f5a6 in __libc_start_main () from /lib/libc.so.6
> #31 0x0000000000415f69 in _start () at ../sysdeps/x86_64/elf/start.S:113
Running just that test in isolation (./protobuf-test
--gtest_filter=CustomOptions.*) fails in the same way.
Running just the GoogleOnceInit tests (./protobuf-test
--gtest_filter=OnceInitTest.*) passes.
Configuring with CXXFLAGS="-g -DNDEBUG -DGOOGLE_PROTOBUF_NO_RTTI"
PROTOBUF_OPT_FLAG="-O2" fails in the same way.
The difference in behaviour is in this bit of generated code:
> void MessageOptions::MergeFrom(const ::google::protobuf::Message& from) {
> GOOGLE_CHECK_NE(&from, this);
> const MessageOptions* source =
> ::google::protobuf::internal::dynamic_cast_if_available<const MessageOptions*>(
> &from);
> if (source == NULL) {
> ::google::protobuf::internal::ReflectionOps::Merge(from, this);
> } else {
> MergeFrom(*source);
> }
> }
When GOOGLE_PROTOBUF_NO_RTTI is defined, dynamic_cast_if_available will
always return NULL and a different code path runs.
I see some search results that say that pthread_once() can deadlock if
called recursively with the same argument, so presumably the root issue
is that GoogleOnceInit doesn't avoid doing that.
-O
>> #4 0x00002b85e3ffb67a in google::protobuf::internal::ReflectionOps::Merge (from=@0x262e320, to=0x268f0e0) at ./google/protobuf/message.h:311
>> #5 0x000000000071dc4a in protobuf_unittest::ComplexOpt6::MergeFrom (this=0x268f0e0, from=@0x262e320) at google/protobuf/unittest_custom_options.pb.cc:3753
>> #6 0x00002b85e3fa844e in google::protobuf::internal::ExtensionSet::MergeFrom (this=0x268f048, other=<value optimized out>) at google/protobuf/extension_set.cc:644
>> #7 0x00002b85e3fdf191 in google::protobuf::MessageOptions::MergeFrom (this=0x268f040, from=@0x268a530) at google/protobuf/descriptor.pb.cc:4732
> The difference in behaviour is in this bit of generated code:
>
>> void MessageOptions::MergeFrom(const ::google::protobuf::Message& from) {
Sorry, wrong bit of code. The MessageOptions::MergeFrom in the
stacktrace is actually the "const MessageOptions &from" variant. It
looks like it's actually ComplexOpt6::MergeFrom that differs in
behaviour with RTTI off.
-O