Эта ошибка появилась у меня в контексте исполняемого файла, связанного с двумя библиотеками (LibA
, LibB
), обе из которых компилировали одно и то же прото-сообщение, где LibB
зависит от LibA
и ссылается на него.
Я столкнулся с этой ситуацией из-за того, что LibA
ранее не зависел ни от какой из инфраструктур протобуфера, а LibB
создал полный набор соответствующих прото-сообщений для этого внутреннего инструментального приложения для связи с другим приложением. С новым выпуском LibA
потребовались новые зависимости от двух других библиотек, которые компилируют различные прото-сообщения (LibC
, LibD
). Проблема проявилась одинаково как с LibC
, так и с LibD
, я буду обсуждать LibC
, так как решение было идентичным.
Во время загрузки приложение загружало LibC
, и, в конце концов, оно загружало самый верхний модуль LibB
, и именно тогда срабатывало прерывание в LogMessage::Finish()
в common.cc
. Я обнаружил, кто выполняет эту двойную загрузку, установив точку останова на несколько уровней выше контекста прерывания. Вот соответствующий источник для прото-сообщения с двойной загрузкой, которое я вызываю SomeMessage
…
void LibC_AddDesc_SomeMessage_2eproto() {
static bool already_here = false; // <--- Breakpoint Set Here
if (already_here) return;
already_here = true;
Точка останова 1: загрузка LibC
LibC.dll!MyNamespace::LibC_AddDesc_SomeMessage_2eproto() Line 415 C++
LibC.dll!MyNamespace::LibC_AddDesc_ParentMessage_2eproto() Line 388 C++
LibC.dll!MyNamespace::StaticDescriptorInitializer_ParentMessage_2eproto::StaticDescriptorInitializer_ParentMessage_2eproto() Line 494 C++
LibC.dll!MyNamespace::`dynamic initializer for 'static_descriptor_initializer_ParentMessage_2eproto_''() Line 495 + 0x21 bytes C++
msvcr100d.dll!_initterm() + 0x2c bytes
LibC.dll!_CRT_INIT(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 289 C
LibC.dll!__DllMainCRTStartup(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 506 + 0x13 bytes C
LibC.dll!_DllMainCRTStartup(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 477 C
ntdll.dll!LdrpRunInitializeRoutines() + 0x1e8 bytes
ntdll.dll!LdrpInitializeProcess() - 0x14c9 bytes
ntdll.dll!string "Enabling heap debug options\n"() + 0x29a99 bytes
ntdll.dll!LdrInitializeThunk() + 0xe bytes
Во время загрузки LibC я мог видеть, что точка останова сработала дважды, а статическая переменная already_here
была установлена с false на true, удерживалась в true и пропустила регистрацию этого сообщения.
Точка останова 2: загрузка LibB
Когда эта библиотека попытается загрузить, переменная already_here
будет повторно инициализирована значением false, и мы попытаемся зарегистрировать это сообщение во второй раз, что вызовет прерывание.
LibB.dll!MyNamespace::LibC_AddDesc_SomeMessage_2eproto() Line 415 C++
LibB.dll!MyNamespace::LibC_AddDesc_ParentMessage_2eproto() Line 388 C++
LibB.dll!MyNamespace::LibC_AddDesc_FullMessage_2eproto() Line 219 C++
LibB.dll!MyNamespace::StaticDescriptorInitializer_FullMessage_2eproto::StaticDescriptorInitializer_FullMessage_2eproto() Line 358 C++
LibB.dll!MyNamespace::`dynamic initializer for 'static_descriptor_initializer_FullMessage_2eproto_''() Line 359 + 0x21 bytes C++
msvcr100d.dll!_initterm() + 0x2c bytes
LibB.dll!_CRT_INIT(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 289 C
LibB.dll!__DllMainCRTStartup(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 506 + 0x13 bytes C
LibB.dll!_DllMainCRTStartup(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 477 C
ntdll.dll!LdrpRunInitializeRoutines() + 0x1e8 bytes
ntdll.dll!LdrpInitializeProcess() - 0x14c9 bytes
ntdll.dll!string "Enabling heap debug options\n"() + 0x29a99 bytes
ntdll.dll!LdrInitializeThunk() + 0xe bytes
... и мы оказывались бы в stubs/common.cc в строке прерывания
void LogMessage::Finish() {
bool suppress = false;
if (level_ != LOGLEVEL_FATAL) {
InitLogSilencerCountOnce();
MutexLock lock(log_silencer_count_mutex_);
suppress = internal::log_silencer_count_ > 0;
}
if (!suppress) {
internal::log_handler_(level_, filename_, line_, message_);
}
if (level_ == LOGLEVEL_FATAL) {
abort(); // <----- runtime crash!
}
}
А для std::err вы найдете следующий текст...
libprotobuf ERROR descriptor_database.cc:57] File already exists in database: SomeMessage.proto
libprotobuf FATAL descriptor.cc:860] CHECK failed: generated_database_->Add(encoded_file_descriptor, size):
Решение было простым: я открыл проект LibC
, поискал pb
и удалил эти прото-сообщения из LibB
. То же самое было сделано для LibD
.
person
jxramos
schedule
10.08.2016