Reputation: 448
I have been using google protobufs successfully for a month and a half now and I have reached a problem I cannot surmount.
Basically, I am now trying to use the oneof
feature in protobufs where I can have multiple types of messages inside of a single message. Basically, I need to be able to send only 1 message but contain multiple different options for submessages. I found many SO posts recommended the oneof
feature, so now I am trying to use it.
https://developers.google.com/protocol-buffers/docs/proto#oneof
Okay, so what is the problem?
Well, I get a huge stack dump with my code. Here are the multiple code files.
This is the .cpp
script that is crashing:
#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;
}
Here are the .proto
files that I am using:
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;
}
Here is the CMakeLists.txt
file that I am using to build the code:
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
And the build.sh
file that I use to compile everything:
#!/bin/bash
cmake -H. -Bbuild
availablethreads=`nproc`
cmake --build build -- -j$availablethreads -l$availablethreads
Then, finally, the error:
*** 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)
I replaced my computer user account with $USER
.
I have narrowed the problem down to this line:
// THIS LINE DOES NOT WORK!!!!!!!
robotdata.set_allocated_control(pointeddata);
I am trying to pass in a protobuf object into another protobuf pointer object and that is totally crashing the program. I do not have any idea why this is crashing. I have gotten rid of all the extra code from my program: this is the minimum to demo my error. I have no idea how to fix this.
I should also mention: if you have not figured out how to do CMake with google protobuf, this is the general format that I always use. It is a pretty good resource IMHO. :)
Upvotes: 1
Views: 1049
Reputation: 886
If you want to use set_allocated_XXX
you cant use objects with local scope because you pass the ownership of your object with that function. At the end of your first iteration robdata goes out of scope. So it will be destroyed. Since it is the owner of payload, it will also destroy/delete payload.
Instead of:
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);
}
Try:
// 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);
}
Upvotes: 1