Hello community, here is the log from the commit of package nanopb for openSUSE:Factory checked in at 2019-12-17 16:54:44 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/nanopb (Old) and /work/SRC/openSUSE:Factory/.nanopb.new.4691 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "nanopb" Tue Dec 17 16:54:44 2019 rev:3 rq:757558 version:0.3.9.4 Changes: -------- --- /work/SRC/openSUSE:Factory/nanopb/nanopb.changes 2019-01-15 09:16:40.766218529 +0100 +++ /work/SRC/openSUSE:Factory/.nanopb.new.4691/nanopb.changes 2019-12-17 16:54:46.161344468 +0100 @@ -1,0 +2,26 @@ +Tue Dec 17 13:41:21 UTC 2019 - mroste...@opensuse.org + +- Update to version 0.3.9.4: + * Publishing nanopb-0.3.9.4 + * Update changelog + * Add test for PB_ENCODE_ARRAYS_UNPACKED + * Fix "unused variable" warning when using PB_ENCODE_ARRAYS_UNPACKED + * Fix undefined behavior with bool fields (#434) + * Make fuzztest detect invalid bool values (#434) + * .gitignore: don't ignore generator-bin files (#419) + * Don't call stream callback with count=0 (#421) + * network_server example: Detect count=0 in read_callback() (#421) + * Add scons package to travis rules, for build automation + * Introduce new compile time flag: PB_ENCODE_ARRAYS_UNPACKED + * Add migration note about enum min/max + * Use min/max enum value for min/max + * Publishing nanopb-0.3.9.3 + * Fix generator error with mangle_names option (#380) + * Add testcase for #380 + * Fix incorrect PB_STATIC_ASSERT for bytes inside oneof (#363) + * Add testcase for #363 + * Generator: Allow comma separated options in plugin mode (#343) + * Fix encoding of fixed size arrays inside proto3 submessages (#376) + * Add regression test for issue #376 + +------------------------------------------------------------------- Old: ---- nanopb-0.3.9.2.tar.xz New: ---- nanopb-0.3.9.4.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ nanopb.spec ++++++ --- /var/tmp/diff_new_pack.FCNOwA/_old 2019-12-17 16:54:46.785344691 +0100 +++ /var/tmp/diff_new_pack.FCNOwA/_new 2019-12-17 16:54:46.785344691 +0100 @@ -20,7 +20,7 @@ %define src_install_dir /usr/src/%{name} Name: nanopb -Version: 0.3.9.2 +Version: 0.3.9.4 Release: 0 Summary: Protocol Buffers with small code size License: Zlib ++++++ _service ++++++ --- /var/tmp/diff_new_pack.FCNOwA/_old 2019-12-17 16:54:46.805344698 +0100 +++ /var/tmp/diff_new_pack.FCNOwA/_new 2019-12-17 16:54:46.805344698 +0100 @@ -6,7 +6,7 @@ <param name="filename">nanopb</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">nanopb(.*)</param> - <param name="revision">refs/tags/nanopb-0.3.9.2</param> + <param name="revision">refs/tags/nanopb-0.3.9.4</param> </service> <service mode="disabled" name="recompress"> <param name="file">*.tar</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.FCNOwA/_old 2019-12-17 16:54:46.821344704 +0100 +++ /var/tmp/diff_new_pack.FCNOwA/_new 2019-12-17 16:54:46.825344705 +0100 @@ -1,4 +1,4 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/nanopb/nanopb</param> - <param name="changesrevision">3626b5c40e2457629ac60a563dde523be7c10bb4</param></service></servicedata> \ No newline at end of file + <param name="changesrevision">493adf3616bee052649c63c473f8355630c2797f</param></service></servicedata> \ No newline at end of file ++++++ nanopb-0.3.9.2.tar.xz -> nanopb-0.3.9.4.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/.travis.yml new/nanopb-0.3.9.4/.travis.yml --- old/nanopb-0.3.9.2/.travis.yml 2018-11-10 12:10:04.000000000 +0100 +++ new/nanopb-0.3.9.4/.travis.yml 2019-10-13 14:06:05.000000000 +0200 @@ -27,6 +27,7 @@ - g++-4.9 - gcc-5 - g++-5 + - scons before_install: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/AUTHORS.txt new/nanopb-0.3.9.4/AUTHORS.txt --- old/nanopb-0.3.9.2/AUTHORS.txt 2018-11-10 12:10:04.000000000 +0100 +++ new/nanopb-0.3.9.4/AUTHORS.txt 2019-10-13 14:06:05.000000000 +0200 @@ -50,3 +50,6 @@ Amarnath <amarnath.h...@gmail.com> Michal Rostecki <mroste...@suse.de> Pei Wang <wangpe...@baidu.com> +Noah Pendleton <2538614+no...@users.noreply.github.com> +Pavol Rusnak <pa...@rusnak.io> + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/CHANGELOG.txt new/nanopb-0.3.9.4/CHANGELOG.txt --- old/nanopb-0.3.9.2/CHANGELOG.txt 2018-11-10 12:10:04.000000000 +0100 +++ new/nanopb-0.3.9.4/CHANGELOG.txt 2019-10-13 14:06:05.000000000 +0200 @@ -1,3 +1,16 @@ +nanopb-0.3.9.4 (2019-10-13) + Fix undefined behavior with bool fields (#434) + Fix enum min/max defines when values are not in order (#405) + Fix network_server socket example with zero-length strings (#421) + Don't call stream read callback with count=0 (#421) + Add compile time flag PB_ENCODE_ARRAYS_UNPACKED (#427) + +nanopb-0.3.9.3 (2019-03-08) + Fix fixed size and callback repeated fields inside proto3 submessages (#376, #382, #386) + Fix incorrect PB_STATIC_ASSERT for bytes inside oneof (#363) + Fix generator error with mangle_names option (#380) + Generator: Allow comma separated options in plugin mode (#343) + nanopb-0.3.9.2 (2018-11-10) Erroneous free() when using callbacks combined with PB_ENABLE_MALLOC (#346) Fix possible null-pointer dereference in decode_callback_field (#342) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/CMakeLists.txt new/nanopb-0.3.9.4/CMakeLists.txt --- old/nanopb-0.3.9.2/CMakeLists.txt 2018-11-10 12:10:04.000000000 +0100 +++ new/nanopb-0.3.9.4/CMakeLists.txt 2019-10-13 14:06:05.000000000 +0200 @@ -2,7 +2,7 @@ project(nanopb C) -set(nanopb_VERSION_STRING nanopb-0.3.9.2) +set(nanopb_VERSION_STRING nanopb-0.3.9.4) set(nanopb_SOVERSION 0) string(REPLACE "nanopb-" "" nanopb_VERSION ${nanopb_VERSION_STRING}) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/docs/migration.rst new/nanopb-0.3.9.4/docs/migration.rst --- old/nanopb-0.3.9.2/docs/migration.rst 2018-11-10 12:10:04.000000000 +0100 +++ new/nanopb-0.3.9.4/docs/migration.rst 2019-10-13 14:06:05.000000000 +0200 @@ -11,7 +11,40 @@ .. contents :: -Nanopb-0.3.9.1, 0.4.0 (2018-xx-xx) +Nanopb-0.3.9.4, 0.4.0 (2019-xx-xx) +================================== + +Fix generation of min/max defines for enum types +------------------------------------------------ + +**Rationale:** Nanopb generator makes #defines for enum minimum and maximum +value. Previously these defines incorrectly had the first and last enum value, +instead of the actual minimum and maximum. (issue #405) + +**Changes:** Minimum define now always has the smallest value, and maximum +define always has the largest value. + +**Required actions:** If these defines are used and enum values in .proto file +are not defined in ascending order, user code behaviour may change. Check that +user code doesn't expect the old, incorrect first/last behaviour. + +Fix undefined behavior related to bool fields +--------------------------------------------- + +**Rationale:** In C99, `bool` variables are not allowed to have other values +than `true` and `false`. Compilers use this fact in optimization, and constructs +like `int foo = msg.has_field ? 100 : 0` will give unexpected results otherwise. +Previously nanopb didn't enforce that decoded bool fields had valid values. + +**Changes:** Bool fields are now handled separately as `PB_LTYPE_BOOL`. The +`LTYPE` descriptor numbers for other field types were renumbered. + +**Required actions:** Source code files must be recompiled, but regenerating +`.pb.h`/`.pb.c` files from `.proto` is not required. If user code directly uses +the nanopb internal field representation (search for `PB_LTYPE_VARINT` in source), +it may need updating. + +Nanopb-0.3.9.1, 0.4.0 (2018-04-14) ================================== Fix handling of string and bytes default values diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/docs/reference.rst new/nanopb-0.3.9.4/docs/reference.rst --- old/nanopb-0.3.9.2/docs/reference.rst 2018-11-10 12:10:04.000000000 +0100 +++ new/nanopb-0.3.9.4/docs/reference.rst 2019-10-13 14:06:05.000000000 +0200 @@ -55,6 +55,10 @@ for example *#define PB_SYSTEM_HEADER "foo.h"*. PB_WITHOUT_64BIT Disable 64-bit support, for old compilers or for a slight speedup on 8-bit platforms. +PB_ENCODE_ARRAYS_UNPACKED Don't encode scalar arrays as packed. + This is only to be used when the decoder on the + receiving side cannot process packed scalar + arrays. Such example is older protobuf.js. ============================ ================================================ The PB_MAX_REQUIRED_FIELDS, PB_FIELD_16BIT and PB_FIELD_32BIT settings allow diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/docs/security.rst new/nanopb-0.3.9.4/docs/security.rst --- old/nanopb-0.3.9.2/docs/security.rst 2018-11-10 12:10:04.000000000 +0100 +++ new/nanopb-0.3.9.4/docs/security.rst 2019-10-13 14:06:05.000000000 +0200 @@ -58,6 +58,7 @@ - The *count* fields of arrays will not exceed the array size. - The *size* field of bytes will not exceed the allocated size. - All string fields will have null terminator. + - bool fields will have valid true/false values (since nanopb-0.3.9.4) 5. After pb_encode() returns successfully, the resulting message is a valid protocol buffers message. (Except if user-defined callbacks write incorrect diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/examples/network_server/common.c new/nanopb-0.3.9.4/examples/network_server/common.c --- old/nanopb-0.3.9.2/examples/network_server/common.c 2018-11-10 12:10:04.000000000 +0100 +++ new/nanopb-0.3.9.4/examples/network_server/common.c 2019-10-13 14:06:05.000000000 +0200 @@ -19,6 +19,9 @@ int fd = (intptr_t)stream->state; int result; + if (count == 0) + return true; + result = recv(fd, buf, count, MSG_WAITALL); if (result == 0) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/generator/nanopb_generator.py new/nanopb-0.3.9.4/generator/nanopb_generator.py --- old/nanopb-0.3.9.2/generator/nanopb_generator.py 2018-11-10 12:10:04.000000000 +0100 +++ new/nanopb-0.3.9.4/generator/nanopb_generator.py 2019-10-13 14:06:05.000000000 +0200 @@ -3,11 +3,12 @@ from __future__ import unicode_literals '''Generate header file for nanopb from a ProtoBuf FileDescriptorSet.''' -nanopb_version = "nanopb-0.3.9.2" +nanopb_version = "nanopb-0.3.9.4" import sys import re import codecs +import copy from functools import reduce try: @@ -223,9 +224,12 @@ result += ' %s;' % self.names - result += '\n#define _%s_MIN %s' % (self.names, self.values[0][0]) - result += '\n#define _%s_MAX %s' % (self.names, self.values[-1][0]) - result += '\n#define _%s_ARRAYSIZE ((%s)(%s+1))' % (self.names, self.names, self.values[-1][0]) + # sort the enum by value + sorted_values = sorted(self.values, key = lambda x: (x[1], x[0])) + + result += '\n#define _%s_MIN %s' % (self.names, sorted_values[0][0]) + result += '\n#define _%s_MAX %s' % (self.names, sorted_values[-1][0]) + result += '\n#define _%s_ARRAYSIZE ((%s)(%s+1))' % (self.names, self.names, sorted_values[-1][0]) if not self.options.long_names: # Define the long names always so that enum value references @@ -347,7 +351,7 @@ if field_options.type == nanopb_pb2.FT_STATIC and not can_be_static: raise Exception("Field '%s' is defined as static, but max_size or " "max_count is not given." % self.name) - + if field_options.fixed_count and self.max_count is None: raise Exception("Field '%s' is defined as fixed count, " "but max_count is not given." % self.name) @@ -617,7 +621,15 @@ '''Determine if this field needs 16bit or 32bit pb_field_t structure to compile properly. Returns numeric value or a C-expression for assert.''' check = [] - if self.pbtype == 'MESSAGE' and self.allocation == 'STATIC': + + need_check = False + + if self.pbtype == 'BYTES' and self.allocation == 'STATIC' and self.max_size > 251: + need_check = True + elif self.pbtype == 'MESSAGE' and self.allocation == 'STATIC': + need_check = True + + if need_check: if self.rules == 'REPEATED': check.append('pb_membersize(%s, %s[0])' % (self.struct_name, self.name)) elif self.rules == 'ONEOF': @@ -627,9 +639,6 @@ check.append('pb_membersize(%s, %s.%s)' % (self.struct_name, self.union_name, self.name)) else: check.append('pb_membersize(%s, %s)' % (self.struct_name, self.name)) - elif self.pbtype == 'BYTES' and self.allocation == 'STATIC': - if self.max_size > 251: - check.append('pb_membersize(%s, %s)' % (self.struct_name, self.name)) return FieldMaxSize([self.tag, self.max_size, self.max_count], check, @@ -1176,11 +1185,11 @@ if message_options.skip_message: continue + message = copy.deepcopy(message) for field in message.field: if field.type in (FieldD.TYPE_MESSAGE, FieldD.TYPE_ENUM): field.type_name = mangle_field_typename(field.type_name) - self.messages.append(Message(name, message, message_options)) for enum in message.enum_type: name = create_name(names + enum.name) @@ -1746,6 +1755,24 @@ import shlex args = shlex.split(params) + + if len(args) == 1 and ',' in args[0]: + # For compatibility with other protoc plugins, support options + # separated by comma. + lex = shlex.shlex(params) + lex.whitespace_split = True + lex.whitespace = ',' + args = list(lex) + + optparser.usage = "Usage: protoc --nanopb_out=[options][,more_options]:outdir file.proto" + optparser.epilog = "Output will be written to file.pb.h and file.pb.c." + + if '-h' in args or '--help' in args: + # By default optparser prints help to stdout, which doesn't work for + # protoc plugins. + optparser.print_help(sys.stderr) + sys.exit(1) + options, dummy = optparser.parse_args(args) Globals.verbose_options = options.verbose diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/library.json new/nanopb-0.3.9.4/library.json --- old/nanopb-0.3.9.2/library.json 2018-11-10 12:10:04.000000000 +0100 +++ new/nanopb-0.3.9.4/library.json 2019-10-13 14:06:05.000000000 +0200 @@ -1,6 +1,6 @@ { "name": "Nanopb", - "version": "0.3.9.2", + "version": "0.3.9.4", "keywords": "protocol buffers, protobuf, google", "description": "Nanopb is a plain-C implementation of Google's Protocol Buffers data format. It is targeted at 32 bit microcontrollers, but is also fit for other embedded systems with tight (2-10 kB ROM, <1 kB RAM) memory constraints.", "repository": { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/pb.h new/nanopb-0.3.9.4/pb.h --- old/nanopb-0.3.9.2/pb.h 2018-11-10 12:10:04.000000000 +0100 +++ new/nanopb-0.3.9.4/pb.h 2019-10-13 14:06:05.000000000 +0200 @@ -38,6 +38,11 @@ /* #define PB_OLD_CALLBACK_STYLE */ +/* Don't encode scalar arrays as packed. This is only to be used when + * the decoder on the receiving side cannot process packed scalar arrays. + * Such example is older protobuf.js. */ +/* #define PB_ENCODE_ARRAYS_UNPACKED 1 */ + /****************************************************************** * You usually don't need to change anything below this line. * * Feel free to look around and use the defined macros, though. * @@ -46,7 +51,7 @@ /* Version of the nanopb library. Just in case you want to check it in * your own program. */ -#define NANOPB_VERSION nanopb-0.3.9.2 +#define NANOPB_VERSION nanopb-0.3.9.4 /* Include all the system headers needed by nanopb. You will need the * definitions of the following: @@ -145,39 +150,40 @@ /**** Field data types ****/ /* Numeric types */ -#define PB_LTYPE_VARINT 0x00 /* int32, int64, enum, bool */ -#define PB_LTYPE_UVARINT 0x01 /* uint32, uint64 */ -#define PB_LTYPE_SVARINT 0x02 /* sint32, sint64 */ -#define PB_LTYPE_FIXED32 0x03 /* fixed32, sfixed32, float */ -#define PB_LTYPE_FIXED64 0x04 /* fixed64, sfixed64, double */ +#define PB_LTYPE_BOOL 0x00 /* bool */ +#define PB_LTYPE_VARINT 0x01 /* int32, int64, enum, bool */ +#define PB_LTYPE_UVARINT 0x02 /* uint32, uint64 */ +#define PB_LTYPE_SVARINT 0x03 /* sint32, sint64 */ +#define PB_LTYPE_FIXED32 0x04 /* fixed32, sfixed32, float */ +#define PB_LTYPE_FIXED64 0x05 /* fixed64, sfixed64, double */ /* Marker for last packable field type. */ -#define PB_LTYPE_LAST_PACKABLE 0x04 +#define PB_LTYPE_LAST_PACKABLE 0x05 /* Byte array with pre-allocated buffer. * data_size is the length of the allocated PB_BYTES_ARRAY structure. */ -#define PB_LTYPE_BYTES 0x05 +#define PB_LTYPE_BYTES 0x06 /* String with pre-allocated buffer. * data_size is the maximum length. */ -#define PB_LTYPE_STRING 0x06 +#define PB_LTYPE_STRING 0x07 /* Submessage * submsg_fields is pointer to field descriptions */ -#define PB_LTYPE_SUBMESSAGE 0x07 +#define PB_LTYPE_SUBMESSAGE 0x08 /* Extension pseudo-field * The field contains a pointer to pb_extension_t */ -#define PB_LTYPE_EXTENSION 0x08 +#define PB_LTYPE_EXTENSION 0x09 /* Byte array with inline, pre-allocated byffer. * data_size is the length of the inline, allocated buffer. * This differs from PB_LTYPE_BYTES by defining the element as * pb_byte_t[data_size] rather than pb_bytes_array_t. */ -#define PB_LTYPE_FIXED_LENGTH_BYTES 0x09 +#define PB_LTYPE_FIXED_LENGTH_BYTES 0x0A /* Number of declared LTYPES */ -#define PB_LTYPES_COUNT 0x0A +#define PB_LTYPES_COUNT 0x0B #define PB_LTYPE_MASK 0x0F /**** Field repetition rules ****/ @@ -486,7 +492,7 @@ PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr) /* The mapping from protobuf types to LTYPEs is done using these macros. */ -#define PB_LTYPE_MAP_BOOL PB_LTYPE_VARINT +#define PB_LTYPE_MAP_BOOL PB_LTYPE_BOOL #define PB_LTYPE_MAP_BYTES PB_LTYPE_BYTES #define PB_LTYPE_MAP_DOUBLE PB_LTYPE_FIXED64 #define PB_LTYPE_MAP_ENUM PB_LTYPE_VARINT diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/pb_decode.c new/nanopb-0.3.9.4/pb_decode.c --- old/nanopb-0.3.9.2/pb_decode.c 2018-11-10 12:10:04.000000000 +0100 +++ new/nanopb-0.3.9.4/pb_decode.c 2019-10-13 14:06:05.000000000 +0200 @@ -34,6 +34,7 @@ static bool checkreturn find_extension_field(pb_field_iter_t *iter); static void pb_field_set_to_default(pb_field_iter_t *iter); static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct); +static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_t *field, void *dest); static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest); static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *dest, bool *eof); static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest); @@ -65,6 +66,7 @@ * Order in the array must match pb_action_t LTYPE numbering. */ static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = { + &pb_dec_bool, &pb_dec_varint, &pb_dec_uvarint, &pb_dec_svarint, @@ -99,6 +101,9 @@ bool checkreturn pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count) { + if (count == 0) + return true; + #ifndef PB_BUFFER_ONLY if (buf == NULL && stream->callback != buf_read) { @@ -1242,6 +1247,11 @@ /* Field decoders */ +bool pb_decode_bool(pb_istream_t *stream, bool *dest) +{ + return pb_dec_bool(stream, NULL, (void*)dest); +} + bool pb_decode_svarint(pb_istream_t *stream, pb_int64_t *dest) { pb_uint64_t value; @@ -1291,6 +1301,17 @@ } #endif +static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + uint32_t value; + PB_UNUSED(field); + if (!pb_decode_varint32(stream, &value)) + return false; + + *(bool*)dest = (value != 0); + return true; +} + static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest) { pb_uint64_t value; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/pb_decode.h new/nanopb-0.3.9.4/pb_decode.h --- old/nanopb-0.3.9.2/pb_decode.h 2018-11-10 12:10:04.000000000 +0100 +++ new/nanopb-0.3.9.4/pb_decode.h 2019-10-13 14:06:05.000000000 +0200 @@ -134,7 +134,7 @@ /* Skip the field payload data, given the wire type. */ bool pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type); -/* Decode an integer in the varint format. This works for bool, enum, int32, +/* Decode an integer in the varint format. This works for enum, int32, * int64, uint32 and uint64 field types. */ #ifndef PB_WITHOUT_64BIT bool pb_decode_varint(pb_istream_t *stream, uint64_t *dest); @@ -142,10 +142,13 @@ #define pb_decode_varint pb_decode_varint32 #endif -/* Decode an integer in the varint format. This works for bool, enum, int32, +/* Decode an integer in the varint format. This works for enum, int32, * and uint32 field types. */ bool pb_decode_varint32(pb_istream_t *stream, uint32_t *dest); +/* Decode a bool value in varint format. */ +bool pb_decode_bool(pb_istream_t *stream, bool *dest); + /* Decode an integer in the zig-zagged svarint format. This works for sint32 * and sint64. */ #ifndef PB_WITHOUT_64BIT diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/pb_encode.c new/nanopb-0.3.9.4/pb_encode.c --- old/nanopb-0.3.9.2/pb_encode.c 2018-11-10 12:10:04.000000000 +0100 +++ new/nanopb-0.3.9.4/pb_encode.c 2019-10-13 14:06:05.000000000 +0200 @@ -28,6 +28,7 @@ static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension); static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData); static void *pb_const_cast(const void *p); +static bool checkreturn pb_enc_bool(pb_ostream_t *stream, const pb_field_t *field, const void *src); static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src); static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src); static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src); @@ -52,6 +53,7 @@ * Order in the array must match pb_action_t LTYPE numbering. */ static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = { + &pb_enc_bool, &pb_enc_varint, &pb_enc_uvarint, &pb_enc_svarint, @@ -100,7 +102,7 @@ bool checkreturn pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count) { - if (stream->callback != NULL) + if (count > 0 && stream->callback != NULL) { if (stream->bytes_written + count > stream->max_size) PB_RETURN_ERROR(stream, "stream full"); @@ -122,20 +124,39 @@ * Encode a single field * *************************/ +/* Read a bool value without causing undefined behavior even if the value + * is invalid. See issue #434 and + * https://stackoverflow.com/questions/27661768/weird-results-for-conditional + */ +static bool safe_read_bool(const void *pSize) +{ + const char *p = (const char *)pSize; + size_t i; + for (i = 0; i < sizeof(bool); i++) + { + if (p[i] != 0) + return true; + } + return false; +} + /* Encode a static array. Handles the size calculations and possible packing. */ static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, const void *pData, size_t count, pb_encoder_t func) { size_t i; const void *p; +#ifndef PB_ENCODE_ARRAYS_UNPACKED size_t size; - +#endif + if (count == 0) return true; if (PB_ATYPE(field->type) != PB_ATYPE_POINTER && count > field->array_size) PB_RETURN_ERROR(stream, "array max size exceeded"); +#ifndef PB_ENCODE_ARRAYS_UNPACKED /* We always pack arrays if the datatype allows it. */ if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE) { @@ -180,6 +201,7 @@ } } else +#endif { p = pData; for (i = 0; i < count; i++) @@ -225,7 +247,10 @@ else if (PB_HTYPE(type) == PB_HTYPE_REPEATED) { /* Repeated fields inside proto3 submessage: present if count != 0 */ - return *(const pb_size_t*)pSize == 0; + if (field->size_offset != 0) + return *(const pb_size_t*)pSize == 0; + else + return false; /* Fixed length array */ } else if (PB_HTYPE(type) == PB_HTYPE_ONEOF) { @@ -235,7 +260,7 @@ else if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && field->size_offset != 0) { /* Proto2 optional fields inside proto3 submessage */ - return *(const bool*)pSize == false; + return safe_read_bool(pSize) == false; } /* Rest is proto3 singular fields */ @@ -351,7 +376,7 @@ break; case PB_HTYPE_OPTIONAL: - if (*(const bool*)pSize) + if (safe_read_bool(pSize)) { if (!pb_encode_tag_for_field(stream, field)) return false; @@ -643,6 +668,7 @@ pb_wire_type_t wiretype; switch (PB_LTYPE(field->type)) { + case PB_LTYPE_BOOL: case PB_LTYPE_VARINT: case PB_LTYPE_UVARINT: case PB_LTYPE_SVARINT: @@ -731,6 +757,13 @@ /* Field encoders */ +static bool checkreturn pb_enc_bool(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + uint32_t value = (uint32_t)safe_read_bool(src); + PB_UNUSED(field); + return pb_encode_varint(stream, value); +} + static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src) { pb_int64_t value = 0; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/tests/SConstruct new/nanopb-0.3.9.4/tests/SConstruct --- old/nanopb-0.3.9.2/tests/SConstruct 2018-11-10 12:10:04.000000000 +0100 +++ new/nanopb-0.3.9.4/tests/SConstruct 2019-10-13 14:06:05.000000000 +0200 @@ -103,7 +103,7 @@ # Check if we can use undefined behaviour sanitizer (only with clang) # TODO: Fuzz test triggers the bool sanitizer, figure out whether to # modify the fuzz test or to keep ignoring the check. - extra = '-fsanitize=undefined,integer -fno-sanitize-recover=undefined,integer -fsanitize-recover=bool ' + extra = '-fsanitize=undefined,integer -fno-sanitize-recover=undefined,integer ' if 'clang' in env['CC']: if conf.CheckCCFLAGS(extra, linkflags = extra): conf.env.Append(CORECFLAGS = extra) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/tests/encode_arrays_unpacked/SConscript new/nanopb-0.3.9.4/tests/encode_arrays_unpacked/SConscript --- old/nanopb-0.3.9.2/tests/encode_arrays_unpacked/SConscript 1970-01-01 01:00:00.000000000 +0100 +++ new/nanopb-0.3.9.4/tests/encode_arrays_unpacked/SConscript 2019-10-13 14:06:05.000000000 +0200 @@ -0,0 +1,28 @@ +# Run the alltypes test case, but compile with PB_ENCODE_ARRAYS_UNPACKED=1 + +Import("env") + +# Take copy of the files for custom build. +c = Copy("$TARGET", "$SOURCE") +env.Command("alltypes.pb.h", "$BUILD/alltypes/alltypes.pb.h", c) +env.Command("alltypes.pb.c", "$BUILD/alltypes/alltypes.pb.c", c) +env.Command("encode_alltypes.c", "$BUILD/alltypes/encode_alltypes.c", c) +env.Command("decode_alltypes.c", "$BUILD/alltypes/decode_alltypes.c", c) + +# Define the compilation options +opts = env.Clone() +opts.Append(CPPDEFINES = {'PB_ENCODE_ARRAYS_UNPACKED': 1}) + +# Build new version of core +strict = opts.Clone() +strict.Append(CFLAGS = strict['CORECFLAGS']) +strict.Object("pb_decode_unpacked.o", "$NANOPB/pb_decode.c") +strict.Object("pb_encode_unpacked.o", "$NANOPB/pb_encode.c") +strict.Object("pb_common_unpacked.o", "$NANOPB/pb_common.c") + +# Now build and run the test normally. +enc = opts.Program(["encode_alltypes.c", "alltypes.pb.c", "pb_encode_unpacked.o", "pb_common_unpacked.o"]) +dec = opts.Program(["decode_alltypes.c", "alltypes.pb.c", "pb_decode_unpacked.o", "pb_common_unpacked.o"]) + +env.RunTest(enc) +env.RunTest([dec, "encode_alltypes.output"]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/tests/enum_minmax/SConscript new/nanopb-0.3.9.4/tests/enum_minmax/SConscript --- old/nanopb-0.3.9.2/tests/enum_minmax/SConscript 1970-01-01 01:00:00.000000000 +0100 +++ new/nanopb-0.3.9.4/tests/enum_minmax/SConscript 2019-10-13 14:06:05.000000000 +0200 @@ -0,0 +1,8 @@ +# Test that different sizes of enum fields are properly encoded and decoded. + +Import('env') + +env.NanopbProto('enumminmax') + +p = env.Program(["enumminmax_unittests.c",]) +env.RunTest(p) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/tests/enum_minmax/enumminmax.proto new/nanopb-0.3.9.4/tests/enum_minmax/enumminmax.proto --- old/nanopb-0.3.9.2/tests/enum_minmax/enumminmax.proto 1970-01-01 01:00:00.000000000 +0100 +++ new/nanopb-0.3.9.4/tests/enum_minmax/enumminmax.proto 2019-10-13 14:06:05.000000000 +0200 @@ -0,0 +1,22 @@ +/* Test out-of-order enum values. + */ + +syntax = "proto3"; + +enum Language { + UNKNOWN = 0; + ENGLISH_EN_GB = 12; + ENGLISH_EN_US = 1; + FRENCH_FR_FR = 2; + ITALIAN_IT_IT = 3; + GERMAN_DE_DE = 4; + SPANISH_ES_AR = 13; + SPANISH_ES_ES = 5; + SPANISH_ES_MX = 14; + SWEDISH_SV_SE = 6; + DUTCH_NL_NL = 7; + KOREAN_KO_KR = 8; + JAPANESE_JA_JP = 9; + CHINESE_SIMPLIFIED_ZH_CN = 10; + CHINESE_TRADITIONAL_ZH_TW = 11; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/tests/enum_minmax/enumminmax_unittests.c new/nanopb-0.3.9.4/tests/enum_minmax/enumminmax_unittests.c --- old/nanopb-0.3.9.2/tests/enum_minmax/enumminmax_unittests.c 1970-01-01 01:00:00.000000000 +0100 +++ new/nanopb-0.3.9.4/tests/enum_minmax/enumminmax_unittests.c 2019-10-13 14:06:05.000000000 +0200 @@ -0,0 +1,16 @@ +#include "unittests.h" +#include "enumminmax.pb.h" + +int main() +{ + int status = 0; + + COMMENT("Verify min/max on unsorted enum"); + { + TEST(_Language_MIN == Language_UNKNOWN); + TEST(_Language_MAX == Language_SPANISH_ES_MX); + TEST(_Language_ARRAYSIZE == (Language_SPANISH_ES_MX+1)); + } + + return status; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/tests/fuzztest/fuzztest.c new/nanopb-0.3.9.4/tests/fuzztest/fuzztest.c --- old/nanopb-0.3.9.2/tests/fuzztest/fuzztest.c 2018-11-10 12:10:04.000000000 +0100 +++ new/nanopb-0.3.9.4/tests/fuzztest/fuzztest.c 2019-10-13 14:06:05.000000000 +0200 @@ -171,6 +171,33 @@ /* Some default data to put in the message */ static const alltypes_static_AllTypes initval = alltypes_static_AllTypes_init_default; +/* Check the invariants defined in security model on decoded structure */ +static void sanity_check_static(alltypes_static_AllTypes *msg) +{ + bool truebool = true; + bool falsebool = false; + + /* TODO: Add more checks, or rather, generate them automatically */ + assert(strlen(msg->req_string) < sizeof(msg->req_string)); + assert(strlen(msg->opt_string) < sizeof(msg->opt_string)); + if (msg->rep_string_count > 0) + { + assert(strlen(msg->rep_string[0]) < sizeof(msg->rep_string[0])); + } + assert(memcmp(&msg->req_bool, &truebool, sizeof(bool)) == 0 || + memcmp(&msg->req_bool, &falsebool, sizeof(bool)) == 0); + assert(memcmp(&msg->has_opt_bool, &truebool, sizeof(bool)) == 0 || + memcmp(&msg->has_opt_bool, &falsebool, sizeof(bool)) == 0); + assert(memcmp(&msg->opt_bool, &truebool, sizeof(bool)) == 0 || + memcmp(&msg->opt_bool, &falsebool, sizeof(bool)) == 0); + assert(msg->rep_bool_count <= pb_arraysize(alltypes_static_AllTypes, rep_bool)); + if (msg->rep_bool_count > 0) + { + assert(memcmp(&msg->rep_bool[0], &truebool, sizeof(bool)) == 0 || + memcmp(&msg->rep_bool[0], &falsebool, sizeof(bool)) == 0); + } +} + #define BUFSIZE 4096 static bool do_static_encode(uint8_t *buffer, size_t *msglen) @@ -230,6 +257,11 @@ rand_fill((uint8_t*)msg, sizeof(alltypes_static_AllTypes)); stream = pb_istream_from_buffer(buffer, msglen); status = pb_decode(&stream, alltypes_static_AllTypes_fields, msg); + + if (status) + { + sanity_check_static(msg); + } if (!status && assert_success) { @@ -285,6 +317,7 @@ pb_istream_t stream = pb_istream_from_buffer(buffer, msglen); status = pb_decode(&stream, alltypes_static_AllTypes_fields, msg1); assert(status); + sanity_check_static(msg1); } { @@ -298,6 +331,7 @@ pb_istream_t stream = pb_istream_from_buffer(buf2, msglen2); status = pb_decode(&stream, alltypes_static_AllTypes_fields, msg2); assert(status); + sanity_check_static(msg2); } { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/tests/regression/issue_363/SConscript new/nanopb-0.3.9.4/tests/regression/issue_363/SConscript --- old/nanopb-0.3.9.2/tests/regression/issue_363/SConscript 1970-01-01 01:00:00.000000000 +0100 +++ new/nanopb-0.3.9.4/tests/regression/issue_363/SConscript 2019-10-13 14:06:05.000000000 +0200 @@ -0,0 +1,14 @@ +# Regression test for #363: +# Incorrect PB_STATIC_ASSERT for bytes inside oneof + +Import("env") + +env.NanopbProto("oneofmsg.proto") +testprog = env.Program(["test_oneofmsg.c", + "oneofmsg.pb.c", + "$COMMON/pb_encode.o", + "$COMMON/pb_decode.o", + "$COMMON/pb_common.o"]) + +env.RunTest(testprog) + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/tests/regression/issue_363/oneofmsg.proto new/nanopb-0.3.9.4/tests/regression/issue_363/oneofmsg.proto --- old/nanopb-0.3.9.2/tests/regression/issue_363/oneofmsg.proto 1970-01-01 01:00:00.000000000 +0100 +++ new/nanopb-0.3.9.4/tests/regression/issue_363/oneofmsg.proto 2019-10-13 14:06:05.000000000 +0200 @@ -0,0 +1,10 @@ +syntax = "proto2"; + +import "nanopb.proto"; + +message BodyMessage { + oneof body_type { + bytes device_data_crypted = 1 [(nanopb).max_size = 252]; + bytes device_config_crypted = 2 [(nanopb).max_size = 252]; + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/tests/regression/issue_363/test_oneofmsg.c new/nanopb-0.3.9.4/tests/regression/issue_363/test_oneofmsg.c --- old/nanopb-0.3.9.2/tests/regression/issue_363/test_oneofmsg.c 1970-01-01 01:00:00.000000000 +0100 +++ new/nanopb-0.3.9.4/tests/regression/issue_363/test_oneofmsg.c 2019-10-13 14:06:05.000000000 +0200 @@ -0,0 +1,42 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <pb_encode.h> +#include <pb_decode.h> +#include "oneofmsg.pb.h" +#include "unittests.h" + +int main(int argc, char **argv) +{ + int status = 0; + uint8_t buffer[512]; + pb_size_t msglen = 0; + + { + pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); + BodyMessage msg = BodyMessage_init_zero; + + msg.which_body_type = BodyMessage_device_data_crypted_tag; + msg.body_type.device_data_crypted.size = 252; + memset(msg.body_type.device_data_crypted.bytes, 0xAA, 252); + + TEST(pb_encode(&stream, BodyMessage_fields, &msg)); + + msglen = stream.bytes_written; + TEST(msglen > 252); + } + + { + pb_istream_t stream = pb_istream_from_buffer(buffer, msglen); + BodyMessage msg = BodyMessage_init_zero; + + TEST(pb_decode(&stream, BodyMessage_fields, &msg)); + + TEST(msg.which_body_type == BodyMessage_device_data_crypted_tag); + TEST(msg.body_type.device_data_crypted.size == 252); + TEST(msg.body_type.device_data_crypted.bytes[251] == 0xAA); + } + + return status; +} + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/tests/regression/issue_376/SConscript new/nanopb-0.3.9.4/tests/regression/issue_376/SConscript --- old/nanopb-0.3.9.2/tests/regression/issue_376/SConscript 1970-01-01 01:00:00.000000000 +0100 +++ new/nanopb-0.3.9.4/tests/regression/issue_376/SConscript 2019-10-13 14:06:05.000000000 +0200 @@ -0,0 +1,14 @@ +# Regression test for #376: +# Problem with fixed array inside proto3 submessage + +Import("env") + +env.NanopbProto(["fixed_array.proto", "fixed_array.options"]) +testprog = env.Program(["test_fixarray.c", + "fixed_array.pb.c", + "$COMMON/pb_encode.o", + "$COMMON/pb_decode.o", + "$COMMON/pb_common.o"]) + +env.RunTest(testprog) + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/tests/regression/issue_376/fixed_array.options new/nanopb-0.3.9.4/tests/regression/issue_376/fixed_array.options --- old/nanopb-0.3.9.2/tests/regression/issue_376/fixed_array.options 1970-01-01 01:00:00.000000000 +0100 +++ new/nanopb-0.3.9.4/tests/regression/issue_376/fixed_array.options 2019-10-13 14:06:05.000000000 +0200 @@ -0,0 +1 @@ +SubMessage.data fixed_count:true,max_count:8 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/tests/regression/issue_376/fixed_array.proto new/nanopb-0.3.9.4/tests/regression/issue_376/fixed_array.proto --- old/nanopb-0.3.9.2/tests/regression/issue_376/fixed_array.proto 1970-01-01 01:00:00.000000000 +0100 +++ new/nanopb-0.3.9.4/tests/regression/issue_376/fixed_array.proto 2019-10-13 14:06:05.000000000 +0200 @@ -0,0 +1,11 @@ +syntax = "proto3"; + +message MainMessage { + SubMessage submsg = 1; +} + +message SubMessage { + repeated int32 data = 1; +} + + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/tests/regression/issue_376/test_fixarray.c new/nanopb-0.3.9.4/tests/regression/issue_376/test_fixarray.c --- old/nanopb-0.3.9.2/tests/regression/issue_376/test_fixarray.c 1970-01-01 01:00:00.000000000 +0100 +++ new/nanopb-0.3.9.4/tests/regression/issue_376/test_fixarray.c 2019-10-13 14:06:05.000000000 +0200 @@ -0,0 +1,40 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <pb_encode.h> +#include <pb_decode.h> +#include "fixed_array.pb.h" +#include "unittests.h" + +int main(int argc, char **argv) +{ + int status = 0; + uint8_t buffer[64]; + pb_size_t msglen = 0; + + { + pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); + MainMessage msg = MainMessage_init_zero; + + msg.submsg.data[0] = 0; + msg.submsg.data[4] = 5; + + TEST(pb_encode(&stream, MainMessage_fields, &msg)); + + msglen = stream.bytes_written; + TEST(msglen > 5); + } + + { + pb_istream_t stream = pb_istream_from_buffer(buffer, msglen); + MainMessage msg = MainMessage_init_zero; + + TEST(pb_decode(&stream, MainMessage_fields, &msg)); + + TEST(msg.submsg.data[0] == 0); + TEST(msg.submsg.data[4] == 5); + } + + return status; +} + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/tests/regression/issue_380/SConscript new/nanopb-0.3.9.4/tests/regression/issue_380/SConscript --- old/nanopb-0.3.9.2/tests/regression/issue_380/SConscript 1970-01-01 01:00:00.000000000 +0100 +++ new/nanopb-0.3.9.4/tests/regression/issue_380/SConscript 2019-10-13 14:06:05.000000000 +0200 @@ -0,0 +1,9 @@ +# Regression test for #380: +# mangle_names:M_STRIP_PACKAGE is broken when message name (partially) +# matches package name + +Import("env") + +env.NanopbProto(["manglenames.proto", "manglenames.options"]) +env.Object("manglenames.pb.o", "manglenames.pb.c") + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/tests/regression/issue_380/manglenames.options new/nanopb-0.3.9.4/tests/regression/issue_380/manglenames.options --- old/nanopb-0.3.9.2/tests/regression/issue_380/manglenames.options 1970-01-01 01:00:00.000000000 +0100 +++ new/nanopb-0.3.9.4/tests/regression/issue_380/manglenames.options 2019-10-13 14:06:05.000000000 +0200 @@ -0,0 +1 @@ +* mangle_names:M_STRIP_PACKAGE diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nanopb-0.3.9.2/tests/regression/issue_380/manglenames.proto new/nanopb-0.3.9.4/tests/regression/issue_380/manglenames.proto --- old/nanopb-0.3.9.2/tests/regression/issue_380/manglenames.proto 1970-01-01 01:00:00.000000000 +0100 +++ new/nanopb-0.3.9.4/tests/regression/issue_380/manglenames.proto 2019-10-13 14:06:05.000000000 +0200 @@ -0,0 +1,16 @@ +syntax = "proto2"; +package A; + +message A { + message B { + optional uint32 val = 1; + } + optional B b = 1; +} + +message AP { + message B { + optional uint32 val = 1; + } + optional B m = 1; +}