我已经成功使用google protobufs一个半月了,但遇到了无法克服的问题。
基本上,我现在正尝试在protobuf中使用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://stackoverflow.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://stackoverflow.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 $ENV{USER})
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://stackoverflow.com/questions/20824194/cmake-with-google-protocol-buffers
# https://stackoverflow.com/questions/32647517/protocol-buffer-with-cmakelists
# https://stackoverflow.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,这是我一直使用的通用格式。这是一个很好的资源恕我直言。 :)
答案 0 :(得分:0)
如果要使用set_allocated_XXX
,则不能使用具有局部作用域的对象,因为您通过该函数传递了对象的所有权。在第一个迭代结束时,robdata超出范围。因此它将被销毁。由于它是有效负载的所有者,因此也会销毁/删除有效负载。
代替:
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);
}