X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=pb_decode.c;h=b21bfe37f37c854cf7898f95f5f4e1ab9e246ebc;hb=1f86b707e3a845f2c403e77173d0859dbf6aa4b0;hp=0677594f813bea2973a4afc6ff1c0ccaaf3e611e;hpb=d2e023e3e5ef888e176292f149d1ba93ba270c94;p=apps%2Fagl-service-can-low-level.git diff --git a/pb_decode.c b/pb_decode.c index 0677594f..b21bfe37 100644 --- a/pb_decode.c +++ b/pb_decode.c @@ -48,6 +48,7 @@ static bool checkreturn pb_skip_string(pb_istream_t *stream); #ifdef PB_ENABLE_MALLOC static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size); +static bool checkreturn pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter); static void pb_release_single_field(const pb_field_iter_t *iter); #endif @@ -395,6 +396,13 @@ 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) + { + /* We memset to zero so that any callbacks are set to NULL. + * Then set any default values. */ + memset(iter->pData, 0, iter->pos->data_size); + pb_message_set_to_defaults((const pb_field_t*)iter->pos->ptr, iter->pData); + } return func(stream, iter->pos, iter->pData); default: @@ -628,6 +636,16 @@ static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) { +#ifdef PB_ENABLE_MALLOC + /* When decoding an oneof field, check if there is old data that must be + * released first. */ + if (PB_HTYPE(iter->pos->type) == PB_HTYPE_ONEOF) + { + if (!pb_release_union_field(stream, iter)) + return false; + } +#endif + switch (PB_ATYPE(iter->pos->type)) { case PB_ATYPE_STATIC: @@ -936,6 +954,34 @@ bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void * } #ifdef PB_ENABLE_MALLOC +/* Given an oneof field, if there has already been a field inside this oneof, + * release it before overwriting with a different one. */ +static bool pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter) +{ + pb_size_t old_tag = *(pb_size_t*)iter->pSize; /* Previous which_ value */ + pb_size_t new_tag = iter->pos->tag; /* New which_ value */ + + if (old_tag == 0) + return true; /* Ok, no old data in union */ + + if (old_tag == new_tag) + return true; /* Ok, old data is of same type => merge */ + + /* Release old data. The find can fail if the message struct contains + * invalid data. */ + if (!pb_field_iter_find(iter, old_tag)) + PB_RETURN_ERROR(stream, "invalid union tag"); + + pb_release_single_field(iter); + + /* Restore iterator to where it should be. + * 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"); + + return true; +} + static void pb_release_single_field(const pb_field_iter_t *iter) { pb_type_t type;