From 53250c85043cc11d3553ccf2c55adcc91f5043d9 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Fri, 5 Nov 2021 15:59:43 -0700 Subject: [PATCH] Fix encoding/decoding for def-to-proto on big-endian systems In a big-endian system, the 64-bit value of 1 is represented as: ``` 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 ``` However, when `d.int32_val` is used, this truncates this and takes the first four bytes: ``` 0x0 0x0 0x0 0x0 ``` As a result, we lose the value of 1 from this truncation and the value beocmes 0. This doesn't happen in a little-endian system because the 1 is in the lowest memory address, so truncating the value to 32 bits doesn't change anything. Previously the DefToProto test was failing on a big-endian system because this truncation caused the key to be incorrectly set to 0. We now use the type-specific functions (e.g. `upb_fielddef_defaultint32`) to do this conversion. Closes https://github.com/protocolbuffers/upb/issues/442 --- upb/def.c | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/upb/def.c b/upb/def.c index 233d7d9eb3..6087293fcb 100644 --- a/upb/def.c +++ b/upb/def.c @@ -574,17 +574,39 @@ const upb_oneofdef *upb_fielddef_realcontainingoneof(const upb_fielddef *f) { upb_msgval upb_fielddef_default(const upb_fielddef *f) { UPB_ASSERT(!upb_fielddef_issubmsg(f)); upb_msgval ret; - if (upb_fielddef_isstring(f)) { - str_t *str = f->defaultval.str; - if (str) { - ret.str_val.data = str->str; - ret.str_val.size = str->len; - } else { - ret.str_val.size = 0; + + switch (upb_fielddef_type(f)) { + case UPB_TYPE_BOOL: + ret.bool_val = upb_fielddef_defaultbool(f); + break; + case UPB_TYPE_INT64: + ret.int64_val = upb_fielddef_defaultint64(f); + break; + case UPB_TYPE_UINT64: + ret.uint64_val = upb_fielddef_defaultuint64(f); + break; + case UPB_TYPE_ENUM: + case UPB_TYPE_INT32: + ret.int32_val = upb_fielddef_defaultint32(f); + break; + case UPB_TYPE_UINT32: + ret.uint32_val = upb_fielddef_defaultuint32(f); + break; + case UPB_TYPE_FLOAT: + ret.float_val = upb_fielddef_defaultfloat(f); + break; + case UPB_TYPE_DOUBLE: + ret.double_val = upb_fielddef_defaultdouble(f); + break; + case UPB_TYPE_STRING: + case UPB_TYPE_BYTES: { + ret.str_val.data = upb_fielddef_defaultstr(f, &ret.str_val.size); + break; } - } else { - memcpy(&ret, &f->defaultval, 8); + default: + UPB_UNREACHABLE(); } + return ret; }