diff --git a/util/numeric/in_range_cast.h b/util/numeric/in_range_cast.h new file mode 100644 index 00000000..3a7bdddf --- /dev/null +++ b/util/numeric/in_range_cast.h @@ -0,0 +1,44 @@ +// Copyright 2014 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. + +#ifndef CRASHPAD_UTIL_NUMERIC_IN_RANGE_CAST_H_ +#define CRASHPAD_UTIL_NUMERIC_IN_RANGE_CAST_H_ + +#include "base/logging.h" +#include "base/numerics/safe_conversions.h" + +namespace crashpad { + +//! \brief Casts to a different type if it can be done without data loss, +//! logging a warning message and returing a default value otherwise. +//! +//! \param[in] source The value to convert and return. +//! \param[in] default_value The default value to return, in the event that \a +//! source cannot be represented in the destination type. +//! +//! \return \a source if it can be represented in the destination type, +//! otherwise \a default_value. +template +Destination InRangeCast(Source source, Destination default_value) { + if (base::IsValueInRangeForNumericType(source)) { + return source; + } + + LOG(WARNING) << "value " << source << " out of range"; + return default_value; +} + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_NUMERIC_IN_RANGE_CAST_H_ diff --git a/util/numeric/in_range_cast_test.cc b/util/numeric/in_range_cast_test.cc new file mode 100644 index 00000000..340c862c --- /dev/null +++ b/util/numeric/in_range_cast_test.cc @@ -0,0 +1,117 @@ +// Copyright 2014 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/numeric/in_range_cast.h" + +#include + +#include + +#include "gtest/gtest.h" + +namespace { + +using namespace crashpad; + +const int32_t kInt32Min = std::numeric_limits::min(); +const int64_t kInt64Min = std::numeric_limits::min(); + +TEST(InRangeCast, Uint32) { + EXPECT_EQ(0u, InRangeCast(0, 1)); + EXPECT_EQ(1u, InRangeCast(1, 1)); + EXPECT_EQ(2u, InRangeCast(2, 1)); + EXPECT_EQ(0u, InRangeCast(-1, 0)); + EXPECT_EQ(1u, InRangeCast(-1, 1)); + EXPECT_EQ(2u, InRangeCast(-1, 2)); + EXPECT_EQ(0xffffffffu, InRangeCast(0xffffffffu, 1)); + EXPECT_EQ(0xffffffffu, InRangeCast(UINT64_C(0xffffffff), 1)); + EXPECT_EQ(1u, InRangeCast(UINT64_C(0x100000000), 1)); + EXPECT_EQ(1u, InRangeCast(UINT64_C(0x100000001), 1)); + EXPECT_EQ(1u, InRangeCast(kInt32Min, 1)); + EXPECT_EQ(0xffffffffu, InRangeCast(-1, 0xffffffffu)); +} + +TEST(InRangeCast, Int32) { + EXPECT_EQ(0, InRangeCast(0, 1)); + EXPECT_EQ(1, InRangeCast(1, 1)); + EXPECT_EQ(2, InRangeCast(2, 1)); + EXPECT_EQ(-1, InRangeCast(-1, 1)); + EXPECT_EQ(0x7fffffff, InRangeCast(0x7fffffff, 1)); + EXPECT_EQ(0x7fffffff, InRangeCast(0x7fffffffu, 1)); + EXPECT_EQ(1, InRangeCast(0x80000000u, 1)); + EXPECT_EQ(1, InRangeCast(0xffffffffu, 1)); + EXPECT_EQ(1, InRangeCast(INT64_C(0x80000000), 1)); + EXPECT_EQ(1, InRangeCast(INT64_C(0xffffffff), 1)); + EXPECT_EQ(1, InRangeCast(INT64_C(0x100000000), 1)); + EXPECT_EQ(kInt32Min, InRangeCast(kInt32Min, 1)); + EXPECT_EQ(kInt32Min, + InRangeCast(static_cast(kInt32Min), 1)); + EXPECT_EQ(1, InRangeCast(static_cast(kInt32Min) - 1, 1)); + EXPECT_EQ(0, InRangeCast(0xffffffffu, 0)); + EXPECT_EQ(-1, InRangeCast(0xffffffffu, -1)); + EXPECT_EQ(kInt32Min, InRangeCast(0xffffffffu, kInt32Min)); + EXPECT_EQ(0x7fffffff, InRangeCast(0xffffffffu, 0x7fffffff)); +} + +TEST(InRangeCast, Uint64) { + EXPECT_EQ(0u, InRangeCast(0, 1)); + EXPECT_EQ(1u, InRangeCast(1, 1)); + EXPECT_EQ(2u, InRangeCast(2, 1)); + EXPECT_EQ(0u, InRangeCast(-1, 0)); + EXPECT_EQ(1u, InRangeCast(-1, 1)); + EXPECT_EQ(2u, InRangeCast(-1, 2)); + EXPECT_EQ(0xffffffffu, InRangeCast(0xffffffffu, 1)); + EXPECT_EQ(0xffffffffu, InRangeCast(UINT64_C(0xffffffff), 1)); + EXPECT_EQ(UINT64_C(0x100000000), + InRangeCast(UINT64_C(0x100000000), 1)); + EXPECT_EQ(UINT64_C(0x100000001), + InRangeCast(UINT64_C(0x100000001), 1)); + EXPECT_EQ(1u, InRangeCast(kInt32Min, 1)); + EXPECT_EQ(1u, InRangeCast(INT64_C(-1), 1)); + EXPECT_EQ(1u, InRangeCast(kInt32Min, 1)); + EXPECT_EQ(1u, InRangeCast(kInt64Min, 1)); + EXPECT_EQ(UINT64_C(0xffffffffffffffff), + InRangeCast(-1, UINT64_C(0xffffffffffffffff))); +} + +TEST(InRangeCast, Int64) { + EXPECT_EQ(0, InRangeCast(0, 1)); + EXPECT_EQ(1, InRangeCast(1, 1)); + EXPECT_EQ(2, InRangeCast(2, 1)); + EXPECT_EQ(-1, InRangeCast(-1, 1)); + EXPECT_EQ(0x7fffffff, InRangeCast(0x7fffffff, 1)); + EXPECT_EQ(0x7fffffff, InRangeCast(0x7fffffffu, 1)); + EXPECT_EQ(INT64_C(0x80000000), InRangeCast(0x80000000u, 1)); + EXPECT_EQ(INT64_C(0xffffffff), InRangeCast(0xffffffffu, 1)); + EXPECT_EQ(INT64_C(0x80000000), InRangeCast(INT64_C(0x80000000), 1)); + EXPECT_EQ(INT64_C(0xffffffff), InRangeCast(INT64_C(0xffffffff), 1)); + EXPECT_EQ(INT64_C(0x100000000), + InRangeCast(INT64_C(0x100000000), 1)); + EXPECT_EQ(INT64_C(0x7fffffffffffffff), + InRangeCast(INT64_C(0x7fffffffffffffff), 1)); + EXPECT_EQ(1, InRangeCast(UINT64_C(0x8000000000000000), 1)); + EXPECT_EQ(1, InRangeCast(UINT64_C(0xffffffffffffffff), 1)); + EXPECT_EQ(kInt32Min, InRangeCast(kInt32Min, 1)); + EXPECT_EQ(kInt32Min, + InRangeCast(static_cast(kInt32Min), 1)); + EXPECT_EQ(0, InRangeCast(UINT64_C(0xffffffffffffffff), 0)); + EXPECT_EQ(-1, InRangeCast(UINT64_C(0xffffffffffffffff), -1)); + EXPECT_EQ(kInt64Min, + InRangeCast(UINT64_C(0xffffffffffffffff), kInt64Min)); + EXPECT_EQ(INT64_C(0x7fffffffffffffff), + InRangeCast(UINT64_C(0xffffffffffffffff), + INT64_C(0x7fffffffffffffff))); +} + +} // namespace diff --git a/util/util.gyp b/util/util.gyp index 923f18a2..b4f34716 100644 --- a/util/util.gyp +++ b/util/util.gyp @@ -41,6 +41,8 @@ 'misc/initialization_state_dcheck.h', 'misc/uuid.cc', 'misc/uuid.h', + 'numeric/in_range_cast.h', + 'numeric/safe_assignment.h', 'posix/process_util.h', 'posix/process_util_mac.cc', 'stdlib/cxx.h', @@ -88,6 +90,7 @@ 'misc/initialization_state_dcheck_test.cc', 'misc/initialization_state_test.cc', 'misc/uuid_test.cc', + 'numeric/in_range_cast_test.cc', 'posix/process_util_test.cc', 'stdlib/strlcpy_test.cc', ],