protobuf“oneof”子protobuf对象指针杀死程序
Posted
技术标签:
【中文标题】protobuf“oneof”子protobuf对象指针杀死程序【英文标题】:protobuf "oneof" sub-protobuf object pointer kills program 【发布时间】:2019-07-12 23:06:24 【问题描述】:我已经成功使用 google protobufs 一个半月了,我遇到了一个我无法克服的问题。
基本上,我现在正在尝试在 protobufs 中使用 oneof
功能,我可以在单个消息中包含多种类型的消息。基本上,我只需要能够发送 1 条消息,但包含多个不同的子消息选项。我发现很多 SO 帖子都推荐了 oneof
功能,所以现在我正在尝试使用它。
https://developers.google.com/protocol-buffers/docs/proto#oneof
好的,那么问题是什么?
好吧,我的代码得到了一个巨大的堆栈转储。这是多个代码文件。
这是正在崩溃的.cpp
脚本:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <thread>
// First, we need to import the main message proto file.
#include "Robotmessage.pb.h"
// Then we include the sub-message
#include "SimpleController.pb.h"
// This is for cout.
#include <iostream>
// Google
#include <google/protobuf/message.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
// https://***.com/questions/1641182/how-can-i-catch-a-ctrl-c-event
#include <signal.h>
using namespace google::protobuf::io;
using namespace std;
// Ctrl+C handler
void my_handler(int s)
printf("Caught signal %d\n",s);
exit(1);
// simple wrapper for code cleanup
void sleepApp(int ms)
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
int main(int argc, char** argv)
// https://developers.google.com/protocol-buffers/docs/cpptutorial
// Verify that the version of the library that we linked against is
// compatible with the version of the headers we compiled against.
GOOGLE_PROTOBUF_VERIFY_VERSION;
// SIGINT registration
struct sigaction sigIntHandler;
sigIntHandler.sa_handler = my_handler;
sigemptyset(&sigIntHandler.sa_mask);
sigIntHandler.sa_flags = 0;
sigaction(SIGINT, &sigIntHandler, NULL);
// If an event is found, allow for printing.
bool eventupdate = false;
// For debugging
int printcounter = 0;
// I would like to create the object here instead...
//Robotmessage robotdata;
// This is the joystick part of the message
Simplecontroller payload;
string joystickname = "joy_1";
const int joystickid = 12345;
// Joystick characteristics
payload.set_name(joystickname);
payload.set_id(joystickid);
// Joystick axis doubles
payload.set_leftstickx(0);
payload.set_leftsticky(0);
payload.set_rightstickx(0);
payload.set_rightsticky(0);
payload.set_lefttrigger(0);
payload.set_righttrigger(0);
// buttons
payload.set_leftstickbutton(true);
payload.set_rightstickbutton(true);
//
payload.set_xbutton(false);
payload.set_abutton(false);
payload.set_ybutton(true);
payload.set_bbutton(true);
//
payload.set_rightbutton(false);
payload.set_leftbutton(false);
//
payload.set_startbutton(true);
payload.set_backbutton(false);
payload.set_centbutton(true);
//
payload.set_pov(11);
// Keep reading the state of the joystick in a loop
while (true)
// Create the new payload object
Robotmessage robotdata;
Simplecontroller * pointeddata = &payload;
// Now we add the joystick payload to the full data holder.
robotdata.Clear();
robotdata.set_msgheader("robot_drive");
robotdata.set_allocated_heartbt(NULL);
// This line works
robotdata.set_allocated_control(NULL);
// THIS LINE DOES NOT WORK!!!!!!!
robotdata.set_allocated_control(pointeddata);
// Show that the script worked.
if (printcounter++ > 2000)
cout << "I worked." << endl;
// Now we clear the object
//payload.Clear();
// Delay so that the socket does not die for some odd reason.
sleepApp(9); // milliseconds
google::protobuf::ShutdownProtobufLibrary();
return 0;
这是我正在使用的.proto
文件:
Heartbeat.proto:
syntax = "proto3";
// protoc --cpp_out=./ SimpleController.proto
message Heartbeat
// Identifiers
int32 beat = 1;
Robotmessage.proto:
syntax = "proto3";
// I need to import the other message definitions
import "Heartbeat.proto";
import "SimpleController.proto";
// protoc --cpp_out=./ SimpleController.proto
message Robotmessage
// Identifiers
string msgheader = 1;
oneof robmessage
Heartbeat heartbt = 2;
Simplecontroller control = 3;
SimpleController.proto:
syntax = "proto3";
// protoc --cpp_out=./ SimpleController.proto
message Simplecontroller
// https://***.com/questions/9496101/protocol-buffer-over-socket-in-c\
// Identifiers
string name = 1;
int32 id = 2;
// 2 axis throttles with integrated buttons
double leftstickX = 3;
double leftstickY = 4;
bool leftstickbutton = 5;
double rightstickX = 6;
double rightstickY = 7;
bool rightstickbutton = 8;
// 2 extra throtle axis
double lefttrigger = 9;
double righttrigger = 10;
// grid of 4 buttons
bool xbutton = 11;
bool abutton = 12;
bool bbutton = 13;
bool ybutton = 14;
// buttons next to triggers.
bool leftbutton = 15;
bool rightbutton = 16;
// butons next to center logo.
bool startbutton = 17;
bool backbutton = 18;
// The center button
bool centbutton = 19;
// The hat on the left
int32 pov = 20;
这是我用来构建代码的CMakeLists.txt
文件:
set(PROJECT_NAME test_protobuf)
cmake_minimum_required(VERSION 3.15 FATAL_ERROR)
PROJECT( $PROJECT_NAME LANGUAGES C CXX )
message(STATUS "Is the C++ compiler loaded? $CMAKE_CXX_COMPILER_LOADED")
if(CMAKE_CXX_COMPILER_LOADED)
message(STATUS "The C++ compiler ID is: $CMAKE_CXX_COMPILER_ID")
message(STATUS "Is the C++ from GNU: $CMAKE_COMPILER_IS_GNUCCX")
message(STATUS "The C++ compiler version is: $CMAKE_CXX_COMPILER_Version")
endif()
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_definitions(-std=c++11)
# CMAKE_CURRENT_SOURCE_DIR - This is the directory where CMake is running.
set(CMAKE_BINARY_DIR $CMAKE_SOURCE_DIR/build)
set(EXECUTABLE_OUTPUT_PATH $CMAKE_BINARY_DIR)
set(LIBRARY_OUTPUT_PATH $CMAKE_BINARY_DIR/lib)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
find_package( Boost REQUIRED system thread timer chrono)
if(Boost_FOUND)
message("Boost was found.")
message($Boost_INCLUDE_DIR)
endif()
set(THE_USER $ENVUSER)
message("This is the com user_:" $THE_USER)
set(PROGRAMS_TO_COMPILE
demobrokeprotobuf
)
set(PROTO_MESSAGES
Robotmessage.proto
SimpleController.proto
Heartbeat.proto
)
# These lines are for autogenerating code from the *.proto files with CMake.
find_package(Protobuf REQUIRED)
if(PROTOBUF_FOUND)
message("Google Protobuf has been found.")
endif()
# Make sure protoc is present, as apparently the above find_package() doesn't check that.
find_program(Protobuf_PROTOC_LOC NAMES protoc)
if (NOT Protobuf_PROTOC_LOC)
message(FATAL_ERROR "Cannot find required 'protoc', cannot process Protobuf files without it. Aborting.")
endif()
# https://cmake.org/cmake/help/git-master/module/FindProtobuf.html
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS $PROTO_MESSAGES)
foreach(aprogram $PROGRAMS_TO_COMPILE)
add_executable($aprogram $PROTO_SRCS $PROTO_HDRS $PROJECT_SOURCE_DIR/$aprogram.cpp)
target_link_libraries($aprogram $Boost_LIBRARIES)
target_link_libraries($aprogram $PROTOBUF_LIBRARIES)
# include directories
# We only include the directories for these specific executables.
target_include_directories($aprogram PRIVATE $Protobuf_INCLUDE_DIRS)
target_include_directories($aprogram PRIVATE $CMAKE_CURRENT_BINARY_DIR)
endforeach()
# Links I have refered to
# https://cmake.org/examples/
# https://***.com/questions/20824194/cmake-with-google-protocol-buffers
# https://***.com/questions/32647517/protocol-buffer-with-cmakelists
# https://***.com/questions/38408486/how-to-build-google-protobuf-environment-with-cmake-on-windows
还有我用来编译所有内容的build.sh
文件:
#!/bin/bash
cmake -H. -Bbuild
availablethreads=`nproc`
cmake --build build -- -j$availablethreads -l$availablethreads
然后,最后,错误:
*** Error in `./build/demobrokeprotobuf': double free or corruption (out): 0x00007ffdad290950 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7fd30e5267e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7fd30e52f37a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7fd30e53353c]
./build/demobrokeprotobuf[0x40733d]
./build/demobrokeprotobuf[0x403ce0]
./build/demobrokeprotobuf[0x4062fd]
./build/demobrokeprotobuf[0x403bbe]
./build/demobrokeprotobuf[0x40d114]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7fd30e4cf830]
./build/demobrokeprotobuf[0x4035c9]
======= Memory map: ========
00400000-00413000 r-xp 00000000 103:03 13111091 /home/$USER/demobrokenprotobuf/build/demobrokeprotobuf
00612000-00613000 r--p 00012000 103:03 13111091 /home/$USER/demobrokenprotobuf/build/demobrokeprotobuf
00613000-00614000 rw-p 00013000 103:03 13111091 /home/$USER/demobrokenprotobuf/build/demobrokeprotobuf
0148d000-014bf000 rw-p 00000000 00:00 0 [heap]
7fd308000000-7fd308021000 rw-p 00000000 00:00 0
7fd308021000-7fd30c000000 ---p 00000000 00:00 0
7fd30df8c000-7fd30e094000 r-xp 00000000 103:03 34879 /lib/x86_64-linux-gnu/libm-2.23.so
7fd30e094000-7fd30e293000 ---p 00108000 103:03 34879 /lib/x86_64-linux-gnu/libm-2.23.so
7fd30e293000-7fd30e294000 r--p 00107000 103:03 34879 /lib/x86_64-linux-gnu/libm-2.23.so
7fd30e294000-7fd30e295000 rw-p 00108000 103:03 34879 /lib/x86_64-linux-gnu/libm-2.23.so
7fd30e295000-7fd30e2ae000 r-xp 00000000 103:03 35030 /lib/x86_64-linux-gnu/libz.so.1.2.8
7fd30e2ae000-7fd30e4ad000 ---p 00019000 103:03 35030 /lib/x86_64-linux-gnu/libz.so.1.2.8
7fd30e4ad000-7fd30e4ae000 r--p 00018000 103:03 35030 /lib/x86_64-linux-gnu/libz.so.1.2.8
7fd30e4ae000-7fd30e4af000 rw-p 00019000 103:03 35030 /lib/x86_64-linux-gnu/libz.so.1.2.8
7fd30e4af000-7fd30e66f000 r-xp 00000000 103:03 34772 /lib/x86_64-linux-gnu/libc-2.23.so
7fd30e66f000-7fd30e86f000 ---p 001c0000 103:03 34772 /lib/x86_64-linux-gnu/libc-2.23.so
7fd30e86f000-7fd30e873000 r--p 001c0000 103:03 34772 /lib/x86_64-linux-gnu/libc-2.23.so
7fd30e873000-7fd30e875000 rw-p 001c4000 103:03 34772 /lib/x86_64-linux-gnu/libc-2.23.so
7fd30e875000-7fd30e879000 rw-p 00000000 00:00 0
7fd30e879000-7fd30e891000 r-xp 00000000 103:03 31752 /lib/x86_64-linux-gnu/libpthread-2.23.so
7fd30e891000-7fd30ea90000 ---p 00018000 103:03 31752 /lib/x86_64-linux-gnu/libpthread-2.23.so
7fd30ea90000-7fd30ea91000 r--p 00017000 103:03 31752 /lib/x86_64-linux-gnu/libpthread-2.23.so
7fd30ea91000-7fd30ea92000 rw-p 00018000 103:03 31752 /lib/x86_64-linux-gnu/libpthread-2.23.so
7fd30ea92000-7fd30ea96000 rw-p 00000000 00:00 0
7fd30ea96000-7fd30eaac000 r-xp 00000000 103:03 34896 /lib/x86_64-linux-gnu/libgcc_s.so.1
7fd30eaac000-7fd30ecab000 ---p 00016000 103:03 34896 /lib/x86_64-linux-gnu/libgcc_s.so.1
7fd30ecab000-7fd30ecac000 rw-p 00015000 103:03 34896 /lib/x86_64-linux-gnu/libgcc_s.so.1
7fd30ecac000-7fd30ee1e000 r-xp 00000000 103:03 8388796 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7fd30ee1e000-7fd30f01e000 ---p 00172000 103:03 8388796 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7fd30f01e000-7fd30f028000 r--p 00172000 103:03 8388796 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7fd30f028000-7fd30f02a000 rw-p 0017c000 103:03 8388796 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7fd30f02a000-7fd30f02e000 rw-p 00000000 00:00 0
7fd30f02e000-7fd30f2cd000 r-xp 00000000 103:03 8922983 /usr/local/lib/libprotobuf.so.19.0.0
7fd30f2cd000-7fd30f4cd000 ---p 0029f000 103:03 8922983 /usr/local/lib/libprotobuf.so.19.0.0
7fd30f4cd000-7fd30f4d6000 r--p 0029f000 103:03 8922983 /usr/local/lib/libprotobuf.so.19.0.0
7fd30f4d6000-7fd30f4dc000 rw-p 002a8000 103:03 8922983 /usr/local/lib/libprotobuf.so.19.0.0
7fd30f4dc000-7fd30f4dd000 rw-p 00000000 00:00 0
7fd30f4dd000-7fd30f503000 r-xp 00000000 103:03 31751 /lib/x86_64-linux-gnu/ld-2.23.so
7fd30f6b5000-7fd30f6bb000 rw-p 00000000 00:00 0
7fd30f700000-7fd30f702000 rw-p 00000000 00:00 0
7fd30f702000-7fd30f703000 r--p 00025000 103:03 31751 /lib/x86_64-linux-gnu/ld-2.23.so
7fd30f703000-7fd30f704000 rw-p 00026000 103:03 31751 /lib/x86_64-linux-gnu/ld-2.23.so
7fd30f704000-7fd30f705000 rw-p 00000000 00:00 0
7ffdad271000-7ffdad293000 rw-p 00000000 00:00 0 [stack]
7ffdad306000-7ffdad309000 r--p 00000000 00:00 0 [vvar]
7ffdad309000-7ffdad30b000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
Aborted (core dumped)
我用$USER
替换了我的计算机用户帐户。
我已将问题缩小到这一行:
// THIS LINE DOES NOT WORK!!!!!!!
robotdata.set_allocated_control(pointeddata);
我试图将一个 protobuf 对象传递给另一个 protobuf 指针对象,这完全使程序崩溃。我不知道为什么会崩溃。我已经从我的程序中删除了所有额外的代码:这是演示我的错误的最低要求。我不知道如何解决这个问题。
我还要提一下:如果您还没有弄清楚如何使用 google protobuf 进行 CMake,这是我一直使用的通用格式。恕我直言,这是一个很好的资源。 :)
【问题讨论】:
【参考方案1】:如果您想使用set_allocated_XXX
,则不能使用具有本地范围的对象,因为您通过该函数传递对象的所有权。在您的第一次迭代结束时, robdata 超出范围。所以它会被摧毁。由于它是payload的所有者,它也会销毁/删除payload。
代替:
Simplecontroller payload;
// Keep reading the state of the joystick in a loop
while (true)
// Create the new payload object
Robotmessage robotdata;
Simplecontroller * pointeddata = &payload;
// THIS LINE DOES NOT WORK!!!!!!!
robotdata.set_allocated_control(pointeddata);
试试:
// Keep reading the state of the joystick in a loop
while (true)
Simplecontroller* payload = new Simplecontroller();
// Create the new payload object
Robotmessage robotdata;
// THIS LINE SHOULD WORK!!!!!!!
robotdata.set_allocated_control(payload);
【讨论】:
在阅读了您的帖子和代码之后,我认为您的意思是:“...具有 global 范围的对象...”。无论如何,这完美地解决了我的问题。我猜谷歌的家伙希望我们cpp
开发人员事先了解所有这些。哈哈谢谢伙计以上是关于protobuf“oneof”子protobuf对象指针杀死程序的主要内容,如果未能解决你的问题,请参考以下文章
.proto 文件中带有 oneof 的 Protobuf-net