使用nanopb时嵌套固定大小重复消息数组编解码失败咨询
nanopb嵌套重复消息编解码核心转储问题排查
使用nanopb时遇到嵌套重复消息编解码失败,最终触发核心转储。以下是触发问题的Proto定义:
import "nanopb.proto"; package tester; message Proto1 { message DoubleNestor { bool worky = 1; } message Nestor { bool working = 1; repeated DoubleNestor doubleNestor = 2 [(nanopb).max_count = 4]; } uint32 status_code = 1; repeated Nestor nestor = 2 [(nanopb).max_count = 2]; }
生成的结构体看似正常,但运行以下测试代码时,最后一行断言会触发核心转储:
uint8_t buffer[1000]; size_t message_length; bool status; tester_Proto1 tmp = tester_Proto1_init_zero; tmp.status_code = 1; tmp.nestor[0].working = true; tmp.nestor[0].doubleNestor[3].worky = true; pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); status = pb_encode(&stream, tester_Proto1_fields, &tmp); message_length = stream.bytes_written; if (!status) { printf("FAILED encoding"); return 1; } tester_Proto1 dec = tester_Proto1_init_zero; /* Create a stream that reads from the buffer. */ pb_istream_t stream2 = pb_istream_from_buffer(buffer, message_length); /* Now we are ready to decode the message. */ status = pb_decode(&stream2, tester_Proto1_fields, &dec); /* Check for errors... */ if (!status) { printf("Decoding failed: %s\n", PB_GET_ERROR(&stream)); return 1; } assert(tmp.status_code == dec.status_code); assert(tmp.nestor[0].doubleNestor[3].worky == dec.nestor[0].doubleNestor[3].worky);
测试不含DoubleNestor的场景时运行完全正常,这不是nanopb的bug,是使用时未遵循重复字段的处理规则:
问题根源
nanopb对重复字段的编码/解码依赖显式的count字段(生成的结构体中,每个重复字段都会对应一个xxx_count字段,比如Nestor里的doubleNestor_count、Proto1里的nestor_count)。你直接给索引3的doubleNestor元素赋值,但未设置doubleNestor_count = 4,编码时nanopb只会处理前count个(默认是0)元素,导致编码后的消息里根本没有第4个DoubleNestor元素。解码后dec.nestor[0].doubleNestor_count仍小于4,直接访问索引3的内存属于越界操作,触发核心转储。
修复步骤
编码前显式设置重复字段的count值,告诉nanopb实际要编码的元素数量:
tester_Proto1 tmp = tester_Proto1_init_zero; tmp.status_code = 1; tmp.nestor_count = 1; // 指定编码1个Nestor元素 tmp.nestor[0].working = true; tmp.nestor[0].doubleNestor_count = 4; // 指定编码4个DoubleNestor元素 tmp.nestor[0].doubleNestor[3].worky = true;解码后先检查count值再访问元素,避免越界:
assert(tmp.status_code == dec.status_code); assert(dec.nestor_count >= 1); assert(dec.nestor[0].doubleNestor_count >= 4); assert(tmp.nestor[0].doubleNestor[3].worky == dec.nestor[0].doubleNestor[3].worky);
不含DoubleNestor时正常,是因为单层级重复字段的使用场景中,可能无意中符合了连续初始化的逻辑,或者没有访问超出count的索引,未触发越界问题。
内容的提问来源于stack exchange,提问作者kagama
相关产品推荐
相关产品推荐

