Skip to content

Segmentation fault during Serialization: caused by message as a field in C++17 #21316

Open
@danilyef

Description

@danilyef

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:

  1. If I remove Date field from the Contact message (and all the code in main() related to setting Date field), then problem disappears.

  2. 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.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions