Skip to content

Commit

Permalink
Change DynamicCastMessage to throw a std::bad_cast exception when e…
Browse files Browse the repository at this point in the history
…xceptions

are enabled.
This makes the function a drop-in replacement for `dynamic_cast` when the user
is expecting exceptions to be thrown.

PiperOrigin-RevId: 689419852
  • Loading branch information
protobuf-github-bot authored and copybara-github committed Oct 24, 2024
1 parent 350e24e commit 33bbbeb
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 2 deletions.
3 changes: 3 additions & 0 deletions src/google/protobuf/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -1268,6 +1268,7 @@ cc_library(
":protobuf",
"//src/google/protobuf/testing",
"//src/google/protobuf/testing:file",
"@com_google_absl//absl/base:config",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/strings",
Expand Down Expand Up @@ -1735,6 +1736,7 @@ cc_test(
"//src/google/protobuf/testing",
"//src/google/protobuf/testing:file",
"//src/google/protobuf/util:differencer",
"@com_google_absl//absl/base:config",
"@com_google_absl//absl/hash:hash_testing",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/log:scoped_mock_log",
Expand Down Expand Up @@ -1766,6 +1768,7 @@ cc_test(
"//src/google/protobuf/testing",
"//src/google/protobuf/testing:file",
"//src/google/protobuf/util:differencer",
"@com_google_absl//absl/base:config",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/log:scoped_mock_log",
"@com_google_absl//absl/strings",
Expand Down
11 changes: 9 additions & 2 deletions src/google/protobuf/lite_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1395,16 +1395,23 @@ TEST(LiteTest, DynamicCastMessage) {
EXPECT_EQ(shared_2, nullptr);
}

#if GTEST_HAS_DEATH_TEST
TEST(LiteTest, DynamicCastMessageInvalidReferenceType) {
CastType1 test_type_1;
const MessageLite& test_type_1_pointer_const_ref = test_type_1;
#if defined(ABSL_HAVE_EXCEPTIONS)
EXPECT_THROW(DynamicCastMessage<CastType2>(test_type_1_pointer_const_ref),
std::bad_cast);
#elif defined(GTEST_HAS_DEATH_TEST)
ASSERT_DEATH(
DynamicCastMessage<CastType2>(test_type_1_pointer_const_ref),
absl::StrCat("Cannot downcast ", test_type_1.GetTypeName(), " to ",
CastType2::default_instance().GetTypeName()));
#else
(void)test_type_1;
(void)test_type_1_pointer_const_ref;
GTEST_SKIP() << "Can't test the failure.";
#endif
}
#endif // GTEST_HAS_DEATH_TEST

TEST(LiteTest, DownCastMessageValidType) {
CastType1 test_type_1;
Expand Down
5 changes: 5 additions & 0 deletions src/google/protobuf/message_lite.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
#include <istream>
#include <ostream>
#include <string>
#include <typeinfo>
#include <utility>

#include "absl/base/config.h"
#include "absl/log/absl_check.h"
#include "absl/log/absl_log.h"
#include "absl/strings/cord.h"
Expand Down Expand Up @@ -198,6 +200,9 @@ void MessageLite::LogInitializationErrorMessage() const {
namespace internal {

void FailDynamicCast(const MessageLite& from, const MessageLite& to) {
#if defined(ABSL_HAVE_EXCEPTIONS)
throw std::bad_cast();
#endif
const auto to_name = to.GetTypeName();
if (internal::GetClassData(from)->is_dynamic) {
ABSL_LOG(FATAL)
Expand Down
7 changes: 7 additions & 0 deletions src/google/protobuf/message_unittest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <gmock/gmock.h>
#include "google/protobuf/testing/googletest.h"
#include <gtest/gtest.h>
#include "absl/base/config.h"
#include "absl/log/absl_check.h"
#include "absl/log/scoped_mock_log.h"
#include "absl/strings/cord.h"
Expand Down Expand Up @@ -816,11 +817,17 @@ TEST(MESSAGE_TEST_NAME, DynamicCastMessage) {
TEST(MESSAGE_TEST_NAME, DynamicCastMessageInvalidReferenceType) {
UNITTEST::TestAllTypes test_all_types;
const MessageLite& test_all_types_pointer_const_ref = test_all_types;
#if defined(ABSL_HAVE_EXCEPTIONS)
EXPECT_THROW(DynamicCastMessage<UNITTEST::TestRequired>(
test_all_types_pointer_const_ref),
std::bad_cast);
#else
ASSERT_DEATH(
DynamicCastMessage<UNITTEST::TestRequired>(
test_all_types_pointer_const_ref),
absl::StrCat("Cannot downcast ", test_all_types.GetTypeName(), " to ",
UNITTEST::TestRequired::default_instance().GetTypeName()));
#endif
}

TEST(MESSAGE_TEST_NAME, DownCastMessageValidType) {
Expand Down

0 comments on commit 33bbbeb

Please sign in to comment.