Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nanopb/nanopb.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPetteri Aimonen <jpa@git.mail.kapsi.fi>2014-12-27 00:57:23 +0300
committerPetteri Aimonen <jpa@git.mail.kapsi.fi>2014-12-27 01:01:45 +0300
commit4ce729df7f5895a70e8e45b82e32da60c97947d6 (patch)
treea87990bae8ff92b0bd92209205bcf3e2ecc7ebd8
parent83157e3362b039bbaba6e75629ed49b055492956 (diff)
Backport memory leak fix for issue 138.
-rw-r--r--pb_decode.c88
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 */