Skip to content

Commit

Permalink
Refactored pb_dec_varint to reduce compiled code size
Browse files Browse the repository at this point in the history
  • Loading branch information
inolen authored and PetteriAimonen committed Nov 19, 2024
1 parent e94839c commit 763a2fc
Showing 1 changed file with 39 additions and 58 deletions.
97 changes: 39 additions & 58 deletions pb_decode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1435,74 1435,55 @@ static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_iter_t

static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_iter_t *field)
{
if (PB_LTYPE(field->type) == PB_LTYPE_UVARINT)
{
pb_uint64_t value, clamped;
if (!pb_decode_varint(stream, &value))
return false;

/* Cast to the proper field size, while checking for overflows */
if (field->data_size == sizeof(pb_uint64_t))
clamped = *(pb_uint64_t*)field->pData = value;
else if (field->data_size == sizeof(uint32_t))
clamped = *(uint32_t*)field->pData = (uint32_t)value;
else if (field->data_size == sizeof(uint_least16_t))
clamped = *(uint_least16_t*)field->pData = (uint_least16_t)value;
else if (field->data_size == sizeof(uint_least8_t))
clamped = *(uint_least8_t*)field->pData = (uint_least8_t)value;
else
PB_RETURN_ERROR(stream, "invalid data_size");
pb_uint64_t overflow;

if (clamped != value)
PB_RETURN_ERROR(stream, "integer too large");
union {
pb_uint64_t u64;
pb_int64_t s64;
} value;

return true;
if (PB_LTYPE(field->type) == PB_LTYPE_SVARINT)
{
if (!pb_decode_svarint(stream, &value.s64))
return false;
}
else
{
pb_uint64_t value;
pb_int64_t svalue;
pb_int64_t clamped;
if (!pb_decode_varint(stream, &value.u64))
return false;
}

if (PB_LTYPE(field->type) == PB_LTYPE_SVARINT)
{
if (!pb_decode_svarint(stream, &svalue))
return false;
}
else
{
if (!pb_decode_varint(stream, &value))
return false;
/* See issue 97: Google's C protobuf allows negative varint values to
* be cast as int32_t, instead of the int64_t that should be used when
* encoding. Nanopb versions before 0.2.5 had a bug in encoding. In order to
* not break decoding of such messages, we cast <=32 bit fields to
* int32_t first to get the sign correct.
*/
if (PB_LTYPE(field->type) == PB_LTYPE_VARINT && field->data_size <= 4)
value.s64 = (int32_t)value.s64;

/* See issue 97: Google's C protobuf allows negative varint values to
* be cast as int32_t, instead of the int64_t that should be used when
* encoding. Nanopb versions before 0.2.5 had a bug in encoding. In order to
* not break decoding of such messages, we cast <=32 bit fields to
* int32_t first to get the sign correct.
*/
if (field->data_size == sizeof(pb_int64_t))
svalue = (pb_int64_t)value;
else
svalue = (int32_t)value;
}
/* Check that the decoded value isn't too small for the field */
if (sizeof(pb_uint64_t) < field->data_size)
PB_RETURN_ERROR(stream, "invalid data_size");

/* Cast to the proper field size, while checking for overflows */
if (field->data_size == sizeof(pb_int64_t))
clamped = *(pb_int64_t*)field->pData = svalue;
else if (field->data_size == sizeof(int32_t))
clamped = *(int32_t*)field->pData = (int32_t)svalue;
else if (field->data_size == sizeof(int_least16_t))
clamped = *(int_least16_t*)field->pData = (int_least16_t)svalue;
else if (field->data_size == sizeof(int_least8_t))
clamped = *(int_least8_t*)field->pData = (int_least8_t)svalue;
else
PB_RETURN_ERROR(stream, "invalid data_size");
/* Check that the decoded value isn't too big for the field. The rules are:
if (clamped != svalue)
PB_RETURN_ERROR(stream, "integer too large");
1.) For unsigned, check if any bit > than field->data_size is set
2.) For positive signed, check if any bit >= the sign bit are set
3.) For negative signed, negate and check if any bit >= the sign bit are set */
overflow = value.u64;

return true;
}
if (PB_LTYPE(field->type) == PB_LTYPE_UVARINT)
overflow >>= 1;
else if (value.s64 < 0)
overflow = ~overflow;

if (overflow >> ((field->data_size << 3) - 1))
PB_RETURN_ERROR(stream, "integer too large");

memcpy(field->pData, &value.u64, field->data_size);

return true;
}

static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_iter_t *field)
Expand Down

0 comments on commit 763a2fc

Please sign in to comment.