Программа Simple Protocol Buffers работает при компиляции с g++, но не с clang++

Я пытаюсь использовать буферы протокола в простой программе на C++. Когда я компилирую с g++, программа выполняется и завершается нормально. Когда я компилирую с clang++, программа дает сбой, жалуясь, что pointer being freed was not allocated.

Определение сообщения буфера протокола

package test;

message Test {
    required int32 id = 1;
    required string name = 2;
}

Основной класс

#include <iostream>
#include "test.pb.h"

int main(void) {
    // Build the original message
    test::Test original;
    original.set_id(0);
    original.set_name("original");

    // Serialize the original message
    int size = original.ByteSize();
    char data[size];
    original.SerializeToArray(data, size);

    // Deserialize the data into a previously initialized message
    test::Test success;
    success.set_id(1);
    success.set_name("success");
    success.ParseFromArray(data, size);
    std::cout << success.id() << ": " << success.name() << std::endl;

    // Deserialize the data into an uninitialized message
    test::Test failure;
    failure.ParseFromArray(data, size); // FAILS HERE WITH CLANG++
    std::cout << failure.id() << ": " << failure.name() << std::endl;
}

Вывод г++

theisenp$ g++ test.pb.cc main.cpp -lprotobuf -o g++.out
theisenp$ ./g++.out 
0: original
0: original

лязг++ вывод

theisenp$ clang++ test.pb.cc main.cpp -L/usr/local/lib -lprotobuf -stdlib=libstdc++ -o clang++.out
theisenp$ ./clang++.out 
0: original
clang++.out(9948,0x7fff71195310) malloc: *** error for object 0x7fff72ed6330: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6

Я новичок как в Protocol Buffers, так и в Clang, поэтому вполне возможно, что я упускаю что-то очевидное. Любые идеи?

Редактировать

Некоторые пояснения по версиям компилятора. Я использую OSX Mavericks (10.9.1). По умолчанию Mavericks сопоставляет вызовы gcc и g++ с clang и clang++ соответственно. Я установил gcc 4.8.2 независимо и переопределил поведение по умолчанию.

g++ версия

theisenp$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/local/Cellar/gcc48/4.8.2/libexec/gcc/x86_64-apple-darwin13.0.2/4.8.2/lto-wrapper
Target: x86_64-apple-darwin13.0.2
Configured with: ../configure
    --build=x86_64-apple-darwin13.0.2
    --prefix=/usr/local/Cellar/gcc48/4.8.2
    --enable-languages=c,c++,objc,obj-c++
    --program-suffix=-4.8
    --with-gmp=/usr/local/opt/gmp4
    --with-mpfr=/usr/local/opt/mpfr2
    --with-mpc=/usr/local/opt/libmpc08
    --with-cloog=/usr/local/opt/cloog018
    --with-isl=/usr/local/opt/isl011
    --with-system-zlib
    --enable-version-specific-runtime-libs
    --enable-libstdcxx-time=yes
    --enable-stage1-checking
    --enable-checking=release
    --enable-lto
    --disable-werror
    --enable-plugin
    --disable-nls
    --disable-multilib
Thread model: posix
gcc version 4.8.2 (GCC) 

clang++ Версия

theisenp$ clang++ -v
Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin13.0.2
Thread model: posix

person theisenp    schedule 28.01.2014    source источник
comment
Я не могу воспроизвести это - g++ 4.8.2 и clang++ 3.3 дают одинаковый результат для меня в Linux. На какой платформе вы находитесь? Кстати, последняя строка вашей основной функции выводит друзей success; Я думаю, вы хотели напечатать failure.   -  person Kenton Varda    schedule 29.01.2014
comment
Я с подозрением отношусь к параметру -stdlib=libstdc++. Нет необходимости указывать это — Clang по умолчанию должен использовать соответствующую библиотеку для вашей платформы. Если вы используете Mac с XCode 5, g++ на самом деле является символической ссылкой на clang++, и я думаю, что libc++ (а не libstdc++) используется по умолчанию. В этом случае ваша ошибка заключается в том, что вы заставляете его использовать другую stdlib, чем была создана libprotobuf, что легко объясняет сбой.   -  person Kenton Varda    schedule 29.01.2014
comment
Спасибо, я хотел напечатать отказ, это была ошибка копирования и вставки. Я обновил вопрос информацией о платформе и компиляторе. Я не могу вспомнить, построил ли я libprotobuf с clang++ или g++, так что я исследую это дальше. На данный момент компиляция clang без флага --stdlib завершается с ошибкой Undefined symbols for architecture x86_64   -  person theisenp    schedule 29.01.2014
comment
@KentonVarda Это исправлено, спасибо! Если вы добавите свой комментарий в качестве ответа, я приму его. Я переназначил clang на gcc, чтобы получить msgpack для компиляции (который я также тестировал), и забыл, что я, по-видимому, также использовал его для компиляции protobuf.   -  person theisenp    schedule 29.01.2014


Ответы (2)


Как обсуждалось в комментариях, важно, чтобы libprotobuf был скомпилирован с той же stdlib, которую вы используете при компиляции своего кода, поскольку libprotobuf использует типы STL (особенно std::string) в своем интерфейсе. Если вы установили GCC 4.8, он будет использовать GCC libstdc++ 4.8. Тем временем Clang, поставляемый с Xcode, будет использовать любые стандартные библиотеки, поставляемые с Xcode, поэтому, даже если вы скажете ему --stdlib=libstdc++, это может быть несовместимая версия.

person Kenton Varda    schedule 30.01.2014

Я подозреваю, что ваша проблема может быть здесь:

int size = original.ByteSize();
char data[size];

Массивы переменной длины недопустимы в C++ (они разрешены в C99), они являются GCC расширение.

Я бы предложил использовать динамически выделяемый буфер и посмотреть, сохраняется ли проблема. Примерно в 2010 году ведутся дискуссии о clang и VLA здесь.

person Nathan Ernst    schedule 30.01.2014
comment
Clang поддерживает некоторые VLA в C++ (включая примитивные массивы) и выдает явную ошибку компиляции для любого неподдерживаемого случая. Итак, это не проблема. - person Kenton Varda; 31.01.2014