Google Protobuf GetStringReference取值错误与字段查找段错误问题
问题原因分析
你的问题核心出在两处使用不当,按影响优先级排序如下:
- 第一处是
GetStringReference接口的错误使用
Protobuf的GetStringReference接口定义为:
其中第三个参数const std::string& GetStringReference(const Message& message, const FieldDescriptor* field, std::string* scratch) const;scratch是临时缓存:如果无法返回字段字符串的内部常驻引用(比如取默认值、使用lite runtime、部分版本optional字段的特殊处理),接口会把字符串值拷贝到scratch指向的对象中,再返回该对象的引用。
你的代码中str = refl->GetStringReference(telemetry, field, &str);同时把str作为赋值目标和scratch参数传入,会触发同对象的自赋值+写入的未定义行为,这是你读key1返回string_2、读key2直接段错误的核心原因。 - 第二处是存在版本不匹配的风险
你用了proto3的optional特性,该特性从Protobuf 3.12版本才开始支持,如果编译.proto用的protoc版本和最终链接的protobuf运行库版本不一致,会导致生成代码的字段内存偏移和运行时反射计算的偏移不匹配,也会出现读错值、访问非法内存的问题。
修复方案
修改反射读取字符串的代码即可,推荐优先用更安全的GetString接口(直接返回值拷贝,无额外坑点),同时增加空指针判断避免异常场景崩溃:
const google::protobuf::FieldDescriptor *field = desc->FindFieldByName("key1"); // 增加空指针判断,避免字段名错误导致的空指针解引用 if (!field) { std::cerr << "field not found" << std::endl; return -1; } const google::protobuf::Reflection *refl = telemetry.GetReflection(); // 方案1:用GetString直接取拷贝,99%场景足够用,无额外注意事项 std::string str = refl->GetString(telemetry, field); std::cout << "Value: " << str << std::endl; // 方案2:如果必须用GetStringReference追求性能,不要复用同一个string对象 std::string scratch; const std::string& ref_str = refl->GetStringReference(telemetry, field, &scratch); std::cout << "Ref Value: " << ref_str << std::endl;
如果修改后还有异常,检查本地protoc版本和链接的protobuf库版本,确保两者大版本号完全一致即可。
内容的提问来源于stack exchange,提问作者plain
相关产品推荐
相关产品推荐

