Hello folks!

Just the other day, we run into a problem in our C++ project, which we 
tracked down to static initialization order fiasco. Specifically, we have a 
global variable/constant container, which includes elements that have a 
proto object container a map. https://godbolt.org/z/49Mx6h7Yz

What happened is that the global variable "store_t::m_map" is initialized 
first. The stack trace shows that the code in protobuf 
UntypedMapBase::TableEntryIsNonEmptyList() gets executed.
==275==ERROR: ThreadSanitizer: SEGV on unknown address 0x0001c8c56070 (pc 
0x7f347b67db2a bp 0x7ffdd006baf0 sp 0x7ffdd006ba90 T275) ==275==The signal 
is caused by a READ memory access. #0 
google::protobuf::internal::UntypedMapBase::TableEntryIsNonEmptyList(unsigned 
long) const 
bazel-out/k8-dbg/bin/external/com_google_protobuf/src/google/protobuf/_virtual_includes/protobuf_lite/google/protobuf/map.h:514
 
#1 google::protobuf::internal::UntypedMapBase::NodeAndBucket 
google::protobuf::internal::KeyMapBase<std::__cxx11::basic_string<char, 
std::char_traits<char>, std::allocator<char> > >::FindHelper<char 
const*>(char const* const&, 
absl::container_internal::btree_iterator<absl::container_internal::btree_node<absl::container_internal::map_params<std::reference_wrapper<std::__cxx11::basic_string<char,
 
std::char_traits<char>, std::allocator<char> > const>, 
google::protobuf::internal::NodeBase*, 
google::protobuf::internal::TransparentSupport<std::__cxx11::basic_string<char, 
std::char_traits<char>, std::allocator<char> > >::less, 
google::protobuf::internal::MapAllocator<std::pair<std::reference_wrapper<std::__cxx11::basic_string<char,
 
std::char_traits<char>, std::allocator<char> > const> const, 
google::protobuf::internal::NodeBase*> >, 256, false> >, 
std::pair<std::reference_wrapper<std::__cxx11::basic_string<char, 
std::char_traits<char>, std::allocator<char> > const> const, 
google::protobuf::internal::NodeBase*>&, 
std::pair<std::reference_wrapper<std::__cxx11::basic_string<char, 
std::char_traits<char>, std::allocator<char> > const> const, 
google::protobuf::internal::NodeBase*>*>*) const 
bazel-out/k8-dbg/bin/external/com_google_protobuf/src/google/protobuf/_virtual_includes/protobuf_lite/google/protobuf/map.h:767
 
#2 std::pair<google::protobuf::Map<std::__cxx11::basic_string<char, 
std::char_traits<char>, std::allocator<char> >, 
md::redundancyType>::iterator, bool> 
google::protobuf::Map<std::__cxx11::basic_string<char, 
std::char_traits<char>, std::allocator<char> >, 
md::redundancyType>::TryEmplaceInternal<char const* const&>(char const* 
const&) 
bazel-out/k8-dbg/bin/external/com_google_protobuf/src/google/protobuf/_virtual_includes/protobuf_lite/google/protobuf/map.h:1463
 
#3 std::pair<google::protobuf::Map<std::__cxx11::basic_string<char, 
std::char_traits<char>, std::allocator<char> >, 
md::redundancyType>::iterator, bool> 
google::protobuf::Map<std::__cxx11::basic_string<char, 
std::char_traits<char>, std::allocator<char> >, 
md::redundancyType>::ArenaAwareTryEmplace<char const* 
const&>(std::integral_constant<bool, false>, char const* const&) 
bazel-out/k8-dbg/bin/external/com_google_protobuf/src/google/protobuf/_virtual_includes/protobuf_lite/google/protobuf/map.h:1532
 
#4 std::pair<google::protobuf::Map<std::__cxx11::basic_string<char, 
std::char_traits<char>, std::allocator<char> >, 
md::redundancyType>::iterator, bool> 
google::protobuf::Map<std::__cxx11::basic_string<char, 
std::char_traits<char>, std::allocator<char> >, 
md::redundancyType>::try_emplace<char const* const&>(char const* const&) 
bazel-out/k8-dbg/bin/external/com_google_protobuf/src/google/protobuf/_virtual_includes/protobuf_lite/google/protobuf/map.h:1300
 
#5 md::redundancyType& 
google::protobuf::Map<std::__cxx11::basic_string<char, 
std::char_traits<char>, std::allocator<char> >, 
md::redundancyType>::operator[]<char const*>(char const* const&) 
bazel-out/k8-dbg/bin/external/com_google_protobuf/src/google/protobuf/_virtual_includes/protobuf_lite/google/protobuf/map.h:1222
 
#6 info_t::constructTI() src/info.cpp:62 #7 info_t::info_t(int) 
src/info.cpp:23 #8 __static_initialization_and_destruction_0 store.cpp:37 
This sigsegv happens if "kGlobalEmptyTable" in protobuf/map.cc was not yet 
initialized and an invalid pointer is dereferenced in 
UntypedMapBase::TableEntryIsNonEmptyList().

I'd like to submit a patch that move the global variable definition inside 
a function, i.e.a a block-scope variable with static storage duration. I'd 
also use an std::array to define "kGlobalEmptyTable". Are there any 
concerns with doing this?

Regards,
Knut Stolze

-- 
You received this message because you are subscribed to the Google Groups 
"Protocol Buffers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/protobuf/b63ec52c-059d-442b-9b17-061f3da469a1n%40googlegroups.com.

Reply via email to