Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect generated data_size when using (nanopb_enumopt).int_size #961

Open
mrjoboto opened this issue May 13, 2024 · 3 comments
Open

Incorrect generated data_size when using (nanopb_enumopt).int_size #961

mrjoboto opened this issue May 13, 2024 · 3 comments

Comments

@mrjoboto
Copy link

Hi there,
I’ve been experimenting with using the (nanopb_enumopt).int_size option to control the size of the generated enum. However, I’ve been running into issues during encode/decode when I set the enum size to 1 byte. Specifically, it seems like the message descriptor that gets generated for the enum field has an incorrect data_size value that doesn’t respect the int_size option used. But the generated struct does respect the int_size option. This leads to the encode function accessing memory beyond the end of the message structure. I tried to put together a contained example that shows the problem:

syntax = "proto3";

import "nanopb.proto";
option (nanopb_fileopt).long_names = false;

enum Foo {
  option (nanopb_enumopt).int_size = IS_8;
  kBar = 0;
  kBaz = 1;
}

message EnumContainer {
  Foo foo = 1;
}

The generated structures are what I would expect:

/* Enum definitions */
typedef enum _Foo
#ifdef __cplusplus
 : uint8_t
#endif
{
    kBar = 0,
    kBaz = 1
} Foo;

/* Struct definitions */
typedef struct _EnumContainer {
    Foo foo;
} EnumContainer;

However, the generated message descriptor seems to result in an inaccurate data_size for the enum field:

EnumContainer message = EnumContainer_init_zero;
message.foo = Foo::kBaz;

pb_field_iter_t iter;
pb_field_iter_begin_const(&iter, EnumContainer_fields, (void*)&message);
printf("%lu, %hu\n", sizeof(message.foo), iter.data_size);

For me this prints “1,4” - the size of the field is 1 byte, but the data_size value is 4 bytes, and data_size is used during encoding to iterate over a void* pointing into the message structure, leading it to access unrelated memory.

Any advice you have to offer would be most appreciated! I'm using nanopb 0.4.8 and clang 15.0.0 targetting arm64-apple-darwin22.6.0.

@PetteriAimonen
Copy link
Member

Hmm, are you perhaps generating the protocol definitions into a .pb.c file, but compiling your user code as .cc file?
Can you try putting definitions to .pb.cc instead?

I think #ifdef __cplusplus should be removed from the generator. Now C23 supports : uint8_t in C mode, and in any case it is better to have compiler error than runtime error.

@mrjoboto
Copy link
Author

Thanks for the prompt reply!

Hmm, are you perhaps generating the protocol definitions into a .pb.c file, but compiling your user code as .cc file? Can you try putting definitions to .pb.cc instead?

Yes, this is the case - I am generating the protocol definitions into a .pb.c file and compiling the user code as cpp. I think I see what you're saying - the field info is getting generated in a context where __cplusplus is not defined and the enum size is 4 bytes.
Manually changing the definition files to .cc resolves the issue. Is there a nanopb option to output .cc files (or otherwise handle this situation)? I couldn't find one.

@PetteriAimonen
Copy link
Member

Yes, --source-extension=.cc for nanopb_generator.py, or --nanopb_opt="--source-extension=.cc" when called through protoc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants