diff --git a/src/google/protobuf/generated_message_tctable_impl.h b/src/google/protobuf/generated_message_tctable_impl.h index 86032ef2c8..910cc2615c 100644 --- a/src/google/protobuf/generated_message_tctable_impl.h +++ b/src/google/protobuf/generated_message_tctable_impl.h @@ -529,6 +529,18 @@ class PROTOBUF_EXPORT TcParser final { const TcParseTableBase* table, google::protobuf::internal::ParseContext* ctx); + // Test only access to verify that the right function is being called via + // MiniParse. + struct TestMiniParseResult { + TailCallParseFunc called_func; + uint32_t tag; + const TcParseTableBase::FieldEntry* found_entry; + const char* ptr; + }; + static TestMiniParseResult TestMiniParse(PROTOBUF_TC_PARAM_DECL); + template + static const char* MiniParseImpl(PROTOBUF_TC_PARAM_DECL); + template static inline const char* SingularParseMessageAuxImpl(PROTOBUF_TC_PARAM_DECL); template diff --git a/src/google/protobuf/generated_message_tctable_lite.cc b/src/google/protobuf/generated_message_tctable_lite.cc index cfa6c9371f..cb4f2cbab7 100644 --- a/src/google/protobuf/generated_message_tctable_lite.cc +++ b/src/google/protobuf/generated_message_tctable_lite.cc @@ -254,15 +254,25 @@ absl::string_view TcParser::FieldName(const TcParseTableBase* table, field_index + 1); } -PROTOBUF_NOINLINE const char* TcParser::MiniParse(PROTOBUF_TC_PARAM_DECL) { +template +inline PROTOBUF_ALWAYS_INLINE const char* TcParser::MiniParseImpl( + PROTOBUF_TC_PARAM_DECL) { + TestMiniParseResult* test_out; + if (export_called_function) { + test_out = reinterpret_cast( + static_cast(data.data)); + } + uint32_t tag; ptr = ReadTagInlined(ptr, &tag); if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) { + if (export_called_function) *test_out = {Error}; return Error(PROTOBUF_TC_PARAM_PASS); } auto* entry = FindFieldEntry(table, tag >> 3); if (entry == nullptr) { + if (export_called_function) *test_out = {table->fallback, tag}; data.data = tag; PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS); } @@ -324,9 +334,22 @@ PROTOBUF_NOINLINE const char* TcParser::MiniParse(PROTOBUF_TC_PARAM_DECL) { "Invalid table order"); TailCallParseFunc parse_fn = kMiniParseTable[field_type]; + if (export_called_function) *test_out = {parse_fn, tag, entry}; + PROTOBUF_MUSTTAIL return parse_fn(PROTOBUF_TC_PARAM_PASS); } +PROTOBUF_NOINLINE const char* TcParser::MiniParse(PROTOBUF_TC_PARAM_DECL) { + PROTOBUF_MUSTTAIL return MiniParseImpl(PROTOBUF_TC_PARAM_PASS); +} +PROTOBUF_NOINLINE TcParser::TestMiniParseResult TcParser::TestMiniParse( + PROTOBUF_TC_PARAM_DECL) { + TestMiniParseResult result = {}; + data.data = reinterpret_cast(&result); + result.ptr = MiniParseImpl(PROTOBUF_TC_PARAM_PASS); + return result; +} + const char* TcParser::MpFallback(PROTOBUF_TC_PARAM_DECL) { PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS); } @@ -1930,6 +1953,7 @@ PROTOBUF_NOINLINE const char* TcParser::MpRepeatedVarint( field.Add(is_zigzag ? WireFormatLite::ZigZagDecode64(tmp) : tmp); if (!ctx->DataAvailable(ptr)) break; ptr2 = ReadTag(ptr, &next_tag); + if (ptr2 == nullptr) return Error(PROTOBUF_TC_PARAM_PASS); } while (next_tag == decoded_tag); } else if (rep == field_layout::kRep32Bits) { auto& field = RefAt>(msg, entry.offset); @@ -1950,6 +1974,7 @@ PROTOBUF_NOINLINE const char* TcParser::MpRepeatedVarint( field.Add(tmp); if (!ctx->DataAvailable(ptr)) break; ptr2 = ReadTag(ptr, &next_tag); + if (ptr2 == nullptr) return Error(PROTOBUF_TC_PARAM_PASS); } while (next_tag == decoded_tag); } else { GOOGLE_DCHECK_EQ(rep, static_cast(field_layout::kRep8Bits)); @@ -1963,6 +1988,7 @@ PROTOBUF_NOINLINE const char* TcParser::MpRepeatedVarint( field.Add(static_cast(tmp)); if (!ctx->DataAvailable(ptr)) break; ptr2 = ReadTag(ptr, &next_tag); + if (ptr2 == nullptr) return Error(PROTOBUF_TC_PARAM_PASS); } while (next_tag == decoded_tag); }