diff options
author | Petteri Aimonen <jpa@git.mail.kapsi.fi> | 2014-09-06 18:21:58 +0300 |
---|---|---|
committer | Petteri Aimonen <jpa@git.mail.kapsi.fi> | 2014-09-11 19:22:57 +0300 |
commit | 13a07e35b6b5f813078bde6a1a17d05f017bf714 (patch) | |
tree | 612468a4d0602ba3f25b810b023526ac65c5eb48 /pb_decode.c | |
parent | 0dce9ef635f8af1b9aa07a43f610295bca8954da (diff) |
Fix crash in pb_release() if called twice on same message.
There was a double-free bug in pb_release() because it didn't set size fields
to zero after deallocation. Most commonly this happens if pb_decode() fails,
internally calls pb_release() and then application code also calls pb_release().
Diffstat (limited to 'pb_decode.c')
-rw-r--r-- | pb_decode.c | 25 |
1 files changed, 15 insertions, 10 deletions
diff --git a/pb_decode.c b/pb_decode.c index 5d211023..ecd46dc1 100644 --- a/pb_decode.c +++ b/pb_decode.c @@ -895,22 +895,27 @@ void pb_release(const pb_field_t fields[], void *dest_struct) pb_free(*pItem); *pItem++ = NULL; } + *(pb_size_t*)iter.pSize = 0; } else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) { /* Release fields in submessages */ void *pItem = *(void**)iter.pData; - pb_size_t count = (pItem ? 1 : 0); - - if (PB_HTYPE(type) == PB_HTYPE_REPEATED) - { - count = *(pb_size_t*)iter.pSize; - } - - while (count--) + if (pItem) { - pb_release((const pb_field_t*)iter.pos->ptr, pItem); - pItem = (uint8_t*)pItem + iter.pos->data_size; + 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; + } } } |