protocolbuffers/protobuf

Stack smashing before `main()` caused by adding `import` to quick start's greeter proto file

Open

#12,732 opened on May 9, 2023

View on GitHub
 (3 comments) (0 reactions) (1 assignee)C++ (16,128 forks)batch import
c++help wanted

Repository metrics

Stars
 (71,223 stars)
PR merge metrics
 (Avg merge 2d 11h) (185 merged PRs in 30d)

Description

Note that I originally thought this is a bug in the gRPC generator, so I filed an issue here. However, I have since realized that this is an issue in protobuf: I can reproduce the issue without grpc.

What version of protobuf and what language are you using? Version: v21.12 Version: v20.2 Version: v19.5 Version: v18.3 Version: v16.2 Version: v3.10.1 Version: v3.6.1.3

Language: C++

What operating system (Linux, Windows, ...) and version? Ubuntu 20.04 LTS

What runtime / compiler are you using (e.g., python version or gcc version) gcc --version ->

gcc (Ubuntu 11.1.0-1ubuntu1~20.04) 11.1.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

What did you do?

  1. Use the Greeter service quickstart example from grpc.io found here.
    1. Copy-pasted the first proto file text found in the quick start website into ./src/proto/greeter.proto
    2. I did not copy the .proto file from the grpc repository
  2. Add import "google/api/field_behavior.proto"; to import a .proto file from googleapis repository here.
  3. Compile the .proto files to generate C++ header and source files into a static library
  4. Instantiate HelloRequest and HelloReply in an executable which links against the static library
  5. Run the built executable

This is verified in a repository I created with a demonstration here.

You can run ./build.sh. It will:

  1. :warning: Prune Docker then remove existing protobuf-toolchain and protobuf-stacksmash images to keep Docker from using tons of resources while iterating changes to the source tree
  2. :information_source: Find or create a few toolchain images
    1. Find, or create and tag, ubuntu-2004-toolchain image which includes only the Ubuntu packages required to compile
      1. this takes a couple minutes
      2. gcc-11 is installed from ubuntu-toolchain PPA
    2. Find, or create and tag, cmake-toolchain image which builds and installs cmake from source
    3. Find, or create and tag, protobuf-toolchain image which builds and installs protobuf from source
      1. NOTE: this image enables Address Sanitizer via environment variables to enforce ASAN throughout the demonstration.
      2. Here is protobuf version. Note that I use version v21.12 due to a separate issue found while constructing this demonstration.
      3. Here is grpc version
  3. :information_source: Create and tag a new protobuf-stacksmash image which compiles a demonstration
  4. :exclamation: Runs the newly-created protobuf-stacksmash image to demonstrate whether the resulting executable is viable

What did you expect to see :heavy_check_mark: Per initial commit here: ./build.sh ->

Successfully built 55df7a9eb834
Successfully tagged grpc-stacksmash:latest
greeter service created -- no stacksmash

What did you see instead? :exclamation: :stop_sign: ./build.sh ->

Successfully tagged protobuf-stacksmash:latest
*** stack smashing detected ***: terminated
AddressSanitizer:DEADLYSIGNAL
=================================================================
==1==ERROR: AddressSanitizer: SEGV on unknown address (pc 0x7f5ca1291941 bp 0x7ffcad720d20 sp 0x7ffcad720ac0 T0)
==1==The signal is caused by a READ memory access.
==1==Hint: this fault was caused by a dereference of a high value address (see register values below).  Dissassemble the provided pc to learn which register was used.
    #0 0x7f5ca1291941 in abort (/lib/x86_64-linux-gnu/libc.so.6+0x22941)
    #1 0x7f5ca12fc26d  (/lib/x86_64-linux-gnu/libc.so.6+0x8d26d)
    #2 0x7f5ca139eab9 in __fortify_fail (/lib/x86_64-linux-gnu/libc.so.6+0x12fab9)
    #3 0x7f5ca139ea85 in __stack_chk_fail (/lib/x86_64-linux-gnu/libc.so.6+0x12fa85)
    #4 0x7f5ca1958f90 in google::protobuf::EncodedDescriptorDatabase::Add(void const*, int) google/protobuf/descriptor_database.cc:322
    #5 0x7f5ca1925663 in google::protobuf::DescriptorPool::InternalAddGeneratedFile(void const*, int) google/protobuf/descriptor.cc:1358
    #6 0x7f5ca191c49d in protobuf_google_2fprotobuf_2fany_2eproto::AddDescriptorsImpl() google/protobuf/any.pb.cc:97
    #7 0x7f5ca17f84de in __pthread_once_slow (/lib/x86_64-linux-gnu/libpthread.so.0+0x114de)
    #8 0x7f5ca191c65e in __gthread_once /usr/include/x86_64-linux-gnu/c++/11/bits/gthr-default.h:700
    #9 0x7f5ca191c65e in void std::call_once<void (&)()>(std::once_flag&, void (&)()) /usr/include/c++/11/mutex:783
    #10 0x7f5ca191c65e in void google::protobuf::internal::call_once<std::once_flag&, void (&)()>(std::once_flag&, void (&)()) google/protobuf/stubs/once.h:91
    #11 0x7f5ca191c65e in protobuf_google_2fprotobuf_2fany_2eproto::AddDescriptors() google/protobuf/any.pb.cc:105
    #12 0x7f5ca24b3b99  (/lib64/ld-linux-x86-64.so.2+0x11b99)
    #13 0x7f5ca24b3ca0  (/lib64/ld-linux-x86-64.so.2+0x11ca0)
    #14 0x7f5ca24a3139  (/lib64/ld-linux-x86-64.so.2+0x1139)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (/lib/x86_64-linux-gnu/libc.so.6+0x22941) in abort
==1==ABORTING

Anything else we should know about your project / environment

./build.sh is the driver for the demo.

./docker contains Dockerfiles and scripts to set up the build toolchain. ./docker/ubuntu-2004-toolchain.Dockerfile installs GCC ./docker/cmake-toolchain.Dockerfile inherits FROM ubuntu-2004-toolchain and builds & installs cmake ./docker/protobuf-toolchain.Dockerfile inherits FROM cmake-toolchain and builds & installs protobufs (especially protoc). The version of protobuf can be configured as an argument. ./Dockerfile inherits FROM protobuf-toolchain and builds the project with cmake.

./src contains the stack smashing demo ./src/proto/external contains a static library whose only purpose is to compile external proto files -- eg proto files that were nominally downloaded from elsewhere (eg, here. ./src/proto contains a static library whose only purpose is to compile proto files into a static library. It contains the greeter service proto. It then links to and imports the external protos. ./src/greeter-service contains an executable. Its only purpose is to link against the static proto library and instantiate the objects that were generated.

The ./Dockerfile then sets greeter-service as its entrypoint so that docker run will run the demo.

This problem is a Minimal Compilable Reproducible Example that has been trimmed down from a larger codebase. The larger codebase includes several golang projects which are currently using the .proto files being imported. This issue blocks me from building a C++ project to communicate with several golang projects that are already importing this file.

Contributor guide