From de1c81b2d2196be611674aa6019b9db3a9329042 Mon Sep 17 00:00:00 2001 From: hbos Date: Tue, 8 Mar 2016 04:46:00 -0800 Subject: [PATCH] Safe numeric library added: base/numerics (copied from Chromium) This copies the contents (unittest excluded) of base/numerics in chromium to base/numerics in webrtc. Files added: - safe_conversions.h - safe_conversions_impl.h - safe_math.h - safe_math_impl.h A really old version of safe_conversions[_impl].h previously existed in base/, this has been deleted and sources using it have been updated to include the new base/numerics/safe_converions.h. This CL also adds a DEPS file to webrtc/base. NOPRESUBMIT=True BUG=webrtc:5548, webrtc:5623 Review URL: https://codereview.webrtc.org/1753293002 Cr-Commit-Position: refs/heads/master@{#11907} --- webrtc/base/BUILD.gn | 26 +- webrtc/base/DEPS | 8 + webrtc/base/base.gyp | 19 +- webrtc/base/numerics/safe_conversions.h | 175 ++++++ webrtc/base/numerics/safe_conversions_impl.h | 273 +++++++++ webrtc/base/numerics/safe_math.h | 312 ++++++++++ webrtc/base/numerics/safe_math_impl.h | 556 ++++++++++++++++++ webrtc/base/openssladapter.cc | 2 +- webrtc/base/opensslstreamadapter.cc | 2 +- webrtc/base/rtccertificate_unittests.cc | 2 +- webrtc/base/safe_conversions.h | 70 --- webrtc/base/safe_conversions_impl.h | 188 ------ webrtc/common_audio/audio_converter.cc | 2 +- webrtc/common_audio/wav_file.cc | 2 +- webrtc/media/engine/webrtcvideocapturer.cc | 2 +- webrtc/media/sctp/sctpdataengine.cc | 2 +- .../modules/audio_coding/acm2/acm_receiver.cc | 2 +- .../acm2/audio_coding_module_impl.cc | 2 +- .../codecs/opus/audio_encoder_opus.cc | 2 +- .../audio_coding/neteq/delay_manager.cc | 2 +- webrtc/modules/audio_coding/neteq/expand.cc | 2 +- .../audio_coding/neteq/expand_unittest.cc | 2 +- .../modules/audio_coding/neteq/neteq_impl.cc | 2 +- .../audio_coding/neteq/neteq_impl_unittest.cc | 2 +- .../neteq/statistics_calculator.cc | 2 +- .../neteq/test/neteq_ilbc_quality_test.cc | 2 +- .../neteq/test/neteq_pcmu_quality_test.cc | 2 +- .../audio_coding/neteq/time_stretch.cc | 2 +- .../audio_coding/neteq/tools/neteq_rtpplay.cc | 2 +- .../audio_processing_performance_unittest.cc | 2 +- 30 files changed, 1380 insertions(+), 289 deletions(-) create mode 100644 webrtc/base/DEPS create mode 100644 webrtc/base/numerics/safe_conversions.h create mode 100644 webrtc/base/numerics/safe_conversions_impl.h create mode 100644 webrtc/base/numerics/safe_math.h create mode 100644 webrtc/base/numerics/safe_math_impl.h delete mode 100644 webrtc/base/safe_conversions.h delete mode 100644 webrtc/base/safe_conversions_impl.h diff --git a/webrtc/base/BUILD.gn b/webrtc/base/BUILD.gn index 5726a26e6a..ac2a3ac59c 100644 --- a/webrtc/base/BUILD.gn +++ b/webrtc/base/BUILD.gn @@ -141,8 +141,6 @@ static_library("rtc_base_approved") { "rate_statistics.cc", "rate_statistics.h", "refcount.h", - "safe_conversions.h", - "safe_conversions_impl.h", "scoped_ptr.h", "scoped_ref_ptr.h", "stringencode.cc", @@ -181,10 +179,6 @@ static_library("rtc_base") { cflags = [] cflags_cc = [] libs = [] - deps = [] - public_deps = [ - ":rtc_base_approved", - ] configs += [ "..:common_config", @@ -198,6 +192,13 @@ static_library("rtc_base") { defines = [ "LOGGING=1" ] + deps = [ + ":safe_numerics", + ] + public_deps = [ + ":rtc_base_approved", + ] + sources = [ "arraysize.h", "asyncfile.cc", @@ -657,3 +658,16 @@ source_set("gtest_prod") { "gtest_prod_util.h", ] } + +# GYP version: webrtc/base/base.gyp:safe_numerics +source_set("safe_numerics") { + deps = [ + ":rtc_base_approved", + ] + sources = [ + "numerics/safe_conversions.h", + "numerics/safe_conversions_impl.h", + "numerics/safe_math.h", + "numerics/safe_math_impl.h", + ] +} diff --git a/webrtc/base/DEPS b/webrtc/base/DEPS new file mode 100644 index 0000000000..afa6a04eed --- /dev/null +++ b/webrtc/base/DEPS @@ -0,0 +1,8 @@ +include_rules = [ + "-base", + "+json", + "+testing", + "+third_party/jsoncpp", + "+webrtc", + "+webrtc/base", +] diff --git a/webrtc/base/base.gyp b/webrtc/base/base.gyp index 5ac173ca91..eef8c2acba 100644 --- a/webrtc/base/base.gyp +++ b/webrtc/base/base.gyp @@ -116,8 +116,6 @@ 'ratetracker.cc', 'ratetracker.h', 'refcount.h', - 'safe_conversions.h', - 'safe_conversions_impl.h', 'scoped_ptr.h', 'scoped_ref_ptr.h', 'stringencode.cc', @@ -160,6 +158,7 @@ 'dependencies': [ '<(webrtc_root)/common.gyp:webrtc_common', 'rtc_base_approved', + 'safe_numerics', ], 'export_dependent_settings': [ 'rtc_base_approved', @@ -500,8 +499,6 @@ 'proxyserver.h', 'referencecountedsingletonfactory.h', 'rollingaccumulator.h', - 'safe_conversions.h', - 'safe_conversions_impl.h', 'scopedptrcollection.h', 'sec_buffer.h', 'sslconfig.h', @@ -752,5 +749,19 @@ 'gtest_prod_util.h', ], }, + { + # GN version: webrtc/base:safe_numerics + 'target_name': 'safe_numerics', + 'type': 'static_library', + 'dependencies': [ + 'rtc_base_approved', + ], + 'sources': [ + 'numerics/safe_conversions.h', + 'numerics/safe_conversions_impl.h', + 'numerics/safe_math.h', + 'numerics/safe_math_impl.h', + ], + }, ], } diff --git a/webrtc/base/numerics/safe_conversions.h b/webrtc/base/numerics/safe_conversions.h new file mode 100644 index 0000000000..1f86ec30eb --- /dev/null +++ b/webrtc/base/numerics/safe_conversions.h @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + * + */ + +// Borrowed from Chromium's src/base/numerics/safe_conversions.h. +// - Modified to work in WebRTC (paths, namespace, use of webrtc/base). +// Based on 'chromium_revision': 'ee311243eae6aef9c907543663754ff38f1f4f40'. + +#ifndef WEBRTC_BASE_NUMERICS_SAFE_CONVERSIONS_H_ +#define WEBRTC_BASE_NUMERICS_SAFE_CONVERSIONS_H_ + +#include + +#include +#include + +#include "webrtc/base/numerics/safe_conversions_impl.h" + +namespace rtc { + +// Convenience function that returns true if the supplied value is in range +// for the destination type. +template +inline bool IsValueInRangeForNumericType(Src value) { + return internal::DstRangeRelationToSrcRange(value) == + internal::RANGE_VALID; +} + +// Convenience function for determining if a numeric value is negative without +// throwing compiler warnings on: unsigned(value) < 0. +template +typename std::enable_if::is_signed, bool>::type +IsValueNegative(T value) { + static_assert(std::numeric_limits::is_specialized, + "Argument must be numeric."); + return value < 0; +} + +template +typename std::enable_if::is_signed, bool>::type + IsValueNegative(T) { + static_assert(std::numeric_limits::is_specialized, + "Argument must be numeric."); + return false; +} + +// checked_cast<> is analogous to static_cast<> for numeric types, +// except that it CHECKs that the specified numeric conversion will not +// overflow or underflow. NaN source will always trigger a CHECK. +template +inline Dst checked_cast(Src value) { + RTC_CHECK(IsValueInRangeForNumericType(value)); + return static_cast(value); +} + +// HandleNaN will cause this class to RTC_CHECK(false). +struct SaturatedCastNaNBehaviorCheck { + template + static T HandleNaN() { + RTC_CHECK(false); + return T(); + } +}; + +// HandleNaN will return 0 in this case. +struct SaturatedCastNaNBehaviorReturnZero { + template + static T HandleNaN() { + return T(); + } +}; + +// saturated_cast<> is analogous to static_cast<> for numeric types, except +// that the specified numeric conversion will saturate rather than overflow or +// underflow. NaN assignment to an integral will defer the behavior to a +// specified class. By default, it will return 0. +template +inline Dst saturated_cast(Src value) { + // Optimization for floating point values, which already saturate. + if (std::numeric_limits::is_iec559) + return static_cast(value); + + switch (internal::DstRangeRelationToSrcRange(value)) { + case internal::RANGE_VALID: + return static_cast(value); + + case internal::RANGE_UNDERFLOW: + return std::numeric_limits::min(); + + case internal::RANGE_OVERFLOW: + return std::numeric_limits::max(); + + // Should fail only on attempting to assign NaN to a saturated integer. + case internal::RANGE_INVALID: + return NaNHandler::template HandleNaN(); + } + + RTC_NOTREACHED(); + return static_cast(value); +} + +// strict_cast<> is analogous to static_cast<> for numeric types, except that +// it will cause a compile failure if the destination type is not large enough +// to contain any value in the source type. It performs no runtime checking. +template +inline Dst strict_cast(Src value) { + static_assert(std::numeric_limits::is_specialized, + "Argument must be numeric."); + static_assert(std::numeric_limits::is_specialized, + "Result must be numeric."); + static_assert((internal::StaticDstRangeRelationToSrcRange::value == + internal::NUMERIC_RANGE_CONTAINED), + "The numeric conversion is out of range for this type. You " + "should probably use one of the following conversion " + "mechanisms on the value you want to pass:\n" + "- rtc::checked_cast\n" + "- rtc::saturated_cast\n" + "- rtc::CheckedNumeric"); + + return static_cast(value); +} + +// StrictNumeric implements compile time range checking between numeric types by +// wrapping assignment operations in a strict_cast. This class is intended to be +// used for function arguments and return types, to ensure the destination type +// can always contain the source type. This is essentially the same as enforcing +// -Wconversion in gcc and C4302 warnings on MSVC, but it can be applied +// incrementally at API boundaries, making it easier to convert code so that it +// compiles cleanly with truncation warnings enabled. +// This template should introduce no runtime overhead, but it also provides no +// runtime checking of any of the associated mathematical operations. Use +// CheckedNumeric for runtime range checks of tha actual value being assigned. +template +class StrictNumeric { + public: + typedef T type; + + StrictNumeric() : value_(0) {} + + // Copy constructor. + template + StrictNumeric(const StrictNumeric& rhs) + : value_(strict_cast(rhs.value_)) {} + + // This is not an explicit constructor because we implicitly upgrade regular + // numerics to StrictNumerics to make them easier to use. + template + StrictNumeric(Src value) + : value_(strict_cast(value)) {} + + // The numeric cast operator basically handles all the magic. + template + operator Dst() const { + return strict_cast(value_); + } + + private: + T value_; +}; + +// Explicitly make a shorter size_t typedef for convenience. +typedef StrictNumeric SizeT; + +} // namespace rtc + +#endif // WEBRTC_BASE_NUMERICS_SAFE_CONVERSIONS_H_ diff --git a/webrtc/base/numerics/safe_conversions_impl.h b/webrtc/base/numerics/safe_conversions_impl.h new file mode 100644 index 0000000000..b2372a67b5 --- /dev/null +++ b/webrtc/base/numerics/safe_conversions_impl.h @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + * + */ + +// Borrowed from Chromium's src/base/numerics/safe_conversions_impl.h. +// - Modified to work in WebRTC (paths, namespace, use of webrtc/base). +// Based on 'chromium_revision': 'ee311243eae6aef9c907543663754ff38f1f4f40'. + +#ifndef WEBRTC_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ +#define WEBRTC_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ + +#include +#include + +#include "webrtc/base/checks.h" + +namespace rtc { +namespace internal { + +// The std library doesn't provide a binary max_exponent for integers, however +// we can compute one by adding one to the number of non-sign bits. This allows +// for accurate range comparisons between floating point and integer types. +template +struct MaxExponent { + static const int value = std::numeric_limits::is_iec559 + ? std::numeric_limits::max_exponent + : (sizeof(NumericType) * 8 + 1 - + std::numeric_limits::is_signed); +}; + +enum IntegerRepresentation { + INTEGER_REPRESENTATION_UNSIGNED, + INTEGER_REPRESENTATION_SIGNED +}; + +// A range for a given nunmeric Src type is contained for a given numeric Dst +// type if both numeric_limits::max() <= numeric_limits::max() and +// numeric_limits::min() >= numeric_limits::min() are true. +// We implement this as template specializations rather than simple static +// comparisons to ensure type correctness in our comparisons. +enum NumericRangeRepresentation { + NUMERIC_RANGE_NOT_CONTAINED, + NUMERIC_RANGE_CONTAINED +}; + +// Helper templates to statically determine if our destination type can contain +// maximum and minimum values represented by the source type. + +template < + typename Dst, + typename Src, + IntegerRepresentation DstSign = std::numeric_limits::is_signed + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED, + IntegerRepresentation SrcSign = + std::numeric_limits::is_signed + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED > +struct StaticDstRangeRelationToSrcRange; + +// Same sign: Dst is guaranteed to contain Src only if its range is equal or +// larger. +template +struct StaticDstRangeRelationToSrcRange { + static const NumericRangeRepresentation value = + MaxExponent::value >= MaxExponent::value + ? NUMERIC_RANGE_CONTAINED + : NUMERIC_RANGE_NOT_CONTAINED; +}; + +// Unsigned to signed: Dst is guaranteed to contain source only if its range is +// larger. +template +struct StaticDstRangeRelationToSrcRange { + static const NumericRangeRepresentation value = + MaxExponent::value > MaxExponent::value + ? NUMERIC_RANGE_CONTAINED + : NUMERIC_RANGE_NOT_CONTAINED; +}; + +// Signed to unsigned: Dst cannot be statically determined to contain Src. +template +struct StaticDstRangeRelationToSrcRange { + static const NumericRangeRepresentation value = NUMERIC_RANGE_NOT_CONTAINED; +}; + +enum RangeConstraint { + RANGE_VALID = 0x0, // Value can be represented by the destination type. + RANGE_UNDERFLOW = 0x1, // Value would overflow. + RANGE_OVERFLOW = 0x2, // Value would underflow. + RANGE_INVALID = RANGE_UNDERFLOW | RANGE_OVERFLOW // Invalid (i.e. NaN). +}; + +// Helper function for coercing an int back to a RangeContraint. +inline RangeConstraint GetRangeConstraint(int integer_range_constraint) { + RTC_DCHECK(integer_range_constraint >= RANGE_VALID && + integer_range_constraint <= RANGE_INVALID); + return static_cast(integer_range_constraint); +} + +// This function creates a RangeConstraint from an upper and lower bound +// check by taking advantage of the fact that only NaN can be out of range in +// both directions at once. +inline RangeConstraint GetRangeConstraint(bool is_in_upper_bound, + bool is_in_lower_bound) { + return GetRangeConstraint((is_in_upper_bound ? 0 : RANGE_OVERFLOW) | + (is_in_lower_bound ? 0 : RANGE_UNDERFLOW)); +} + +// The following helper template addresses a corner case in range checks for +// conversion from a floating-point type to an integral type of smaller range +// but larger precision (e.g. float -> unsigned). The problem is as follows: +// 1. Integral maximum is always one less than a power of two, so it must be +// truncated to fit the mantissa of the floating point. The direction of +// rounding is implementation defined, but by default it's always IEEE +// floats, which round to nearest and thus result in a value of larger +// magnitude than the integral value. +// Example: float f = UINT_MAX; // f is 4294967296f but UINT_MAX +// // is 4294967295u. +// 2. If the floating point value is equal to the promoted integral maximum +// value, a range check will erroneously pass. +// Example: (4294967296f <= 4294967295u) // This is true due to a precision +// // loss in rounding up to float. +// 3. When the floating point value is then converted to an integral, the +// resulting value is out of range for the target integral type and +// thus is implementation defined. +// Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0. +// To fix this bug we manually truncate the maximum value when the destination +// type is an integral of larger precision than the source floating-point type, +// such that the resulting maximum is represented exactly as a floating point. +template +struct NarrowingRange { + typedef typename std::numeric_limits SrcLimits; + typedef typename std::numeric_limits DstLimits; + + static Dst max() { + // The following logic avoids warnings where the max function is + // instantiated with invalid values for a bit shift (even though + // such a function can never be called). + static const int shift = + (MaxExponent::value > MaxExponent::value && + SrcLimits::digits < DstLimits::digits && SrcLimits::is_iec559 && + DstLimits::is_integer) + ? (DstLimits::digits - SrcLimits::digits) + : 0; + + // We use UINTMAX_C below to avoid compiler warnings about shifting floating + // points. Since it's a compile time calculation, it shouldn't have any + // performance impact. + return DstLimits::max() - static_cast((UINTMAX_C(1) << shift) - 1); + } + + static Dst min() { + return std::numeric_limits::is_iec559 ? -DstLimits::max() + : DstLimits::min(); + } +}; + +template < + typename Dst, + typename Src, + IntegerRepresentation DstSign = std::numeric_limits::is_signed + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED, + IntegerRepresentation SrcSign = std::numeric_limits::is_signed + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED, + NumericRangeRepresentation DstRange = + StaticDstRangeRelationToSrcRange::value > +struct DstRangeRelationToSrcRangeImpl; + +// The following templates are for ranges that must be verified at runtime. We +// split it into checks based on signedness to avoid confusing casts and +// compiler warnings on signed an unsigned comparisons. + +// Dst range is statically determined to contain Src: Nothing to check. +template +struct DstRangeRelationToSrcRangeImpl { + static RangeConstraint Check(Src value) { return RANGE_VALID; } +}; + +// Signed to signed narrowing: Both the upper and lower boundaries may be +// exceeded. +template +struct DstRangeRelationToSrcRangeImpl { + static RangeConstraint Check(Src value) { + return GetRangeConstraint((value <= NarrowingRange::max()), + (value >= NarrowingRange::min())); + } +}; + +// Unsigned to unsigned narrowing: Only the upper boundary can be exceeded. +template +struct DstRangeRelationToSrcRangeImpl { + static RangeConstraint Check(Src value) { + return GetRangeConstraint(value <= NarrowingRange::max(), true); + } +}; + +// Unsigned to signed: The upper boundary may be exceeded. +template +struct DstRangeRelationToSrcRangeImpl { + static RangeConstraint Check(Src value) { + return sizeof(Dst) > sizeof(Src) + ? RANGE_VALID + : GetRangeConstraint( + value <= static_cast(NarrowingRange::max()), + true); + } +}; + +// Signed to unsigned: The upper boundary may be exceeded for a narrower Dst, +// and any negative value exceeds the lower boundary. +template +struct DstRangeRelationToSrcRangeImpl { + static RangeConstraint Check(Src value) { + return (MaxExponent::value >= MaxExponent::value) + ? GetRangeConstraint(true, value >= static_cast(0)) + : GetRangeConstraint( + value <= static_cast(NarrowingRange::max()), + value >= static_cast(0)); + } +}; + +template +inline RangeConstraint DstRangeRelationToSrcRange(Src value) { + static_assert(std::numeric_limits::is_specialized, + "Argument must be numeric."); + static_assert(std::numeric_limits::is_specialized, + "Result must be numeric."); + return DstRangeRelationToSrcRangeImpl::Check(value); +} + +} // namespace internal +} // namespace rtc + +#endif // WEBRTC_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ diff --git a/webrtc/base/numerics/safe_math.h b/webrtc/base/numerics/safe_math.h new file mode 100644 index 0000000000..a02cd46881 --- /dev/null +++ b/webrtc/base/numerics/safe_math.h @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + * + */ + +// Borrowed from Chromium's src/base/numerics/safe_math.h. +// - Modified to work in WebRTC (paths, namespace, use of webrtc/base). +// Based on 'chromium_revision': 'ee311243eae6aef9c907543663754ff38f1f4f40'. + +#ifndef WEBRTC_BASE_NUMERICS_SAFE_MATH_H_ +#define WEBRTC_BASE_NUMERICS_SAFE_MATH_H_ + +#include +#include + +#include "webrtc/base/checks.h" +#include "webrtc/base/numerics/safe_math_impl.h" + +namespace rtc { + +namespace internal { + +// CheckedNumeric implements all the logic and operators for detecting integer +// boundary conditions such as overflow, underflow, and invalid conversions. +// The CheckedNumeric type implicitly converts from floating point and integer +// data types, and contains overloads for basic arithmetic operations (i.e.: +, +// -, *, /, %). +// +// The following methods convert from CheckedNumeric to standard numeric values: +// IsValid() - Returns true if the underlying numeric value is valid (i.e. has +// has not wrapped and is not the result of an invalid conversion). +// ValueOrDie() - Returns the underlying value. If the state is not valid this +// call will crash on a RTC_CHECK. +// ValueOrDefault() - Returns the current value, or the supplied default if the +// state is not valid. +// ValueFloating() - Returns the underlying floating point value (valid only +// only for floating point CheckedNumeric types). +// +// Bitwise operations are explicitly not supported, because correct +// handling of some cases (e.g. sign manipulation) is ambiguous. Comparison +// operations are explicitly not supported because they could result in a crash +// on a RTC_CHECK condition. You should use patterns like the following for +// these operations: +// Bitwise operation: +// CheckedNumeric checked_int = untrusted_input_value; +// int x = checked_int.ValueOrDefault(0) | kFlagValues; +// Comparison: +// CheckedNumeric checked_size = untrusted_input_value; +// checked_size += HEADER LENGTH; +// if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size) +// Do stuff... +template +class CheckedNumeric { + public: + typedef T type; + + CheckedNumeric() {} + + // Copy constructor. + template + CheckedNumeric(const CheckedNumeric& rhs) + : state_(rhs.ValueUnsafe(), rhs.validity()) {} + + template + CheckedNumeric(Src value, RangeConstraint validity) + : state_(value, validity) {} + + // This is not an explicit constructor because we implicitly upgrade regular + // numerics to CheckedNumerics to make them easier to use. + template + CheckedNumeric(Src value) + : state_(value) { + static_assert(std::numeric_limits::is_specialized, + "Argument must be numeric."); + } + + // This is not an explicit constructor because we want a seamless conversion + // from StrictNumeric types. + template + CheckedNumeric(StrictNumeric value) + : state_(static_cast(value)) { + } + + // IsValid() is the public API to test if a CheckedNumeric is currently valid. + bool IsValid() const { return validity() == RANGE_VALID; } + + // ValueOrDie() The primary accessor for the underlying value. If the current + // state is not valid it will RTC_CHECK and crash. + T ValueOrDie() const { + RTC_CHECK(IsValid()); + return state_.value(); + } + + // ValueOrDefault(T default_value) A convenience method that returns the + // current value if the state is valid, and the supplied default_value for + // any other state. + T ValueOrDefault(T default_value) const { + return IsValid() ? state_.value() : default_value; + } + + // ValueFloating() - Since floating point values include their validity state, + // we provide an easy method for extracting them directly, without a risk of + // crashing on a RTC_CHECK. + T ValueFloating() const { + static_assert(std::numeric_limits::is_iec559, "Argument must be float."); + return CheckedNumeric::cast(*this).ValueUnsafe(); + } + + // validity() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now for + // tests and to avoid a big matrix of friend operator overloads. But the + // values it returns are likely to change in the future. + // Returns: current validity state (i.e. valid, overflow, underflow, nan). + // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for + // saturation/wrapping so we can expose this state consistently and implement + // saturated arithmetic. + RangeConstraint validity() const { return state_.validity(); } + + // ValueUnsafe() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now + // for tests and to avoid a big matrix of friend operator overloads. But the + // values it returns are likely to change in the future. + // Returns: the raw numeric value, regardless of the current state. + // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for + // saturation/wrapping so we can expose this state consistently and implement + // saturated arithmetic. + T ValueUnsafe() const { return state_.value(); } + + // Prototypes for the supported arithmetic operator overloads. + template CheckedNumeric& operator+=(Src rhs); + template CheckedNumeric& operator-=(Src rhs); + template CheckedNumeric& operator*=(Src rhs); + template CheckedNumeric& operator/=(Src rhs); + template CheckedNumeric& operator%=(Src rhs); + + CheckedNumeric operator-() const { + RangeConstraint validity; + T value = CheckedNeg(state_.value(), &validity); + // Negation is always valid for floating point. + if (std::numeric_limits::is_iec559) + return CheckedNumeric(value); + + validity = GetRangeConstraint(state_.validity() | validity); + return CheckedNumeric(value, validity); + } + + CheckedNumeric Abs() const { + RangeConstraint validity; + T value = CheckedAbs(state_.value(), &validity); + // Absolute value is always valid for floating point. + if (std::numeric_limits::is_iec559) + return CheckedNumeric(value); + + validity = GetRangeConstraint(state_.validity() | validity); + return CheckedNumeric(value, validity); + } + + // This function is available only for integral types. It returns an unsigned + // integer of the same width as the source type, containing the absolute value + // of the source, and properly handling signed min. + CheckedNumeric::type> UnsignedAbs() const { + return CheckedNumeric::type>( + CheckedUnsignedAbs(state_.value()), state_.validity()); + } + + CheckedNumeric& operator++() { + *this += 1; + return *this; + } + + CheckedNumeric operator++(int) { + CheckedNumeric value = *this; + *this += 1; + return value; + } + + CheckedNumeric& operator--() { + *this -= 1; + return *this; + } + + CheckedNumeric operator--(int) { + CheckedNumeric value = *this; + *this -= 1; + return value; + } + + // These static methods behave like a convenience cast operator targeting + // the desired CheckedNumeric type. As an optimization, a reference is + // returned when Src is the same type as T. + template + static CheckedNumeric cast( + Src u, + typename std::enable_if::is_specialized, + int>::type = 0) { + return u; + } + + template + static CheckedNumeric cast( + const CheckedNumeric& u, + typename std::enable_if::value, int>::type = 0) { + return u; + } + + static const CheckedNumeric& cast(const CheckedNumeric& u) { return u; } + + private: + template + struct UnderlyingType { + using type = NumericType; + }; + + template + struct UnderlyingType> { + using type = NumericType; + }; + + CheckedNumericState state_; +}; + +// This is the boilerplate for the standard arithmetic operator overloads. A +// macro isn't the prettiest solution, but it beats rewriting these five times. +// Some details worth noting are: +// * We apply the standard arithmetic promotions. +// * We skip range checks for floating points. +// * We skip range checks for destination integers with sufficient range. +// TODO(jschuh): extract these out into templates. +#define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP) \ + /* Binary arithmetic operator for CheckedNumerics of the same type. */ \ + template \ + CheckedNumeric::type> operator OP( \ + const CheckedNumeric& lhs, const CheckedNumeric& rhs) { \ + typedef typename ArithmeticPromotion::type Promotion; \ + /* Floating point always takes the fast path */ \ + if (std::numeric_limits::is_iec559) \ + return CheckedNumeric(lhs.ValueUnsafe() OP rhs.ValueUnsafe()); \ + if (IsIntegerArithmeticSafe::value) \ + return CheckedNumeric( \ + lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \ + GetRangeConstraint(rhs.validity() | lhs.validity())); \ + RangeConstraint validity = RANGE_VALID; \ + T result = static_cast(Checked##NAME( \ + static_cast(lhs.ValueUnsafe()), \ + static_cast(rhs.ValueUnsafe()), \ + &validity)); \ + return CheckedNumeric( \ + result, \ + GetRangeConstraint(validity | lhs.validity() | rhs.validity())); \ + } \ + /* Assignment arithmetic operator implementation from CheckedNumeric. */ \ + template \ + template \ + CheckedNumeric& CheckedNumeric::operator COMPOUND_OP(Src rhs) { \ + *this = CheckedNumeric::cast(*this) \ + OP CheckedNumeric::type>::cast(rhs); \ + return *this; \ + } \ + /* Binary arithmetic operator for CheckedNumeric of different type. */ \ + template \ + CheckedNumeric::type> operator OP( \ + const CheckedNumeric& lhs, const CheckedNumeric& rhs) { \ + typedef typename ArithmeticPromotion::type Promotion; \ + if (IsIntegerArithmeticSafe::value) \ + return CheckedNumeric( \ + lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \ + GetRangeConstraint(rhs.validity() | lhs.validity())); \ + return CheckedNumeric::cast(lhs) \ + OP CheckedNumeric::cast(rhs); \ + } \ + /* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \ + template \ + CheckedNumeric::type> operator OP( \ + const CheckedNumeric& lhs, Src rhs) { \ + typedef typename ArithmeticPromotion::type Promotion; \ + if (IsIntegerArithmeticSafe::value) \ + return CheckedNumeric(lhs.ValueUnsafe() OP rhs, \ + lhs.validity()); \ + return CheckedNumeric::cast(lhs) \ + OP CheckedNumeric::cast(rhs); \ + } \ + /* Binary arithmetic operator for right numeric and left CheckedNumeric. */ \ + template \ + CheckedNumeric::type> operator OP( \ + Src lhs, const CheckedNumeric& rhs) { \ + typedef typename ArithmeticPromotion::type Promotion; \ + if (IsIntegerArithmeticSafe::value) \ + return CheckedNumeric(lhs OP rhs.ValueUnsafe(), \ + rhs.validity()); \ + return CheckedNumeric::cast(lhs) \ + OP CheckedNumeric::cast(rhs); \ + } + +BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, += ) +BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -= ) +BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *= ) +BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /= ) +BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %= ) + +#undef BASE_NUMERIC_ARITHMETIC_OPERATORS + +} // namespace internal + +using internal::CheckedNumeric; + +} // namespace rtc + +#endif // WEBRTC_BASE_NUMERICS_SAFE_MATH_H_ diff --git a/webrtc/base/numerics/safe_math_impl.h b/webrtc/base/numerics/safe_math_impl.h new file mode 100644 index 0000000000..fc1ce0e20a --- /dev/null +++ b/webrtc/base/numerics/safe_math_impl.h @@ -0,0 +1,556 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + * + */ + +// Borrowed from Chromium's src/base/numerics/safe_math_impl.h. +// - Modified to work in WebRTC (paths, namespace, use of webrtc/base). +// Based on 'chromium_revision': 'ee311243eae6aef9c907543663754ff38f1f4f40'. + +#ifndef WEBRTC_BASE_NUMERICS_SAFE_MATH_IMPL_H_ +#define WEBRTC_BASE_NUMERICS_SAFE_MATH_IMPL_H_ + +#include +#include + +#include +#include +#include +#include + +#include "webrtc/base/checks.h" +#include "webrtc/base/numerics/safe_conversions.h" + +namespace rtc { +namespace internal { + +// Everything from here up to the floating point operations is portable C++, +// but it may not be fast. This code could be split based on +// platform/architecture and replaced with potentially faster implementations. + +// Integer promotion templates used by the portable checked integer arithmetic. +template +struct IntegerForSizeAndSign; +template <> +struct IntegerForSizeAndSign<1, true> { + typedef int8_t type; +}; +template <> +struct IntegerForSizeAndSign<1, false> { + typedef uint8_t type; +}; +template <> +struct IntegerForSizeAndSign<2, true> { + typedef int16_t type; +}; +template <> +struct IntegerForSizeAndSign<2, false> { + typedef uint16_t type; +}; +template <> +struct IntegerForSizeAndSign<4, true> { + typedef int32_t type; +}; +template <> +struct IntegerForSizeAndSign<4, false> { + typedef uint32_t type; +}; +template <> +struct IntegerForSizeAndSign<8, true> { + typedef int64_t type; +}; +template <> +struct IntegerForSizeAndSign<8, false> { + typedef uint64_t type; +}; + +// WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to +// support 128-bit math, then the ArithmeticPromotion template below will need +// to be updated (or more likely replaced with a decltype expression). + +template +struct UnsignedIntegerForSize { + typedef typename std::enable_if< + std::numeric_limits::is_integer, + typename IntegerForSizeAndSign::type>::type type; +}; + +template +struct SignedIntegerForSize { + typedef typename std::enable_if< + std::numeric_limits::is_integer, + typename IntegerForSizeAndSign::type>::type type; +}; + +template +struct TwiceWiderInteger { + typedef typename std::enable_if< + std::numeric_limits::is_integer, + typename IntegerForSizeAndSign< + sizeof(Integer) * 2, + std::numeric_limits::is_signed>::type>::type type; +}; + +template +struct PositionOfSignBit { + static const typename std::enable_if::is_integer, + size_t>::type value = + 8 * sizeof(Integer) - 1; +}; + +// This is used for UnsignedAbs, where we need to support floating-point +// template instantiations even though we don't actually support the operations. +// However, there is no corresponding implementation of e.g. CheckedUnsignedAbs, +// so the float versions will not compile. +template ::is_integer, + bool IsFloat = std::numeric_limits::is_iec559> +struct UnsignedOrFloatForSize; + +template +struct UnsignedOrFloatForSize { + typedef typename UnsignedIntegerForSize::type type; +}; + +template +struct UnsignedOrFloatForSize { + typedef Numeric type; +}; + +// Helper templates for integer manipulations. + +template +bool HasSignBit(T x) { + // Cast to unsigned since right shift on signed is undefined. + return !!(static_cast::type>(x) >> + PositionOfSignBit::value); +} + +// This wrapper undoes the standard integer promotions. +template +T BinaryComplement(T x) { + return ~x; +} + +// Here are the actual portable checked integer math implementations. +// TODO(jschuh): Break this code out from the enable_if pattern and find a clean +// way to coalesce things into the CheckedNumericState specializations below. + +template +typename std::enable_if::is_integer, T>::type +CheckedAdd(T x, T y, RangeConstraint* validity) { + // Since the value of x+y is undefined if we have a signed type, we compute + // it using the unsigned type of the same size. + typedef typename UnsignedIntegerForSize::type UnsignedDst; + UnsignedDst ux = static_cast(x); + UnsignedDst uy = static_cast(y); + UnsignedDst uresult = ux + uy; + // Addition is valid if the sign of (x + y) is equal to either that of x or + // that of y. + if (std::numeric_limits::is_signed) { + if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy)))) + *validity = RANGE_VALID; + else // Direction of wrap is inverse of result sign. + *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; + + } else { // Unsigned is either valid or overflow. + *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW; + } + return static_cast(uresult); +} + +template +typename std::enable_if::is_integer, T>::type +CheckedSub(T x, T y, RangeConstraint* validity) { + // Since the value of x+y is undefined if we have a signed type, we compute + // it using the unsigned type of the same size. + typedef typename UnsignedIntegerForSize::type UnsignedDst; + UnsignedDst ux = static_cast(x); + UnsignedDst uy = static_cast(y); + UnsignedDst uresult = ux - uy; + // Subtraction is valid if either x and y have same sign, or (x-y) and x have + // the same sign. + if (std::numeric_limits::is_signed) { + if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy)))) + *validity = RANGE_VALID; + else // Direction of wrap is inverse of result sign. + *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; + + } else { // Unsigned is either valid or underflow. + *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW; + } + return static_cast(uresult); +} + +// Integer multiplication is a bit complicated. In the fast case we just +// we just promote to a twice wider type, and range check the result. In the +// slow case we need to manually check that the result won't be truncated by +// checking with division against the appropriate bound. +template +typename std::enable_if::is_integer && + sizeof(T) * 2 <= sizeof(uintmax_t), + T>::type +CheckedMul(T x, T y, RangeConstraint* validity) { + typedef typename TwiceWiderInteger::type IntermediateType; + IntermediateType tmp = + static_cast(x) * static_cast(y); + *validity = DstRangeRelationToSrcRange(tmp); + return static_cast(tmp); +} + +template +typename std::enable_if::is_integer && + std::numeric_limits::is_signed && + (sizeof(T) * 2 > sizeof(uintmax_t)), + T>::type +CheckedMul(T x, T y, RangeConstraint* validity) { + // If either side is zero then the result will be zero. + if (!x || !y) { + return RANGE_VALID; + + } else if (x > 0) { + if (y > 0) + *validity = + x <= std::numeric_limits::max() / y ? RANGE_VALID : RANGE_OVERFLOW; + else + *validity = y >= std::numeric_limits::min() / x ? RANGE_VALID + : RANGE_UNDERFLOW; + + } else { + if (y > 0) + *validity = x >= std::numeric_limits::min() / y ? RANGE_VALID + : RANGE_UNDERFLOW; + else + *validity = + y >= std::numeric_limits::max() / x ? RANGE_VALID : RANGE_OVERFLOW; + } + + return x * y; +} + +template +typename std::enable_if::is_integer && + !std::numeric_limits::is_signed && + (sizeof(T) * 2 > sizeof(uintmax_t)), + T>::type +CheckedMul(T x, T y, RangeConstraint* validity) { + *validity = (y == 0 || x <= std::numeric_limits::max() / y) + ? RANGE_VALID + : RANGE_OVERFLOW; + return x * y; +} + +// Division just requires a check for an invalid negation on signed min/-1. +template +T CheckedDiv(T x, + T y, + RangeConstraint* validity, + typename std::enable_if::is_integer, + int>::type = 0) { + if (std::numeric_limits::is_signed && x == std::numeric_limits::min() && + y == static_cast(-1)) { + *validity = RANGE_OVERFLOW; + return std::numeric_limits::min(); + } + + *validity = RANGE_VALID; + return x / y; +} + +template +typename std::enable_if::is_integer && + std::numeric_limits::is_signed, + T>::type +CheckedMod(T x, T y, RangeConstraint* validity) { + *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; + return x % y; +} + +template +typename std::enable_if::is_integer && + !std::numeric_limits::is_signed, + T>::type +CheckedMod(T x, T y, RangeConstraint* validity) { + *validity = RANGE_VALID; + return x % y; +} + +template +typename std::enable_if::is_integer && + std::numeric_limits::is_signed, + T>::type +CheckedNeg(T value, RangeConstraint* validity) { + *validity = + value != std::numeric_limits::min() ? RANGE_VALID : RANGE_OVERFLOW; + // The negation of signed min is min, so catch that one. + return -value; +} + +template +typename std::enable_if::is_integer && + !std::numeric_limits::is_signed, + T>::type +CheckedNeg(T value, RangeConstraint* validity) { + // The only legal unsigned negation is zero. + *validity = value ? RANGE_UNDERFLOW : RANGE_VALID; + return static_cast( + -static_cast::type>(value)); +} + +template +typename std::enable_if::is_integer && + std::numeric_limits::is_signed, + T>::type +CheckedAbs(T value, RangeConstraint* validity) { + *validity = + value != std::numeric_limits::min() ? RANGE_VALID : RANGE_OVERFLOW; + return static_cast(std::abs(value)); +} + +template +typename std::enable_if::is_integer && + !std::numeric_limits::is_signed, + T>::type +CheckedAbs(T value, RangeConstraint* validity) { + // T is unsigned, so |value| must already be positive. + *validity = RANGE_VALID; + return value; +} + +template +typename std::enable_if::is_integer && + std::numeric_limits::is_signed, + typename UnsignedIntegerForSize::type>::type +CheckedUnsignedAbs(T value) { + typedef typename UnsignedIntegerForSize::type UnsignedT; + return value == std::numeric_limits::min() + ? static_cast(std::numeric_limits::max()) + 1 + : static_cast(std::abs(value)); +} + +template +typename std::enable_if::is_integer && + !std::numeric_limits::is_signed, + T>::type +CheckedUnsignedAbs(T value) { + // T is unsigned, so |value| must already be positive. + return value; +} + +// These are the floating point stubs that the compiler needs to see. Only the +// negation operation is ever called. +#define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ + template \ + typename std::enable_if::is_iec559, T>::type \ + Checked##NAME(T, T, RangeConstraint*) { \ + RTC_NOTREACHED(); \ + return 0; \ + } + +BASE_FLOAT_ARITHMETIC_STUBS(Add) +BASE_FLOAT_ARITHMETIC_STUBS(Sub) +BASE_FLOAT_ARITHMETIC_STUBS(Mul) +BASE_FLOAT_ARITHMETIC_STUBS(Div) +BASE_FLOAT_ARITHMETIC_STUBS(Mod) + +#undef BASE_FLOAT_ARITHMETIC_STUBS + +template +typename std::enable_if::is_iec559, T>::type CheckedNeg( + T value, + RangeConstraint*) { + return -value; +} + +template +typename std::enable_if::is_iec559, T>::type CheckedAbs( + T value, + RangeConstraint*) { + return std::abs(value); +} + +// Floats carry around their validity state with them, but integers do not. So, +// we wrap the underlying value in a specialization in order to hide that detail +// and expose an interface via accessors. +enum NumericRepresentation { + NUMERIC_INTEGER, + NUMERIC_FLOATING, + NUMERIC_UNKNOWN +}; + +template +struct GetNumericRepresentation { + static const NumericRepresentation value = + std::numeric_limits::is_integer + ? NUMERIC_INTEGER + : (std::numeric_limits::is_iec559 ? NUMERIC_FLOATING + : NUMERIC_UNKNOWN); +}; + +template ::value> +class CheckedNumericState {}; + +// Integrals require quite a bit of additional housekeeping to manage state. +template +class CheckedNumericState { + private: + T value_; + RangeConstraint validity_; + + public: + template + friend class CheckedNumericState; + + CheckedNumericState() : value_(0), validity_(RANGE_VALID) {} + + template + CheckedNumericState(Src value, RangeConstraint validity) + : value_(static_cast(value)), + validity_(GetRangeConstraint(validity | + DstRangeRelationToSrcRange(value))) { + static_assert(std::numeric_limits::is_specialized, + "Argument must be numeric."); + } + + // Copy constructor. + template + CheckedNumericState(const CheckedNumericState& rhs) + : value_(static_cast(rhs.value())), + validity_(GetRangeConstraint( + rhs.validity() | DstRangeRelationToSrcRange(rhs.value()))) {} + + template + explicit CheckedNumericState( + Src value, + typename std::enable_if::is_specialized, + int>::type = 0) + : value_(static_cast(value)), + validity_(DstRangeRelationToSrcRange(value)) {} + + RangeConstraint validity() const { return validity_; } + T value() const { return value_; } +}; + +// Floating points maintain their own validity, but need translation wrappers. +template +class CheckedNumericState { + private: + T value_; + + public: + template + friend class CheckedNumericState; + + CheckedNumericState() : value_(0.0) {} + + template + CheckedNumericState( + Src value, + RangeConstraint validity, + typename std::enable_if::is_integer, int>::type = + 0) { + switch (DstRangeRelationToSrcRange(value)) { + case RANGE_VALID: + value_ = static_cast(value); + break; + + case RANGE_UNDERFLOW: + value_ = -std::numeric_limits::infinity(); + break; + + case RANGE_OVERFLOW: + value_ = std::numeric_limits::infinity(); + break; + + case RANGE_INVALID: + value_ = std::numeric_limits::quiet_NaN(); + break; + + default: + RTC_NOTREACHED(); + } + } + + template + explicit CheckedNumericState( + Src value, + typename std::enable_if::is_specialized, + int>::type = 0) + : value_(static_cast(value)) {} + + // Copy constructor. + template + CheckedNumericState(const CheckedNumericState& rhs) + : value_(static_cast(rhs.value())) {} + + RangeConstraint validity() const { + return GetRangeConstraint(value_ <= std::numeric_limits::max(), + value_ >= -std::numeric_limits::max()); + } + T value() const { return value_; } +}; + +// For integers less than 128-bit and floats 32-bit or larger, we can distil +// C/C++ arithmetic promotions down to two simple rules: +// 1. The type with the larger maximum exponent always takes precedence. +// 2. The resulting type must be promoted to at least an int. +// The following template specializations implement that promotion logic. +enum ArithmeticPromotionCategory { + LEFT_PROMOTION, + RIGHT_PROMOTION, + DEFAULT_PROMOTION +}; + +template ::value > MaxExponent::value) + ? (MaxExponent::value > MaxExponent::value + ? LEFT_PROMOTION + : DEFAULT_PROMOTION) + : (MaxExponent::value > MaxExponent::value + ? RIGHT_PROMOTION + : DEFAULT_PROMOTION) > +struct ArithmeticPromotion; + +template +struct ArithmeticPromotion { + typedef Lhs type; +}; + +template +struct ArithmeticPromotion { + typedef Rhs type; +}; + +template +struct ArithmeticPromotion { + typedef int type; +}; + +// We can statically check if operations on the provided types can wrap, so we +// can skip the checked operations if they're not needed. So, for an integer we +// care if the destination type preserves the sign and is twice the width of +// the source. +template +struct IsIntegerArithmeticSafe { + static const bool value = !std::numeric_limits::is_iec559 && + StaticDstRangeRelationToSrcRange::value == + NUMERIC_RANGE_CONTAINED && + sizeof(T) >= (2 * sizeof(Lhs)) && + StaticDstRangeRelationToSrcRange::value != + NUMERIC_RANGE_CONTAINED && + sizeof(T) >= (2 * sizeof(Rhs)); +}; + +} // namespace internal +} // namespace rtc + +#endif // WEBRTC_BASE_NUMERICS_SAFE_MATH_IMPL_H_ diff --git a/webrtc/base/openssladapter.cc b/webrtc/base/openssladapter.cc index 264dae9e28..a7eb728b7b 100644 --- a/webrtc/base/openssladapter.cc +++ b/webrtc/base/openssladapter.cc @@ -34,8 +34,8 @@ #include "webrtc/base/arraysize.h" #include "webrtc/base/common.h" #include "webrtc/base/logging.h" +#include "webrtc/base/numerics/safe_conversions.h" #include "webrtc/base/openssl.h" -#include "webrtc/base/safe_conversions.h" #include "webrtc/base/sslroots.h" #include "webrtc/base/stringutils.h" #include "webrtc/base/thread.h" diff --git a/webrtc/base/opensslstreamadapter.cc b/webrtc/base/opensslstreamadapter.cc index 30326f57a2..b2afebb75b 100644 --- a/webrtc/base/opensslstreamadapter.cc +++ b/webrtc/base/opensslstreamadapter.cc @@ -27,7 +27,7 @@ #include "webrtc/base/common.h" #include "webrtc/base/logging.h" -#include "webrtc/base/safe_conversions.h" +#include "webrtc/base/numerics/safe_conversions.h" #include "webrtc/base/stream.h" #include "webrtc/base/openssl.h" #include "webrtc/base/openssladapter.h" diff --git a/webrtc/base/rtccertificate_unittests.cc b/webrtc/base/rtccertificate_unittests.cc index 84c854478b..5fc0919fe8 100644 --- a/webrtc/base/rtccertificate_unittests.cc +++ b/webrtc/base/rtccertificate_unittests.cc @@ -14,8 +14,8 @@ #include "webrtc/base/fakesslidentity.h" #include "webrtc/base/gunit.h" #include "webrtc/base/logging.h" +#include "webrtc/base/numerics/safe_conversions.h" #include "webrtc/base/rtccertificate.h" -#include "webrtc/base/safe_conversions.h" #include "webrtc/base/scoped_ptr.h" #include "webrtc/base/sslidentity.h" #include "webrtc/base/thread.h" diff --git a/webrtc/base/safe_conversions.h b/webrtc/base/safe_conversions.h deleted file mode 100644 index 51239bc65d..0000000000 --- a/webrtc/base/safe_conversions.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2014 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -// Borrowed from Chromium's src/base/numerics/safe_conversions.h. - -#ifndef WEBRTC_BASE_SAFE_CONVERSIONS_H_ -#define WEBRTC_BASE_SAFE_CONVERSIONS_H_ - -#include - -#include "webrtc/base/checks.h" -#include "webrtc/base/safe_conversions_impl.h" - -namespace rtc { - -// Convenience function that returns true if the supplied value is in range -// for the destination type. -template -inline bool IsValueInRangeForNumericType(Src value) { - return internal::RangeCheck(value) == internal::TYPE_VALID; -} - -// checked_cast<> is analogous to static_cast<> for numeric types, -// except that it CHECKs that the specified numeric conversion will not -// overflow or underflow. NaN source will always trigger a CHECK. -template -inline Dst checked_cast(Src value) { - RTC_CHECK(IsValueInRangeForNumericType(value)); - return static_cast(value); -} - -// saturated_cast<> is analogous to static_cast<> for numeric types, except -// that the specified numeric conversion will saturate rather than overflow or -// underflow. NaN assignment to an integral will trigger a RTC_CHECK condition. -template -inline Dst saturated_cast(Src value) { - // Optimization for floating point values, which already saturate. - if (std::numeric_limits::is_iec559) - return static_cast(value); - - switch (internal::RangeCheck(value)) { - case internal::TYPE_VALID: - return static_cast(value); - - case internal::TYPE_UNDERFLOW: - return std::numeric_limits::min(); - - case internal::TYPE_OVERFLOW: - return std::numeric_limits::max(); - - // Should fail only on attempting to assign NaN to a saturated integer. - case internal::TYPE_INVALID: - FATAL(); - return std::numeric_limits::max(); - } - - FATAL(); - return static_cast(value); -} - -} // namespace rtc - -#endif // WEBRTC_BASE_SAFE_CONVERSIONS_H_ diff --git a/webrtc/base/safe_conversions_impl.h b/webrtc/base/safe_conversions_impl.h deleted file mode 100644 index 52e52eff82..0000000000 --- a/webrtc/base/safe_conversions_impl.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright 2014 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -// Borrowed from Chromium's src/base/numerics/safe_conversions_impl.h. - -#ifndef WEBRTC_BASE_SAFE_CONVERSIONS_IMPL_H_ -#define WEBRTC_BASE_SAFE_CONVERSIONS_IMPL_H_ - -#include - -namespace rtc { -namespace internal { - -enum DstSign { - DST_UNSIGNED, - DST_SIGNED -}; - -enum SrcSign { - SRC_UNSIGNED, - SRC_SIGNED -}; - -enum DstRange { - OVERLAPS_RANGE, - CONTAINS_RANGE -}; - -// Helper templates to statically determine if our destination type can contain -// all values represented by the source type. - -template ::is_signed ? - DST_SIGNED : DST_UNSIGNED, - SrcSign IsSrcSigned = std::numeric_limits::is_signed ? - SRC_SIGNED : SRC_UNSIGNED> -struct StaticRangeCheck {}; - -template -struct StaticRangeCheck { - typedef std::numeric_limits DstLimits; - typedef std::numeric_limits SrcLimits; - // Compare based on max_exponent, which we must compute for integrals. - static const size_t kDstMaxExponent = DstLimits::is_iec559 ? - DstLimits::max_exponent : - (sizeof(Dst) * 8 - 1); - static const size_t kSrcMaxExponent = SrcLimits::is_iec559 ? - SrcLimits::max_exponent : - (sizeof(Src) * 8 - 1); - static const DstRange value = kDstMaxExponent >= kSrcMaxExponent ? - CONTAINS_RANGE : OVERLAPS_RANGE; -}; - -template -struct StaticRangeCheck { - static const DstRange value = sizeof(Dst) >= sizeof(Src) ? - CONTAINS_RANGE : OVERLAPS_RANGE; -}; - -template -struct StaticRangeCheck { - typedef std::numeric_limits DstLimits; - typedef std::numeric_limits SrcLimits; - // Compare based on max_exponent, which we must compute for integrals. - static const size_t kDstMaxExponent = DstLimits::is_iec559 ? - DstLimits::max_exponent : - (sizeof(Dst) * 8 - 1); - static const size_t kSrcMaxExponent = sizeof(Src) * 8; - static const DstRange value = kDstMaxExponent >= kSrcMaxExponent ? - CONTAINS_RANGE : OVERLAPS_RANGE; -}; - -template -struct StaticRangeCheck { - static const DstRange value = OVERLAPS_RANGE; -}; - - -enum RangeCheckResult { - TYPE_VALID = 0, // Value can be represented by the destination type. - TYPE_UNDERFLOW = 1, // Value would overflow. - TYPE_OVERFLOW = 2, // Value would underflow. - TYPE_INVALID = 3 // Source value is invalid (i.e. NaN). -}; - -// This macro creates a RangeCheckResult from an upper and lower bound -// check by taking advantage of the fact that only NaN can be out of range in -// both directions at once. -#define BASE_NUMERIC_RANGE_CHECK_RESULT(is_in_upper_bound, is_in_lower_bound) \ - RangeCheckResult(((is_in_upper_bound) ? 0 : TYPE_OVERFLOW) | \ - ((is_in_lower_bound) ? 0 : TYPE_UNDERFLOW)) - -template ::is_signed ? - DST_SIGNED : DST_UNSIGNED, - SrcSign IsSrcSigned = std::numeric_limits::is_signed ? - SRC_SIGNED : SRC_UNSIGNED, - DstRange IsSrcRangeContained = StaticRangeCheck::value> -struct RangeCheckImpl {}; - -// The following templates are for ranges that must be verified at runtime. We -// split it into checks based on signedness to avoid confusing casts and -// compiler warnings on signed an unsigned comparisons. - -// Dst range always contains the result: nothing to check. -template -struct RangeCheckImpl { - static RangeCheckResult Check(Src value) { - return TYPE_VALID; - } -}; - -// Signed to signed narrowing. -template -struct RangeCheckImpl { - static RangeCheckResult Check(Src value) { - typedef std::numeric_limits DstLimits; - return DstLimits::is_iec559 ? - BASE_NUMERIC_RANGE_CHECK_RESULT( - value <= static_cast(DstLimits::max()), - value >= static_cast(DstLimits::max() * -1)) : - BASE_NUMERIC_RANGE_CHECK_RESULT( - value <= static_cast(DstLimits::max()), - value >= static_cast(DstLimits::min())); - } -}; - -// Unsigned to unsigned narrowing. -template -struct RangeCheckImpl { - static RangeCheckResult Check(Src value) { - typedef std::numeric_limits DstLimits; - return BASE_NUMERIC_RANGE_CHECK_RESULT( - value <= static_cast(DstLimits::max()), true); - } -}; - -// Unsigned to signed. -template -struct RangeCheckImpl { - static RangeCheckResult Check(Src value) { - typedef std::numeric_limits DstLimits; - return sizeof(Dst) > sizeof(Src) ? TYPE_VALID : - BASE_NUMERIC_RANGE_CHECK_RESULT( - value <= static_cast(DstLimits::max()), true); - } -}; - -// Signed to unsigned. -template -struct RangeCheckImpl { - static RangeCheckResult Check(Src value) { - typedef std::numeric_limits DstLimits; - typedef std::numeric_limits SrcLimits; - // Compare based on max_exponent, which we must compute for integrals. - static const size_t kDstMaxExponent = sizeof(Dst) * 8; - static const size_t kSrcMaxExponent = SrcLimits::is_iec559 ? - SrcLimits::max_exponent : - (sizeof(Src) * 8 - 1); - return (kDstMaxExponent >= kSrcMaxExponent) ? - BASE_NUMERIC_RANGE_CHECK_RESULT(true, value >= static_cast(0)) : - BASE_NUMERIC_RANGE_CHECK_RESULT( - value <= static_cast(DstLimits::max()), - value >= static_cast(0)); - } -}; - -template -inline RangeCheckResult RangeCheck(Src value) { - static_assert(std::numeric_limits::is_specialized, - "argument must be numeric"); - static_assert(std::numeric_limits::is_specialized, - "result must be numeric"); - return RangeCheckImpl::Check(value); -} - -} // namespace internal -} // namespace rtc - -#endif // WEBRTC_BASE_SAFE_CONVERSIONS_IMPL_H_ diff --git a/webrtc/common_audio/audio_converter.cc b/webrtc/common_audio/audio_converter.cc index d6334b3866..2c1b632b96 100644 --- a/webrtc/common_audio/audio_converter.cc +++ b/webrtc/common_audio/audio_converter.cc @@ -14,7 +14,7 @@ #include #include "webrtc/base/checks.h" -#include "webrtc/base/safe_conversions.h" +#include "webrtc/base/numerics/safe_conversions.h" #include "webrtc/common_audio/channel_buffer.h" #include "webrtc/common_audio/resampler/push_sinc_resampler.h" #include "webrtc/system_wrappers/include/scoped_vector.h" diff --git a/webrtc/common_audio/wav_file.cc b/webrtc/common_audio/wav_file.cc index 572c94ba3d..a622bca7ab 100644 --- a/webrtc/common_audio/wav_file.cc +++ b/webrtc/common_audio/wav_file.cc @@ -16,7 +16,7 @@ #include #include "webrtc/base/checks.h" -#include "webrtc/base/safe_conversions.h" +#include "webrtc/base/numerics/safe_conversions.h" #include "webrtc/common_audio/include/audio_util.h" #include "webrtc/common_audio/wav_header.h" diff --git a/webrtc/media/engine/webrtcvideocapturer.cc b/webrtc/media/engine/webrtcvideocapturer.cc index a1848e933c..8042b277b3 100644 --- a/webrtc/media/engine/webrtcvideocapturer.cc +++ b/webrtc/media/engine/webrtcvideocapturer.cc @@ -19,7 +19,7 @@ #include "webrtc/base/checks.h" #include "webrtc/base/criticalsection.h" #include "webrtc/base/logging.h" -#include "webrtc/base/safe_conversions.h" +#include "webrtc/base/numerics/safe_conversions.h" #include "webrtc/base/thread.h" #include "webrtc/base/timeutils.h" #include "webrtc/media/engine/webrtcvideoframe.h" diff --git a/webrtc/media/sctp/sctpdataengine.cc b/webrtc/media/sctp/sctpdataengine.cc index ce0f91ae39..e60a890b2c 100644 --- a/webrtc/media/sctp/sctpdataengine.cc +++ b/webrtc/media/sctp/sctpdataengine.cc @@ -22,7 +22,7 @@ #include "webrtc/base/buffer.h" #include "webrtc/base/helpers.h" #include "webrtc/base/logging.h" -#include "webrtc/base/safe_conversions.h" +#include "webrtc/base/numerics/safe_conversions.h" #include "webrtc/media/base/codec.h" #include "webrtc/media/base/mediaconstants.h" #include "webrtc/media/base/streamparams.h" diff --git a/webrtc/modules/audio_coding/acm2/acm_receiver.cc b/webrtc/modules/audio_coding/acm2/acm_receiver.cc index 5649f07b2b..507e553069 100644 --- a/webrtc/modules/audio_coding/acm2/acm_receiver.cc +++ b/webrtc/modules/audio_coding/acm2/acm_receiver.cc @@ -18,7 +18,7 @@ #include "webrtc/base/checks.h" #include "webrtc/base/format_macros.h" #include "webrtc/base/logging.h" -#include "webrtc/base/safe_conversions.h" +#include "webrtc/base/numerics/safe_conversions.h" #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" #include "webrtc/common_types.h" #include "webrtc/modules/audio_coding/codecs/audio_decoder.h" diff --git a/webrtc/modules/audio_coding/acm2/audio_coding_module_impl.cc b/webrtc/modules/audio_coding/acm2/audio_coding_module_impl.cc index ff779a28b1..2b62022489 100644 --- a/webrtc/modules/audio_coding/acm2/audio_coding_module_impl.cc +++ b/webrtc/modules/audio_coding/acm2/audio_coding_module_impl.cc @@ -15,7 +15,7 @@ #include #include "webrtc/base/checks.h" -#include "webrtc/base/safe_conversions.h" +#include "webrtc/base/numerics/safe_conversions.h" #include "webrtc/engine_configurations.h" #include "webrtc/modules/audio_coding/include/audio_coding_module_typedefs.h" #include "webrtc/modules/audio_coding/acm2/acm_common_defs.h" diff --git a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc index a599e291d4..e3f1a2b75c 100644 --- a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc +++ b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc @@ -11,7 +11,7 @@ #include "webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h" #include "webrtc/base/checks.h" -#include "webrtc/base/safe_conversions.h" +#include "webrtc/base/numerics/safe_conversions.h" #include "webrtc/common_types.h" #include "webrtc/modules/audio_coding/codecs/opus/opus_interface.h" diff --git a/webrtc/modules/audio_coding/neteq/delay_manager.cc b/webrtc/modules/audio_coding/neteq/delay_manager.cc index af49f00f8a..d0dfbfd648 100644 --- a/webrtc/modules/audio_coding/neteq/delay_manager.cc +++ b/webrtc/modules/audio_coding/neteq/delay_manager.cc @@ -15,7 +15,7 @@ #include // max, min -#include "webrtc/base/safe_conversions.h" +#include "webrtc/base/numerics/safe_conversions.h" #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" #include "webrtc/modules/audio_coding/neteq/delay_peak_detector.h" #include "webrtc/modules/include/module_common_types.h" diff --git a/webrtc/modules/audio_coding/neteq/expand.cc b/webrtc/modules/audio_coding/neteq/expand.cc index ef7af46597..f092a62e69 100644 --- a/webrtc/modules/audio_coding/neteq/expand.cc +++ b/webrtc/modules/audio_coding/neteq/expand.cc @@ -16,7 +16,7 @@ #include // min, max #include // numeric_limits -#include "webrtc/base/safe_conversions.h" +#include "webrtc/base/numerics/safe_conversions.h" #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" #include "webrtc/modules/audio_coding/neteq/background_noise.h" #include "webrtc/modules/audio_coding/neteq/dsp_helper.h" diff --git a/webrtc/modules/audio_coding/neteq/expand_unittest.cc b/webrtc/modules/audio_coding/neteq/expand_unittest.cc index 1441704102..6ca77064c4 100644 --- a/webrtc/modules/audio_coding/neteq/expand_unittest.cc +++ b/webrtc/modules/audio_coding/neteq/expand_unittest.cc @@ -13,7 +13,7 @@ #include "webrtc/modules/audio_coding/neteq/expand.h" #include "testing/gtest/include/gtest/gtest.h" -#include "webrtc/base/safe_conversions.h" +#include "webrtc/base/numerics/safe_conversions.h" #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" #include "webrtc/modules/audio_coding/neteq/background_noise.h" #include "webrtc/modules/audio_coding/neteq/random_vector.h" diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl.cc b/webrtc/modules/audio_coding/neteq/neteq_impl.cc index b4cc915951..a6666a6d35 100644 --- a/webrtc/modules/audio_coding/neteq/neteq_impl.cc +++ b/webrtc/modules/audio_coding/neteq/neteq_impl.cc @@ -17,7 +17,7 @@ #include "webrtc/base/checks.h" #include "webrtc/base/logging.h" -#include "webrtc/base/safe_conversions.h" +#include "webrtc/base/numerics/safe_conversions.h" #include "webrtc/base/trace_event.h" #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" #include "webrtc/modules/audio_coding/codecs/audio_decoder.h" diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc b/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc index e1eb403022..7b73d01628 100644 --- a/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc +++ b/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc @@ -13,7 +13,7 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -#include "webrtc/base/safe_conversions.h" +#include "webrtc/base/numerics/safe_conversions.h" #include "webrtc/modules/audio_coding/neteq/accelerate.h" #include "webrtc/modules/audio_coding/neteq/expand.h" #include "webrtc/modules/audio_coding/neteq/mock/mock_audio_decoder.h" diff --git a/webrtc/modules/audio_coding/neteq/statistics_calculator.cc b/webrtc/modules/audio_coding/neteq/statistics_calculator.cc index d16a11bc63..c853b363f4 100644 --- a/webrtc/modules/audio_coding/neteq/statistics_calculator.cc +++ b/webrtc/modules/audio_coding/neteq/statistics_calculator.cc @@ -15,7 +15,7 @@ #include #include "webrtc/base/checks.h" -#include "webrtc/base/safe_conversions.h" +#include "webrtc/base/numerics/safe_conversions.h" #include "webrtc/modules/audio_coding/neteq/decision_logic.h" #include "webrtc/modules/audio_coding/neteq/delay_manager.h" #include "webrtc/system_wrappers/include/metrics.h" diff --git a/webrtc/modules/audio_coding/neteq/test/neteq_ilbc_quality_test.cc b/webrtc/modules/audio_coding/neteq/test/neteq_ilbc_quality_test.cc index fdbe39cce2..83cc5401b0 100644 --- a/webrtc/modules/audio_coding/neteq/test/neteq_ilbc_quality_test.cc +++ b/webrtc/modules/audio_coding/neteq/test/neteq_ilbc_quality_test.cc @@ -11,7 +11,7 @@ #include #include "webrtc/base/checks.h" -#include "webrtc/base/safe_conversions.h" +#include "webrtc/base/numerics/safe_conversions.h" #include "webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h" #include "webrtc/modules/audio_coding/neteq/tools/neteq_quality_test.h" #include "webrtc/test/testsupport/fileutils.h" diff --git a/webrtc/modules/audio_coding/neteq/test/neteq_pcmu_quality_test.cc b/webrtc/modules/audio_coding/neteq/test/neteq_pcmu_quality_test.cc index 8c7e5b7a93..526dcc1388 100644 --- a/webrtc/modules/audio_coding/neteq/test/neteq_pcmu_quality_test.cc +++ b/webrtc/modules/audio_coding/neteq/test/neteq_pcmu_quality_test.cc @@ -11,7 +11,7 @@ #include #include "webrtc/base/checks.h" -#include "webrtc/base/safe_conversions.h" +#include "webrtc/base/numerics/safe_conversions.h" #include "webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.h" #include "webrtc/modules/audio_coding/neteq/tools/neteq_quality_test.h" #include "webrtc/test/testsupport/fileutils.h" diff --git a/webrtc/modules/audio_coding/neteq/time_stretch.cc b/webrtc/modules/audio_coding/neteq/time_stretch.cc index 6a91ea487b..9d27e35fac 100644 --- a/webrtc/modules/audio_coding/neteq/time_stretch.cc +++ b/webrtc/modules/audio_coding/neteq/time_stretch.cc @@ -13,7 +13,7 @@ #include // min, max #include -#include "webrtc/base/safe_conversions.h" +#include "webrtc/base/numerics/safe_conversions.h" #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" #include "webrtc/modules/audio_coding/neteq/background_noise.h" #include "webrtc/modules/audio_coding/neteq/dsp_helper.h" diff --git a/webrtc/modules/audio_coding/neteq/tools/neteq_rtpplay.cc b/webrtc/modules/audio_coding/neteq/tools/neteq_rtpplay.cc index fdb66714cf..9216764f85 100644 --- a/webrtc/modules/audio_coding/neteq/tools/neteq_rtpplay.cc +++ b/webrtc/modules/audio_coding/neteq/tools/neteq_rtpplay.cc @@ -25,7 +25,7 @@ #include "gflags/gflags.h" #include "webrtc/base/checks.h" -#include "webrtc/base/safe_conversions.h" +#include "webrtc/base/numerics/safe_conversions.h" #include "webrtc/modules/audio_coding/codecs/pcm16b/pcm16b.h" #include "webrtc/modules/audio_coding/neteq/include/neteq.h" #include "webrtc/modules/audio_coding/neteq/tools/input_audio_file.h" diff --git a/webrtc/modules/audio_processing/audio_processing_performance_unittest.cc b/webrtc/modules/audio_processing/audio_processing_performance_unittest.cc index a4a8351a17..81aa298689 100644 --- a/webrtc/modules/audio_processing/audio_processing_performance_unittest.cc +++ b/webrtc/modules/audio_processing/audio_processing_performance_unittest.cc @@ -18,9 +18,9 @@ #include "testing/gtest/include/gtest/gtest.h" #include "webrtc/base/array_view.h" #include "webrtc/base/atomicops.h" +#include "webrtc/base/numerics/safe_conversions.h" #include "webrtc/base/platform_thread.h" #include "webrtc/base/random.h" -#include "webrtc/base/safe_conversions.h" #include "webrtc/config.h" #include "webrtc/modules/audio_processing/test/test_utils.h" #include "webrtc/modules/include/module_common_types.h"