Release memory when overwriting oneof fields.
Update issue 131 Status: FixedInGit
This commit is contained in:
39
pb_decode.c
39
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
|
||||
|
||||
@@ -628,6 +629,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 +947,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;
|
||||
|
||||
Reference in New Issue
Block a user