// Copyright 2017 The Crashpad Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "util/misc/from_pointer_cast.h" #include #include #include #include "build/build_config.h" #include "gtest/gtest.h" #include "test/gtest_death.h" namespace crashpad { namespace test { namespace { struct SomeType {}; template class FromPointerCastTest : public testing::Test {}; using FromPointerCastTestTypes = testing::Types; TYPED_TEST_SUITE(FromPointerCastTest, FromPointerCastTestTypes); TYPED_TEST(FromPointerCastTest, ToSigned) { EXPECT_EQ(FromPointerCast(nullptr), 0); EXPECT_EQ(FromPointerCast(reinterpret_cast(1)), 1); EXPECT_EQ(FromPointerCast(reinterpret_cast(-1)), -1); EXPECT_EQ(FromPointerCast(reinterpret_cast( std::numeric_limits::max())), static_cast(std::numeric_limits::max())); EXPECT_EQ(FromPointerCast(reinterpret_cast( std::numeric_limits::min())), std::numeric_limits::min()); EXPECT_EQ(FromPointerCast(reinterpret_cast( std::numeric_limits::max())), std::numeric_limits::max()); } TYPED_TEST(FromPointerCastTest, ToUnsigned) { EXPECT_EQ(FromPointerCast(nullptr), 0u); EXPECT_EQ(FromPointerCast(reinterpret_cast(1)), 1u); EXPECT_EQ(FromPointerCast(reinterpret_cast(-1)), static_cast(-1)); EXPECT_EQ(FromPointerCast(reinterpret_cast( std::numeric_limits::max())), std::numeric_limits::max()); EXPECT_EQ(FromPointerCast(reinterpret_cast( std::numeric_limits::min())), static_cast(std::numeric_limits::min())); EXPECT_EQ(FromPointerCast(reinterpret_cast( std::numeric_limits::max())), static_cast(std::numeric_limits::max())); } // MatchCV::Type adapts YourType to match the // const/void qualification of CVQualifiedType. template struct MatchCV { private: using NonCVBase = typename std::remove_cv::type; public: using Type = typename std::conditional< std::is_const::value, typename std::conditional::value, const volatile NonCVBase, const NonCVBase>::type, typename std::conditional::value, volatile NonCVBase, NonCVBase>::type>::type; }; #if defined(COMPILER_MSVC) && _MSC_VER < 1910 // Google Test under MSVS 2015 (MSC 19.0) doesn’t handle EXPECT_EQ(a, b) when a // or b is a pointer to a volatile type, because it can’t figure out how to // print them. template typename std::remove_volatile::type>::type* MaybeRemoveVolatile(const T& value) { return const_cast::type>::type*>(value); } #else // COMPILER_MSVC && _MSC_VER < 1910 // This isn’t a problem in MSVS 2017 (MSC 19.1) or with other compilers. template T MaybeRemoveVolatile(const T& value) { return value; } #endif // COMPILER_MSVC && _MSC_VER < 1910 TYPED_TEST(FromPointerCastTest, ToPointer) { using CVSomeType = typename MatchCV::type>::Type; EXPECT_EQ(MaybeRemoveVolatile(FromPointerCast(nullptr)), MaybeRemoveVolatile(static_cast(nullptr))); EXPECT_EQ(MaybeRemoveVolatile( FromPointerCast(reinterpret_cast(1))), MaybeRemoveVolatile(reinterpret_cast(1))); EXPECT_EQ(MaybeRemoveVolatile( FromPointerCast(reinterpret_cast(-1))), MaybeRemoveVolatile(reinterpret_cast(-1))); EXPECT_EQ( MaybeRemoveVolatile(FromPointerCast( reinterpret_cast(std::numeric_limits::max()))), MaybeRemoveVolatile(reinterpret_cast( std::numeric_limits::max()))); EXPECT_EQ( MaybeRemoveVolatile(FromPointerCast( reinterpret_cast(std::numeric_limits::min()))), MaybeRemoveVolatile( reinterpret_cast(std::numeric_limits::min()))); EXPECT_EQ( MaybeRemoveVolatile(FromPointerCast( reinterpret_cast(std::numeric_limits::max()))), MaybeRemoveVolatile( reinterpret_cast(std::numeric_limits::max()))); } TEST(FromPointerCast, FromFunctionPointer) { // These casts should work with or without the & in &malloc. EXPECT_NE(FromPointerCast(malloc), 0); EXPECT_NE(FromPointerCast(&malloc), 0); EXPECT_NE(FromPointerCast(malloc), 0u); EXPECT_NE(FromPointerCast(&malloc), 0u); EXPECT_EQ(FromPointerCast(malloc), reinterpret_cast(malloc)); EXPECT_EQ(FromPointerCast(&malloc), reinterpret_cast(malloc)); EXPECT_EQ(FromPointerCast(malloc), reinterpret_cast(malloc)); EXPECT_EQ(FromPointerCast(&malloc), reinterpret_cast(malloc)); EXPECT_EQ(MaybeRemoveVolatile(FromPointerCast(malloc)), MaybeRemoveVolatile(reinterpret_cast(malloc))); EXPECT_EQ(MaybeRemoveVolatile(FromPointerCast(&malloc)), MaybeRemoveVolatile(reinterpret_cast(malloc))); EXPECT_EQ( MaybeRemoveVolatile(FromPointerCast(malloc)), MaybeRemoveVolatile(reinterpret_cast(malloc))); EXPECT_EQ( MaybeRemoveVolatile(FromPointerCast(&malloc)), MaybeRemoveVolatile(reinterpret_cast(malloc))); EXPECT_EQ(FromPointerCast(malloc), reinterpret_cast(malloc)); EXPECT_EQ(FromPointerCast(&malloc), reinterpret_cast(malloc)); EXPECT_EQ(FromPointerCast(malloc), reinterpret_cast(malloc)); EXPECT_EQ(FromPointerCast(&malloc), reinterpret_cast(malloc)); EXPECT_EQ(MaybeRemoveVolatile(FromPointerCast(malloc)), MaybeRemoveVolatile(reinterpret_cast(malloc))); EXPECT_EQ(MaybeRemoveVolatile(FromPointerCast(&malloc)), MaybeRemoveVolatile(reinterpret_cast(malloc))); EXPECT_EQ( MaybeRemoveVolatile(FromPointerCast(malloc)), MaybeRemoveVolatile(reinterpret_cast(malloc))); EXPECT_EQ( MaybeRemoveVolatile(FromPointerCast(&malloc)), MaybeRemoveVolatile(reinterpret_cast(malloc))); } TEST(FromPointerCast, ToNarrowInteger) { EXPECT_EQ(FromPointerCast(nullptr), 0); EXPECT_EQ(FromPointerCast(reinterpret_cast(1)), 1); EXPECT_EQ(FromPointerCast(reinterpret_cast(-1)), -1); EXPECT_EQ(FromPointerCast(reinterpret_cast( static_cast(std::numeric_limits::max()))), std::numeric_limits::max()); EXPECT_EQ(FromPointerCast(reinterpret_cast( static_cast(std::numeric_limits::min()))), std::numeric_limits::min()); EXPECT_EQ(FromPointerCast(nullptr), 0u); EXPECT_EQ(FromPointerCast(reinterpret_cast(1)), 1u); EXPECT_EQ( FromPointerCast(reinterpret_cast( static_cast(std::numeric_limits::max()))), std::numeric_limits::max()); EXPECT_EQ(FromPointerCast(reinterpret_cast( static_cast(std::numeric_limits::max()))), static_cast(std::numeric_limits::max())); // int and unsigned int may not be narrower than a pointer, so also test short // and unsigned short. EXPECT_EQ(FromPointerCast(nullptr), 0); EXPECT_EQ(FromPointerCast(reinterpret_cast(1)), 1); EXPECT_EQ(FromPointerCast(reinterpret_cast(-1)), -1); EXPECT_EQ(FromPointerCast(reinterpret_cast( static_cast(std::numeric_limits::max()))), std::numeric_limits::max()); EXPECT_EQ(FromPointerCast(reinterpret_cast( static_cast(std::numeric_limits::min()))), std::numeric_limits::min()); EXPECT_EQ(FromPointerCast(nullptr), 0u); EXPECT_EQ(FromPointerCast(reinterpret_cast(1)), 1u); EXPECT_EQ( FromPointerCast(reinterpret_cast( static_cast(std::numeric_limits::max()))), std::numeric_limits::max()); EXPECT_EQ(FromPointerCast(reinterpret_cast( static_cast(std::numeric_limits::max()))), static_cast(std::numeric_limits::max())); } TEST(FromPointerCastDeathTest, ToNarrowInteger) { if (sizeof(int) < sizeof(void*)) { EXPECT_DEATH_CHECK( FromPointerCast(reinterpret_cast(static_cast( std::numeric_limits::max() + 1ull))), ""); EXPECT_DEATH_CHECK( FromPointerCast( reinterpret_cast(static_cast( std::numeric_limits::max() + 1ull))), ""); } // int and unsigned int may not be narrower than a pointer, so also test short // and unsigned short. EXPECT_DEATH_CHECK( FromPointerCast(reinterpret_cast(static_cast( std::numeric_limits::max() + 1u))), ""); EXPECT_DEATH_CHECK(FromPointerCast( reinterpret_cast(static_cast( std::numeric_limits::max() + 1u))), ""); } } // namespace } // namespace test } // namespace crashpad