Protobuf SetString GetString GetStringReference段错误

时间:2016-02-10 19:31:32

标签: string c++11 protocol-buffers

我正在使用protobuf创建一个支持许多不同消息的系统,我依赖于动态消息,工厂和反射界面。除了字符串类型,我可以获取并设置所有不同的字段数据类型(uint32,int64,...等)。当我尝试使用字符串数据类型的字段的任何getter或setter时,我的代码段错误。第一块代码是最小的例子(对不起,这很长,但是进口商,工厂等需要到位才有意义)。第二块代码是我一直用于测试的proto文件。我的问题是如何访问字符串字段以设置或获取数据。

#include <vector>
#include <string>
#include <sstream>
#include <dirent.h>
#include <stdexcept>
#include <iostream>

#include <google/protobuf/message.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/io/tokenizer.h>
#include <google/protobuf/compiler/parser.h>
#include <google/protobuf/descriptor_database.h>
#include <google/protobuf/dynamic_message.h>
#include <google/protobuf/compiler/importer.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/arena.h>

class errCollector : public google::protobuf::compiler::MultiFileErrorCollector
{
public:
    ~errCollector() {};
    void AddError(const std::string& filename,
                  int line, int column, const std::string& message) {};
};

google::protobuf::compiler::Importer* createImporter( );
void buildSubMessages(const google::protobuf::Descriptor* desc,
                      google::protobuf::Message* msg, const google::protobuf::Reflection* ref,
                      google::protobuf::DynamicMessageFactory* factory);

int main(int argc, char** argv)
{

    // Usage: ProtobufMinimalExample <message type name>
    std::string msgType(argv[1]);

    // Error message stream
    std::ostringstream msgStream;

    // Create the importer object which holds all of the .proto files.
    google::protobuf::compiler::Importer* importer = createImporter();
    // Create the descriptor pool which holds all of the message descriptors.
    const google::protobuf::DescriptorPool* pool(importer->pool());
    // Create an object to hold the top-level message.
    google::protobuf::Message* mutableMsg;
    // Create an object to hold the top-level message descriptor.
    const google::protobuf::Descriptor* messageDesc;
    // Create a message to hold the prototype description of the dynamic message
    const google::protobuf::Message* protoTypeMsg;
    // Create the message factory.
    google::protobuf::DynamicMessageFactory* factory( new google::protobuf::DynamicMessageFactory);

    messageDesc = pool->FindMessageTypeByName(msgType);
    protoTypeMsg = factory->GetPrototype(messageDesc);
    mutableMsg = protoTypeMsg->New();

    // Get a submessage in the field named "yellow".
    const google::protobuf::FieldDescriptor* field = messageDesc->FindFieldByName("yellow");
    const google::protobuf::Descriptor* subMsgDesc = field->message_type();
    const google::protobuf::Message* subProtoTypeMsg = factory->GetPrototype(subMsgDesc);
    google::protobuf::Message* subMutableMsg = subProtoTypeMsg->New();
    const google::protobuf::Reflection* subReflection = (subMutableMsg->GetReflection());
    const google::protobuf::Descriptor* subMutableDesc = subMutableMsg->GetDescriptor();

    std::string* name = new std::string();

    // Segfault
    //const google::protobuf::FieldDescriptor* subField = subMutableDesc->FindFieldByName("name");
    //subReflection->SetString(mutableMsg, subField, "Hello");
    //subReflection->GetString(*(mutableMsg), subField);
    //subReflection->GetStringReference(*(mutableMsg), subField, name);

    // Works
    //const google::protobuf::FieldDescriptor* subField = subMutableDesc->FindFieldByName("score");
    //subReflection->SetUInt32(mutableMsg, subField, 9);
    //subReflection->GetUInt32(*(mutableMsg), subField);

    return 0;
}

google::protobuf::compiler::Importer* createImporter()
{
    google::protobuf::compiler::DiskSourceTree srcTree;
    errCollector error;
    google::protobuf::compiler::Importer* fdProtoImporter(new google::protobuf::compiler::Importer(&srcTree, &error));
    const char* protoFilePath = "./proto";

    struct dirent* entry;
    DIR* dp;
    std::vector<std::string> importProtoFilenames;

    dp = opendir(protoFilePath);

    unsigned char isFile = 0x8;
    while( (entry = readdir(dp)) )
    {
        if(entry->d_type != isFile)
            continue;
        importProtoFilenames.push_back(std::string(entry->d_name));
    }
    closedir(dp);

    srcTree.MapPath("", protoFilePath);

    for( auto protoFilename : importProtoFilenames )
    {
        if(fdProtoImporter->Import(protoFilename) == NULL)
        {
            continue;
        }
    }
    return std::move(fdProtoImporter);
}
message SSL_Referee {

required uint64 packet_timestamp = 1;

enum Stage {
    NORMAL_FIRST_HALF_PRE = 0;
    NORMAL_FIRST_HALF = 1;
    NORMAL_HALF_TIME = 2;
    NORMAL_SECOND_HALF_PRE = 3;
    NORMAL_SECOND_HALF = 4;
    EXTRA_TIME_BREAK = 5;
    EXTRA_FIRST_HALF_PRE = 6;
    EXTRA_FIRST_HALF = 7;
    EXTRA_HALF_TIME = 8;
    EXTRA_SECOND_HALF_PRE = 9;
    EXTRA_SECOND_HALF = 10;
    PENALTY_SHOOTOUT_BREAK = 11;
    PENALTY_SHOOTOUT = 12;
    POST_GAME = 13;
}
required Stage stage = 2;

optional sint32 stage_time_left = 3;

// These are the "fine" states of play on the field.
enum Command {
    // All robots should completely stop moving.
    HALT = 0;
    // Robots must keep 50 cm from the ball.
    STOP = 1;
    // A prepared kickoff or penalty may now be taken.
    NORMAL_START = 2;
    // The ball is dropped and free for either team.
    FORCE_START = 3;
    // The yellow team may move into kickoff position.
    PREPARE_KICKOFF_YELLOW = 4;
    // The blue team may move into kickoff position.
    PREPARE_KICKOFF_BLUE = 5;
    // The yellow team may move into penalty position.
    PREPARE_PENALTY_YELLOW = 6;
    // The blue team may move into penalty position.
    PREPARE_PENALTY_BLUE = 7;
    // The yellow team may take a direct free kick.
    DIRECT_FREE_YELLOW = 8;
    // The blue team may take a direct free kick.
    DIRECT_FREE_BLUE = 9;
    // The yellow team may take an indirect free kick.
    INDIRECT_FREE_YELLOW = 10;
    // The blue team may take an indirect free kick.
    INDIRECT_FREE_BLUE = 11;
    // The yellow team is currently in a timeout.
    TIMEOUT_YELLOW = 12;
    // The blue team is currently in a timeout.
    TIMEOUT_BLUE = 13;
    // The yellow team just scored a goal.
    // For information only.
    // For rules compliance, teams must treat as STOP.
    GOAL_YELLOW = 14;
    // The blue team just scored a goal.
    GOAL_BLUE = 15;
}
required Command command = 4;

// The number of commands issued since startup (mod 2^32).
required uint32 command_counter = 5;

// The UNIX timestamp when the command was issued, in microseconds.
// This value changes only when a new command is issued, not on each packet.
required uint64 command_timestamp = 6;

// Information about a single team.
message TeamInfo {
    // The team's name (empty string if operator has not typed anything).
    required string name = 1;
    // The number of goals scored by the team during normal play and overtime.
    required uint32 score = 2;
    // The number of red cards issued to the team since the beginning of the game.
    required uint32 red_cards = 3;
    // The amount of time (in microseconds) left on each yellow card issued to the team.
    // If no yellow cards are issued, this array has no elements.
    // Otherwise, times are ordered from smallest to largest.
    repeated uint32 yellow_card_times = 4 [packed=true];
    // The total number of yellow cards ever issued to the team.
    required uint32 yellow_cards = 5;
    // The number of timeouts this team can still call.
    // If in a timeout right now, that timeout is excluded.
    required uint32 timeouts = 6;
    // The number of microseconds of timeout this team can use.
    required uint32 timeout_time = 7;
    // The pattern number of this team's goalie.
    required uint32 goalie = 8;
}

// Information about the two teams.
required TeamInfo yellow = 7;
required TeamInfo blue = 8;
}

1 个答案:

答案 0 :(得分:0)

// Segfault
const google::protobuf::FieldDescriptor* subField = subMutableDesc->FindFieldByName("name");
subReflection->SetString(mutableMsg, subField, "Hello");
subReflection->GetString(*(mutableMsg), subField);
subReflection->GetStringReference(*(mutableMsg), subField, name);

我相信您在此代码中撰写mutableMsg的位置,您的意思是subMutableMsg。因此,您尝试修改错误的消息,并且您传入的消息具有不同的布局,因此当反射代码尝试访问字符串类型的字段时,它最终会尝试遵循指针无效。

// Works
const google::protobuf::FieldDescriptor* subField = subMutableDesc->FindFieldByName("score");
subReflection->SetUInt32(mutableMsg, subField, 9);
subReflection->GetUInt32(*(mutableMsg), subField);

这种情况不是&#34;工作&#34;,它只是没有段错误。我相信这段代码实际上会破坏mutableMsg中的内存,但由于你正在修改一个简单的原始字段,反射代码不会尝试跟随任何指针,因此不会出现段错误。