kagama
kagama

Reputation: 311

Nested fixed size message arrays (repeated fields) not working in protobuf with nano

I'm using nanopb and have so far been more than pleased with it, but have run into an issue: It seems to fail when encoding/decoding nested repeated messages.

This is a simple example of a proto that will fail:


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];
}

The generated structs look perfect, but running this code on the compiled proto will fail on the last line with a core dump:

    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);

I've tested the same thing without the DoubleNestor, and that's working just fine. Am I doing something wrong, or is this an actual issue with nanopb?

Upvotes: 2

Views: 95

Answers (1)

kagama
kagama

Reputation: 311

This turned out to be me misusing nanopg.

It needs to be manually specified how many repeated messages the struct has.

So in the above, it would work adding a tmp.nestor_count = 2 for the outer repeated message and tmp.nestor[i].doubleNestor[j].nestor_count = 4 for the inner. So if we ignore the inner doubleNestor, the full correct usage would be:

    uint8_t buffer[1000];
    size_t message_length;
    bool status;

    tester_Proto1 tmp = tester_Proto1_init_zero;
    tmp.status_code = 1;
    tmp.nestor_count = 2;    
    tmp.nestor[0].working = true;
    tmp.nestor[1].working = 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) {
        return 1;
    }

    tester_Proto1 dec = tester_Proto1_init_zero;
    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_count == dec.nestor_count); 
    assert(tmp.nestor[0].working == dec.nestor[0].working);
    ```

Upvotes: 1

Related Questions