From dd0994d377f2f10a2dd5d6e562a628d5ea86f719 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Sun, 1 Nov 2020 15:42:10 -0800 Subject: [PATCH] Bugfix for JSON decoding: only check real oneofs for duplicates. Also fixed upb_msg_whichoneof() to work properly for synthetic fields, and to be simpler in general. --- upb/json_decode.c | 2 +- upb/reflection.c | 25 +++++++++++-------------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/upb/json_decode.c b/upb/json_decode.c index 769c9ea062..fb53c3de35 100644 --- a/upb/json_decode.c +++ b/upb/json_decode.c @@ -910,7 +910,7 @@ static void jsondec_field(jsondec *d, upb_msg *msg, const upb_msgdef *m) { return; } - if (upb_fielddef_containingoneof(f) && + if (upb_fielddef_realcontainingoneof(f) && upb_msg_whichoneof(msg, upb_fielddef_containingoneof(f))) { jsondec_err(d, "More than one field for this oneof."); } diff --git a/upb/reflection.c b/upb/reflection.c index 738bb186ec..fd8623253a 100644 --- a/upb/reflection.c +++ b/upb/reflection.c @@ -96,20 +96,17 @@ bool upb_msg_has(const upb_msg *msg, const upb_fielddef *f) { const upb_fielddef *upb_msg_whichoneof(const upb_msg *msg, const upb_oneofdef *o) { - upb_oneof_iter i; - const upb_fielddef *f; - const upb_msglayout_field *field; - const upb_msgdef *m = upb_oneofdef_containingtype(o); - uint32_t oneof_case; - - /* This is far from optimal. */ - upb_oneof_begin(&i, o); - if (upb_oneof_done(&i)) return false; - f = upb_oneof_iter_field(&i); - field = upb_fielddef_layout(f); - oneof_case = _upb_getoneofcase_field(msg, field); - - return oneof_case ? upb_msgdef_itof(m, oneof_case) : NULL; + const upb_fielddef *f = upb_oneofdef_field(o, 0); + if (upb_oneofdef_issynthetic(o)) { + UPB_ASSERT(upb_oneofdef_fieldcount(o) == 1); + return upb_msg_has(msg, f) ? f : NULL; + } else { + const upb_msglayout_field *field = upb_fielddef_layout(f); + uint32_t oneof_case = _upb_getoneofcase_field(msg, field); + f = oneof_case ? upb_oneofdef_itof(o, oneof_case) : NULL; + UPB_ASSERT((f != NULL) == (oneof_case != 0)); + return f; + } } upb_msgval upb_msg_get(const upb_msg *msg, const upb_fielddef *f) {