fix unset mini table field presence bug
PiperOrigin-RevId: 495373227
diff --git a/upb/message/test.cc b/upb/message/test.cc
index e0f439ce..bd0e296 100644
--- a/upb/message/test.cc
+++ b/upb/message/test.cc
@@ -596,4 +596,10 @@
// std::string("\035|", 2), 65536, 3);
// }
//
+// // This test found a case where presence was unset for a mini table field.
+// TEST(FuzzTest, DecodeEncodeArbitrarySchemaAndPayloadRegressionMsan) {
+// DecodeEncodeArbitrarySchemaAndPayload({{"%-#^#"}, {}, "", {}}, std::string(),
+// -1960166338, 16809991);
+// }
+//
// end:google_only
diff --git a/upb/mini_table/decode.c b/upb/mini_table/decode.c
index a34b387..d88d72e 100644
--- a/upb/mini_table/decode.c
+++ b/upb/mini_table/decode.c
@@ -693,22 +693,36 @@
}
upb_MtDecoder_ParseMessage(d, data, len);
+ upb_MtDecoder_AssignHasbits(d->table);
+
if (UPB_UNLIKELY(d->table->field_count != 2)) {
upb_MtDecoder_ErrorFormat(d, "%hu fields in map", d->table->field_count);
UPB_UNREACHABLE();
}
- if (UPB_UNLIKELY(d->table->fields[0].number != 1)) {
- upb_MtDecoder_ErrorFormat(d, "field %d in map key",
- d->table->fields[0].number);
- UPB_UNREACHABLE();
- }
- if (UPB_UNLIKELY(d->table->fields[1].number != 2)) {
- upb_MtDecoder_ErrorFormat(d, "field %d in map val",
- d->table->fields[1].number);
+
+ const int num0 = d->table->fields[0].number;
+ if (UPB_UNLIKELY(num0 != 1)) {
+ upb_MtDecoder_ErrorFormat(d, "field %d in map key", num0);
UPB_UNREACHABLE();
}
- upb_MtDecoder_AssignHasbits(d->table);
+ const int num1 = d->table->fields[1].number;
+ if (UPB_UNLIKELY(num1 != 2)) {
+ upb_MtDecoder_ErrorFormat(d, "field %d in map val", num1);
+ UPB_UNREACHABLE();
+ }
+
+ const int off0 = d->table->fields[0].offset;
+ if (UPB_UNLIKELY(off0 != kNoPresence && off0 != kHasbitPresence)) {
+ upb_MtDecoder_ErrorFormat(d, "bad offset %d in map key", off0);
+ UPB_UNREACHABLE();
+ }
+
+ const int off1 = d->table->fields[1].offset;
+ if (UPB_UNLIKELY(off1 != kNoPresence && off1 != kHasbitPresence)) {
+ upb_MtDecoder_ErrorFormat(d, "bad offset %d in map val", off1);
+ UPB_UNREACHABLE();
+ }
// Map entries have a pre-determined layout, regardless of types.
// NOTE: sync with mini_table/message_internal.h.