summaryrefslogtreecommitdiffstats
path: root/generator
diff options
context:
space:
mode:
authorPetteri Aimonen <jpa@git.mail.kapsi.fi>2016-12-31 10:33:48 +0200
committerPetteri Aimonen <jpa@git.mail.kapsi.fi>2016-12-31 10:42:22 +0200
commit48f5dd83530a46dd2423277f4488fd4ce9c93b72 (patch)
tree366642f135defe7d57fe9b88a705d5fe3cce24f4 /generator
parent90a19bf0368035147a74b9b8edd65d672a03cd00 (diff)
Fix multiple oneofs in same message (issue #229)
Previously the field iterator logic didn't know whether two oneof fields were part of the same union, or separate. This caused wrong pointers to be calculated if multiple oneofs were inside a single message. This commit fixes this by using dataoffset of PB_SIZE_MAX to indicate union fields after the first field. Theoretically PB_SIZE_MAX is also a valid value for data offset, which could cause errors. Adding a compile-time assert for this is somewhat difficult. However I consider it extremely unlikely that there is any platform that could trigger this situation, as it would require 255 bytes of extra data/padding between two protobuf oneof fields. On 64-bit architectures the worst case is 16 bytes, and even esoteric platforms only align to 64 bytes or so. Manual modification of the generated .pb.h file could trigger this, but even then it would require pretty bad luck to happen.
Diffstat (limited to 'generator')
-rwxr-xr-xgenerator/nanopb_generator.py20
1 files changed, 15 insertions, 5 deletions
diff --git a/generator/nanopb_generator.py b/generator/nanopb_generator.py
index a2ee22db..6e5ebaf9 100755
--- a/generator/nanopb_generator.py
+++ b/generator/nanopb_generator.py
@@ -509,9 +509,10 @@ class Field:
identifier = '%s_%s_tag' % (self.struct_name, self.name)
return '#define %-40s %d\n' % (identifier, self.tag)
- def pb_field_t(self, prev_field_name):
+ def pb_field_t(self, prev_field_name, union_index = None):
'''Return the pb_field_t initializer to use in the constant array.
- prev_field_name is the name of the previous field or None.
+ prev_field_name is the name of the previous field or None. For OneOf
+ unions, union_index is the index of this field inside the OneOf.
'''
if self.rules == 'ONEOF':
@@ -526,7 +527,14 @@ class Field:
result += '%-8s, ' % self.pbtype
result += '%s, ' % self.rules
result += '%-8s, ' % (self.allocation if not self.inline else "INLINE")
- result += '%s, ' % ("FIRST" if not prev_field_name else "OTHER")
+
+ if union_index is not None and union_index > 0:
+ result += 'UNION, '
+ elif prev_field_name is None:
+ result += 'FIRST, '
+ else:
+ result += 'OTHER, '
+
result += '%s, ' % self.struct_name
result += '%s, ' % self.name
result += '%s, ' % (prev_field_name or self.name)
@@ -767,8 +775,10 @@ class OneOf(Field):
return ''.join([f.tags() for f in self.fields])
def pb_field_t(self, prev_field_name):
- result = ',\n'.join([f.pb_field_t(prev_field_name) for f in self.fields])
- return result
+ parts = []
+ for union_index, field in enumerate(self.fields):
+ parts.append(field.pb_field_t(prev_field_name, union_index))
+ return ',\n'.join(parts)
def get_last_field_name(self):
if self.anonymous: