You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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的内存属于越界操作,触发核心转储。

修复步骤

  1. 编码前显式设置重复字段的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;
    
  2. 解码后先检查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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 09:34:57