diff options
author | Petteri Aimonen <jpa@git.mail.kapsi.fi> | 2014-12-27 00:57:23 +0300 |
---|---|---|
committer | Petteri Aimonen <jpa@git.mail.kapsi.fi> | 2014-12-27 01:01:45 +0300 |
commit | 4ce729df7f5895a70e8e45b82e32da60c97947d6 (patch) | |
tree | a87990bae8ff92b0bd92209205bcf3e2ecc7ebd8 | |
parent | 83157e3362b039bbaba6e75629ed49b055492956 (diff) |
Backport memory leak fix for issue 138.
-rw-r--r-- | pb_decode.c | 88 |
1 files changed, 60 insertions, 28 deletions
diff --git a/pb_decode.c b/pb_decode.c index cebf596..9edc8b3 100644 --- a/pb_decode.c +++ b/pb_decode.c @@ -42,6 +42,7 @@ static bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag); static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter); static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter); static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter); +static void iter_from_extension(pb_field_iterator_t *iter, pb_extension_t *extension); static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type); static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iterator_t *iter); static bool checkreturn find_extension_field(pb_field_iterator_t *iter); @@ -696,6 +697,19 @@ static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_t } } +static void iter_from_extension(pb_field_iterator_t *iter, pb_extension_t *extension) +{ + const pb_field_t *field = (const pb_field_t*)extension->type->arg; + + iter->start = field; + iter->pos = field; + iter->field_index = 0; + iter->required_field_index = 0; + iter->dest_struct = extension->dest; + iter->pData = extension->dest; + iter->pSize = &extension->found; +} + /* Default handler for extension fields. Expects a pb_field_t structure * in extension->type->arg. */ static bool checkreturn default_extension_decoder(pb_istream_t *stream, @@ -707,14 +721,7 @@ static bool checkreturn default_extension_decoder(pb_istream_t *stream, if (field->tag != tag) return true; - iter.start = field; - iter.pos = field; - iter.field_index = 0; - iter.required_field_index = 0; - iter.dest_struct = extension->dest; - iter.pData = extension->dest; - iter.pSize = &extension->found; - + iter_from_extension(&iter, extension); return decode_field(stream, wire_type, &iter); } @@ -956,6 +963,47 @@ static void pb_release_single_field(const pb_field_iterator_t *iter) pb_type_t type; type = iter->pos->type; + /* Release anything contained inside an extension or submsg. + * This has to be done even if the submsg itself is statically + * allocated. */ + if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) + { + /* Release fields from all extensions in the linked list */ + pb_extension_t *ext = *(pb_extension_t**)iter->pData; + while (ext != NULL) + { + pb_field_iterator_t ext_iter; + iter_from_extension(&ext_iter, ext); + pb_release_single_field(&ext_iter); + ext = ext->next; + } + } + else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) + { + /* Release fields in submessage or submsg array */ + void *pItem = iter->pData; + pb_size_t count = 1; + + if (PB_ATYPE(type) == PB_ATYPE_POINTER) + { + pItem = *(void**)iter->pData; + } + + if (PB_HTYPE(type) == PB_HTYPE_REPEATED) + { + count = *(pb_size_t*)iter->pSize; + } + + if (pItem) + { + while (count--) + { + pb_release((const pb_field_t*)iter->pos->ptr, pItem); + pItem = (uint8_t*)pItem + iter->pos->data_size; + } + } + } + if (PB_ATYPE(type) == PB_ATYPE_POINTER) { if (PB_HTYPE(type) == PB_HTYPE_REPEATED && @@ -970,28 +1018,12 @@ static void pb_release_single_field(const pb_field_iterator_t *iter) pb_free(*pItem); *pItem++ = NULL; } - *(pb_size_t*)iter->pSize = 0; } - else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) + + if (PB_HTYPE(type) == PB_HTYPE_REPEATED) { - /* Release fields in submessages */ - void *pItem = *(void**)iter->pData; - if (pItem) - { - pb_size_t count = 1; - - if (PB_HTYPE(type) == PB_HTYPE_REPEATED) - { - count = *(pb_size_t*)iter->pSize; - *(pb_size_t*)iter->pSize = 0; - } - - while (count--) - { - pb_release((const pb_field_t*)iter->pos->ptr, pItem); - pItem = (uint8_t*)pItem + iter->pos->data_size; - } - } + /* We are going to release the array, so set the size to 0 */ + *(pb_size_t*)iter->pSize = 0; } /* Release main item */ |