Protobuf ShortDebugString() 崩溃
Protobuf ShortDebugString() crash
我有以下原型:
syntax = "proto3";
package pb;
message FooBar {
string foo = 1;
string bar = 2;
}
message FooBarList {
repeated FooBar foobar = 1;
}
我只是用 2 个值填充重复列表并尝试按如下方式打印它:
#include <iostream>
#include "foobar.pb.h"
int main()
{
pb::FooBarList foobar_list;
auto foobar1 = foobar_list.add_foobar();
foobar1->set_foo("foo1");
foobar1->set_bar("bar1");
auto foobar2 = foobar_list.add_foobar();
foobar2->set_foo("foo2");
foobar2->set_bar("bar2");
try {
std::cout << foobar_list.ShortDebugString() << std::endl;
}
catch (const std::exception& e) {
std::cout << "error: " << e.what() << std::endl;
return -1;
}
return 0;
}
这会生成以下输出:
error: Unknown error -1
因此,ShortDebugString()
触发了一个没有任何有意义信息的异常。
我做错了什么,还是我需要以某种方式在调用 ShortDebugString()
之前触发序列化?
这是 gdb callstack
如果我让异常传播:
Program received signal SIGABRT, Aborted.
0x00007ffff7add355 in raise () from /usr/lib/libc.so.6
(gdb) bt
#0 0x00007ffff7add355 in raise () from /usr/lib/libc.so.6
#1 0x00007ffff7ac6853 in abort () from /usr/lib/libc.so.6
#2 0x00007ffff7e5d86a in __gnu_cxx::__verbose_terminate_handler () at /build/gcc/src/gcc/libstdc++-v3/libsupc++/vterminate.cc:95
#3 0x00007ffff7e69d8a in __cxxabiv1::__terminate (handler=<optimized out>) at /build/gcc/src/gcc/libstdc++-v3/libsupc++/eh_terminate.cc:48
#4 0x00007ffff7e69df7 in std::terminate () at /build/gcc/src/gcc/libstdc++-v3/libsupc++/eh_terminate.cc:58
#5 0x00007ffff7e6a09e in __cxxabiv1::__cxa_throw (obj=obj@entry=0x5555556e1550,
tinfo=tinfo@entry=0x7ffff7f97590 <typeinfo for std::system_error>, dest=dest@entry=0x7ffff7e96860 <std::system_error::~system_error()>)
at /build/gcc/src/gcc/libstdc++-v3/libsupc++/eh_throw.cc:95
#6 0x00007ffff7e609bc in std::__throw_system_error (__i=-1)
at /build/gcc/src/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/ext/new_allocator.h:89
#7 0x00005555555a1018 in google::protobuf::internal::AssignDescriptors(google::protobuf::internal::DescriptorTable const*, bool) ()
#8 0x000055555556e77f in pb::FooBarList::GetMetadataStatic() ()
#9 0x000055555556ceb9 in pb::FooBarList::GetMetadata() const ()
#10 0x00005555555d1fb4 in google::protobuf::TextFormat::Printer::Print(google::protobuf::Message const&, google::protobuf::TextFormat::Printer::TextGenerator*) const ()
#11 0x00005555555d3ef9 in google::protobuf::Message::ShortDebugString[abi:cxx11]() const ()
#12 0x00005555555705ac in main ()
(gdb)
编辑
这是用于构建此项目的 CMakeLists.txt
:
cmake_minimum_required(VERSION 3.10)
project(proto-foobar)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(Protobuf_USE_STATIC_LIBS ON)
find_package(Protobuf MODULE REQUIRED)
set(PROTO_DEFINITIONS_PATH "${CMAKE_SOURCE_DIR}/protos")
set(PROTO_DEFINITIONS "${PROTO_DEFINITIONS_PATH}/*.proto")
set(PROTO_OUTPUT_PATH "${CMAKE_SOURCE_DIR}/source")
file(MAKE_DIRECTORY ${PROTO_OUTPUT_PATH})
set(PROTO_HEADERS "${PROTO_OUTPUT_PATH}/foobar.pb.h")
set(PROTO_SOURCES "${PROTO_OUTPUT_PATH}/foobar.pb.cc")
add_custom_command(OUTPUT ${PROTO_HEADERS} ${PROTO_SOURCES}
COMMAND ${PROTOBUF_PROTOC_EXECUTABLE}
ARGS --cpp_out=${PROTO_OUTPUT_PATH}
--proto_path=${PROTO_DEFINITIONS_PATH}
${PROTO_DEFINITIONS}
DEPENDS ${PROTO_DEFINITIONS}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Compiling ${PROJECT_NAME} protos")
file(GLOB_RECURSE PROJECT_FILES "${CMAKE_SOURCE_DIR}/source/*.cpp")
add_executable(${PROJECT_NAME} ${PROTO_SOURCES} ${PROJECT_FILES})
target_link_libraries(${PROJECT_NAME} PUBLIC ${PROTOBUF_LIBRARY})
target_include_directories(${PROJECT_NAME} PUBLIC ${PROTO_OUTPUT_PATH})
这是项目树:
├── CMakeLists.txt
├── protos
│ └── foobar.proto
└── source
├── foobar.pb.cc
├── foobar.pb.h
└── main.cpp
(有完全相同的问题并深入研究了一下。)
本例中的触发器是 this piece of code. It contains (indirectly) a call to std::call_once
,它在 Linux 上使用 pthread_once
实现。反过来,这需要您的二进制文件链接到 pthread
库(即它需要一个 -lpthread
链接器标志)。
如果您的二进制文件没有链接到 pthread
,您会看到您看到的错误,如前所述 以及修复此问题的方法。
我有以下原型:
syntax = "proto3";
package pb;
message FooBar {
string foo = 1;
string bar = 2;
}
message FooBarList {
repeated FooBar foobar = 1;
}
我只是用 2 个值填充重复列表并尝试按如下方式打印它:
#include <iostream>
#include "foobar.pb.h"
int main()
{
pb::FooBarList foobar_list;
auto foobar1 = foobar_list.add_foobar();
foobar1->set_foo("foo1");
foobar1->set_bar("bar1");
auto foobar2 = foobar_list.add_foobar();
foobar2->set_foo("foo2");
foobar2->set_bar("bar2");
try {
std::cout << foobar_list.ShortDebugString() << std::endl;
}
catch (const std::exception& e) {
std::cout << "error: " << e.what() << std::endl;
return -1;
}
return 0;
}
这会生成以下输出:
error: Unknown error -1
因此,ShortDebugString()
触发了一个没有任何有意义信息的异常。
我做错了什么,还是我需要以某种方式在调用 ShortDebugString()
之前触发序列化?
这是 gdb callstack
如果我让异常传播:
Program received signal SIGABRT, Aborted.
0x00007ffff7add355 in raise () from /usr/lib/libc.so.6
(gdb) bt
#0 0x00007ffff7add355 in raise () from /usr/lib/libc.so.6
#1 0x00007ffff7ac6853 in abort () from /usr/lib/libc.so.6
#2 0x00007ffff7e5d86a in __gnu_cxx::__verbose_terminate_handler () at /build/gcc/src/gcc/libstdc++-v3/libsupc++/vterminate.cc:95
#3 0x00007ffff7e69d8a in __cxxabiv1::__terminate (handler=<optimized out>) at /build/gcc/src/gcc/libstdc++-v3/libsupc++/eh_terminate.cc:48
#4 0x00007ffff7e69df7 in std::terminate () at /build/gcc/src/gcc/libstdc++-v3/libsupc++/eh_terminate.cc:58
#5 0x00007ffff7e6a09e in __cxxabiv1::__cxa_throw (obj=obj@entry=0x5555556e1550,
tinfo=tinfo@entry=0x7ffff7f97590 <typeinfo for std::system_error>, dest=dest@entry=0x7ffff7e96860 <std::system_error::~system_error()>)
at /build/gcc/src/gcc/libstdc++-v3/libsupc++/eh_throw.cc:95
#6 0x00007ffff7e609bc in std::__throw_system_error (__i=-1)
at /build/gcc/src/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/ext/new_allocator.h:89
#7 0x00005555555a1018 in google::protobuf::internal::AssignDescriptors(google::protobuf::internal::DescriptorTable const*, bool) ()
#8 0x000055555556e77f in pb::FooBarList::GetMetadataStatic() ()
#9 0x000055555556ceb9 in pb::FooBarList::GetMetadata() const ()
#10 0x00005555555d1fb4 in google::protobuf::TextFormat::Printer::Print(google::protobuf::Message const&, google::protobuf::TextFormat::Printer::TextGenerator*) const ()
#11 0x00005555555d3ef9 in google::protobuf::Message::ShortDebugString[abi:cxx11]() const ()
#12 0x00005555555705ac in main ()
(gdb)
编辑
这是用于构建此项目的 CMakeLists.txt
:
cmake_minimum_required(VERSION 3.10)
project(proto-foobar)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(Protobuf_USE_STATIC_LIBS ON)
find_package(Protobuf MODULE REQUIRED)
set(PROTO_DEFINITIONS_PATH "${CMAKE_SOURCE_DIR}/protos")
set(PROTO_DEFINITIONS "${PROTO_DEFINITIONS_PATH}/*.proto")
set(PROTO_OUTPUT_PATH "${CMAKE_SOURCE_DIR}/source")
file(MAKE_DIRECTORY ${PROTO_OUTPUT_PATH})
set(PROTO_HEADERS "${PROTO_OUTPUT_PATH}/foobar.pb.h")
set(PROTO_SOURCES "${PROTO_OUTPUT_PATH}/foobar.pb.cc")
add_custom_command(OUTPUT ${PROTO_HEADERS} ${PROTO_SOURCES}
COMMAND ${PROTOBUF_PROTOC_EXECUTABLE}
ARGS --cpp_out=${PROTO_OUTPUT_PATH}
--proto_path=${PROTO_DEFINITIONS_PATH}
${PROTO_DEFINITIONS}
DEPENDS ${PROTO_DEFINITIONS}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Compiling ${PROJECT_NAME} protos")
file(GLOB_RECURSE PROJECT_FILES "${CMAKE_SOURCE_DIR}/source/*.cpp")
add_executable(${PROJECT_NAME} ${PROTO_SOURCES} ${PROJECT_FILES})
target_link_libraries(${PROJECT_NAME} PUBLIC ${PROTOBUF_LIBRARY})
target_include_directories(${PROJECT_NAME} PUBLIC ${PROTO_OUTPUT_PATH})
这是项目树:
├── CMakeLists.txt
├── protos
│ └── foobar.proto
└── source
├── foobar.pb.cc
├── foobar.pb.h
└── main.cpp
(有完全相同的问题并深入研究了一下。)
本例中的触发器是 this piece of code. It contains (indirectly) a call to std::call_once
,它在 Linux 上使用 pthread_once
实现。反过来,这需要您的二进制文件链接到 pthread
库(即它需要一个 -lpthread
链接器标志)。
如果您的二进制文件没有链接到 pthread
,您会看到您看到的错误,如前所述