diff --git a/upb/decode.c b/upb/decode.c index c981d106e1..e4ab49b31a 100644 --- a/upb/decode.c +++ b/upb/decode.c @@ -92,6 +92,7 @@ static const unsigned fixed64_ok = (1 << UPB_DTYPE_DOUBLE) | (1 << UPB_DTYPE_SFIXED64); /* Op: an action to be performed for a wire-type/field-type combination. */ +#define OP_UNKNOWN -1 #define OP_SCALAR_LG2(n) (n) /* n in [0, 2, 3] => op in [0, 2, 3] */ #define OP_STRING 4 #define OP_BYTES 5 @@ -101,48 +102,48 @@ static const unsigned fixed64_ok = (1 << UPB_DTYPE_DOUBLE) | #define OP_VARPCK_LG2(n) (n + 9) /* n in [0, 2, 3] => op in [9, 11, 12] */ static const int8_t varint_ops[19] = { - -1, /* field not found */ - -1, /* DOUBLE */ - -1, /* FLOAT */ + OP_UNKNOWN, /* field not found */ + OP_UNKNOWN, /* DOUBLE */ + OP_UNKNOWN, /* FLOAT */ OP_SCALAR_LG2(3), /* INT64 */ OP_SCALAR_LG2(3), /* UINT64 */ OP_SCALAR_LG2(2), /* INT32 */ - -1, /* FIXED64 */ - -1, /* FIXED32 */ + OP_UNKNOWN, /* FIXED64 */ + OP_UNKNOWN, /* FIXED32 */ OP_SCALAR_LG2(0), /* BOOL */ - -1, /* STRING */ - -1, /* GROUP */ - -1, /* MESSAGE */ - -1, /* BYTES */ + OP_UNKNOWN, /* STRING */ + OP_UNKNOWN, /* GROUP */ + OP_UNKNOWN, /* MESSAGE */ + OP_UNKNOWN, /* BYTES */ OP_SCALAR_LG2(2), /* UINT32 */ OP_SCALAR_LG2(2), /* ENUM */ - -1, /* SFIXED32 */ - -1, /* SFIXED64 */ + OP_UNKNOWN, /* SFIXED32 */ + OP_UNKNOWN, /* SFIXED64 */ OP_SCALAR_LG2(2), /* SINT32 */ OP_SCALAR_LG2(3), /* SINT64 */ }; static const int8_t delim_ops[37] = { /* For non-repeated field type. */ - -1, /* field not found */ - -1, /* DOUBLE */ - -1, /* FLOAT */ - -1, /* INT64 */ - -1, /* UINT64 */ - -1, /* INT32 */ - -1, /* FIXED64 */ - -1, /* FIXED32 */ - -1, /* BOOL */ - OP_STRING, /* STRING */ - -1, /* GROUP */ - OP_SUBMSG, /* MESSAGE */ - OP_BYTES, /* BYTES */ - -1, /* UINT32 */ - -1, /* ENUM */ - -1, /* SFIXED32 */ - -1, /* SFIXED64 */ - -1, /* SINT32 */ - -1, /* SINT64 */ + OP_UNKNOWN, /* field not found */ + OP_UNKNOWN, /* DOUBLE */ + OP_UNKNOWN, /* FLOAT */ + OP_UNKNOWN, /* INT64 */ + OP_UNKNOWN, /* UINT64 */ + OP_UNKNOWN, /* INT32 */ + OP_UNKNOWN, /* FIXED64 */ + OP_UNKNOWN, /* FIXED32 */ + OP_UNKNOWN, /* BOOL */ + OP_STRING, /* STRING */ + OP_UNKNOWN, /* GROUP */ + OP_SUBMSG, /* MESSAGE */ + OP_BYTES, /* BYTES */ + OP_UNKNOWN, /* UINT32 */ + OP_UNKNOWN, /* ENUM */ + OP_UNKNOWN, /* SFIXED32 */ + OP_UNKNOWN, /* SFIXED64 */ + OP_UNKNOWN, /* SINT32 */ + OP_UNKNOWN, /* SINT64 */ /* For repeated field type. */ OP_FIXPCK_LG2(3), /* REPEATED DOUBLE */ OP_FIXPCK_LG2(2), /* REPEATED FLOAT */ @@ -608,6 +609,76 @@ static bool decode_tryfastdispatch(upb_decstate *d, const char **ptr, return false; } +UPB_FORCEINLINE +static const char *decode_wireval(upb_decstate *d, const char *ptr, + const upb_msglayout_field *field, + int wire_type, wireval *val, int *op) { + switch (wire_type) { + case UPB_WIRE_TYPE_VARINT: + ptr = decode_varint64(d, ptr, &val->uint64_val); + *op = varint_ops[field->descriptortype]; + decode_munge(field->descriptortype, val); + return ptr; + case UPB_WIRE_TYPE_32BIT: + memcpy(&val->uint32_val, ptr, 4); + val->uint32_val = _upb_be_swap32(val->uint32_val); + *op = OP_SCALAR_LG2(2); + if (((1 << field->descriptortype) & fixed32_ok) == 0) *op = OP_UNKNOWN; + return ptr + 4; + case UPB_WIRE_TYPE_64BIT: + memcpy(&val->uint64_val, ptr, 8); + val->uint64_val = _upb_be_swap64(val->uint64_val); + *op = OP_SCALAR_LG2(3); + if (((1 << field->descriptortype) & fixed64_ok) == 0) *op = OP_UNKNOWN; + return ptr + 8; + case UPB_WIRE_TYPE_DELIMITED: { + int ndx = field->descriptortype; + uint64_t size; + if (_upb_getmode(field) == _UPB_MODE_ARRAY) ndx += 18; + ptr = decode_varint64(d, ptr, &size); + if (size >= INT32_MAX || + ptr - d->end + (int32_t)size > d->limit) { + decode_err(d); /* Length overflow. */ + } + *op = delim_ops[ndx]; + val->size = size; + return ptr; + } + case UPB_WIRE_TYPE_START_GROUP: + val->uint32_val = field->number; + *op = OP_SUBMSG; + if (field->descriptortype != UPB_DTYPE_GROUP) *op = OP_UNKNOWN; + return ptr; + default: + decode_err(d); + } +} + +UPB_FORCEINLINE +static const char *decode_skipunknown(upb_decstate *d, const char *ptr, + upb_msg *msg, int field_number, + int wire_type, wireval val, + const char **field_start) { + if (field_number == 0) decode_err(d); + if (wire_type == UPB_WIRE_TYPE_DELIMITED) ptr += val.size; + if (msg) { + if (wire_type == UPB_WIRE_TYPE_START_GROUP) { + d->unknown = *field_start; + d->unknown_msg = msg; + ptr = decode_group(d, ptr, NULL, NULL, field_number); + d->unknown_msg = NULL; + *field_start = d->unknown; + } + if (!_upb_msg_addunknown(msg, *field_start, ptr - *field_start, + &d->arena)) { + decode_err(d); + } + } else if (wire_type == UPB_WIRE_TYPE_START_GROUP) { + ptr = decode_group(d, ptr, NULL, NULL, field_number); + } + return ptr; +} + UPB_NOINLINE static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg, const upb_msglayout *layout) { @@ -628,51 +699,13 @@ static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg, field = upb_find_field(d, layout, field_number, &last_field_index); - switch (wire_type) { - case UPB_WIRE_TYPE_VARINT: - ptr = decode_varint64(d, ptr, &val.uint64_val); - op = varint_ops[field->descriptortype]; - decode_munge(field->descriptortype, &val); - break; - case UPB_WIRE_TYPE_32BIT: - memcpy(&val.uint32_val, ptr, 4); - val.uint32_val = _upb_be_swap32(val.uint32_val); - ptr += 4; - op = OP_SCALAR_LG2(2); - if (((1 << field->descriptortype) & fixed32_ok) == 0) goto unknown; - break; - case UPB_WIRE_TYPE_64BIT: - memcpy(&val.uint64_val, ptr, 8); - val.uint64_val = _upb_be_swap64(val.uint64_val); - ptr += 8; - op = OP_SCALAR_LG2(3); - if (((1 << field->descriptortype) & fixed64_ok) == 0) goto unknown; - break; - case UPB_WIRE_TYPE_DELIMITED: { - int ndx = field->descriptortype; - uint64_t size; - if (_upb_getmode(field) == _UPB_MODE_ARRAY) ndx += 18; - ptr = decode_varint64(d, ptr, &size); - if (size >= INT32_MAX || - ptr - d->end + (int32_t)size > d->limit) { - decode_err(d); /* Length overflow. */ - } - op = delim_ops[ndx]; - val.size = size; - break; - } - case UPB_WIRE_TYPE_START_GROUP: - val.uint32_val = field_number; - op = OP_SUBMSG; - if (field->descriptortype != UPB_DTYPE_GROUP) goto unknown; - break; - case UPB_WIRE_TYPE_END_GROUP: - d->end_group = field_number; - return ptr; - default: - decode_err(d); + if (wire_type == UPB_WIRE_TYPE_END_GROUP) { + d->end_group = field_number; + return ptr; } + ptr = decode_wireval(d, ptr, field, wire_type, &val, &op); + if (op >= 0) { /* Known field, possibly an extension. */ upb_msg *field_msg = msg; @@ -702,25 +735,8 @@ static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg, UPB_UNREACHABLE(); } } else { - unknown: - /* Skip unknown field. */ - if (field_number == 0) decode_err(d); - if (wire_type == UPB_WIRE_TYPE_DELIMITED) ptr += val.size; - if (msg) { - if (wire_type == UPB_WIRE_TYPE_START_GROUP) { - d->unknown = field_start; - d->unknown_msg = msg; - ptr = decode_group(d, ptr, NULL, NULL, field_number); - d->unknown_msg = NULL; - field_start = d->unknown; - } - if (!_upb_msg_addunknown(msg, field_start, ptr - field_start, - &d->arena)) { - decode_err(d); - } - } else if (wire_type == UPB_WIRE_TYPE_START_GROUP) { - ptr = decode_group(d, ptr, NULL, NULL, field_number); - } + ptr = decode_skipunknown(d, ptr, msg, field_number, wire_type, val, + &field_start); } if (decode_isdone(d, &ptr)) return ptr;