aboutsummaryrefslogtreecommitdiff
path: root/pb_decode.c
diff options
context:
space:
mode:
Diffstat (limited to 'pb_decode.c')
-rw-r--r--pb_decode.c85
1 files changed, 68 insertions, 17 deletions
diff --git a/pb_decode.c b/pb_decode.c
index 2c652f1..4efe8a3 100644
--- a/pb_decode.c
+++ b/pb_decode.c
@@ -34,6 +34,7 @@ static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_
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 @@ static void pb_release_single_field(const pb_field_iter_t *iter);
* 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 @@ static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t co
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)
{
@@ -459,14 +464,17 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t
}
case PB_HTYPE_ONEOF:
- *(pb_size_t*)iter->pSize = iter->pos->tag;
- if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE)
+ if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE &&
+ *(pb_size_t*)iter->pSize != iter->pos->tag)
{
/* We memset to zero so that any callbacks are set to NULL.
- * Then set any default values. */
+ * This is because the callbacks might otherwise have values
+ * from some other union field. */
memset(iter->pData, 0, iter->pos->data_size);
pb_message_set_to_defaults((const pb_field_t*)iter->pos->ptr, iter->pData);
}
+ *(pb_size_t*)iter->pSize = iter->pos->tag;
+
return func(stream, iter->pos, iter->pData);
default:
@@ -486,6 +494,16 @@ static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t
if (data_size == 0 || array_size == 0)
PB_RETURN_ERROR(stream, "invalid size");
+#ifdef __AVR__
+ /* Workaround for AVR libc bug 53284: http://savannah.nongnu.org/bugs/?53284
+ * Realloc to size of 1 byte can cause corruption of the malloc structures.
+ */
+ if (data_size == 1 && array_size == 1)
+ {
+ data_size = 2;
+ }
+#endif
+
/* Check for multiplication overflows.
* This code avoids the costly division if the sizes are small enough.
* Multiplication is safe as long as only half of bits are set
@@ -592,12 +610,25 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_
while (substream.bytes_left)
{
+ if (*size == PB_SIZE_MAX)
+ {
+#ifndef PB_NO_ERRMSG
+ stream->errmsg = "too many array entries";
+#endif
+ status = false;
+ break;
+ }
+
if ((size_t)*size + 1 > allocated_size)
{
/* Allocate more storage. This tries to guess the
* number of remaining entries. Round the division
* upwards. */
- allocated_size += (substream.bytes_left - 1) / iter->pos->data_size + 1;
+ size_t remain = (substream.bytes_left - 1) / iter->pos->data_size + 1;
+ if (remain < PB_SIZE_MAX - allocated_size)
+ allocated_size += remain;
+ else
+ allocated_size += 1;
if (!allocate_field(&substream, iter->pData, iter->pos->data_size, allocated_size))
{
@@ -615,15 +646,6 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_
break;
}
- if (*size == PB_SIZE_MAX)
- {
-#ifndef PB_NO_ERRMSG
- stream->errmsg = "too many array entries";
-#endif
- status = false;
- break;
- }
-
(*size)++;
}
if (!pb_close_string_substream(stream, &substream))
@@ -640,11 +662,11 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_
if (*size == PB_SIZE_MAX)
PB_RETURN_ERROR(stream, "too many array entries");
- (*size)++;
- if (!allocate_field(stream, iter->pData, iter->pos->data_size, *size))
+ if (!allocate_field(stream, iter->pData, iter->pos->data_size, (size_t)(*size + 1)))
return false;
- pItem = *(char**)iter->pData + iter->pos->data_size * (*size - 1);
+ pItem = *(char**)iter->pData + iter->pos->data_size * (*size);
+ (*size)++;
initialize_pointer_field(pItem, iter);
return func(stream, iter->pos, pItem);
}
@@ -1128,7 +1150,14 @@ static bool pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter)
* This shouldn't fail unless the pb_field_t structure is corrupted. */
if (!pb_field_iter_find(iter, new_tag))
PB_RETURN_ERROR(stream, "iterator error");
-
+
+ if (PB_ATYPE(iter->pos->type) == PB_ATYPE_POINTER)
+ {
+ /* Initialize the pointer to NULL to make sure it is valid
+ * even in case of error return. */
+ *(void**)iter->pData = NULL;
+ }
+
return true;
}
@@ -1242,6 +1271,11 @@ void pb_release(const pb_field_t fields[], void *dest_struct)
/* 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 +1325,17 @@ bool pb_decode_fixed64(pb_istream_t *stream, void *dest)
}
#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;
@@ -1414,6 +1459,9 @@ static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *fie
#ifndef PB_ENABLE_MALLOC
PB_RETURN_ERROR(stream, "no malloc support");
#else
+ if (stream->bytes_left < size)
+ PB_RETURN_ERROR(stream, "end-of-stream");
+
if (!allocate_field(stream, dest, alloc_size, 1))
return false;
bdest = *(pb_bytes_array_t**)dest;
@@ -1449,6 +1497,9 @@ static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *fi
#ifndef PB_ENABLE_MALLOC
PB_RETURN_ERROR(stream, "no malloc support");
#else
+ if (stream->bytes_left < size)
+ PB_RETURN_ERROR(stream, "end-of-stream");
+
if (!allocate_field(stream, dest, alloc_size, 1))
return false;
dest = *(void**)dest;