To reproduce protocolbuffers/protobuf#435.
onnx.pb.cc
is generated by protoc 2.6.1 from onnx.proto
(licensed by MIT License). I added printf
s for debugging.
- Download source code of
protobuf
and build it
$ curl -LO https://github.com/google/protobuf/releases/download/v2.6.1/protobuf-2.6.1.tar.gz
$ tar xvf protobuf-2.6.1.tar.gz
$ cd protobuf-2.6.1
$ ./configure --prefix=/home/<user>/protobuf-2.6.1 CFLAGS=-fPIC CXXFLAGS=-fPIC
$ make
$ make install
- Clone the repository and copy
protobuf
toinclude/
andlib/
directory
$ git clone https://github.pfidev.jp/okamoto/protobuf-shareddtor.git
$ cd protobuf-shareddtor
$ cp -r ~/protobuf-2.6.1/include/google protobuf-shareddtor/include
$ cp -r ~/protobuf-2.6.1/lib/libprotobuf.* protobuf-shareddtor/lib
- Build and run the reproduction code
$ export LD_LIBRARY_PATH=/<somewhere>/protobuf-shareddtor-crash/lib
$ mkdir -p build
$ cd build/
$ cmake ..
$ ./myapp
$ ./myapp
### Starting: ModelProto::SharedCtor() (0xf810e0)
### Finishing: ModelProto::SharedCtor() (0xf810e0)
### Starting: ModelProto::SharedCtor() (0xf89320)
### Finishing: ModelProto::SharedCtor() (0xf89320)
# Invoking: foo::new_onnx_model()
## Starting: onnx::ModelProto::new_onnx_model()
### Starting: ModelProto::SharedCtor() (0x7ffea029c020)
### Finishing: ModelProto::SharedCtor() (0x7ffea029c020)
## GetEmptyStringAlreadyInited in libfoo.so is 0xf7d260
## Finishing: onnx::ModelProto::new_onnx_model() (returns 0x7ffea029c020)
# Finished: foo::new_onnx_model() (returned value is 0x7ffea029c020)
producer_name:
### Starting: ModelProto::SharedDtor() (0x7ffea029c020)
### GetEmptyStringAlreadyInited() is 0xf85fb0
### Deleting: producer_name_ (= 0xf7d260)
### Deleting: producer_version_ (= 0xf7d260)
*** Error in `./myapp': double free or corruption (out): 0x0000000000f83ae0 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f7d751077e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7f7d7511037a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f7d7511453c]
./myapp(_ZN4onnx10ModelProto10SharedDtorEv+0x183)[0x42d799]
./myapp(_ZN4onnx10ModelProtoD1Ev+0x24)[0x42d59c]
./myapp(main+0xde)[0x45134d]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f7d750b0830]
./myapp(_start+0x29)[0x422449]
======= Memory map: ========
...
The conditions in SharedDtor()
are always true
even if the actual value of producer_name_
and producer_version_
are GetEmptyStringAlreadyInited()
because it is allocated by libfoo.so
not by myapp
. As pointed out in the issue, it points to different address between libfoo.so
and myapp
(See GetEmptyStringAlreadyInited() is ...
in the result).
As it turned out, it tries to delete GetEmptyStringAlreadyInited()
in libfoo.so
(= 0xf7d260
) twice and produces double free or corruption
error.
void ModelProto::SharedCtor() {
::google::protobuf::internal::GetEmptyString();
...
producer_name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
producer_version_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
...
}
void ModelProto::SharedDtor() {
if (producer_name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
delete producer_name_;
}
if (producer_version_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
delete producer_version_;
}
...