diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc index 5bdb7503cf..f3457d158d 100644 --- a/src/google/protobuf/dynamic_message.cc +++ b/src/google/protobuf/dynamic_message.cc @@ -666,6 +666,7 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock( *target = type_info; type_info->class_data.descriptor = type; + type_info->class_data.is_dynamic = true; type_info->pool = (pool_ == nullptr) ? type->file()->pool() : pool_; type_info->factory = this; diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc index a2aca8a8c0..b70fc3fba7 100644 --- a/src/google/protobuf/message_lite.cc +++ b/src/google/protobuf/message_lite.cc @@ -195,6 +195,17 @@ void MessageLite::LogInitializationErrorMessage() const { namespace internal { +void FailDynamicCast(const MessageLite& from, const MessageLite& to) { + const auto to_name = to.GetTypeName(); + if (internal::GetClassData(from)->is_dynamic) { + ABSL_LOG(FATAL) + << "Cannot downcast from a DynamicMessage to generated type " + << to_name; + } + const auto from_name = from.GetTypeName(); + ABSL_LOG(FATAL) << "Cannot downcast " << from_name << " to " << to_name; +} + template bool MergeFromImpl(absl::string_view input, MessageLite* msg, const internal::TcParseTableBase* tc_table, diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h index 45645cd236..cee8c9bbdb 100644 --- a/src/google/protobuf/message_lite.h +++ b/src/google/protobuf/message_lite.h @@ -649,6 +649,7 @@ class PROTOBUF_EXPORT MessageLite { // LITE objects (ie !descriptor_methods) collocate their name as a // char[] just beyond the ClassData. bool is_lite; + bool is_dynamic = false; // In normal mode we have the small constructor to avoid the cost in // codegen. @@ -1087,12 +1088,19 @@ T* DynamicCastMessage(MessageLite* from) { DynamicCastMessage(static_cast(from))); } +namespace internal { +[[noreturn]] PROTOBUF_EXPORT void FailDynamicCast(const MessageLite& from, + const MessageLite& to); +} // namespace internal + template const T& DynamicCastMessage(const MessageLite& from) { const T* destination_message = DynamicCastMessage(&from); - ABSL_CHECK(destination_message != nullptr) - << "Cannot downcast " << from.GetTypeName() << " to " - << T::default_instance().GetTypeName(); + if (ABSL_PREDICT_FALSE(destination_message == nullptr)) { + // Move the logging into an out-of-line function to reduce bloat in the + // caller. + internal::FailDynamicCast(from, T::default_instance()); + } return *destination_message; }