diff options
author | Petteri Aimonen <jpa@git.mail.kapsi.fi> | 2014-12-26 23:14:39 +0200 |
---|---|---|
committer | Petteri Aimonen <jpa@git.mail.kapsi.fi> | 2014-12-26 23:27:35 +0200 |
commit | 88b2efe0477f4f9e313b5d7307dfd347b6893376 (patch) | |
tree | b650e4df6f5cf652fa829ea442d70a68ef5815f7 /pb_decode.c | |
parent | 500883048860cc98745d69ae1d16d85523cd5291 (diff) |
Fix memory leaks with PB_ENABLE_MALLOC and certain submessage type combinations.
There was a memory leak when:
1) A statically allocated submessage or
2) an extension field submessage
contained
A) a pointer-type field or
B) a submessage that further contained a pointer-type field.
This was because pb_release() didn't recurse into non-pointer fields.
Update issue 138
Status: FixedInGit
Diffstat (limited to 'pb_decode.c')
-rw-r--r-- | pb_decode.c | 65 |
1 files changed, 45 insertions, 20 deletions
diff --git a/pb_decode.c b/pb_decode.c index f0fa1cce..367f073b 100644 --- a/pb_decode.c +++ b/pb_decode.c @@ -928,6 +928,47 @@ static void pb_release_single_field(const pb_field_iter_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_iter_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 && @@ -942,28 +983,12 @@ static void pb_release_single_field(const pb_field_iter_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 */ |