summaryrefslogtreecommitdiffstats
path: root/pb_decode.c
diff options
context:
space:
mode:
authorPetteri Aimonen <jpa@git.mail.kapsi.fi>2014-12-26 23:14:39 +0200
committerPetteri Aimonen <jpa@git.mail.kapsi.fi>2014-12-26 23:27:35 +0200
commit88b2efe0477f4f9e313b5d7307dfd347b6893376 (patch)
treeb650e4df6f5cf652fa829ea442d70a68ef5815f7 /pb_decode.c
parent500883048860cc98745d69ae1d16d85523cd5291 (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.c65
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 */