Add upb_MiniTable_FindUnknown depth_limit parameter. Fix UpbMessageIsEqual IsMap fallthrough. PiperOrigin-RevId: 522961305
diff --git a/BUILD b/BUILD index 0985927..24bde07 100644 --- a/BUILD +++ b/BUILD
@@ -139,6 +139,7 @@ "upb/string_view.h", "upb/upb.h", "upb/upb.hpp", + "upb/wire/common.h", "upb/wire/decode.h", "upb/wire/encode.h", ], @@ -880,6 +881,7 @@ "upb/wire/encode.c", ], hdrs = [ + "upb/wire/common.h", "upb/wire/common_internal.h", "upb/wire/decode.h", "upb/wire/decode_fast.h",
diff --git a/python/message.c b/python/message.c index 753cc74..2fe5126 100644 --- a/python/message.c +++ b/python/message.c
@@ -36,6 +36,7 @@ #include "upb/reflection/message.h" #include "upb/text/encode.h" #include "upb/util/required_fields.h" +#include "upb/wire/common.h" static const upb_MessageDef* PyUpb_MessageMeta_GetMsgdef(PyObject* cls); static PyObject* PyUpb_MessageMeta_GetAttr(PyObject* self, PyObject* name); @@ -1254,8 +1255,9 @@ const upb_MiniTable* layout = upb_MessageDef_MiniTable(msgdef); upb_Arena* arena = PyUpb_Arena_Get(self->arena); PyUpb_ModuleState* state = PyUpb_ModuleState_Get(); - int options = - UPB_DECODE_MAXDEPTH(state->allow_oversize_protos ? UINT32_MAX : 100); + int options = upb_DecodeOptions_MaxDepth( + state->allow_oversize_protos ? UINT16_MAX + : kUpb_WireFormat_DefaultDepthLimit); upb_DecodeStatus status = upb_Decode(buf, size, self->ptr.msg, layout, extreg, options, arena); Py_XDECREF(bytes);
diff --git a/upb/message/accessors.c b/upb/message/accessors.c index 2ed872a..c10ffec 100644 --- a/upb/message/accessors.c +++ b/upb/message/accessors.c
@@ -32,6 +32,7 @@ #include "upb/collections/map.h" #include "upb/message/message.h" #include "upb/mini_table/field_internal.h" +#include "upb/wire/common.h" #include "upb/wire/decode.h" #include "upb/wire/encode.h" #include "upb/wire/eps_copy_input_stream.h" @@ -83,7 +84,8 @@ // Check unknown fields, if available promote. int field_number = ext_table->field.number; - upb_FindUnknownRet result = upb_MiniTable_FindUnknown(msg, field_number); + upb_FindUnknownRet result = upb_MiniTable_FindUnknown( + msg, field_number, kUpb_WireFormat_DefaultDepthLimit); if (result.status != kUpb_FindUnknown_Ok) { return kUpb_GetExtension_NotPresent; } @@ -134,7 +136,8 @@ return kUpb_GetExtensionAsBytes_Ok; } int field_number = ext_table->field.number; - upb_FindUnknownRet result = upb_MiniTable_FindUnknown(msg, field_number); + upb_FindUnknownRet result = upb_MiniTable_FindUnknown( + msg, field_number, upb_DecodeOptions_GetMaxDepth(encode_options)); if (result.status != kUpb_FindUnknown_Ok) { return kUpb_GetExtensionAsBytes_NotPresent; } @@ -153,8 +156,8 @@ } upb_FindUnknownRet upb_MiniTable_FindUnknown(const upb_Message* msg, - uint32_t field_number) { - const int depth_limit = 100; // TODO: this should be a parameter + uint32_t field_number, + int depth_limit) { size_t size; upb_FindUnknownRet ret; @@ -204,7 +207,8 @@ upb_UnknownToMessageRet ret; ret.status = kUpb_UnknownToMessage_Ok; do { - unknown = upb_MiniTable_FindUnknown(msg, field->number); + unknown = upb_MiniTable_FindUnknown( + msg, field->number, upb_DecodeOptions_GetMaxDepth(decode_options)); switch (unknown.status) { case kUpb_FindUnknown_Ok: { const char* unknown_data = unknown.ptr; @@ -250,7 +254,8 @@ // Find all unknowns with given field number and parse. upb_FindUnknownRet unknown; do { - unknown = upb_MiniTable_FindUnknown(msg, field->number); + unknown = upb_MiniTable_FindUnknown( + msg, field->number, upb_DecodeOptions_GetMaxDepth(decode_options)); if (unknown.status == kUpb_FindUnknown_Ok) { upb_UnknownToMessageRet ret = upb_MiniTable_ParseUnknownMessage( unknown.ptr, unknown.len, mini_table, @@ -314,7 +319,8 @@ // Find all unknowns with given field number and parse. upb_FindUnknownRet unknown; while (1) { - unknown = upb_MiniTable_FindUnknown(msg, field->number); + unknown = upb_MiniTable_FindUnknown( + msg, field->number, upb_DecodeOptions_GetMaxDepth(decode_options)); if (unknown.status != kUpb_FindUnknown_Ok) break; upb_UnknownToMessageRet ret = upb_MiniTable_ParseUnknownMessage( unknown.ptr, unknown.len, map_entry_mini_table,
diff --git a/upb/message/accessors.h b/upb/message/accessors.h index 6b56e58..74ca1f2 100644 --- a/upb/message/accessors.h +++ b/upb/message/accessors.h
@@ -708,7 +708,8 @@ // Finds first occurrence of unknown data by tag id in message. upb_FindUnknownRet upb_MiniTable_FindUnknown(const upb_Message* msg, - uint32_t field_number); + uint32_t field_number, + int depth_limit); typedef enum { kUpb_UnknownToMessage_Ok,
diff --git a/upb/message/accessors_test.cc b/upb/message/accessors_test.cc index d299acd..a0dece4 100644 --- a/upb/message/accessors_test.cc +++ b/upb/message/accessors_test.cc
@@ -33,6 +33,8 @@ #include "upb/message/accessors.h" +#include <string> + #include "gtest/gtest.h" #include "google/protobuf/test_messages_proto2.upb.h" #include "google/protobuf/test_messages_proto3.upb.h" @@ -44,6 +46,7 @@ #include "upb/mini_table/field_internal.h" #include "upb/test/test.upb.h" #include "upb/upb.h" +#include "upb/wire/common.h" #include "upb/wire/decode.h" namespace { @@ -163,7 +166,7 @@ 0, protobuf_test_messages_proto2_TestAllTypesProto2_optional_int32(msg)); EXPECT_EQ(0, upb_Message_GetInt32(msg, optional_int32_field, 0)); - upb_Message_SetInt32(msg, optional_int32_field, kTestInt32, NULL); + upb_Message_SetInt32(msg, optional_int32_field, kTestInt32, nullptr); EXPECT_EQ(true, upb_Message_HasField(msg, optional_int32_field)); EXPECT_EQ(kTestInt32, upb_Message_GetInt32(msg, optional_int32_field, 0)); EXPECT_EQ( @@ -176,7 +179,7 @@ EXPECT_EQ( 0, protobuf_test_messages_proto2_TestAllTypesProto2_optional_uint32(msg)); EXPECT_EQ(0, upb_Message_GetUInt32(msg, optional_uint32_field, 0)); - upb_Message_SetUInt32(msg, optional_uint32_field, kTestUInt32, NULL); + upb_Message_SetUInt32(msg, optional_uint32_field, kTestUInt32, nullptr); EXPECT_EQ(kTestUInt32, upb_Message_GetUInt32(msg, optional_uint32_field, 0)); EXPECT_EQ( kTestUInt32, @@ -197,14 +200,14 @@ EXPECT_EQ( 0, protobuf_test_messages_proto3_TestAllTypesProto3_optional_int64(msg)); - upb_Message_SetInt64(msg, optional_int64_field, -1, NULL); + upb_Message_SetInt64(msg, optional_int64_field, -1, nullptr); EXPECT_EQ( -1, protobuf_test_messages_proto3_TestAllTypesProto3_optional_int64(msg)); EXPECT_EQ(-1, upb_Message_GetInt64(msg, optional_int64_field, 0)); EXPECT_EQ( 0, protobuf_test_messages_proto3_TestAllTypesProto3_optional_uint64(msg)); - upb_Message_SetUInt64(msg, optional_uint64_field, kTestUInt64, NULL); + upb_Message_SetUInt64(msg, optional_uint64_field, kTestUInt64, nullptr); EXPECT_EQ( kTestUInt64, protobuf_test_messages_proto3_TestAllTypesProto3_optional_uint64(msg)); @@ -239,7 +242,7 @@ protobuf_test_messages_proto2_TestAllTypesProto2_has_optional_string( msg)); upb_Message_SetString(msg, optional_string_field, - upb_StringView_FromString(kTestStr2), NULL); + upb_StringView_FromString(kTestStr2), nullptr); EXPECT_EQ(true, upb_Message_HasField(msg, optional_string_field)); EXPECT_EQ( true, @@ -261,8 +264,8 @@ find_proto2_field(kFieldOptionalNestedMessage); const upb_Message* test_message = - upb_Message_GetMessage(msg, optional_message_field, NULL); - EXPECT_EQ(NULL, test_message); + upb_Message_GetMessage(msg, optional_message_field, nullptr); + EXPECT_EQ(nullptr, test_message); EXPECT_EQ(false, upb_Message_HasField(msg, optional_message_field)); @@ -277,8 +280,8 @@ // Read back using mini table API. const upb_Message* sub_message = - upb_Message_GetMessage(msg, optional_message_field, NULL); - EXPECT_EQ(true, sub_message != NULL); + upb_Message_GetMessage(msg, optional_message_field, nullptr); + EXPECT_EQ(true, sub_message != nullptr); const upb_MiniTableField* nested_message_a_field = upb_MiniTable_FindFieldByNumber( @@ -288,14 +291,15 @@ upb_Message_ClearField(msg, optional_message_field); EXPECT_EQ( - NULL, + nullptr, protobuf_test_messages_proto2_TestAllTypesProto2_optional_nested_message( msg)); EXPECT_EQ(false, upb_Message_HasField(msg, optional_message_field)); upb_Message* new_nested_message = protobuf_test_messages_proto2_TestAllTypesProto2_NestedMessage_new(arena); - upb_Message_SetInt32(new_nested_message, nested_message_a_field, 123, NULL); + upb_Message_SetInt32(new_nested_message, nested_message_a_field, 123, + nullptr); upb_Message_SetMessage( msg, &protobuf_test_messages_proto2_TestAllTypesProto2_msg_init, optional_message_field, new_nested_message); @@ -306,7 +310,7 @@ EXPECT_EQ( true, protobuf_test_messages_proto2_TestAllTypesProto2_optional_nested_message( - msg) != NULL); + msg) != nullptr); EXPECT_EQ(true, upb_Message_HasField(msg, optional_message_field)); EXPECT_EQ(123, upb_Message_GetInt32(mutable_message, nested_message_a_field, 0)); @@ -328,8 +332,8 @@ &len); // Test Get/Set Array values, validate with C API. EXPECT_EQ(0, len); - EXPECT_EQ(NULL, arr); - EXPECT_EQ(NULL, upb_Message_GetArray(msg, repeated_int32_field)); + EXPECT_EQ(nullptr, arr); + EXPECT_EQ(nullptr, upb_Message_GetArray(msg, repeated_int32_field)); protobuf_test_messages_proto2_TestAllTypesProto2_resize_repeated_int32( msg, 10, arena); int32_t* mutable_values = @@ -361,7 +365,7 @@ protobuf_test_messages_proto2_TestAllTypesProto2_repeated_int32(msg, &len); EXPECT_EQ(0, len); - EXPECT_EQ(true, zero_length_array != NULL); + EXPECT_EQ(true, zero_length_array != nullptr); upb_Arena_Free(arena); } @@ -407,11 +411,13 @@ arena); upb_FindUnknownRet result = upb_MiniTable_FindUnknown( - base_msg, upb_test_ModelExtension1_model_ext_ext.field.number); + base_msg, upb_test_ModelExtension1_model_ext_ext.field.number, + kUpb_WireFormat_DefaultDepthLimit); EXPECT_EQ(kUpb_FindUnknown_Ok, result.status); result = upb_MiniTable_FindUnknown( - base_msg, upb_test_ModelExtension2_model_ext_ext.field.number); + base_msg, upb_test_ModelExtension2_model_ext_ext.field.number, + kUpb_WireFormat_DefaultDepthLimit); EXPECT_EQ(kUpb_FindUnknown_NotPresent, result.status); upb_Arena_Free(arena); @@ -639,21 +645,22 @@ int32_t val = upb_Message_GetInt32( msg, upb_MiniTable_FindFieldByNumber(mini_table, 4), 0); EXPECT_EQ(val, 11); - upb_FindUnknownRet unknown = upb_MiniTable_FindUnknown(msg, 5); + upb_FindUnknownRet unknown = + upb_MiniTable_FindUnknown(msg, 5, kUpb_WireFormat_DefaultDepthLimit); EXPECT_EQ(unknown.status, kUpb_FindUnknown_Ok); // Update mini table and promote unknown to a message. EXPECT_TRUE(upb_MiniTable_SetSubMessage( mini_table, (upb_MiniTableField*)&mini_table->fields[1], &upb_test_ModelWithExtensions_msg_init)); - const int decode_options = - UPB_DECODE_MAXDEPTH(100); // UPB_DECODE_ALIAS disabled. + const int decode_options = upb_DecodeOptions_MaxDepth( + kUpb_WireFormat_DefaultDepthLimit); // UPB_DECODE_ALIAS disabled. upb_UnknownToMessageRet promote_result = upb_MiniTable_PromoteUnknownToMessage( msg, mini_table, &mini_table->fields[1], &upb_test_ModelWithExtensions_msg_init, decode_options, arena); EXPECT_EQ(promote_result.status, kUpb_UnknownToMessage_Ok); const upb_Message* promoted_message = - upb_Message_GetMessage(msg, &mini_table->fields[1], NULL); + upb_Message_GetMessage(msg, &mini_table->fields[1], nullptr); EXPECT_EQ(upb_test_ModelWithExtensions_random_int32( (upb_test_ModelWithExtensions*)promoted_message), 12); @@ -687,15 +694,16 @@ EXPECT_EQ(val, 123); // Check that we have repeated field data in an unknown. - upb_FindUnknownRet unknown = upb_MiniTable_FindUnknown(msg, 6); + upb_FindUnknownRet unknown = + upb_MiniTable_FindUnknown(msg, 6, kUpb_WireFormat_DefaultDepthLimit); EXPECT_EQ(unknown.status, kUpb_FindUnknown_Ok); // Update mini table and promote unknown to a message. EXPECT_TRUE(upb_MiniTable_SetSubMessage( mini_table, (upb_MiniTableField*)&mini_table->fields[2], &upb_test_ModelWithExtensions_msg_init)); - const int decode_options = - UPB_DECODE_MAXDEPTH(100); // UPB_DECODE_ALIAS disabled. + const int decode_options = upb_DecodeOptions_MaxDepth( + kUpb_WireFormat_DefaultDepthLimit); // UPB_DECODE_ALIAS disabled. upb_UnknownToMessage_Status promote_result = upb_MiniTable_PromoteUnknownToMessageArray( msg, &mini_table->fields[2], &upb_test_ModelWithExtensions_msg_init, @@ -734,23 +742,25 @@ upb_MiniTable* mini_table = CreateMiniTableWithEmptySubTablesForMaps(arena); upb_MiniTable* map_entry_mini_table = CreateMapEntryMiniTable(arena); upb_Message* msg = _upb_Message_New(mini_table, arena); - upb_DecodeStatus decode_status = upb_Decode(serialized, serialized_size, msg, - mini_table, nullptr, 0, arena); + const int decode_options = + upb_DecodeOptions_MaxDepth(kUpb_WireFormat_DefaultDepthLimit); + upb_DecodeStatus decode_status = + upb_Decode(serialized, serialized_size, msg, mini_table, nullptr, + decode_options, arena); EXPECT_EQ(decode_status, kUpb_DecodeStatus_Ok); int32_t val = upb_Message_GetInt32( msg, upb_MiniTable_FindFieldByNumber(mini_table, 1), 0); EXPECT_EQ(val, 123); // Check that we have map data in an unknown. - upb_FindUnknownRet unknown = upb_MiniTable_FindUnknown(msg, 3); + upb_FindUnknownRet unknown = + upb_MiniTable_FindUnknown(msg, 3, kUpb_WireFormat_DefaultDepthLimit); EXPECT_EQ(unknown.status, kUpb_FindUnknown_Ok); // Update mini table and promote unknown to a message. EXPECT_TRUE(upb_MiniTable_SetSubMessage( mini_table, (upb_MiniTableField*)&mini_table->fields[1], map_entry_mini_table)); - const int decode_options = - UPB_DECODE_MAXDEPTH(100); // UPB_DECODE_ALIAS disabled. upb_UnknownToMessage_Status promote_result = upb_MiniTable_PromoteUnknownToMap(msg, mini_table, &mini_table->fields[1], decode_options, arena);
diff --git a/upb/wire/common.h b/upb/wire/common.h new file mode 100644 index 0000000..c35b575 --- /dev/null +++ b/upb/wire/common.h
@@ -0,0 +1,44 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UPB_WIRE_COMMON_H_ +#define UPB_WIRE_COMMON_H_ + +// Must be last. +#include "upb/port/def.inc" + +#ifdef __cplusplus +extern "C" { +#endif + +#define kUpb_WireFormat_DefaultDepthLimit 100 + +#ifdef __cplusplus +} +#endif + +#endif // UPB_WIRE_COMMON_H_
diff --git a/upb/wire/decode.c b/upb/wire/decode.c index ed2ee98..c2ab7e0 100644 --- a/upb/wire/decode.c +++ b/upb/wire/decode.c
@@ -35,6 +35,7 @@ #include "upb/mini_table/common.h" #include "upb/mini_table/enum_internal.h" #include "upb/port/atomic.h" +#include "upb/wire/common.h" #include "upb/wire/common_internal.h" #include "upb/wire/decode_internal.h" #include "upb/wire/encode.h" @@ -1301,7 +1302,7 @@ decoder.extreg = extreg; decoder.unknown = NULL; - decoder.depth = depth ? depth : 64; + decoder.depth = depth ? depth : kUpb_WireFormat_DefaultDepthLimit; decoder.end_group = DECODE_NOGROUP; decoder.options = (uint16_t)options; decoder.missing_required = false;
diff --git a/upb/wire/decode.h b/upb/wire/decode.h index 95c831e..b2198f9 100644 --- a/upb/wire/decode.h +++ b/upb/wire/decode.h
@@ -66,13 +66,19 @@ kUpb_DecodeOption_CheckRequired = 2, }; -#define UPB_DECODE_MAXDEPTH(depth) ((depth) << 16) +UPB_INLINE uint32_t upb_DecodeOptions_MaxDepth(uint16_t depth) { + return (uint32_t)depth << 16; +} + +UPB_INLINE uint16_t upb_DecodeOptions_GetMaxDepth(uint32_t options) { + return options >> 16; +} // Enforce an upper bound on recursion depth. UPB_INLINE int upb_Decode_LimitDepth(uint32_t decode_options, uint32_t limit) { - uint32_t max_depth = decode_options >> 16; + uint32_t max_depth = upb_DecodeOptions_GetMaxDepth(decode_options); if (max_depth > limit) max_depth = limit; - return (max_depth << 16) | (decode_options & 0xffff); + return upb_DecodeOptions_MaxDepth(max_depth) | (decode_options & 0xffff); } typedef enum {
diff --git a/upb/wire/encode.c b/upb/wire/encode.c index ef3b4ad..ef931a7 100644 --- a/upb/wire/encode.c +++ b/upb/wire/encode.c
@@ -35,6 +35,7 @@ #include "upb/collections/map_sorter_internal.h" #include "upb/message/extension_internal.h" #include "upb/mini_table/sub_internal.h" +#include "upb/wire/common.h" #include "upb/wire/common_internal.h" #include "upb/wire/swap_internal.h" #include "upb/wire/types.h" @@ -622,7 +623,7 @@ e.buf = NULL; e.limit = NULL; e.ptr = NULL; - e.depth = depth ? depth : 64; + e.depth = depth ? depth : kUpb_WireFormat_DefaultDepthLimit; e.options = options; _upb_mapsorter_init(&e.sorter);