Fix crash in pb_release() if called twice on same message.
authorPetteri Aimonen <jpa@git.mail.kapsi.fi>
Sat, 6 Sep 2014 15:21:58 +0000 (18:21 +0300)
committerPetteri Aimonen <jpa@git.mail.kapsi.fi>
Thu, 11 Sep 2014 16:22:57 +0000 (19:22 +0300)
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().

pb_decode.c

index 5d21102..ecd46dc 100644 (file)
@@ -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;
+                    }
                 }
             }