Skip to content

Commit c16ac66

Browse files
habermancopybara-github
authored andcommitted
Fixed non-conformance in upb JSON enum decoding when ignoring unknown enum values.
PiperOrigin-RevId: 594322509
1 parent 4ec9170 commit c16ac66

5 files changed

Lines changed: 41 additions & 29 deletions

File tree

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +0,0 @@
1-
Recommended.Proto3.JsonInput.IgnoreUnknownEnumStringValueInMapValue.ProtobufOutput
2-
Recommended.Proto3.JsonInput.IgnoreUnknownEnumStringValueInRepeatedField.ProtobufOutput

conformance/failure_list_php_c.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,2 @@
11
Recommended.Proto2.JsonInput.FieldNameExtension.Validator
2-
Recommended.Proto3.JsonInput.IgnoreUnknownEnumStringValueInMapValue.ProtobufOutput
3-
Recommended.Proto3.JsonInput.IgnoreUnknownEnumStringValueInRepeatedField.ProtobufOutput
42
Required.Proto2.JsonInput.StoresDefaultPrimitive.Validator

conformance/failure_list_ruby.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +0,0 @@
1-
Recommended.Proto3.JsonInput.IgnoreUnknownEnumStringValueInMapValue.ProtobufOutput
2-
Recommended.Proto3.JsonInput.IgnoreUnknownEnumStringValueInRepeatedField.ProtobufOutput
Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +0,0 @@
1-
Recommended.Proto3.JsonInput.IgnoreUnknownEnumStringValueInMapValue.ProtobufOutput
2-
Recommended.Proto3.JsonInput.IgnoreUnknownEnumStringValueInRepeatedField.ProtobufOutput
3-
Recommended.Editions_Proto3.JsonInput.IgnoreUnknownEnumStringValueInMapValue.ProtobufOutput
4-
Recommended.Editions_Proto3.JsonInput.IgnoreUnknownEnumStringValueInRepeatedField.ProtobufOutput

upb/json/decode.c

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,17 @@ typedef struct {
5151
const upb_FieldDef* debug_field;
5252
} jsondec;
5353

54+
typedef struct {
55+
upb_MessageValue value;
56+
bool ignore;
57+
} upb_JsonMessageValue;
58+
5459
enum { JD_OBJECT, JD_ARRAY, JD_STRING, JD_NUMBER, JD_TRUE, JD_FALSE, JD_NULL };
5560

5661
/* Forward declarations of mutually-recursive functions. */
5762
static void jsondec_wellknown(jsondec* d, upb_Message* msg,
5863
const upb_MessageDef* m);
59-
static upb_MessageValue jsondec_value(jsondec* d, const upb_FieldDef* f);
64+
static upb_JsonMessageValue jsondec_value(jsondec* d, const upb_FieldDef* f);
6065
static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg,
6166
const upb_MessageDef* m);
6267
static void jsondec_object(jsondec* d, upb_Message* msg,
@@ -787,19 +792,19 @@ static upb_MessageValue jsondec_strfield(jsondec* d, const upb_FieldDef* f) {
787792
return val;
788793
}
789794

790-
static upb_MessageValue jsondec_enum(jsondec* d, const upb_FieldDef* f) {
795+
static upb_JsonMessageValue jsondec_enum(jsondec* d, const upb_FieldDef* f) {
791796
switch (jsondec_peek(d)) {
792797
case JD_STRING: {
793798
upb_StringView str = jsondec_string(d);
794799
const upb_EnumDef* e = upb_FieldDef_EnumSubDef(f);
795800
const upb_EnumValueDef* ev =
796801
upb_EnumDef_FindValueByNameWithSize(e, str.data, str.size);
797-
upb_MessageValue val;
802+
upb_JsonMessageValue val = {.ignore = false};
798803
if (ev) {
799-
val.int32_val = upb_EnumValueDef_Number(ev);
804+
val.value.int32_val = upb_EnumValueDef_Number(ev);
800805
} else {
801806
if (d->options & upb_JsonDecode_IgnoreUnknown) {
802-
val.int32_val = 0;
807+
val.ignore = true;
803808
} else {
804809
jsondec_errf(d, "Unknown enumerator: '" UPB_STRINGVIEW_FORMAT "'",
805810
UPB_STRINGVIEW_ARGS(str));
@@ -809,15 +814,16 @@ static upb_MessageValue jsondec_enum(jsondec* d, const upb_FieldDef* f) {
809814
}
810815
case JD_NULL: {
811816
if (jsondec_isnullvalue(f)) {
812-
upb_MessageValue val;
817+
upb_JsonMessageValue val = {.ignore = false};
813818
jsondec_null(d);
814-
val.int32_val = 0;
819+
val.value.int32_val = 0;
815820
return val;
816821
}
817822
}
818823
/* Fallthrough. */
819824
default:
820-
return jsondec_int(d, f);
825+
return (upb_JsonMessageValue){.value = jsondec_int(d, f),
826+
.ignore = false};
821827
}
822828
}
823829

@@ -860,8 +866,10 @@ static void jsondec_array(jsondec* d, upb_Message* msg, const upb_FieldDef* f) {
860866

861867
jsondec_arrstart(d);
862868
while (jsondec_arrnext(d)) {
863-
upb_MessageValue elem = jsondec_value(d, f);
864-
upb_Array_Append(arr, elem, d->arena);
869+
upb_JsonMessageValue elem = jsondec_value(d, f);
870+
if (!elem.ignore) {
871+
upb_Array_Append(arr, elem.value, d->arena);
872+
}
865873
}
866874
jsondec_arrend(d);
867875
}
@@ -874,11 +882,14 @@ static void jsondec_map(jsondec* d, upb_Message* msg, const upb_FieldDef* f) {
874882

875883
jsondec_objstart(d);
876884
while (jsondec_objnext(d)) {
877-
upb_MessageValue key, val;
885+
upb_JsonMessageValue key, val;
878886
key = jsondec_value(d, key_f);
887+
UPB_ASSUME(!key.ignore); // Map key cannot be enum.
879888
jsondec_entrysep(d);
880889
val = jsondec_value(d, val_f);
881-
upb_Map_Set(map, key, val, d->arena);
890+
if (!val.ignore) {
891+
upb_Map_Set(map, key.value, val.value, d->arena);
892+
}
882893
}
883894
jsondec_objend(d);
884895
}
@@ -959,8 +970,10 @@ static void jsondec_field(jsondec* d, upb_Message* msg,
959970
const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f);
960971
jsondec_tomsg(d, submsg, subm);
961972
} else {
962-
upb_MessageValue val = jsondec_value(d, f);
963-
upb_Message_SetFieldByDef(msg, f, val, d->arena);
973+
upb_JsonMessageValue val = jsondec_value(d, f);
974+
if (!val.ignore) {
975+
upb_Message_SetFieldByDef(msg, f, val.value, d->arena);
976+
}
964977
}
965978

966979
d->debug_field = preserved;
@@ -975,7 +988,7 @@ static void jsondec_object(jsondec* d, upb_Message* msg,
975988
jsondec_objend(d);
976989
}
977990

978-
static upb_MessageValue jsondec_value(jsondec* d, const upb_FieldDef* f) {
991+
static upb_MessageValue jsondec_nonenum(jsondec* d, const upb_FieldDef* f) {
979992
switch (upb_FieldDef_CType(f)) {
980993
case kUpb_CType_Bool:
981994
return jsondec_bool(d, f);
@@ -991,15 +1004,23 @@ static upb_MessageValue jsondec_value(jsondec* d, const upb_FieldDef* f) {
9911004
case kUpb_CType_String:
9921005
case kUpb_CType_Bytes:
9931006
return jsondec_strfield(d, f);
994-
case kUpb_CType_Enum:
995-
return jsondec_enum(d, f);
9961007
case kUpb_CType_Message:
9971008
return jsondec_msg(d, f);
1009+
case kUpb_CType_Enum:
9981010
default:
9991011
UPB_UNREACHABLE();
10001012
}
10011013
}
10021014

1015+
static upb_JsonMessageValue jsondec_value(jsondec* d, const upb_FieldDef* f) {
1016+
if (upb_FieldDef_CType(f) == kUpb_CType_Enum) {
1017+
return jsondec_enum(d, f);
1018+
} else {
1019+
return (upb_JsonMessageValue){.value = jsondec_nonenum(d, f),
1020+
.ignore = false};
1021+
}
1022+
}
1023+
10031024
/* Well-known types ***********************************************************/
10041025

10051026
static int jsondec_tsdigits(jsondec* d, const char** ptr, size_t digits,
@@ -1424,8 +1445,9 @@ static void jsondec_any(jsondec* d, upb_Message* msg, const upb_MessageDef* m) {
14241445
static void jsondec_wrapper(jsondec* d, upb_Message* msg,
14251446
const upb_MessageDef* m) {
14261447
const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 1);
1427-
upb_MessageValue val = jsondec_value(d, value_f);
1428-
upb_Message_SetFieldByDef(msg, value_f, val, d->arena);
1448+
upb_JsonMessageValue val = jsondec_value(d, value_f);
1449+
UPB_ASSUME(val.ignore == false); // Wrapper cannot be an enum.
1450+
upb_Message_SetFieldByDef(msg, value_f, val.value, d->arena);
14291451
}
14301452

14311453
static void jsondec_wellknown(jsondec* d, upb_Message* msg,

0 commit comments

Comments
 (0)