summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pb_decode.c29
1 files changed, 12 insertions, 17 deletions
diff --git a/pb_decode.c b/pb_decode.c
index 8b782a6f..4e187256 100644
--- a/pb_decode.c
+++ b/pb_decode.c
@@ -471,36 +471,31 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t
#ifdef PB_ENABLE_MALLOC
/* Allocate storage for the field and store the pointer at iter->pData.
* array_size is the number of entries to reserve in an array.
+ * Zero size is not allowed, use pb_free() for releasing.
*/
static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size)
{
void *ptr = *(void**)pData;
- /* Check for multiplication overflows. */
- size_t size = 0;
- if (data_size > 0 && array_size > 0)
+ /* Check for multiplication overflows.
+ * This code avoids the costly division if the sizes are small enough.
+ * Multiplication is safe as long as only half of bits are set
+ * in either multiplicand.
+ */
+ const size_t check_limit = (size_t)1 << (sizeof(size_t) * 4);
+ if (data_size >= check_limit || array_size >= check_limit)
{
- /* Avoid the costly division if the sizes are small enough.
- * Multiplication is safe as long as only half of bits are set
- * in either multiplicand.
- */
- const size_t check_limit = (size_t)1 << (sizeof(size_t) * 4);
- if (data_size >= check_limit || array_size >= check_limit)
+ const size_t size_max = (size_t)-1;
+ if (size_max / array_size < data_size)
{
- const size_t size_max = (size_t)-1;
- if (size_max / array_size < data_size)
- {
- PB_RETURN_ERROR(stream, "size too large");
- }
+ PB_RETURN_ERROR(stream, "size too large");
}
-
- size = array_size * data_size;
}
/* Allocate new or expand previous allocation */
/* Note: on failure the old pointer will remain in the structure,
* the message must be freed by caller also on error return. */
- ptr = pb_realloc(ptr, size);
+ ptr = pb_realloc(ptr, array_size * data_size);
if (ptr == NULL)
PB_RETURN_ERROR(stream, "realloc failed");