Compare commits

...

21 Commits

Author SHA1 Message Date
Petteri Aimonen
2c51fb7771 Update changelog for 0.2.8 2014-05-20 19:46:48 +03:00
Petteri Aimonen
916bcb3643 Publishing nanopb-0.2.8 2014-05-20 19:35:00 +03:00
Petteri Aimonen
9cf788de54 Fix bug in alltypes test case that made fuzzing difficult. 2014-05-17 20:28:33 +03:00
Petteri Aimonen
5ef128616b Fix security issue with PB_ENABLE_MALLOC.
The multiplication in allocate_field could potentially overflow,
leading to allocating too little memory. This could subsequently
allow an attacker to cause a write past the buffer, overwriting
other memory contents.

The attack is possible if untrusted message data is decoded using
nanopb, and the message type includes a pointer-type string or bytes
field, or a repeated numeric field. Submessage fields are not
affected.

This issue only affects systems that have been compiled with
PB_ENABLE_MALLOC enabled. Only version nanopb-0.2.7 is affected,
as prior versions do not include this functionality.

Update issue 117
Status: FixedInGit
2014-05-17 20:06:55 +03:00
Petteri Aimonen
ba2ab9ea65 Docs update, remove malloc from limitations list 2014-04-26 20:11:54 +03:00
Petteri Aimonen
e6a57e512f Add option to not add timestamps to .pb.h and .pb.c preambles.
Patch by rusnakp.

Update issue 115
Status: FixedInGit
2014-04-18 15:40:40 +03:00
Petteri Aimonen
d177af1639 Fix typos in scons command line options 2014-04-15 20:30:50 +03:00
Petteri Aimonen
3b36235cef Remove -O0 from tests CFLAGS so that optimized builds can be tested also 2014-04-15 20:27:38 +03:00
Petteri Aimonen
1d249a48ea Fix bug in missing_fields test case 2014-04-09 19:39:12 +03:00
Petteri Aimonen
3e83d81b09 Use -fsanitize=undefined when running tests with clang 2014-04-09 19:28:57 +03:00
Petteri Aimonen
938c7ac3f3 Setting version to 0.2.8-dev 2014-04-07 20:45:04 +03:00
Petteri Aimonen
6d74c66ada Publishing nanopb-0.2.7 2014-04-07 20:30:42 +03:00
Petteri Aimonen
c998ffe117 Update changelog 2014-04-07 20:30:12 +03:00
Petteri Aimonen
a8de6acf2d Add rule for building coverage summary using lcov.
Also modified a few tests to be more compatible with coverage information,
so that they use the same pb_encode/decode.c instead of making a copy.
2014-04-05 13:26:37 +03:00
Petteri Aimonen
7880f308ea Fix unused parameter warning when building without errmsg. 2014-04-05 13:25:44 +03:00
Petteri Aimonen
b63e582bdb Add a convenience function pb_get_encoded_size()
There is minimal size penalty from this, and it is probably much more
intuitive to use than PB_OSTREAM_SIZING itself.

This has been suggested before also, but I ended up refusing it back
them. Reconsidering it now, I see that an intuitive API is much better
than any amount of documentation explaining a non-intuitive API.

Update issue 16
Status: FixedInGit
2014-04-05 11:26:39 +03:00
Petteri Aimonen
e5b855fec5 Add a 'found' field to pb_extension_t.
Update issue 112
Status: FixedInGit
2014-04-05 11:11:05 +03:00
Petteri Aimonen
70dee34da6 Add some missing 'static' specifiers
Update issue 91
Status: FixedInGit
2014-04-02 21:08:15 +03:00
Petteri Aimonen
99434724d0 Fix splint warnings, add splint test case 2014-04-02 21:07:30 +03:00
Petteri Aimonen
6c90e824c4 Fix compile error when default value given for extension field.
Update issue 111
Status: FixedInGit
2014-04-01 16:47:53 +03:00
Petteri Aimonen
f4949119ad Add stdlib.h to pb_syshdr.h for dynamic allocation 2014-03-18 16:13:54 +02:00
26 changed files with 255 additions and 72 deletions

View File

@@ -1,3 +1,17 @@
nanopb-0.2.8 (2014-05-20)
Fix security issue with PB_ENABLE_MALLOC. (issue 117)
Add option to not add timestamps to .pb.h and .pb.c preambles. (issue 115)
Documentation updates
Improved tests
nanopb-0.2.7 (2014-04-07)
Fix bug with default values for extension fields (issue 111)
Fix some MISRA-C warnings (issue 91)
Implemented optional malloc() support (issue 80)
Changed pointer-type bytes field datatype
Add a "found" field to pb_extension_t (issue 112)
Add convenience function pb_get_encoded_size() (issue 16)
nanopb-0.2.6 (2014-02-15) nanopb-0.2.6 (2014-02-15)
Fix generator error with bytes callback fields (issue 99) Fix generator error with bytes callback fields (issue 99)
Fix warnings about large integer constants (issue 102) Fix warnings about large integer constants (issue 102)

View File

@@ -47,7 +47,6 @@ Features and limitations
**Limitations** **Limitations**
#) User must provide callbacks when decoding arrays or strings without maximum size. Malloc support could be added as a separate module.
#) Some speed has been sacrificed for code size. #) Some speed has been sacrificed for code size.
#) Encoding is focused on writing to streams. For memory buffers only it could be made more efficient. #) Encoding is focused on writing to streams. For memory buffers only it could be made more efficient.
#) The deprecated Protocol Buffers feature called "groups" is not supported. #) The deprecated Protocol Buffers feature called "groups" is not supported.

View File

@@ -24,10 +24,6 @@ __BIG_ENDIAN__ Set this if your platform stores integers and
floats in big-endian format. Mixed-endian floats in big-endian format. Mixed-endian
systems (different layout for ints and floats) systems (different layout for ints and floats)
are currently not supported. are currently not supported.
NANOPB_INTERNALS Set this to expose the field encoder functions
that are hidden since nanopb-0.1.3. Starting
with nanopb-0.2.4, this flag does nothing. Use
the newer functions that have better interface.
PB_ENABLE_MALLOC Set this to enable dynamic allocation support PB_ENABLE_MALLOC Set this to enable dynamic allocation support
in the decoder. in the decoder.
PB_MAX_REQUIRED_FIELDS Maximum number of required fields to check for PB_MAX_REQUIRED_FIELDS Maximum number of required fields to check for

View File

@@ -53,6 +53,16 @@ typedef int bool;
#endif #endif
/* stdlib.h subset */
#ifdef PB_ENABLE_MALLOC
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#else
void *realloc(void *ptr, size_t size);
void free(void *ptr);
#endif
#endif
/* string.h subset */ /* string.h subset */
#ifdef HAVE_STRING_H #ifdef HAVE_STRING_H
#include <string.h> #include <string.h>

View File

@@ -1,7 +1,7 @@
#!/usr/bin/python #!/usr/bin/python
'''Generate header file for nanopb from a ProtoBuf FileDescriptorSet.''' '''Generate header file for nanopb from a ProtoBuf FileDescriptorSet.'''
nanopb_version = "nanopb-0.2.7-dev" nanopb_version = "nanopb-0.2.8"
import sys import sys
@@ -351,6 +351,8 @@ class Field:
result += '0)' result += '0)'
elif self.pbtype in ['BYTES', 'STRING'] and self.allocation != 'STATIC': elif self.pbtype in ['BYTES', 'STRING'] and self.allocation != 'STATIC':
result += '0)' # Arbitrary size default values not implemented result += '0)' # Arbitrary size default values not implemented
elif self.rules == 'OPTEXT':
result += '0)' # Default value for extensions is not implemented
else: else:
result += '&%s_default)' % (self.struct_name + self.name) result += '&%s_default)' % (self.struct_name + self.name)
@@ -705,6 +707,9 @@ def generate_header(dependencies, headername, enums, messages, extensions, optio
''' '''
yield '/* Automatically generated nanopb header */\n' yield '/* Automatically generated nanopb header */\n'
if options.notimestamp:
yield '/* Generated by %s */\n\n' % (nanopb_version)
else:
yield '/* Generated by %s at %s. */\n\n' % (nanopb_version, time.asctime()) yield '/* Generated by %s at %s. */\n\n' % (nanopb_version, time.asctime())
symbol = make_identifier(headername) symbol = make_identifier(headername)
@@ -778,6 +783,9 @@ def generate_source(headername, enums, messages, extensions, options):
'''Generate content for a source file.''' '''Generate content for a source file.'''
yield '/* Automatically generated nanopb constant definitions */\n' yield '/* Automatically generated nanopb constant definitions */\n'
if options.notimestamp:
yield '/* Generated by %s */\n\n' % (nanopb_version)
else:
yield '/* Generated by %s at %s. */\n\n' % (nanopb_version, time.asctime()) yield '/* Generated by %s at %s. */\n\n' % (nanopb_version, time.asctime())
yield options.genformat % (headername) yield options.genformat % (headername)
yield '\n' yield '\n'
@@ -961,6 +969,8 @@ optparser.add_option("-Q", "--generated-include-format", dest="genformat",
optparser.add_option("-L", "--library-include-format", dest="libformat", optparser.add_option("-L", "--library-include-format", dest="libformat",
metavar="FORMAT", default='#include <%s>\n', metavar="FORMAT", default='#include <%s>\n',
help="Set format string to use for including the nanopb pb.h header. [default: %default]") help="Set format string to use for including the nanopb pb.h header. [default: %default]")
optparser.add_option("-T", "--no-timestamp", dest="notimestamp", action="store_true", default=False,
help="Don't add timestamp to .pb.h and .pb.c preambles")
optparser.add_option("-q", "--quiet", dest="quiet", action="store_true", default=False, optparser.add_option("-q", "--quiet", dest="quiet", action="store_true", default=False,
help="Don't print anything except errors.") help="Don't print anything except errors.")
optparser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False, optparser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False,

12
pb.h
View File

@@ -46,7 +46,7 @@
/* Version of the nanopb library. Just in case you want to check it in /* Version of the nanopb library. Just in case you want to check it in
* your own program. */ * your own program. */
#define NANOPB_VERSION nanopb-0.2.7-dev #define NANOPB_VERSION nanopb-0.2.8
/* Include all the system headers needed by nanopb. You will need the /* Include all the system headers needed by nanopb. You will need the
* definitions of the following: * definitions of the following:
@@ -341,6 +341,10 @@ struct _pb_extension_t {
* If this extension does not match a field, the next handler is * If this extension does not match a field, the next handler is
* automatically called. */ * automatically called. */
pb_extension_t *next; pb_extension_t *next;
/* The decoder sets this to true if the extension was found.
* Ignored for encoding. */
bool found;
}; };
/* Memory allocation functions to use. You can define pb_realloc and /* Memory allocation functions to use. You can define pb_realloc and
@@ -496,7 +500,11 @@ struct _pb_extension_t {
* messages if not used. * messages if not used.
*/ */
#ifdef PB_NO_ERRMSG #ifdef PB_NO_ERRMSG
#define PB_RETURN_ERROR(stream,msg) return false #define PB_RETURN_ERROR(stream,msg) \
do {\
UNUSED(stream); \
return false; \
} while(0)
#define PB_GET_ERROR(stream) "(errmsg disabled)" #define PB_GET_ERROR(stream) "(errmsg disabled)"
#else #else
#define PB_RETURN_ERROR(stream,msg) \ #define PB_RETURN_ERROR(stream,msg) \

View File

@@ -13,7 +13,6 @@
#define checkreturn __attribute__((warn_unused_result)) #define checkreturn __attribute__((warn_unused_result))
#endif #endif
#define NANOPB_INTERNALS
#include "pb.h" #include "pb.h"
#include "pb_decode.h" #include "pb_decode.h"
@@ -130,7 +129,7 @@ bool checkreturn pb_read(pb_istream_t *stream, uint8_t *buf, size_t count)
* This is an optimization for the varint decoding. */ * This is an optimization for the varint decoding. */
static bool checkreturn pb_readbyte(pb_istream_t *stream, uint8_t *buf) static bool checkreturn pb_readbyte(pb_istream_t *stream, uint8_t *buf)
{ {
if (!stream->bytes_left) if (stream->bytes_left == 0)
PB_RETURN_ERROR(stream, "end-of-stream"); PB_RETURN_ERROR(stream, "end-of-stream");
#ifndef PB_BUFFER_ONLY #ifndef PB_BUFFER_ONLY
@@ -174,7 +173,7 @@ static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest)
if (!pb_readbyte(stream, &byte)) if (!pb_readbyte(stream, &byte))
return false; return false;
if (!(byte & 0x80)) if ((byte & 0x80) == 0)
{ {
/* Quick case, 1 byte value */ /* Quick case, 1 byte value */
result = byte; result = byte;
@@ -397,7 +396,7 @@ static bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag)
{ {
return true; return true;
} }
pb_field_next(iter); (void)pb_field_next(iter);
} while (iter->field_index != start); } while (iter->field_index != start);
return false; return false;
@@ -435,7 +434,7 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t
if (!pb_make_string_substream(stream, &substream)) if (!pb_make_string_substream(stream, &substream))
return false; return false;
while (substream.bytes_left && *size < iter->pos->array_size) while (substream.bytes_left > 0 && *size < iter->pos->array_size)
{ {
void *pItem = (uint8_t*)iter->pData + iter->pos->data_size * (*size); void *pItem = (uint8_t*)iter->pData + iter->pos->data_size * (*size);
if (!func(&substream, iter->pos, pItem)) if (!func(&substream, iter->pos, pItem))
@@ -471,11 +470,31 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t
#ifdef PB_ENABLE_MALLOC #ifdef PB_ENABLE_MALLOC
/* Allocate storage for the field and store the pointer at iter->pData. /* Allocate storage for the field and store the pointer at iter->pData.
* array_size is the number of entries to reserve in an array. */ * array_size is the number of entries to reserve in an array.
*/
static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size) static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size)
{ {
void *ptr = *(void**)pData; void *ptr = *(void**)pData;
size_t size = array_size * data_size;
/* Check for multiplication overflows. */
size_t size = 0;
if (data_size > 0 && array_size > 0)
{
/* Avoid the costly division if the sizes are small enough.
* Multiplication is safe as long as only half of bits are set
* in either multiplicand.
*/
const size_t check_limit = (size_t)1 << (sizeof(size_t) * 4);
if (data_size >= check_limit || array_size >= check_limit)
{
if (SIZE_MAX / array_size < data_size)
{
PB_RETURN_ERROR(stream, "size too large");
}
}
size = array_size * data_size;
}
/* Allocate new or expand previous allocation */ /* Allocate new or expand previous allocation */
/* Note: on failure the old pointer will remain in the structure, /* Note: on failure the old pointer will remain in the structure,
@@ -671,7 +690,6 @@ static bool checkreturn default_extension_decoder(pb_istream_t *stream,
{ {
const pb_field_t *field = (const pb_field_t*)extension->type->arg; const pb_field_t *field = (const pb_field_t*)extension->type->arg;
pb_field_iterator_t iter; pb_field_iterator_t iter;
bool dummy;
if (field->tag != tag) if (field->tag != tag)
return true; return true;
@@ -682,7 +700,7 @@ static bool checkreturn default_extension_decoder(pb_istream_t *stream,
iter.required_field_index = 0; iter.required_field_index = 0;
iter.dest_struct = extension->dest; iter.dest_struct = extension->dest;
iter.pData = extension->dest; iter.pData = extension->dest;
iter.pSize = &dummy; iter.pSize = &extension->found;
return decode_field(stream, wire_type, &iter); return decode_field(stream, wire_type, &iter);
} }
@@ -695,7 +713,7 @@ static bool checkreturn decode_extension(pb_istream_t *stream,
pb_extension_t *extension = *(pb_extension_t* const *)iter->pData; pb_extension_t *extension = *(pb_extension_t* const *)iter->pData;
size_t pos = stream->bytes_left; size_t pos = stream->bytes_left;
while (extension && pos == stream->bytes_left) while (extension != NULL && pos == stream->bytes_left)
{ {
bool status; bool status;
if (extension->type->decode) if (extension->type->decode)
@@ -722,7 +740,7 @@ static bool checkreturn find_extension_field(pb_field_iterator_t *iter)
do { do {
if (PB_LTYPE(iter->pos->type) == PB_LTYPE_EXTENSION) if (PB_LTYPE(iter->pos->type) == PB_LTYPE_EXTENSION)
return true; return true;
pb_field_next(iter); (void)pb_field_next(iter);
} while (iter->field_index != start); } while (iter->field_index != start);
return false; return false;
@@ -798,7 +816,7 @@ static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_str
bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct)
{ {
uint8_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 7) / 8] = {0}; /* Used to check for required fields */ uint8_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 7) / 8] = {0, 0, 0, 0, 0, 0, 0, 0};
uint32_t extension_range_start = 0; uint32_t extension_range_start = 0;
pb_field_iterator_t iter; pb_field_iterator_t iter;
@@ -874,7 +892,7 @@ bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[
} while (pb_field_next(&iter)); } while (pb_field_next(&iter));
/* Fixup if last field was also required. */ /* Fixup if last field was also required. */
if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.pos->tag) if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.pos->tag != 0)
req_field_count++; req_field_count++;
/* Check the whole bytes */ /* Check the whole bytes */
@@ -1033,7 +1051,7 @@ bool pb_decode_fixed64(pb_istream_t *stream, void *dest)
#endif #endif
} }
bool checkreturn pb_dec_varint(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)
{ {
uint64_t value; uint64_t value;
if (!pb_decode_varint(stream, &value)) if (!pb_decode_varint(stream, &value))
@@ -1051,7 +1069,7 @@ bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, vo
return true; return true;
} }
bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest) static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest)
{ {
uint64_t value; uint64_t value;
if (!pb_decode_varint(stream, &value)) if (!pb_decode_varint(stream, &value))
@@ -1067,7 +1085,7 @@ bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, v
return true; return true;
} }
bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest) static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest)
{ {
int64_t value; int64_t value;
if (!pb_decode_svarint(stream, &value)) if (!pb_decode_svarint(stream, &value))
@@ -1083,19 +1101,19 @@ bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, v
return true; return true;
} }
bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest) static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest)
{ {
UNUSED(field); UNUSED(field);
return pb_decode_fixed32(stream, dest); return pb_decode_fixed32(stream, dest);
} }
bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest) static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest)
{ {
UNUSED(field); UNUSED(field);
return pb_decode_fixed64(stream, dest); return pb_decode_fixed64(stream, dest);
} }
bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest) static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest)
{ {
uint32_t size; uint32_t size;
pb_bytes_array_t *bdest; pb_bytes_array_t *bdest;
@@ -1124,7 +1142,7 @@ bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, voi
return pb_read(stream, bdest->bytes, size); return pb_read(stream, bdest->bytes, size);
} }
bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest) static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest)
{ {
uint32_t size; uint32_t size;
size_t alloc_size; size_t alloc_size;
@@ -1156,7 +1174,7 @@ bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, vo
return status; return status;
} }
bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest) static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest)
{ {
bool status; bool status;
pb_istream_t substream; pb_istream_t substream;

View File

@@ -3,7 +3,6 @@
* 2011 Petteri Aimonen <jpa@kapsi.fi> * 2011 Petteri Aimonen <jpa@kapsi.fi>
*/ */
#define NANOPB_INTERNALS
#include "pb.h" #include "pb.h"
#include "pb_encode.h" #include "pb_encode.h"
@@ -379,6 +378,17 @@ bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const
return pb_encode_submessage(stream, fields, src_struct); return pb_encode_submessage(stream, fields, src_struct);
} }
bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct)
{
pb_ostream_t stream = PB_OSTREAM_SIZING;
if (!pb_encode(&stream, fields, src_struct))
return false;
*size = stream.bytes_written;
return true;
}
/******************** /********************
* Helper functions * * Helper functions *
********************/ ********************/
@@ -405,9 +415,9 @@ bool checkreturn pb_encode_svarint(pb_ostream_t *stream, int64_t value)
{ {
uint64_t zigzagged; uint64_t zigzagged;
if (value < 0) if (value < 0)
zigzagged = (uint64_t)(~(value << 1)); zigzagged = ~((uint64_t)value << 1);
else else
zigzagged = (uint64_t)(value << 1); zigzagged = (uint64_t)value << 1;
return pb_encode_varint(stream, zigzagged); return pb_encode_varint(stream, zigzagged);
} }
@@ -448,7 +458,7 @@ bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value)
bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number) bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number)
{ {
uint64_t tag = wiretype | (field_number << 3); uint64_t tag = ((uint64_t)field_number << 3) | wiretype;
return pb_encode_varint(stream, tag); return pb_encode_varint(stream, tag);
} }
@@ -544,7 +554,7 @@ bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fie
/* Field encoders */ /* Field encoders */
bool checkreturn pb_enc_varint(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)
{ {
int64_t value = 0; int64_t value = 0;
@@ -562,7 +572,7 @@ bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, co
return pb_encode_varint(stream, (uint64_t)value); return pb_encode_varint(stream, (uint64_t)value);
} }
bool checkreturn pb_enc_uvarint(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)
{ {
uint64_t value = 0; uint64_t value = 0;
@@ -576,7 +586,7 @@ bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, c
return pb_encode_varint(stream, value); return pb_encode_varint(stream, value);
} }
bool checkreturn pb_enc_svarint(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)
{ {
int64_t value = 0; int64_t value = 0;
@@ -590,19 +600,19 @@ bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, c
return pb_encode_svarint(stream, value); return pb_encode_svarint(stream, value);
} }
bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src) static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src)
{ {
UNUSED(field); UNUSED(field);
return pb_encode_fixed64(stream, src); return pb_encode_fixed64(stream, src);
} }
bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src) static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src)
{ {
UNUSED(field); UNUSED(field);
return pb_encode_fixed32(stream, src); return pb_encode_fixed32(stream, src);
} }
bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src) static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src)
{ {
const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)src; const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)src;
@@ -621,7 +631,7 @@ bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, con
return pb_encode_string(stream, bytes->bytes, bytes->size); return pb_encode_string(stream, bytes->bytes, bytes->size);
} }
bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src) static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src)
{ {
/* strnlen() is not always available, so just use a loop */ /* strnlen() is not always available, so just use a loop */
size_t size = 0; size_t size = 0;
@@ -647,7 +657,7 @@ bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, co
return pb_encode_string(stream, (const uint8_t*)src, size); return pb_encode_string(stream, (const uint8_t*)src, size);
} }
bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src) static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src)
{ {
if (field->ptr == NULL) if (field->ptr == NULL)
PB_RETURN_ERROR(stream, "invalid field descriptor"); PB_RETURN_ERROR(stream, "invalid field descriptor");

View File

@@ -71,6 +71,10 @@ bool pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_
*/ */
bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct);
/* Encode the message to get the size of the encoded data, but do not store
* the data. */
bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct);
/************************************** /**************************************
* Functions for manipulating streams * * Functions for manipulating streams *
**************************************/ **************************************/

View File

@@ -4,3 +4,18 @@ all:
clean: clean:
scons -c scons -c
coverage:
rm -rf build coverage
# LCOV does not like the newer gcov format
scons CC=gcc-4.6 CXX=gcc-4.6
# We are only interested in pb_encode.o and pb_decode.o
find build -name '*.gcda' -and \! \( -name '*pb_encode*' -or -name '*pb_decode*' \) -exec rm '{}' \;
# Collect the data
mkdir build/coverage
lcov --base-directory . --directory build/ --gcov-tool gcov-4.6 -c -o build/coverage/nanopb.info
# Generate HTML
genhtml -o build/coverage build/coverage/nanopb.info

View File

@@ -19,8 +19,8 @@ env = Environment(ENV = os.environ, tools = ['default', 'nanopb'])
# Allow overriding the compiler with scons CC=??? # Allow overriding the compiler with scons CC=???
if 'CC' in ARGUMENTS: env.Replace(CC = ARGUMENTS['CC']) if 'CC' in ARGUMENTS: env.Replace(CC = ARGUMENTS['CC'])
if 'CXX' in ARGUMENTS: env.Replace(CXX = ARGUMENTS['CXX']) if 'CXX' in ARGUMENTS: env.Replace(CXX = ARGUMENTS['CXX'])
if 'CFLAGS' in ARGUMENTS: env.Append(CCFLAGS = ARGUMENTS['CFLAGS']) if 'CCFLAGS' in ARGUMENTS: env.Append(CCFLAGS = ARGUMENTS['CCFLAGS'])
if 'CXXFLAGS' in ARGUMENTS: env.Append(CCFLAGS = ARGUMENTS['CXXFLAGS']) if 'CXXFLAGS' in ARGUMENTS: env.Append(CXXFLAGS = ARGUMENTS['CXXFLAGS'])
# Add the builders defined in site_init.py # Add the builders defined in site_init.py
add_nanopb_builders(env) add_nanopb_builders(env)
@@ -33,13 +33,16 @@ env.Append(PROTOCPATH = '#../generator')
# Check the compilation environment, unless we are just cleaning up. # Check the compilation environment, unless we are just cleaning up.
if not env.GetOption('clean'): if not env.GetOption('clean'):
def check_ccflags(context, flags): def check_ccflags(context, flags, linkflags = ''):
'''Check if given CCFLAGS are supported''' '''Check if given CCFLAGS are supported'''
context.Message('Checking support for CCFLAGS="%s"... ' % flags) context.Message('Checking support for CCFLAGS="%s"... ' % flags)
oldflags = context.env['CCFLAGS'] oldflags = context.env['CCFLAGS']
oldlinkflags = context.env['CCFLAGS']
context.env.Append(CCFLAGS = flags) context.env.Append(CCFLAGS = flags)
context.env.Append(LINKFLAGS = linkflags)
result = context.TryCompile("int main() {return 0;}", '.c') result = context.TryCompile("int main() {return 0;}", '.c')
context.env.Replace(CCFLAGS = oldflags) context.env.Replace(CCFLAGS = oldflags)
context.env.Replace(LINKFLAGS = oldlinkflags)
context.Result(result) context.Result(result)
return result return result
@@ -50,6 +53,7 @@ if not env.GetOption('clean'):
stdint = conf.CheckCHeader('stdint.h') stdint = conf.CheckCHeader('stdint.h')
stddef = conf.CheckCHeader('stddef.h') stddef = conf.CheckCHeader('stddef.h')
string = conf.CheckCHeader('string.h') string = conf.CheckCHeader('string.h')
stdlib = conf.CheckCHeader('stdlib.h')
if not stdbool or not stdint or not stddef or not string: if not stdbool or not stdint or not stddef or not string:
conf.env.Append(CPPDEFINES = {'PB_SYSTEM_HEADER': '\\"pb_syshdr.h\\"'}) conf.env.Append(CPPDEFINES = {'PB_SYSTEM_HEADER': '\\"pb_syshdr.h\\"'})
conf.env.Append(CPPPATH = "#../extra") conf.env.Append(CPPPATH = "#../extra")
@@ -58,6 +62,7 @@ if not env.GetOption('clean'):
if stdint: conf.env.Append(CPPDEFINES = {'HAVE_STDINT_H': 1}) if stdint: conf.env.Append(CPPDEFINES = {'HAVE_STDINT_H': 1})
if stddef: conf.env.Append(CPPDEFINES = {'HAVE_STDDEF_H': 1}) if stddef: conf.env.Append(CPPDEFINES = {'HAVE_STDDEF_H': 1})
if string: conf.env.Append(CPPDEFINES = {'HAVE_STRING_H': 1}) if string: conf.env.Append(CPPDEFINES = {'HAVE_STRING_H': 1})
if stdlib: conf.env.Append(CPPDEFINES = {'HAVE_STDLIB_H': 1})
# Check if we can use pkg-config to find protobuf include path # Check if we can use pkg-config to find protobuf include path
status, output = conf.TryAction('pkg-config protobuf --variable=includedir > $TARGET') status, output = conf.TryAction('pkg-config protobuf --variable=includedir > $TARGET')
@@ -81,6 +86,13 @@ if not env.GetOption('clean'):
if conf.CheckCCFLAGS(extra): if conf.CheckCCFLAGS(extra):
conf.env.Append(CORECFLAGS = extra) conf.env.Append(CORECFLAGS = extra)
# Check if we can use undefined behaviour sanitizer (only with clang)
extra = '-fsanitize=undefined '
if 'clang' in env['CC']:
if conf.CheckCCFLAGS(extra, linkflags = extra):
conf.env.Append(CORECFLAGS = extra)
conf.env.Append(LINKFLAGS = extra)
# End the config stuff # End the config stuff
env = conf.Finish() env = conf.Finish()
@@ -89,15 +101,15 @@ if 'gcc' in env['CC']:
# GNU Compiler Collection # GNU Compiler Collection
# Debug info, warnings as errors # Debug info, warnings as errors
env.Append(CFLAGS = '-ansi -pedantic -g -O0 -Wall -Werror --coverage -fstack-protector-all') env.Append(CFLAGS = '-ansi -pedantic -g -Wall -Werror -fprofile-arcs -ftest-coverage -fstack-protector-all')
env.Append(CORECFLAGS = '-Wextra') env.Append(CORECFLAGS = '-Wextra')
env.Append(LINKFLAGS = '--coverage') env.Append(LINKFLAGS = '-g --coverage')
# We currently need uint64_t anyway, even though ANSI C90 otherwise.. # We currently need uint64_t anyway, even though ANSI C90 otherwise..
env.Append(CFLAGS = '-Wno-long-long') env.Append(CFLAGS = '-Wno-long-long')
elif 'clang' in env['CC']: elif 'clang' in env['CC']:
# CLang # CLang
env.Append(CFLAGS = '-ansi -g -O0 -Wall -Werror') env.Append(CFLAGS = '-ansi -g -Wall -Werror')
env.Append(CORECFLAGS = ' -Wextra -Wcast-qual -Wconversion') env.Append(CORECFLAGS = ' -Wextra -Wcast-qual -Wconversion')
elif 'cl' in env['CC']: elif 'cl' in env['CC']:
# Microsoft Visual C++ # Microsoft Visual C++
@@ -117,10 +129,10 @@ elif 'tcc' in env['CC']:
env.SetDefault(CORECFLAGS = '') env.SetDefault(CORECFLAGS = '')
if 'clang++' in env['CXX']: if 'clang' in env['CXX']:
env.Append(CXXFLAGS = '-g -O0 -Wall -Werror -Wextra -Wno-missing-field-initializers') env.Append(CXXFLAGS = '-g -Wall -Werror -Wextra -Wno-missing-field-initializers')
elif 'g++' in env['CXX']: elif 'g++' in env['CXX'] or 'gcc' in env['CXX']:
env.Append(CXXFLAGS = '-g -O0 -Wall -Werror -Wextra -Wno-missing-field-initializers') env.Append(CXXFLAGS = '-g -Wall -Werror -Wextra -Wno-missing-field-initializers')
elif 'cl' in env['CXX']: elif 'cl' in env['CXX']:
env.Append(CXXFLAGS = '/Zi /W2 /WX') env.Append(CXXFLAGS = '/Zi /W2 /WX')

View File

@@ -23,6 +23,7 @@ bool check_alltypes(pb_istream_t *stream, int mode)
/* Fill with garbage to better detect initialization errors */ /* Fill with garbage to better detect initialization errors */
memset(&alltypes, 0xAA, sizeof(alltypes)); memset(&alltypes, 0xAA, sizeof(alltypes));
alltypes.extensions = 0;
if (!pb_decode(stream, AllTypes_fields, &alltypes)) if (!pb_decode(stream, AllTypes_fields, &alltypes))
return false; return false;

View File

@@ -220,6 +220,7 @@ bool check_alltypes(pb_istream_t *stream, int mode)
/* Fill with garbage to better detect initialization errors */ /* Fill with garbage to better detect initialization errors */
memset(&alltypes, 0xAA, sizeof(alltypes)); memset(&alltypes, 0xAA, sizeof(alltypes));
alltypes.extensions = 0;
alltypes.req_int32.funcs.decode = &read_varint; alltypes.req_int32.funcs.decode = &read_varint;
alltypes.req_int32.arg = (void*)-1001; alltypes.req_int32.arg = (void*)-1001;

View File

@@ -19,6 +19,7 @@ bool check_alltypes(pb_istream_t *stream, int mode)
/* Fill with garbage to better detect initialization errors */ /* Fill with garbage to better detect initialization errors */
memset(&alltypes, 0xAA, sizeof(alltypes)); memset(&alltypes, 0xAA, sizeof(alltypes));
alltypes.extensions = 0;
if (!pb_decode(stream, AllTypes_fields, &alltypes)) if (!pb_decode(stream, AllTypes_fields, &alltypes))
return false; return false;

View File

@@ -4,8 +4,6 @@ Import("env")
# Take copy of the files for custom build. # Take copy of the files for custom build.
c = Copy("$TARGET", "$SOURCE") c = Copy("$TARGET", "$SOURCE")
env.Command("pb_encode.c", "#../pb_encode.c", c)
env.Command("pb_decode.c", "#../pb_decode.c", c)
env.Command("alltypes.pb.h", "$BUILD/alltypes/alltypes.pb.h", c) env.Command("alltypes.pb.h", "$BUILD/alltypes/alltypes.pb.h", c)
env.Command("alltypes.pb.c", "$BUILD/alltypes/alltypes.pb.c", 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("encode_alltypes.c", "$BUILD/alltypes/encode_alltypes.c", c)
@@ -15,9 +13,15 @@ env.Command("decode_alltypes.c", "$BUILD/alltypes/decode_alltypes.c", c)
opts = env.Clone() opts = env.Clone()
opts.Append(CPPDEFINES = {'PB_BUFFER_ONLY': 1}) opts.Append(CPPDEFINES = {'PB_BUFFER_ONLY': 1})
# Build new version of core
strict = opts.Clone()
strict.Append(CFLAGS = strict['CORECFLAGS'])
strict.Object("pb_decode_bufonly.o", "$NANOPB/pb_decode.c")
strict.Object("pb_encode_bufonly.o", "$NANOPB/pb_encode.c")
# Now build and run the test normally. # Now build and run the test normally.
enc = opts.Program(["encode_alltypes.c", "alltypes.pb.c", "pb_encode.c"]) enc = opts.Program(["encode_alltypes.c", "alltypes.pb.c", "pb_encode_bufonly.o"])
dec = opts.Program(["decode_alltypes.c", "alltypes.pb.c", "pb_decode.c"]) dec = opts.Program(["decode_alltypes.c", "alltypes.pb.c", "pb_decode_bufonly.o"])
env.RunTest(enc) env.RunTest(enc)
env.RunTest([dec, "encode_alltypes.output"]) env.RunTest([dec, "encode_alltypes.output"])

View File

@@ -282,6 +282,15 @@ int main()
"\x09\x0A\x07\x0A\x05\x01\x02\x03\x04\x05")) "\x09\x0A\x07\x0A\x05\x01\x02\x03\x04\x05"))
} }
{
IntegerContainer msg = {{5, {1,2,3,4,5}}};
size_t size;
COMMENT("Test pb_get_encoded_size.")
TEST(pb_get_encoded_size(&size, IntegerContainer_fields, &msg) &&
size == 9);
}
{ {
uint8_t buffer[10]; uint8_t buffer[10];
pb_ostream_t s; pb_ostream_t s;

View File

@@ -49,7 +49,9 @@ int main(int argc, char **argv)
} }
/* Check that the extensions decoded properly */ /* Check that the extensions decoded properly */
TEST(ext1.found)
TEST(extensionfield1 == 12345) TEST(extensionfield1 == 12345)
TEST(ext2.found)
TEST(strcmp(extensionfield2.test1, "test") == 0) TEST(strcmp(extensionfield2.test1, "test") == 0)
TEST(extensionfield2.test2 == 54321) TEST(extensionfield2.test2 == 54321)

View File

@@ -1,7 +1,7 @@
import 'alltypes.proto'; import 'alltypes.proto';
extend AllTypes { extend AllTypes {
optional int32 AllTypes_extensionfield1 = 255; optional int32 AllTypes_extensionfield1 = 255 [default = 5];
} }
message ExtensionMessage { message ExtensionMessage {

View File

@@ -5,8 +5,6 @@ Import("env")
# Take copy of the files for custom build. # Take copy of the files for custom build.
c = Copy("$TARGET", "$SOURCE") c = Copy("$TARGET", "$SOURCE")
env.Command("pb_encode.c", "#../pb_encode.c", c)
env.Command("pb_decode.c", "#../pb_decode.c", c)
env.Command("encode_alltypes.c", "$BUILD/alltypes/encode_alltypes.c", c) env.Command("encode_alltypes.c", "$BUILD/alltypes/encode_alltypes.c", c)
env.Command("decode_alltypes.c", "$BUILD/alltypes/decode_alltypes.c", c) env.Command("decode_alltypes.c", "$BUILD/alltypes/decode_alltypes.c", c)
@@ -16,9 +14,15 @@ env.NanopbProto(["alltypes", "alltypes.options"])
opts = env.Clone() opts = env.Clone()
opts.Append(CPPDEFINES = {'PB_FIELD_16BIT': 1}) opts.Append(CPPDEFINES = {'PB_FIELD_16BIT': 1})
# Build new version of core
strict = opts.Clone()
strict.Append(CFLAGS = strict['CORECFLAGS'])
strict.Object("pb_decode_fields16.o", "$NANOPB/pb_decode.c")
strict.Object("pb_encode_fields16.o", "$NANOPB/pb_encode.c")
# Now build and run the test normally. # Now build and run the test normally.
enc = opts.Program(["encode_alltypes.c", "alltypes.pb.c", "pb_encode.c"]) enc = opts.Program(["encode_alltypes.c", "alltypes.pb.c", "pb_encode_fields16.o"])
dec = opts.Program(["decode_alltypes.c", "alltypes.pb.c", "pb_decode.c"]) dec = opts.Program(["decode_alltypes.c", "alltypes.pb.c", "pb_decode_fields16.o"])
env.RunTest(enc) env.RunTest(enc)
env.RunTest([dec, "encode_alltypes.output"]) env.RunTest([dec, "encode_alltypes.output"])

View File

@@ -107,5 +107,7 @@ message AllTypes {
// Just to make sure that the size of the fields has been calculated // Just to make sure that the size of the fields has been calculated
// properly, i.e. otherwise a bug in last field might not be detected. // properly, i.e. otherwise a bug in last field might not be detected.
required int32 end = 10099; required int32 end = 10099;
extensions 200 to 255;
} }

View File

@@ -5,8 +5,6 @@ Import("env")
# Take copy of the files for custom build. # Take copy of the files for custom build.
c = Copy("$TARGET", "$SOURCE") c = Copy("$TARGET", "$SOURCE")
env.Command("pb_encode.c", "#../pb_encode.c", c)
env.Command("pb_decode.c", "#../pb_decode.c", c)
env.Command("encode_alltypes.c", "$BUILD/alltypes/encode_alltypes.c", c) env.Command("encode_alltypes.c", "$BUILD/alltypes/encode_alltypes.c", c)
env.Command("decode_alltypes.c", "$BUILD/alltypes/decode_alltypes.c", c) env.Command("decode_alltypes.c", "$BUILD/alltypes/decode_alltypes.c", c)
@@ -16,9 +14,15 @@ env.NanopbProto(["alltypes", "alltypes.options"])
opts = env.Clone() opts = env.Clone()
opts.Append(CPPDEFINES = {'PB_FIELD_32BIT': 1}) opts.Append(CPPDEFINES = {'PB_FIELD_32BIT': 1})
# Build new version of core
strict = opts.Clone()
strict.Append(CFLAGS = strict['CORECFLAGS'])
strict.Object("pb_decode_fields32.o", "$NANOPB/pb_decode.c")
strict.Object("pb_encode_fields32.o", "$NANOPB/pb_encode.c")
# Now build and run the test normally. # Now build and run the test normally.
enc = opts.Program(["encode_alltypes.c", "alltypes.pb.c", "pb_encode.c"]) enc = opts.Program(["encode_alltypes.c", "alltypes.pb.c", "pb_encode_fields32.o"])
dec = opts.Program(["decode_alltypes.c", "alltypes.pb.c", "pb_decode.c"]) dec = opts.Program(["decode_alltypes.c", "alltypes.pb.c", "pb_decode_fields32.o"])
env.RunTest(enc) env.RunTest(enc)
env.RunTest([dec, "encode_alltypes.output"]) env.RunTest([dec, "encode_alltypes.output"])

View File

@@ -107,5 +107,7 @@ message AllTypes {
// Just to make sure that the size of the fields has been calculated // Just to make sure that the size of the fields has been calculated
// properly, i.e. otherwise a bug in last field might not be detected. // properly, i.e. otherwise a bug in last field might not be detected.
required int32 end = 13432099; required int32 end = 13432099;
extensions 200 to 255;
} }

View File

@@ -8,6 +8,7 @@
int main() int main()
{ {
uint8_t buffer[512]; uint8_t buffer[512];
size_t size;
/* Create a message with one missing field */ /* Create a message with one missing field */
{ {
@@ -19,12 +20,14 @@ int main()
printf("Encode failed.\n"); printf("Encode failed.\n");
return 1; return 1;
} }
size = stream.bytes_written;
} }
/* Test that it decodes properly if we don't require that field */ /* Test that it decodes properly if we don't require that field */
{ {
MissingField msg = {0}; MissingField msg = {0};
pb_istream_t stream = pb_istream_from_buffer(buffer, sizeof(buffer)); pb_istream_t stream = pb_istream_from_buffer(buffer, size);
if (!pb_decode(&stream, MissingField_fields, &msg)) if (!pb_decode(&stream, MissingField_fields, &msg))
{ {
@@ -36,7 +39,7 @@ int main()
/* Test that it does *not* decode properly if we require the field */ /* Test that it does *not* decode properly if we require the field */
{ {
AllFields msg = {0}; AllFields msg = {0};
pb_istream_t stream = pb_istream_from_buffer(buffer, sizeof(buffer)); pb_istream_t stream = pb_istream_from_buffer(buffer, size);
if (pb_decode(&stream, AllFields_fields, &msg)) if (pb_decode(&stream, AllFields_fields, &msg))
{ {

View File

@@ -4,8 +4,6 @@ Import("env")
# Take copy of the files for custom build. # Take copy of the files for custom build.
c = Copy("$TARGET", "$SOURCE") c = Copy("$TARGET", "$SOURCE")
env.Command("pb_encode.c", "#../pb_encode.c", c)
env.Command("pb_decode.c", "#../pb_decode.c", c)
env.Command("alltypes.pb.h", "$BUILD/alltypes/alltypes.pb.h", c) env.Command("alltypes.pb.h", "$BUILD/alltypes/alltypes.pb.h", c)
env.Command("alltypes.pb.c", "$BUILD/alltypes/alltypes.pb.c", 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("encode_alltypes.c", "$BUILD/alltypes/encode_alltypes.c", c)
@@ -15,9 +13,15 @@ env.Command("decode_alltypes.c", "$BUILD/alltypes/decode_alltypes.c", c)
opts = env.Clone() opts = env.Clone()
opts.Append(CPPDEFINES = {'PB_NO_ERRMSG': 1}) opts.Append(CPPDEFINES = {'PB_NO_ERRMSG': 1})
# Build new version of core
strict = opts.Clone()
strict.Append(CFLAGS = strict['CORECFLAGS'])
strict.Object("pb_decode_noerr.o", "$NANOPB/pb_decode.c")
strict.Object("pb_encode_noerr.o", "$NANOPB/pb_encode.c")
# Now build and run the test normally. # Now build and run the test normally.
enc = opts.Program(["encode_alltypes.c", "alltypes.pb.c", "pb_encode.c"]) enc = opts.Program(["encode_alltypes.c", "alltypes.pb.c", "pb_encode_noerr.o"])
dec = opts.Program(["decode_alltypes.c", "alltypes.pb.c", "pb_decode.c"]) dec = opts.Program(["decode_alltypes.c", "alltypes.pb.c", "pb_decode_noerr.o"])
env.RunTest(enc) env.RunTest(enc)
env.RunTest([dec, "encode_alltypes.output"]) env.RunTest([dec, "encode_alltypes.output"])

13
tests/splint/SConscript Normal file
View File

@@ -0,0 +1,13 @@
# Check the nanopb core using splint
Import('env')
p = env.WhereIs('splint')
if p:
env.Command('pb_decode.splint', '$NANOPB/pb_decode.c',
'splint -f splint/splint.rc $SOURCE 2> $TARGET')
env.Command('pb_encode.splint', '$NANOPB/pb_encode.c',
'splint -f splint/splint.rc $SOURCE 2> $TARGET')

37
tests/splint/splint.rc Normal file
View File

@@ -0,0 +1,37 @@
+checks
+partial
+matchanyintegral
+strictlib
-isoreserved # to be fixed in 0.3
-nullassign
-predboolint
-predboolptr
+ptrnegate
-switchloopbreak
+ignoresigns
-infloopsuncon
-type
# splint's memory checks don't quite work without annotations
-mustfreeonly
-compmempass
-nullret
-observertrans
-statictrans
-compdestroy
-nullpass
-nullstate
-compdef
-usereleased
-temptrans
-dependenttrans
-kepttrans
-branchstate
-immediatetrans
# These tests give false positives, compiler typically has
# better warnings for these.
-noret
-noeffect
-usedef