X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=pb_decode.c;h=d8ac9ee231e3cc4ddaee53d8577a19fe03ad8aa0;hb=70dee34da6578ab76dbf00009357d679e154e04b;hp=4411e26a7b4306c0205303d325e9cdb44ec89fec;hpb=011a30af9c015b1edd67420d9ca947e9fb499e73;p=apps%2Fagl-service-can-low-level.git diff --git a/pb_decode.c b/pb_decode.c index 4411e26a..d8ac9ee2 100644 --- a/pb_decode.c +++ b/pb_decode.c @@ -13,7 +13,6 @@ #define checkreturn __attribute__((warn_unused_result)) #endif -#define NANOPB_INTERNALS #include "pb.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. */ 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"); #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)) return false; - if (!(byte & 0x80)) + if ((byte & 0x80) == 0) { /* Quick case, 1 byte value */ result = byte; @@ -359,6 +358,10 @@ static bool pb_field_next(pb_field_iterator_t *iter) { prev_size *= iter->pos->array_size; } + else if (PB_ATYPE(iter->pos->type) == PB_ATYPE_POINTER) + { + prev_size = sizeof(void*); + } if (iter->pos->tag == 0) return false; /* Only happens with empty message types */ @@ -393,7 +396,7 @@ static bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag) { return true; } - pb_field_next(iter); + (void)pb_field_next(iter); } while (iter->field_index != start); return false; @@ -431,7 +434,7 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t if (!pb_make_string_substream(stream, &substream)) 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); if (!func(&substream, iter->pos, pItem)) @@ -468,30 +471,34 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t #ifdef PB_ENABLE_MALLOC /* Allocate storage for the field and store the pointer at iter->pData. * array_size is the number of entries to reserve in an array. */ -static bool checkreturn allocate_field(pb_istream_t *stream, pb_field_iterator_t *iter, 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**)iter->pData; - size_t size = array_size * iter->pos->data_size; + void *ptr = *(void**)pData; + size_t size = array_size * data_size; + /* Allocate new or expand previous allocation */ + /* Note: on failure the old pointer will remain in the structure, + * the message must be freed by caller also on error return. */ + ptr = pb_realloc(ptr, size); if (ptr == NULL) + PB_RETURN_ERROR(stream, "realloc failed"); + + *(void**)pData = ptr; + return true; +} + +/* Clear a newly allocated item in case it contains a pointer, or is a submessage. */ +static void initialize_pointer_field(void *pItem, pb_field_iterator_t *iter) +{ + if (PB_LTYPE(iter->pos->type) == PB_LTYPE_STRING || + PB_LTYPE(iter->pos->type) == PB_LTYPE_BYTES) { - /* First allocation */ - ptr = malloc(size); - if (ptr == NULL) - PB_RETURN_ERROR(stream, "malloc failed"); + *(void**)pItem = NULL; } - else + else if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE) { - /* Expand previous allocation */ - /* Note: on failure the old pointer will remain in the structure, - * the message must be freed by caller also on error return. */ - ptr = realloc(ptr, size); - if (ptr == NULL) - PB_RETURN_ERROR(stream, "realloc failed"); + pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, pItem); } - - *(void**)iter->pData = ptr; - return true; } #endif @@ -512,9 +519,19 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ { case PB_HTYPE_REQUIRED: case PB_HTYPE_OPTIONAL: - if (!allocate_field(stream, iter, 1)) - return false; - return func(stream, iter->pos, iter->pData); + if (PB_LTYPE(type) == PB_LTYPE_STRING || + PB_LTYPE(type) == PB_LTYPE_BYTES) + { + return func(stream, iter->pos, iter->pData); + } + else + { + if (!allocate_field(stream, iter->pData, iter->pos->data_size, 1)) + return false; + + initialize_pointer_field(*(void**)iter->pData, iter); + return func(stream, iter->pos, *(void**)iter->pData); + } case PB_HTYPE_REPEATED: if (wire_type == PB_WT_STRING @@ -535,26 +552,26 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ if (*size + 1 > allocated_size) { /* Allocate more storage. This tries to guess the - * number of remaining entries. */ - allocated_size += substream.bytes_left / iter->pos->data_size; - if (*size + 1 > allocated_size) - allocated_size++; /* Division gave zero. */ + * number of remaining entries. Round the division + * upwards. */ + allocated_size += (substream.bytes_left - 1) / iter->pos->data_size + 1; - if (!allocate_field(&substream, iter, allocated_size)) + if (!allocate_field(&substream, iter->pData, iter->pos->data_size, allocated_size)) { status = false; break; } + } - /* Decode the array entry */ - pItem = (uint8_t*)iter->pData + iter->pos->data_size * (*size); - if (!func(&substream, iter->pos, pItem)) - { - status = false; - break; - } - (*size)++; + /* Decode the array entry */ + pItem = *(uint8_t**)iter->pData + iter->pos->data_size * (*size); + initialize_pointer_field(pItem, iter); + if (!func(&substream, iter->pos, pItem)) + { + status = false; + break; } + (*size)++; } pb_close_string_substream(stream, &substream); @@ -564,13 +581,14 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ { /* Normal repeated field, i.e. only one item at a time. */ size_t *size = (size_t*)iter->pSize; - void *pItem = (uint8_t*)iter->pData + iter->pos->data_size * (*size); + void *pItem; - if (!allocate_field(stream, iter, *size + 1)) + (*size)++; + if (!allocate_field(stream, iter->pData, iter->pos->data_size, *size)) return false; - - (*size)++; + pItem = *(uint8_t**)iter->pData + iter->pos->data_size * (*size - 1); + initialize_pointer_field(pItem, iter); return func(stream, iter->pos, pItem); } @@ -676,7 +694,7 @@ static bool checkreturn decode_extension(pb_istream_t *stream, pb_extension_t *extension = *(pb_extension_t* const *)iter->pData; size_t pos = stream->bytes_left; - while (extension && pos == stream->bytes_left) + while (extension != NULL && pos == stream->bytes_left) { bool status; if (extension->type->decode) @@ -703,7 +721,7 @@ static bool checkreturn find_extension_field(pb_field_iterator_t *iter) do { if (PB_LTYPE(iter->pos->type) == PB_LTYPE_EXTENSION) return true; - pb_field_next(iter); + (void)pb_field_next(iter); } while (iter->field_index != start); return false; @@ -779,7 +797,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) { - 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; pb_field_iterator_t iter; @@ -855,7 +873,7 @@ bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[ } while (pb_field_next(&iter)); /* 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++; /* Check the whole bytes */ @@ -875,8 +893,16 @@ bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[ bool checkreturn pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) { + bool status; pb_message_set_to_defaults(fields, dest_struct); - return pb_decode_noinit(stream, fields, dest_struct); + status = pb_decode_noinit(stream, fields, dest_struct); + +#ifdef PB_ENABLE_MALLOC + if (!status) + pb_release(fields, dest_struct); +#endif + + return status; } bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) @@ -892,6 +918,62 @@ bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void * return status; } +#ifdef PB_ENABLE_MALLOC +void pb_release(const pb_field_t fields[], void *dest_struct) +{ + pb_field_iterator_t iter; + pb_field_init(&iter, fields, dest_struct); + + do + { + pb_type_t type; + type = iter.pos->type; + + /* Avoid crash on empty message types (zero fields) */ + if (iter.pos->tag == 0) + continue; + + if (PB_ATYPE(type) == PB_ATYPE_POINTER) + { + if (PB_HTYPE(type) == PB_HTYPE_REPEATED && + (PB_LTYPE(type) == PB_LTYPE_STRING || + PB_LTYPE(type) == PB_LTYPE_BYTES)) + { + /* Release entries in repeated string or bytes array */ + void **pItem = *(void***)iter.pData; + size_t count = *(size_t*)iter.pSize; + while (count--) + { + pb_free(*pItem); + *pItem++ = NULL; + } + } + else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) + { + /* Release fields in submessages */ + void *pItem = *(void**)iter.pData; + size_t count = (pItem ? 1 : 0); + + if (PB_HTYPE(type) == PB_HTYPE_REPEATED) + { + count = *(size_t*)iter.pSize; + } + + while (count--) + { + pb_release((const pb_field_t*)iter.pos->ptr, pItem); + pItem = (uint8_t*)pItem + iter.pos->data_size; + } + } + + /* Release main item */ + pb_free(*(void**)iter.pData); + *(void**)iter.pData = NULL; + } + } while (pb_field_next(&iter)); +} +#endif + /* Field decoders */ bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest) @@ -950,7 +1032,7 @@ bool pb_decode_fixed64(pb_istream_t *stream, void *dest) #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; if (!pb_decode_varint(stream, &value)) @@ -968,7 +1050,7 @@ bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, vo 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; if (!pb_decode_varint(stream, &value)) @@ -984,7 +1066,7 @@ bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, v 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; if (!pb_decode_svarint(stream, &value)) @@ -1000,51 +1082,80 @@ bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, v 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); 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); 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) { - pb_bytes_array_t *x = (pb_bytes_array_t*)dest; + uint32_t size; + pb_bytes_array_t *bdest; - uint32_t temp; - if (!pb_decode_varint32(stream, &temp)) + if (!pb_decode_varint32(stream, &size)) return false; - x->size = temp; - /* Check length, noting the space taken by the size_t header. */ - if (x->size > field->data_size - offsetof(pb_bytes_array_t, bytes)) - PB_RETURN_ERROR(stream, "bytes overflow"); + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { +#ifndef PB_ENABLE_MALLOC + PB_RETURN_ERROR(stream, "no malloc support"); +#else + if (!allocate_field(stream, dest, PB_BYTES_ARRAY_T_ALLOCSIZE(size), 1)) + return false; + bdest = *(pb_bytes_array_t**)dest; +#endif + } + else + { + if (PB_BYTES_ARRAY_T_ALLOCSIZE(size) > field->data_size) + PB_RETURN_ERROR(stream, "bytes overflow"); + bdest = (pb_bytes_array_t*)dest; + } - return pb_read(stream, x->bytes, x->size); + bdest->size = 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; + size_t alloc_size; bool status; if (!pb_decode_varint32(stream, &size)) return false; - /* Check length, noting the null terminator */ - if (size + 1 > field->data_size) - PB_RETURN_ERROR(stream, "string overflow"); + /* Space for null terminator */ + alloc_size = size + 1; + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { +#ifndef PB_ENABLE_MALLOC + PB_RETURN_ERROR(stream, "no malloc support"); +#else + if (!allocate_field(stream, dest, alloc_size, 1)) + return false; + dest = *(void**)dest; +#endif + } + else + { + if (alloc_size > field->data_size) + PB_RETURN_ERROR(stream, "string overflow"); + } status = pb_read(stream, (uint8_t*)dest, size); *((uint8_t*)dest + size) = 0; 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; pb_istream_t substream;