Description
This post is related to this one: https://stackoverflow.com/questions/79576605/segmentation-fault-during-serialization-by-using-protobuf-in-c17
But I have narrowed it down to the specific problem and decided to make separated post.
My goal is to serialize information by using protobuf in C++.
proto file from ./proto folder:
syntax="proto3";
package PhoneBookSerialize;
message Date {
int32 year = 1;
int32 month = 2;
int32 day = 3;
}
message Contact {
string name = 1;
Date birthday = 2;
repeated string phone_number = 3;
}
message ContactList {
repeated Contact contact = 1;
}
main.cpp in ./src folder
#include "contact.pb.h"
#include <sstream>
#include <iostream>
using namespace std;
int main() {
// Example 2: Serialize single Date
PhoneBookSerialize::Date date;
date.set_year(1990);
date.set_month(6);
date.set_day(15);
// Serialize Date
ostringstream date_output(std::ios::binary);
date.SerializeToOstream(&date_output);
std::string serialized_date = date_output.str();
std::cout << "Serialized date size: " << serialized_date.size() << std::endl;
// Deserialize Date
PhoneBookSerialize::Date parsed_date;
istringstream date_input(serialized_date, std::ios::binary);
parsed_date.ParseFromIstream(&date_input);
std::cout << "Deserialized date: "
<< parsed_date.year() << "-"
<< parsed_date.month() << "-"
<< parsed_date.day() << std::endl;
std::cout << "================================================" << std::endl;
// Example 3: Serialize single Contact
PhoneBookSerialize::Contact contact;
contact.set_name("John Doe");
contact.mutable_birthday()->set_year(1990);
contact.mutable_birthday()->set_month(6);
contact.mutable_birthday()->set_day(15);
contact.add_phone_number("+1234567890");
contact.add_phone_number("+1234567891");
// Serialize Contact
ostringstream contact_output(std::ios::binary);
if (!contact.SerializeToOstream(&contact_output)) {
std::cerr << "Failed to serialize contact!" << std::endl;
} else {
std::cout << "Successfully serialized contact (size: " << contact_output.str().size() << " bytes)" << std::endl;
}
std::string serialized_contact = contact_output.str();
std::cout << "Serialized contact size: " << serialized_contact.size() << std::endl;
// Deserialize Contact
PhoneBookSerialize::Contact parsed_contact;
istringstream contact_input(serialized_contact, std::ios::binary);
if (!parsed_contact.ParseFromIstream(&contact_input)) {
std::cerr << "Failed to parse contact!" << std::endl;
}
std::cout << "Deserialized contact:" << std::endl
<< "Name: " << parsed_contact.name() << std::endl
<< "Birthday: "
<< parsed_contact.birthday().year() << "-"
<< parsed_contact.birthday().month() << "-"
<< parsed_contact.birthday().day() << std::endl
<< "Phone number: " << parsed_contact.phone_number(0) << std::endl
<< "Phone number: " << parsed_contact.phone_number(1) << std::endl;
return 0;
}
CMakeLists.txt file in . folder:
cmake_minimum_required(VERSION 3.20)
project(PhoneBookProtobuf LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Add debug flags
set(CMAKE_BUILD_TYPE Debug)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -fcolor-diagnostics -fansi-escape-codes -fsanitize=address -fsanitize=undefined -DDEBUG -fno-omit-frame-pointer -fno-optimize-sibling-calls -Werror")
# Find Protocol Buffers package
find_package(Protobuf REQUIRED)
# Find Abseil package
find_package(absl REQUIRED)
include_directories(${Protobuf_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
# Generate protobuf files from proto directory
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS proto/contact.proto)
# Add all source files
add_executable(main
src/main.cpp
${PROTO_SRCS}
${PROTO_HDRS}
)
# Link necessary libraries
target_link_libraries(main
${Protobuf_LIBRARIES}
absl::log
absl::log_internal_message
absl::log_internal_check_op
)
# Add include directories
target_include_directories(main PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_BINARY_DIR}
${Protobuf_INCLUDE_DIRS}
)
after I build (creates a ./build folder) and run the code I am getting the following error message:
./build/main
Serialized date size: 7
Deserialized date: 1990-6-15
================================================
Successfully serialized contact (size: 45 bytes)
Serialized contact size: 45
AddressSanitizer:DEADLYSIGNAL
=================================================================
==76867==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x000000000000 bp 0x7ff7b890a050 sp 0x7ff7b890a008 T0)
==76867==Hint: pc points to the zero page.
==76867==The signal is caused by a READ memory access.
==76867==Hint: address points to the zero page.
#0 0x000000000000 (<unknown module>)
#1 0x000107a3dbdb in bool google::protobuf::internal::MergeFromImpl<false>(google::protobuf::io::ZeroCopyInputStream*, google::protobuf::MessageLite*, google::protobuf::internal::TcParseTableBase const*, google::protobuf::MessageLite::ParseFlags)+0xd1 (libprotobuf.29.3.0.dylib:x86_64+0x10cbdb)
#2 0x000107a3eda2 in google::protobuf::MessageLite::ParseFromIstream(std::__1::basic_istream<char, std::__1::char_traits<char>>*)+0x32 (libprotobuf.29.3.0.dylib:x86_64+0x10dda2)
#3 0x000107603cd7 in main main.cpp:57
#4 0x7ff8165ad52f in start+0xbef (dyld:x86_64+0xfffffffffff1f52f)
The error is cased by the birthday field of the type Date in the Contact message.
For some reason when I use:
contact.mutable_birthday()->set_year(1990);
contact.mutable_birthday()->set_month(6);
contact.mutable_birthday()->set_day(15);
or CopyFrom
method it causes a segmentation fault.
Summary:
-
If I remove Date field from the Contact message (and all the code in main() related to setting Date field), then problem disappears.
-
When I leave Date field in the Contact message BUT I don't use set methods for this field in main(), then problem dissappears as well.
Basically: problem occurs due to set methods (contact.mutable_birthday()->set_year(1990)
etc.)
- OS: macOS
- protoc version: libprotoc 29.3
- generated files contact.pb.cc and contact.pb.h are in the build folder, if it's important.