From 0a7aebadfbb3534284546aa3ca8612314c08f136 Mon Sep 17 00:00:00 2001 From: Miguel Costa Date: Tue, 26 Jun 2018 16:56:45 +0200 Subject: Update ANGLE to chromium/3280 Change-Id: I0802c0d7486f772d361f87a544d6c5af937f4ca1 Reviewed-by: Friedemann Kleint --- .../third_party/base/anglebase/base_export.h | 13 + .../base/anglebase/containers/mru_cache.h | 275 ++++++++ .../common/third_party/base/anglebase/logging.h | 26 + .../src/common/third_party/base/anglebase/macros.h | 17 + .../third_party/base/anglebase/numerics/OWNERS | 3 + .../base/anglebase/numerics/safe_conversions.h | 179 +++++ .../anglebase/numerics/safe_conversions_impl.h | 274 ++++++++ .../base/anglebase/numerics/safe_math.h | 329 +++++++++ .../base/anglebase/numerics/safe_math_impl.h | 575 +++++++++++++++ .../anglebase/numerics/safe_numerics_unittest.cc | 771 +++++++++++++++++++++ .../src/common/third_party/base/anglebase/sha1.cc | 245 +++++++ .../src/common/third_party/base/anglebase/sha1.h | 36 + .../third_party/base/anglebase/sys_byteorder.h | 49 ++ 13 files changed, 2792 insertions(+) create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/base_export.h create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/containers/mru_cache.h create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/logging.h create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/macros.h create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/OWNERS create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_conversions.h create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_conversions_impl.h create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_math.h create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_math_impl.h create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_numerics_unittest.cc create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/sha1.cc create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/sha1.h create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/sys_byteorder.h (limited to 'src/3rdparty/angle/src/common/third_party/base/anglebase') diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/base_export.h b/src/3rdparty/angle/src/common/third_party/base/anglebase/base_export.h new file mode 100644 index 0000000000..1af5485336 --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/base_export.h @@ -0,0 +1,13 @@ +// +// Copyright 2017 The ANGLE 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. +// +// base_export.h: Compatiblity hacks for importing Chromium's base/SHA1. + +#ifndef ANGLEBASE_BASE_EXPORT_H_ +#define ANGLEBASE_BASE_EXPORT_H_ + +#define ANGLEBASE_EXPORT + +#endif // ANGLEBASE_BASE_EXPORT_H_ \ No newline at end of file diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/containers/mru_cache.h b/src/3rdparty/angle/src/common/third_party/base/anglebase/containers/mru_cache.h new file mode 100644 index 0000000000..fe4fec5768 --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/containers/mru_cache.h @@ -0,0 +1,275 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file contains a template for a Most Recently Used cache that allows +// constant-time access to items using a key, but easy identification of the +// least-recently-used items for removal. Each key can only be associated with +// one payload item at a time. +// +// The key object will be stored twice, so it should support efficient copying. +// +// NOTE: While all operations are O(1), this code is written for +// legibility rather than optimality. If future profiling identifies this as +// a bottleneck, there is room for smaller values of 1 in the O(1). :] + +#ifndef ANGLEBASE_CONTAINERS_MRU_CACHE_H_ +#define ANGLEBASE_CONTAINERS_MRU_CACHE_H_ + +#include + +#include +#include +#include +#include +#include +#include + +#include "anglebase/logging.h" +#include "anglebase/macros.h" + +namespace angle +{ + +namespace base +{ + +// MRUCacheBase ---------------------------------------------------------------- + +// This template is used to standardize map type containers that can be used +// by MRUCacheBase. This level of indirection is necessary because of the way +// that template template params and default template params interact. +template +struct MRUCacheStandardMap +{ + typedef std::map Type; +}; + +// Base class for the MRU cache specializations defined below. +template class MapType = MRUCacheStandardMap> +class MRUCacheBase +{ + public: + // The payload of the list. This maintains a copy of the key so we can + // efficiently delete things given an element of the list. + typedef std::pair value_type; + + private: + typedef std::list PayloadList; + typedef + typename MapType::Type KeyIndex; + + public: + typedef typename PayloadList::size_type size_type; + + typedef typename PayloadList::iterator iterator; + typedef typename PayloadList::const_iterator const_iterator; + typedef typename PayloadList::reverse_iterator reverse_iterator; + typedef typename PayloadList::const_reverse_iterator const_reverse_iterator; + + enum + { + NO_AUTO_EVICT = 0 + }; + + // The max_size is the size at which the cache will prune its members to when + // a new item is inserted. If the caller wants to manager this itself (for + // example, maybe it has special work to do when something is evicted), it + // can pass NO_AUTO_EVICT to not restrict the cache size. + explicit MRUCacheBase(size_type max_size) : max_size_(max_size) {} + + virtual ~MRUCacheBase() {} + + size_type max_size() const { return max_size_; } + + // Inserts a payload item with the given key. If an existing item has + // the same key, it is removed prior to insertion. An iterator indicating the + // inserted item will be returned (this will always be the front of the list). + // + // The payload will be forwarded. + template + iterator Put(const KeyType &key, Payload &&payload) + { + // Remove any existing payload with that key. + typename KeyIndex::iterator index_iter = index_.find(key); + if (index_iter != index_.end()) + { + // Erase the reference to it. The index reference will be replaced in the + // code below. + Erase(index_iter->second); + } + else if (max_size_ != NO_AUTO_EVICT) + { + // New item is being inserted which might make it larger than the maximum + // size: kick the oldest thing out if necessary. + ShrinkToSize(max_size_ - 1); + } + + ordering_.emplace_front(key, std::forward(payload)); + index_.emplace(key, ordering_.begin()); + return ordering_.begin(); + } + + // Retrieves the contents of the given key, or end() if not found. This method + // has the side effect of moving the requested item to the front of the + // recency list. + iterator Get(const KeyType &key) + { + typename KeyIndex::iterator index_iter = index_.find(key); + if (index_iter == index_.end()) + return end(); + typename PayloadList::iterator iter = index_iter->second; + + // Move the touched item to the front of the recency ordering. + ordering_.splice(ordering_.begin(), ordering_, iter); + return ordering_.begin(); + } + + // Retrieves the payload associated with a given key and returns it via + // result without affecting the ordering (unlike Get). + iterator Peek(const KeyType &key) + { + typename KeyIndex::const_iterator index_iter = index_.find(key); + if (index_iter == index_.end()) + return end(); + return index_iter->second; + } + + const_iterator Peek(const KeyType &key) const + { + typename KeyIndex::const_iterator index_iter = index_.find(key); + if (index_iter == index_.end()) + return end(); + return index_iter->second; + } + + // Exchanges the contents of |this| by the contents of the |other|. + void Swap(MRUCacheBase &other) + { + ordering_.swap(other.ordering_); + index_.swap(other.index_); + std::swap(max_size_, other.max_size_); + } + + // Erases the item referenced by the given iterator. An iterator to the item + // following it will be returned. The iterator must be valid. + iterator Erase(iterator pos) + { + index_.erase(pos->first); + return ordering_.erase(pos); + } + + // MRUCache entries are often processed in reverse order, so we add this + // convenience function (not typically defined by STL containers). + reverse_iterator Erase(reverse_iterator pos) + { + // We have to actually give it the incremented iterator to delete, since + // the forward iterator that base() returns is actually one past the item + // being iterated over. + return reverse_iterator(Erase((++pos).base())); + } + + // Shrinks the cache so it only holds |new_size| items. If |new_size| is + // bigger or equal to the current number of items, this will do nothing. + void ShrinkToSize(size_type new_size) + { + for (size_type i = size(); i > new_size; i--) + Erase(rbegin()); + } + + // Deletes everything from the cache. + void Clear() + { + index_.clear(); + ordering_.clear(); + } + + // Returns the number of elements in the cache. + size_type size() const + { + // We don't use ordering_.size() for the return value because + // (as a linked list) it can be O(n). + DCHECK(index_.size() == ordering_.size()); + return index_.size(); + } + + // Allows iteration over the list. Forward iteration starts with the most + // recent item and works backwards. + // + // Note that since these iterators are actually iterators over a list, you + // can keep them as you insert or delete things (as long as you don't delete + // the one you are pointing to) and they will still be valid. + iterator begin() { return ordering_.begin(); } + const_iterator begin() const { return ordering_.begin(); } + iterator end() { return ordering_.end(); } + const_iterator end() const { return ordering_.end(); } + + reverse_iterator rbegin() { return ordering_.rbegin(); } + const_reverse_iterator rbegin() const { return ordering_.rbegin(); } + reverse_iterator rend() { return ordering_.rend(); } + const_reverse_iterator rend() const { return ordering_.rend(); } + + bool empty() const { return ordering_.empty(); } + + private: + PayloadList ordering_; + KeyIndex index_; + + size_type max_size_; + + DISALLOW_COPY_AND_ASSIGN(MRUCacheBase); +}; + +// MRUCache -------------------------------------------------------------------- + +// A container that does not do anything to free its data. Use this when storing +// value types (as opposed to pointers) in the list. +template > +class MRUCache : public MRUCacheBase +{ + private: + using ParentType = MRUCacheBase; + + public: + // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT. + explicit MRUCache(typename ParentType::size_type max_size) : ParentType(max_size) {} + virtual ~MRUCache() {} + + private: + DISALLOW_COPY_AND_ASSIGN(MRUCache); +}; + +// HashingMRUCache ------------------------------------------------------------ + +template +struct MRUCacheHashMap +{ + typedef std::unordered_map Type; +}; + +// This class is similar to MRUCache, except that it uses std::unordered_map as +// the map type instead of std::map. Note that your KeyType must be hashable to +// use this cache or you need to provide a hashing class. +template > +class HashingMRUCache : public MRUCacheBase +{ + private: + using ParentType = MRUCacheBase; + + public: + // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT. + explicit HashingMRUCache(typename ParentType::size_type max_size) : ParentType(max_size) {} + virtual ~HashingMRUCache() {} + + private: + DISALLOW_COPY_AND_ASSIGN(HashingMRUCache); +}; + +} // namespace base + +} // namespace angle + +#endif // ANGLEBASE_CONTAINERS_MRU_CACHE_H_ diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/logging.h b/src/3rdparty/angle/src/common/third_party/base/anglebase/logging.h new file mode 100644 index 0000000000..85ad82b47d --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/logging.h @@ -0,0 +1,26 @@ +// +// Copyright 2016 The ANGLE 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. +// +// logging.h: Compatiblity hacks for importing Chromium's base/numerics. + +#ifndef ANGLEBASE_LOGGING_H_ +#define ANGLEBASE_LOGGING_H_ + +#include "common/debug.h" + +#ifndef DCHECK +#define DCHECK(X) ASSERT(X) +#endif + +#ifndef CHECK +#define CHECK(X) ASSERT(X) +#endif + +// Unfortunately ANGLE relies on ASSERT being an empty statement, which these libs don't respect. +#ifndef NOTREACHED +#define NOTREACHED() UNREACHABLE() +#endif + +#endif // ANGLEBASE_LOGGING_H_ diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/macros.h b/src/3rdparty/angle/src/common/third_party/base/anglebase/macros.h new file mode 100644 index 0000000000..06391784e4 --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/macros.h @@ -0,0 +1,17 @@ +// +// Copyright 2017 The ANGLE 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. +// +// macros.h: Compatiblity hacks for importing Chromium's MRUCache. + +#ifndef ANGLEBASE_MACROS_H_ +#define ANGLEBASE_MACROS_H_ + +// A macro to disallow the copy constructor and operator= functions. +// This should be used in the private: declarations for a class. +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName &) = delete; \ + void operator=(const TypeName &) = delete + +#endif // ANGLEBASE_MACROS_H_ diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/OWNERS b/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/OWNERS new file mode 100644 index 0000000000..41f35fc79b --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/OWNERS @@ -0,0 +1,3 @@ +jschuh@chromium.org +tsepez@chromium.org + diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_conversions.h b/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_conversions.h new file mode 100644 index 0000000000..43babc31a8 --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_conversions.h @@ -0,0 +1,179 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ANGLEBASE_NUMERICS_SAFE_CONVERSIONS_H_ +#define ANGLEBASE_NUMERICS_SAFE_CONVERSIONS_H_ + +#include + +#include +#include + +#include "anglebase/logging.h" +#include "anglebase/numerics/safe_conversions_impl.h" + +namespace angle +{ + +namespace base +{ + +// Convenience function that returns true if the supplied value is in range +// for the destination type. +template +constexpr 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 +constexpr 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 +constexpr 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) +{ + CHECK(IsValueInRangeForNumericType(value)); + return static_cast(value); +} + +// HandleNaN will cause this class to CHECK(false). +struct SaturatedCastNaNBehaviorCheck +{ + template + static T HandleNaN() + { + CHECK(false); + return T(); + } +}; + +// HandleNaN will return 0 in this case. +struct SaturatedCastNaNBehaviorReturnZero +{ + template + static constexpr T HandleNaN() + { + return T(); + } +}; + +namespace internal +{ +// This wrapper is used for C++11 constexpr support by avoiding the declaration +// of local variables in the saturated_cast template function. +template +constexpr Dst saturated_cast_impl(const Src value, const RangeConstraint constraint) +{ + return constraint == RANGE_VALID + ? static_cast(value) + : (constraint == RANGE_UNDERFLOW + ? std::numeric_limits::min() + : (constraint == RANGE_OVERFLOW + ? std::numeric_limits::max() + : (constraint == RANGE_INVALID + ? NaNHandler::template HandleNaN() + : (NOTREACHED(), static_cast(value))))); +} +} // namespace internal + +// 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 +constexpr Dst saturated_cast(Src value) +{ + return std::numeric_limits::is_iec559 + ? static_cast(value) // Floating point optimization. + : internal::saturated_cast_impl( + value, internal::DstRangeRelationToSrcRange(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 +constexpr 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" + "- base::checked_cast\n" + "- base::saturated_cast\n" + "- base::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 the actual value being assigned. +template +class StrictNumeric +{ + public: + typedef T type; + + constexpr StrictNumeric() : value_(0) {} + + // Copy constructor. + template + constexpr 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 + constexpr StrictNumeric(Src value) : value_(strict_cast(value)) + { + } + + // The numeric cast operator basically handles all the magic. + template + constexpr operator Dst() const + { + return strict_cast(value_); + } + + private: + const T value_; +}; + +// Explicitly make a shorter size_t typedef for convenience. +typedef StrictNumeric SizeT; + +} // namespace base + +} // namespace angle + +#endif // ANGLEBASE_NUMERICS_SAFE_CONVERSIONS_H_ diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_conversions_impl.h b/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_conversions_impl.h new file mode 100644 index 0000000000..10ed6c7a7f --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_conversions_impl.h @@ -0,0 +1,274 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ANGLEBASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ +#define ANGLEBASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ + +#include +#include + +#include +#include + +namespace angle +{ + +namespace base +{ +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_assert(std::is_arithmetic::value, "Argument must be numeric."); + static const int value = + std::numeric_limits::is_iec559 + ? std::numeric_limits::max_exponent + : (sizeof(NumericType) * CHAR_BIT + 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 ::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 : unsigned char +{ + 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. +constexpr RangeConstraint GetRangeConstraint(int integer_range_constraint) +{ + // TODO(jschuh): Once we get full C++14 support we want this + // assert(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. +constexpr 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; + // 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; + + static constexpr Dst max() + { + // 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 constexpr Dst min() + { + return std::numeric_limits::is_iec559 ? -DstLimits::max() : DstLimits::min(); + } +}; + +template ::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 constexpr RangeConstraint Check(Src value) { return RANGE_VALID; } +}; + +// Signed to signed narrowing: Both the upper and lower boundaries may be +// exceeded. +template +struct DstRangeRelationToSrcRangeImpl +{ + static constexpr 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 constexpr RangeConstraint Check(Src value) + { + return GetRangeConstraint(value <= NarrowingRange::max(), true); + } +}; + +// Unsigned to signed: The upper boundary may be exceeded. +template +struct DstRangeRelationToSrcRangeImpl +{ + static constexpr 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 constexpr 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 +constexpr 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 base + +} // namespace angle + +#endif // ANGLEBASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_math.h b/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_math.h new file mode 100644 index 0000000000..3af4db63f7 --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_math.h @@ -0,0 +1,329 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ANGLEBASE_NUMERICS_SAFE_MATH_H_ +#define ANGLEBASE_NUMERICS_SAFE_MATH_H_ + +#include + +#include +#include + +#include "anglebase/logging.h" +#include "anglebase/numerics/safe_math_impl.h" + +namespace angle +{ + +namespace base +{ + +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 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 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 +{ + static_assert(std::is_arithmetic::value, "CheckedNumeric: T must be a numeric type."); + + 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) // NOLINT(runtime/explicit) + : 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) // NOLINT(runtime/explicit) + : 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 CHECK and crash. + T ValueOrDie() const + { + 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 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 ANGLEBASE_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 ::value>::type * = nullptr> \ + 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 left numeric and right CheckedNumeric. */ \ + template ::value>::type * = nullptr> \ + 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); \ + } + +ANGLEBASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, +=) +ANGLEBASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -=) +ANGLEBASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *=) +ANGLEBASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /=) +ANGLEBASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %=) + +#undef ANGLEBASE_NUMERIC_ARITHMETIC_OPERATORS + +} // namespace internal + +using internal::CheckedNumeric; + +} // namespace base + +} // namespace angle + +#endif // ANGLEBASE_NUMERICS_SAFE_MATH_H_ diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_math_impl.h b/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_math_impl.h new file mode 100644 index 0000000000..2831cc6ceb --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_math_impl.h @@ -0,0 +1,575 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ANGLEBASE_NUMERICS_SAFE_MATH_IMPL_H_ +#define ANGLEBASE_NUMERICS_SAFE_MATH_IMPL_H_ + +#include +#include + +#include +#include +#include +#include +#include + +#include "anglebase/numerics/safe_conversions.h" + +namespace angle +{ + +namespace base +{ +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::is_integer, + typename IntegerForSizeAndSign::type>::type + type; +}; + +template +struct SignedIntegerForSize +{ + typedef + typename std::enable_if::is_integer, + typename IntegerForSizeAndSign::type>::type + type; +}; + +template +struct TwiceWiderInteger +{ + typedef typename std::enable_if< + std::numeric_limits::is_integer, + typename IntegerForSizeAndSign::is_signed>::type>::type type; +}; + +template +struct PositionOfSignBit +{ + static const typename std::enable_if::is_integer, size_t>::type + value = CHAR_BIT * 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 +constexpr 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 +constexpr T BinaryComplement(T x) +{ + return static_cast(~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 = static_cast(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(static_cast((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 = static_cast(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(static_cast((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) + { + *validity = RANGE_VALID; + return static_cast(0); + } + 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 static_cast(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 static_cast(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 static_cast(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 static_cast(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 static_cast(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 static_cast(-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 static_cast(value); +} + +// These are the floating point stubs that the compiler needs to see. Only the +// negation operation is ever called. +#define ANGLEBASE_FLOAT_ARITHMETIC_STUBS(NAME) \ + template \ + typename std::enable_if::is_iec559, T>::type Checked##NAME( \ + T, T, RangeConstraint *) \ + { \ + NOTREACHED(); \ + return static_cast(0); \ + } + +ANGLEBASE_FLOAT_ARITHMETIC_STUBS(Add) +ANGLEBASE_FLOAT_ARITHMETIC_STUBS(Sub) +ANGLEBASE_FLOAT_ARITHMETIC_STUBS(Mul) +ANGLEBASE_FLOAT_ARITHMETIC_STUBS(Div) +ANGLEBASE_FLOAT_ARITHMETIC_STUBS(Mod) + +#undef ANGLEBASE_FLOAT_ARITHMETIC_STUBS + +template +typename std::enable_if::is_iec559, T>::type CheckedNeg(T value, + RangeConstraint *) +{ + return static_cast(-value); +} + +template +typename std::enable_if::is_iec559, T>::type CheckedAbs(T value, + RangeConstraint *) +{ + return static_cast(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_ : CHAR_BIT; // Actually requires only two bits. + + 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: + 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 have the type +// with the larger maximum exponent take precedence. +enum ArithmeticPromotionCategory +{ + LEFT_PROMOTION, + RIGHT_PROMOTION +}; + +template ::value > MaxExponent::value) ? LEFT_PROMOTION + : RIGHT_PROMOTION> +struct ArithmeticPromotion; + +template +struct ArithmeticPromotion +{ + typedef Lhs type; +}; + +template +struct ArithmeticPromotion +{ + typedef Rhs 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 base + +} // namespace angle + +#endif // ANGLEBASE_NUMERICS_SAFE_MATH_IMPL_H_ diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_numerics_unittest.cc b/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_numerics_unittest.cc new file mode 100644 index 0000000000..052d850427 --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_numerics_unittest.cc @@ -0,0 +1,771 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include + +#include +#include + +#include "base/compiler_specific.h" +#include "base/numerics/safe_conversions.h" +#include "base/numerics/safe_math.h" +#include "build/build_config.h" +#include "testing/gtest/include/gtest/gtest.h" + +#if defined(COMPILER_MSVC) && defined(ARCH_CPU_32_BITS) +#include +#endif + +using std::numeric_limits; +using base::CheckedNumeric; +using base::checked_cast; +using base::IsValueInRangeForNumericType; +using base::IsValueNegative; +using base::SizeT; +using base::StrictNumeric; +using base::saturated_cast; +using base::strict_cast; +using base::internal::MaxExponent; +using base::internal::RANGE_VALID; +using base::internal::RANGE_INVALID; +using base::internal::RANGE_OVERFLOW; +using base::internal::RANGE_UNDERFLOW; +using base::internal::SignedIntegerForSize; + +// These tests deliberately cause arithmetic overflows. If the compiler is +// aggressive enough, it can const fold these overflows. Disable warnings about +// overflows for const expressions. +#if defined(OS_WIN) +#pragma warning(disable : 4756) +#endif + +// This is a helper function for finding the maximum value in Src that can be +// wholy represented as the destination floating-point type. +template +Dst GetMaxConvertibleToFloat() +{ + typedef numeric_limits DstLimits; + typedef numeric_limits SrcLimits; + static_assert(SrcLimits::is_specialized, "Source must be numeric."); + static_assert(DstLimits::is_specialized, "Destination must be numeric."); + CHECK(DstLimits::is_iec559); + + if (SrcLimits::digits <= DstLimits::digits && + MaxExponent::value <= MaxExponent::value) + return SrcLimits::max(); + Src max = SrcLimits::max() / 2 + (SrcLimits::is_integer ? 1 : 0); + while (max != static_cast(static_cast(max))) + { + max /= 2; + } + return static_cast(max); +} + +// Helper macros to wrap displaying the conversion types and line numbers. +#define TEST_EXPECTED_VALIDITY(expected, actual) \ + EXPECT_EQ(expected, CheckedNumeric(actual).IsValid()) \ + << "Result test: Value " << +(actual).ValueUnsafe() << " as " << dst << " on line " \ + << line; + +#define TEST_EXPECTED_SUCCESS(actual) TEST_EXPECTED_VALIDITY(true, actual) +#define TEST_EXPECTED_FAILURE(actual) TEST_EXPECTED_VALIDITY(false, actual) + +#define TEST_EXPECTED_VALUE(expected, actual) \ + EXPECT_EQ(static_cast(expected), CheckedNumeric(actual).ValueUnsafe()) \ + << "Result test: Value " << +((actual).ValueUnsafe()) << " as " << dst << " on line " \ + << line; + +// Signed integer arithmetic. +template +static void TestSpecializedArithmetic( + const char *dst, + int line, + typename std::enable_if::is_integer && numeric_limits::is_signed, + int>::type = 0) +{ + typedef numeric_limits DstLimits; + TEST_EXPECTED_FAILURE(-CheckedNumeric(DstLimits::min())); + TEST_EXPECTED_FAILURE(CheckedNumeric(DstLimits::min()).Abs()); + TEST_EXPECTED_VALUE(1, CheckedNumeric(-1).Abs()); + + TEST_EXPECTED_SUCCESS(CheckedNumeric(DstLimits::max()) + -1); + TEST_EXPECTED_FAILURE(CheckedNumeric(DstLimits::min()) + -1); + TEST_EXPECTED_FAILURE(CheckedNumeric(-DstLimits::max()) + -DstLimits::max()); + + TEST_EXPECTED_FAILURE(CheckedNumeric(DstLimits::min()) - 1); + TEST_EXPECTED_SUCCESS(CheckedNumeric(DstLimits::min()) - -1); + TEST_EXPECTED_FAILURE(CheckedNumeric(DstLimits::max()) - -DstLimits::max()); + TEST_EXPECTED_FAILURE(CheckedNumeric(-DstLimits::max()) - DstLimits::max()); + + TEST_EXPECTED_FAILURE(CheckedNumeric(DstLimits::min()) * 2); + + TEST_EXPECTED_FAILURE(CheckedNumeric(DstLimits::min()) / -1); + TEST_EXPECTED_VALUE(0, CheckedNumeric(-1) / 2); + + // Modulus is legal only for integers. + TEST_EXPECTED_VALUE(0, CheckedNumeric() % 1); + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) % 1); + TEST_EXPECTED_VALUE(-1, CheckedNumeric(-1) % 2); + TEST_EXPECTED_FAILURE(CheckedNumeric(-1) % -2); + TEST_EXPECTED_VALUE(0, CheckedNumeric(DstLimits::min()) % 2); + TEST_EXPECTED_VALUE(1, CheckedNumeric(DstLimits::max()) % 2); + // Test all the different modulus combinations. + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) % CheckedNumeric(1)); + TEST_EXPECTED_VALUE(0, 1 % CheckedNumeric(1)); + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) % 1); + CheckedNumeric checked_dst = 1; + TEST_EXPECTED_VALUE(0, checked_dst %= 1); +} + +// Unsigned integer arithmetic. +template +static void TestSpecializedArithmetic( + const char *dst, + int line, + typename std::enable_if::is_integer && !numeric_limits::is_signed, + int>::type = 0) +{ + typedef numeric_limits DstLimits; + TEST_EXPECTED_SUCCESS(-CheckedNumeric(DstLimits::min())); + TEST_EXPECTED_SUCCESS(CheckedNumeric(DstLimits::min()).Abs()); + TEST_EXPECTED_FAILURE(CheckedNumeric(DstLimits::min()) + -1); + TEST_EXPECTED_FAILURE(CheckedNumeric(DstLimits::min()) - 1); + TEST_EXPECTED_VALUE(0, CheckedNumeric(DstLimits::min()) * 2); + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) / 2); + TEST_EXPECTED_SUCCESS(CheckedNumeric(DstLimits::min()).UnsignedAbs()); + TEST_EXPECTED_SUCCESS(CheckedNumeric::type>( + std::numeric_limits::type>::min()) + .UnsignedAbs()); + + // Modulus is legal only for integers. + TEST_EXPECTED_VALUE(0, CheckedNumeric() % 1); + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) % 1); + TEST_EXPECTED_VALUE(1, CheckedNumeric(1) % 2); + TEST_EXPECTED_VALUE(0, CheckedNumeric(DstLimits::min()) % 2); + TEST_EXPECTED_VALUE(1, CheckedNumeric(DstLimits::max()) % 2); + // Test all the different modulus combinations. + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) % CheckedNumeric(1)); + TEST_EXPECTED_VALUE(0, 1 % CheckedNumeric(1)); + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) % 1); + CheckedNumeric checked_dst = 1; + TEST_EXPECTED_VALUE(0, checked_dst %= 1); +} + +// Floating point arithmetic. +template +void TestSpecializedArithmetic( + const char *dst, + int line, + typename std::enable_if::is_iec559, int>::type = 0) +{ + typedef numeric_limits DstLimits; + TEST_EXPECTED_SUCCESS(-CheckedNumeric(DstLimits::min())); + + TEST_EXPECTED_SUCCESS(CheckedNumeric(DstLimits::min()).Abs()); + TEST_EXPECTED_VALUE(1, CheckedNumeric(-1).Abs()); + + TEST_EXPECTED_SUCCESS(CheckedNumeric(DstLimits::min()) + -1); + TEST_EXPECTED_SUCCESS(CheckedNumeric(DstLimits::max()) + 1); + TEST_EXPECTED_FAILURE(CheckedNumeric(-DstLimits::max()) + -DstLimits::max()); + + TEST_EXPECTED_FAILURE(CheckedNumeric(DstLimits::max()) - -DstLimits::max()); + TEST_EXPECTED_FAILURE(CheckedNumeric(-DstLimits::max()) - DstLimits::max()); + + TEST_EXPECTED_SUCCESS(CheckedNumeric(DstLimits::min()) * 2); + + TEST_EXPECTED_VALUE(-0.5, CheckedNumeric(-1.0) / 2); + EXPECT_EQ(static_cast(1.0), CheckedNumeric(1.0).ValueFloating()); +} + +// Generic arithmetic tests. +template +static void TestArithmetic(const char *dst, int line) +{ + typedef numeric_limits DstLimits; + + EXPECT_EQ(true, CheckedNumeric().IsValid()); + EXPECT_EQ( + false, + CheckedNumeric(CheckedNumeric(DstLimits::max()) * DstLimits::max()).IsValid()); + EXPECT_EQ(static_cast(0), CheckedNumeric().ValueOrDie()); + EXPECT_EQ(static_cast(0), CheckedNumeric().ValueOrDefault(1)); + EXPECT_EQ(static_cast(1), + CheckedNumeric(CheckedNumeric(DstLimits::max()) * DstLimits::max()) + .ValueOrDefault(1)); + + // Test the operator combinations. + TEST_EXPECTED_VALUE(2, CheckedNumeric(1) + CheckedNumeric(1)); + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) - CheckedNumeric(1)); + TEST_EXPECTED_VALUE(1, CheckedNumeric(1) * CheckedNumeric(1)); + TEST_EXPECTED_VALUE(1, CheckedNumeric(1) / CheckedNumeric(1)); + TEST_EXPECTED_VALUE(2, 1 + CheckedNumeric(1)); + TEST_EXPECTED_VALUE(0, 1 - CheckedNumeric(1)); + TEST_EXPECTED_VALUE(1, 1 * CheckedNumeric(1)); + TEST_EXPECTED_VALUE(1, 1 / CheckedNumeric(1)); + TEST_EXPECTED_VALUE(2, CheckedNumeric(1) + 1); + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) - 1); + TEST_EXPECTED_VALUE(1, CheckedNumeric(1) * 1); + TEST_EXPECTED_VALUE(1, CheckedNumeric(1) / 1); + CheckedNumeric checked_dst = 1; + TEST_EXPECTED_VALUE(2, checked_dst += 1); + checked_dst = 1; + TEST_EXPECTED_VALUE(0, checked_dst -= 1); + checked_dst = 1; + TEST_EXPECTED_VALUE(1, checked_dst *= 1); + checked_dst = 1; + TEST_EXPECTED_VALUE(1, checked_dst /= 1); + + // Generic negation. + TEST_EXPECTED_VALUE(0, -CheckedNumeric()); + TEST_EXPECTED_VALUE(-1, -CheckedNumeric(1)); + TEST_EXPECTED_VALUE(1, -CheckedNumeric(-1)); + TEST_EXPECTED_VALUE(static_cast(DstLimits::max() * -1), + -CheckedNumeric(DstLimits::max())); + + // Generic absolute value. + TEST_EXPECTED_VALUE(0, CheckedNumeric().Abs()); + TEST_EXPECTED_VALUE(1, CheckedNumeric(1).Abs()); + TEST_EXPECTED_VALUE(DstLimits::max(), CheckedNumeric(DstLimits::max()).Abs()); + + // Generic addition. + TEST_EXPECTED_VALUE(1, (CheckedNumeric() + 1)); + TEST_EXPECTED_VALUE(2, (CheckedNumeric(1) + 1)); + TEST_EXPECTED_VALUE(0, (CheckedNumeric(-1) + 1)); + TEST_EXPECTED_SUCCESS(CheckedNumeric(DstLimits::min()) + 1); + TEST_EXPECTED_FAILURE(CheckedNumeric(DstLimits::max()) + DstLimits::max()); + + // Generic subtraction. + TEST_EXPECTED_VALUE(-1, (CheckedNumeric() - 1)); + TEST_EXPECTED_VALUE(0, (CheckedNumeric(1) - 1)); + TEST_EXPECTED_VALUE(-2, (CheckedNumeric(-1) - 1)); + TEST_EXPECTED_SUCCESS(CheckedNumeric(DstLimits::max()) - 1); + + // Generic multiplication. + TEST_EXPECTED_VALUE(0, (CheckedNumeric() * 1)); + TEST_EXPECTED_VALUE(1, (CheckedNumeric(1) * 1)); + TEST_EXPECTED_VALUE(-2, (CheckedNumeric(-1) * 2)); + TEST_EXPECTED_VALUE(0, (CheckedNumeric(0) * 0)); + TEST_EXPECTED_VALUE(0, (CheckedNumeric(-1) * 0)); + TEST_EXPECTED_VALUE(0, (CheckedNumeric(0) * -1)); + TEST_EXPECTED_FAILURE(CheckedNumeric(DstLimits::max()) * DstLimits::max()); + + // Generic division. + TEST_EXPECTED_VALUE(0, CheckedNumeric() / 1); + TEST_EXPECTED_VALUE(1, CheckedNumeric(1) / 1); + TEST_EXPECTED_VALUE(DstLimits::min() / 2, CheckedNumeric(DstLimits::min()) / 2); + TEST_EXPECTED_VALUE(DstLimits::max() / 2, CheckedNumeric(DstLimits::max()) / 2); + + TestSpecializedArithmetic(dst, line); +} + +// Helper macro to wrap displaying the conversion types and line numbers. +#define TEST_ARITHMETIC(Dst) TestArithmetic(#Dst, __LINE__) + +TEST(SafeNumerics, SignedIntegerMath) +{ + TEST_ARITHMETIC(int8_t); + TEST_ARITHMETIC(int); + TEST_ARITHMETIC(intptr_t); + TEST_ARITHMETIC(intmax_t); +} + +TEST(SafeNumerics, UnsignedIntegerMath) +{ + TEST_ARITHMETIC(uint8_t); + TEST_ARITHMETIC(unsigned int); + TEST_ARITHMETIC(uintptr_t); + TEST_ARITHMETIC(uintmax_t); +} + +TEST(SafeNumerics, FloatingPointMath) +{ + TEST_ARITHMETIC(float); + TEST_ARITHMETIC(double); +} + +// Enumerates the five different conversions types we need to test. +enum NumericConversionType +{ + SIGN_PRESERVING_VALUE_PRESERVING, + SIGN_PRESERVING_NARROW, + SIGN_TO_UNSIGN_WIDEN_OR_EQUAL, + SIGN_TO_UNSIGN_NARROW, + UNSIGN_TO_SIGN_NARROW_OR_EQUAL, +}; + +// Template covering the different conversion tests. +template +struct TestNumericConversion +{ +}; + +// EXPECT_EQ wrappers providing specific detail on test failures. +#define TEST_EXPECTED_RANGE(expected, actual) \ + EXPECT_EQ(expected, base::internal::DstRangeRelationToSrcRange(actual)) \ + << "Conversion test: " << src << " value " << actual << " to " << dst << " on line " \ + << line; + +template +struct TestNumericConversion +{ + static void Test(const char *dst, const char *src, int line) + { + typedef numeric_limits SrcLimits; + typedef numeric_limits DstLimits; + // Integral to floating. + static_assert( + (DstLimits::is_iec559 && SrcLimits::is_integer) || + // Not floating to integral and... + (!(DstLimits::is_integer && SrcLimits::is_iec559) && + // Same sign, same numeric, source is narrower or same. + ((SrcLimits::is_signed == DstLimits::is_signed && sizeof(Dst) >= sizeof(Src)) || + // Or signed destination and source is smaller + (DstLimits::is_signed && sizeof(Dst) > sizeof(Src)))), + "Comparison must be sign preserving and value preserving"); + + const CheckedNumeric checked_dst = SrcLimits::max(); + TEST_EXPECTED_SUCCESS(checked_dst); + if (MaxExponent::value > MaxExponent::value) + { + if (MaxExponent::value >= MaxExponent::value * 2 - 1) + { + // At least twice larger type. + TEST_EXPECTED_SUCCESS(SrcLimits::max() * checked_dst); + } + else + { // Larger, but not at least twice as large. + TEST_EXPECTED_FAILURE(SrcLimits::max() * checked_dst); + TEST_EXPECTED_SUCCESS(checked_dst + 1); + } + } + else + { // Same width type. + TEST_EXPECTED_FAILURE(checked_dst + 1); + } + + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(1)); + if (SrcLimits::is_iec559) + { + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max() * static_cast(-1)); + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity()); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1); + TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN()); + } + else if (numeric_limits::is_signed) + { + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(-1)); + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::min()); + } + } +}; + +template +struct TestNumericConversion +{ + static void Test(const char *dst, const char *src, int line) + { + typedef numeric_limits SrcLimits; + typedef numeric_limits DstLimits; + static_assert(SrcLimits::is_signed == DstLimits::is_signed, + "Destination and source sign must be the same"); + static_assert(sizeof(Dst) < sizeof(Src) || (DstLimits::is_integer && SrcLimits::is_iec559), + "Destination must be narrower than source"); + + const CheckedNumeric checked_dst; + TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::max()); + TEST_EXPECTED_VALUE(1, checked_dst + static_cast(1)); + TEST_EXPECTED_FAILURE(checked_dst - SrcLimits::max()); + + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(1)); + if (SrcLimits::is_iec559) + { + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::max() * -1); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(-1)); + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity()); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1); + TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN()); + if (DstLimits::is_integer) + { + if (SrcLimits::digits < DstLimits::digits) + { + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, static_cast(DstLimits::max())); + } + else + { + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(DstLimits::max())); + } + TEST_EXPECTED_RANGE(RANGE_VALID, + static_cast(GetMaxConvertibleToFloat())); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(DstLimits::min())); + } + } + else if (SrcLimits::is_signed) + { + TEST_EXPECTED_VALUE(-1, checked_dst - static_cast(1)); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(-1)); + } + else + { + TEST_EXPECTED_FAILURE(checked_dst - static_cast(1)); + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::min()); + } + } +}; + +template +struct TestNumericConversion +{ + static void Test(const char *dst, const char *src, int line) + { + typedef numeric_limits SrcLimits; + typedef numeric_limits DstLimits; + static_assert(sizeof(Dst) >= sizeof(Src), + "Destination must be equal or wider than source."); + static_assert(SrcLimits::is_signed, "Source must be signed"); + static_assert(!DstLimits::is_signed, "Destination must be unsigned"); + + const CheckedNumeric checked_dst; + TEST_EXPECTED_VALUE(SrcLimits::max(), checked_dst + SrcLimits::max()); + TEST_EXPECTED_FAILURE(checked_dst + static_cast(-1)); + TEST_EXPECTED_FAILURE(checked_dst + -SrcLimits::max()); + + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min()); + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(1)); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, static_cast(-1)); + } +}; + +template +struct TestNumericConversion +{ + static void Test(const char *dst, const char *src, int line) + { + typedef numeric_limits SrcLimits; + typedef numeric_limits DstLimits; + static_assert( + (DstLimits::is_integer && SrcLimits::is_iec559) || (sizeof(Dst) < sizeof(Src)), + "Destination must be narrower than source."); + static_assert(SrcLimits::is_signed, "Source must be signed."); + static_assert(!DstLimits::is_signed, "Destination must be unsigned."); + + const CheckedNumeric checked_dst; + TEST_EXPECTED_VALUE(1, checked_dst + static_cast(1)); + TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::max()); + TEST_EXPECTED_FAILURE(checked_dst + static_cast(-1)); + TEST_EXPECTED_FAILURE(checked_dst + -SrcLimits::max()); + + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(1)); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, static_cast(-1)); + if (SrcLimits::is_iec559) + { + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::max() * -1); + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity()); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1); + TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN()); + if (DstLimits::is_integer) + { + if (SrcLimits::digits < DstLimits::digits) + { + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, static_cast(DstLimits::max())); + } + else + { + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(DstLimits::max())); + } + TEST_EXPECTED_RANGE(RANGE_VALID, + static_cast(GetMaxConvertibleToFloat())); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(DstLimits::min())); + } + } + else + { + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min()); + } + } +}; + +template +struct TestNumericConversion +{ + static void Test(const char *dst, const char *src, int line) + { + typedef numeric_limits SrcLimits; + typedef numeric_limits DstLimits; + static_assert(sizeof(Dst) <= sizeof(Src), + "Destination must be narrower or equal to source."); + static_assert(!SrcLimits::is_signed, "Source must be unsigned."); + static_assert(DstLimits::is_signed, "Destination must be signed."); + + const CheckedNumeric checked_dst; + TEST_EXPECTED_VALUE(1, checked_dst + static_cast(1)); + TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::max()); + TEST_EXPECTED_VALUE(SrcLimits::min(), checked_dst + SrcLimits::min()); + + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::min()); + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(1)); + } +}; + +// Helper macro to wrap displaying the conversion types and line numbers +#define TEST_NUMERIC_CONVERSION(d, s, t) TestNumericConversion::Test(#d, #s, __LINE__) + +TEST(SafeNumerics, IntMinOperations) +{ + TEST_NUMERIC_CONVERSION(int8_t, int8_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(uint8_t, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING); + + TEST_NUMERIC_CONVERSION(int8_t, int, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(uint8_t, unsigned int, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(int8_t, float, SIGN_PRESERVING_NARROW); + + TEST_NUMERIC_CONVERSION(uint8_t, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + + TEST_NUMERIC_CONVERSION(uint8_t, int, SIGN_TO_UNSIGN_NARROW); + TEST_NUMERIC_CONVERSION(uint8_t, intmax_t, SIGN_TO_UNSIGN_NARROW); + TEST_NUMERIC_CONVERSION(uint8_t, float, SIGN_TO_UNSIGN_NARROW); + + TEST_NUMERIC_CONVERSION(int8_t, unsigned int, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); + TEST_NUMERIC_CONVERSION(int8_t, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); +} + +TEST(SafeNumerics, IntOperations) +{ + TEST_NUMERIC_CONVERSION(int, int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(unsigned int, unsigned int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(int, int8_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(unsigned int, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(int, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING); + + TEST_NUMERIC_CONVERSION(int, intmax_t, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(unsigned int, uintmax_t, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(int, float, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(int, double, SIGN_PRESERVING_NARROW); + + TEST_NUMERIC_CONVERSION(unsigned int, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + TEST_NUMERIC_CONVERSION(unsigned int, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + + TEST_NUMERIC_CONVERSION(unsigned int, intmax_t, SIGN_TO_UNSIGN_NARROW); + TEST_NUMERIC_CONVERSION(unsigned int, float, SIGN_TO_UNSIGN_NARROW); + TEST_NUMERIC_CONVERSION(unsigned int, double, SIGN_TO_UNSIGN_NARROW); + + TEST_NUMERIC_CONVERSION(int, unsigned int, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); + TEST_NUMERIC_CONVERSION(int, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); +} + +TEST(SafeNumerics, IntMaxOperations) +{ + TEST_NUMERIC_CONVERSION(intmax_t, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(uintmax_t, uintmax_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(intmax_t, int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(uintmax_t, unsigned int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(intmax_t, unsigned int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(intmax_t, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING); + + TEST_NUMERIC_CONVERSION(intmax_t, float, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(intmax_t, double, SIGN_PRESERVING_NARROW); + + TEST_NUMERIC_CONVERSION(uintmax_t, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + TEST_NUMERIC_CONVERSION(uintmax_t, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + + TEST_NUMERIC_CONVERSION(uintmax_t, float, SIGN_TO_UNSIGN_NARROW); + TEST_NUMERIC_CONVERSION(uintmax_t, double, SIGN_TO_UNSIGN_NARROW); + + TEST_NUMERIC_CONVERSION(intmax_t, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); +} + +TEST(SafeNumerics, FloatOperations) +{ + TEST_NUMERIC_CONVERSION(float, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(float, uintmax_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(float, int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(float, unsigned int, SIGN_PRESERVING_VALUE_PRESERVING); + + TEST_NUMERIC_CONVERSION(float, double, SIGN_PRESERVING_NARROW); +} + +TEST(SafeNumerics, DoubleOperations) +{ + TEST_NUMERIC_CONVERSION(double, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(double, uintmax_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(double, int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(double, unsigned int, SIGN_PRESERVING_VALUE_PRESERVING); +} + +TEST(SafeNumerics, SizeTOperations) +{ + TEST_NUMERIC_CONVERSION(size_t, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + TEST_NUMERIC_CONVERSION(int, size_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); +} + +TEST(SafeNumerics, CastTests) +{ +// MSVC catches and warns that we're forcing saturation in these tests. +// Since that's intentional, we need to shut this warning off. +#if defined(COMPILER_MSVC) +#pragma warning(disable : 4756) +#endif + + int small_positive = 1; + int small_negative = -1; + double double_small = 1.0; + double double_large = numeric_limits::max(); + double double_infinity = numeric_limits::infinity(); + double double_large_int = numeric_limits::max(); + double double_small_int = numeric_limits::min(); + + // Just test that the casts compile, since the other tests cover logic. + EXPECT_EQ(0, checked_cast(static_cast(0))); + EXPECT_EQ(0, strict_cast(static_cast(0))); + EXPECT_EQ(0, strict_cast(static_cast(0))); + EXPECT_EQ(0U, strict_cast(static_cast(0))); + EXPECT_EQ(1ULL, static_cast(StrictNumeric(1U))); + EXPECT_EQ(1ULL, static_cast(SizeT(1U))); + EXPECT_EQ(1U, static_cast(StrictNumeric(1U))); + + EXPECT_TRUE(CheckedNumeric(StrictNumeric(1U)).IsValid()); + EXPECT_TRUE(CheckedNumeric(StrictNumeric(1U)).IsValid()); + EXPECT_FALSE(CheckedNumeric(StrictNumeric(-1)).IsValid()); + + EXPECT_TRUE(IsValueNegative(-1)); + EXPECT_TRUE(IsValueNegative(numeric_limits::min())); + EXPECT_FALSE(IsValueNegative(numeric_limits::min())); + EXPECT_TRUE(IsValueNegative(-numeric_limits::max())); + EXPECT_FALSE(IsValueNegative(0)); + EXPECT_FALSE(IsValueNegative(1)); + EXPECT_FALSE(IsValueNegative(0u)); + EXPECT_FALSE(IsValueNegative(1u)); + EXPECT_FALSE(IsValueNegative(numeric_limits::max())); + EXPECT_FALSE(IsValueNegative(numeric_limits::max())); + EXPECT_FALSE(IsValueNegative(numeric_limits::max())); + + // These casts and coercions will fail to compile: + // EXPECT_EQ(0, strict_cast(static_cast(0))); + // EXPECT_EQ(0, strict_cast(static_cast(0))); + // EXPECT_EQ(1ULL, StrictNumeric(1)); + // EXPECT_EQ(1, StrictNumeric(1U)); + + // Test various saturation corner cases. + EXPECT_EQ(saturated_cast(small_negative), static_cast(small_negative)); + EXPECT_EQ(saturated_cast(small_positive), static_cast(small_positive)); + EXPECT_EQ(saturated_cast(small_negative), static_cast(0)); + EXPECT_EQ(saturated_cast(double_small), static_cast(double_small)); + EXPECT_EQ(saturated_cast(double_large), numeric_limits::max()); + EXPECT_EQ(saturated_cast(double_large), double_infinity); + EXPECT_EQ(saturated_cast(-double_large), -double_infinity); + EXPECT_EQ(numeric_limits::min(), saturated_cast(double_small_int)); + EXPECT_EQ(numeric_limits::max(), saturated_cast(double_large_int)); + + float not_a_number = + std::numeric_limits::infinity() - std::numeric_limits::infinity(); + EXPECT_TRUE(std::isnan(not_a_number)); + EXPECT_EQ(0, saturated_cast(not_a_number)); +} + +#if GTEST_HAS_DEATH_TEST + +TEST(SafeNumerics, SaturatedCastChecks) +{ + float not_a_number = + std::numeric_limits::infinity() - std::numeric_limits::infinity(); + EXPECT_TRUE(std::isnan(not_a_number)); + EXPECT_DEATH((saturated_cast(not_a_number)), ""); +} + +#endif // GTEST_HAS_DEATH_TEST + +TEST(SafeNumerics, IsValueInRangeForNumericType) +{ + EXPECT_TRUE(IsValueInRangeForNumericType(0)); + EXPECT_TRUE(IsValueInRangeForNumericType(1)); + EXPECT_TRUE(IsValueInRangeForNumericType(2)); + EXPECT_FALSE(IsValueInRangeForNumericType(-1)); + EXPECT_TRUE(IsValueInRangeForNumericType(0xffffffffu)); + EXPECT_TRUE(IsValueInRangeForNumericType(UINT64_C(0xffffffff))); + EXPECT_FALSE(IsValueInRangeForNumericType(UINT64_C(0x100000000))); + EXPECT_FALSE(IsValueInRangeForNumericType(UINT64_C(0x100000001))); + EXPECT_FALSE(IsValueInRangeForNumericType(std::numeric_limits::min())); + EXPECT_FALSE(IsValueInRangeForNumericType(std::numeric_limits::min())); + + EXPECT_TRUE(IsValueInRangeForNumericType(0)); + EXPECT_TRUE(IsValueInRangeForNumericType(1)); + EXPECT_TRUE(IsValueInRangeForNumericType(2)); + EXPECT_TRUE(IsValueInRangeForNumericType(-1)); + EXPECT_TRUE(IsValueInRangeForNumericType(0x7fffffff)); + EXPECT_TRUE(IsValueInRangeForNumericType(0x7fffffffu)); + EXPECT_FALSE(IsValueInRangeForNumericType(0x80000000u)); + EXPECT_FALSE(IsValueInRangeForNumericType(0xffffffffu)); + EXPECT_FALSE(IsValueInRangeForNumericType(INT64_C(0x80000000))); + EXPECT_FALSE(IsValueInRangeForNumericType(INT64_C(0xffffffff))); + EXPECT_FALSE(IsValueInRangeForNumericType(INT64_C(0x100000000))); + EXPECT_TRUE(IsValueInRangeForNumericType(std::numeric_limits::min())); + EXPECT_TRUE(IsValueInRangeForNumericType( + static_cast(std::numeric_limits::min()))); + EXPECT_FALSE(IsValueInRangeForNumericType( + static_cast(std::numeric_limits::min()) - 1)); + EXPECT_FALSE(IsValueInRangeForNumericType(std::numeric_limits::min())); + + EXPECT_TRUE(IsValueInRangeForNumericType(0)); + EXPECT_TRUE(IsValueInRangeForNumericType(1)); + EXPECT_TRUE(IsValueInRangeForNumericType(2)); + EXPECT_FALSE(IsValueInRangeForNumericType(-1)); + EXPECT_TRUE(IsValueInRangeForNumericType(0xffffffffu)); + EXPECT_TRUE(IsValueInRangeForNumericType(UINT64_C(0xffffffff))); + EXPECT_TRUE(IsValueInRangeForNumericType(UINT64_C(0x100000000))); + EXPECT_TRUE(IsValueInRangeForNumericType(UINT64_C(0x100000001))); + EXPECT_FALSE(IsValueInRangeForNumericType(std::numeric_limits::min())); + EXPECT_FALSE(IsValueInRangeForNumericType(INT64_C(-1))); + EXPECT_FALSE(IsValueInRangeForNumericType(std::numeric_limits::min())); + + EXPECT_TRUE(IsValueInRangeForNumericType(0)); + EXPECT_TRUE(IsValueInRangeForNumericType(1)); + EXPECT_TRUE(IsValueInRangeForNumericType(2)); + EXPECT_TRUE(IsValueInRangeForNumericType(-1)); + EXPECT_TRUE(IsValueInRangeForNumericType(0x7fffffff)); + EXPECT_TRUE(IsValueInRangeForNumericType(0x7fffffffu)); + EXPECT_TRUE(IsValueInRangeForNumericType(0x80000000u)); + EXPECT_TRUE(IsValueInRangeForNumericType(0xffffffffu)); + EXPECT_TRUE(IsValueInRangeForNumericType(INT64_C(0x80000000))); + EXPECT_TRUE(IsValueInRangeForNumericType(INT64_C(0xffffffff))); + EXPECT_TRUE(IsValueInRangeForNumericType(INT64_C(0x100000000))); + EXPECT_TRUE(IsValueInRangeForNumericType(INT64_C(0x7fffffffffffffff))); + EXPECT_TRUE(IsValueInRangeForNumericType(UINT64_C(0x7fffffffffffffff))); + EXPECT_FALSE(IsValueInRangeForNumericType(UINT64_C(0x8000000000000000))); + EXPECT_FALSE(IsValueInRangeForNumericType(UINT64_C(0xffffffffffffffff))); + EXPECT_TRUE(IsValueInRangeForNumericType(std::numeric_limits::min())); + EXPECT_TRUE(IsValueInRangeForNumericType( + static_cast(std::numeric_limits::min()))); + EXPECT_TRUE(IsValueInRangeForNumericType(std::numeric_limits::min())); +} + +TEST(SafeNumerics, CompoundNumericOperations) +{ + CheckedNumeric a = 1; + CheckedNumeric b = 2; + CheckedNumeric c = 3; + CheckedNumeric d = 4; + a += b; + EXPECT_EQ(3, a.ValueOrDie()); + a -= c; + EXPECT_EQ(0, a.ValueOrDie()); + d /= b; + EXPECT_EQ(2, d.ValueOrDie()); + d *= d; + EXPECT_EQ(4, d.ValueOrDie()); + + CheckedNumeric too_large = std::numeric_limits::max(); + EXPECT_TRUE(too_large.IsValid()); + too_large += d; + EXPECT_FALSE(too_large.IsValid()); + too_large -= d; + EXPECT_FALSE(too_large.IsValid()); + too_large /= d; + EXPECT_FALSE(too_large.IsValid()); +} diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/sha1.cc b/src/3rdparty/angle/src/common/third_party/base/anglebase/sha1.cc new file mode 100644 index 0000000000..cb88ba06e1 --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/sha1.cc @@ -0,0 +1,245 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "anglebase/sha1.h" + +#include +#include +#include + +#include "anglebase/sys_byteorder.h" + +namespace angle +{ + +namespace base +{ + +// Implementation of SHA-1. Only handles data in byte-sized blocks, +// which simplifies the code a fair bit. + +// Identifier names follow notation in FIPS PUB 180-3, where you'll +// also find a description of the algorithm: +// http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf + +// Usage example: +// +// SecureHashAlgorithm sha; +// while(there is data to hash) +// sha.Update(moredata, size of data); +// sha.Final(); +// memcpy(somewhere, sha.Digest(), 20); +// +// to reuse the instance of sha, call sha.Init(); + +// TODO(jhawkins): Replace this implementation with a per-platform +// implementation using each platform's crypto library. See +// http://crbug.com/47218 + +class SecureHashAlgorithm +{ + public: + SecureHashAlgorithm() { Init(); } + + static const int kDigestSizeBytes; + + void Init(); + void Update(const void *data, size_t nbytes); + void Final(); + + // 20 bytes of message digest. + const unsigned char *Digest() const { return reinterpret_cast(H); } + + private: + void Pad(); + void Process(); + + uint32_t A, B, C, D, E; + + uint32_t H[5]; + + union { + uint32_t W[80]; + uint8_t M[64]; + }; + + uint32_t cursor; + uint64_t l; +}; + +static inline uint32_t f(uint32_t t, uint32_t B, uint32_t C, uint32_t D) +{ + if (t < 20) + { + return (B & C) | ((~B) & D); + } + else if (t < 40) + { + return B ^ C ^ D; + } + else if (t < 60) + { + return (B & C) | (B & D) | (C & D); + } + else + { + return B ^ C ^ D; + } +} + +static inline uint32_t S(uint32_t n, uint32_t X) +{ + return (X << n) | (X >> (32 - n)); +} + +static inline uint32_t K(uint32_t t) +{ + if (t < 20) + { + return 0x5a827999; + } + else if (t < 40) + { + return 0x6ed9eba1; + } + else if (t < 60) + { + return 0x8f1bbcdc; + } + else + { + return 0xca62c1d6; + } +} + +const int SecureHashAlgorithm::kDigestSizeBytes = 20; + +void SecureHashAlgorithm::Init() +{ + A = 0; + B = 0; + C = 0; + D = 0; + E = 0; + cursor = 0; + l = 0; + H[0] = 0x67452301; + H[1] = 0xefcdab89; + H[2] = 0x98badcfe; + H[3] = 0x10325476; + H[4] = 0xc3d2e1f0; +} + +void SecureHashAlgorithm::Final() +{ + Pad(); + Process(); + + for (int t = 0; t < 5; ++t) + H[t] = ByteSwap(H[t]); +} + +void SecureHashAlgorithm::Update(const void *data, size_t nbytes) +{ + const uint8_t *d = reinterpret_cast(data); + while (nbytes--) + { + M[cursor++] = *d++; + if (cursor >= 64) + Process(); + l += 8; + } +} + +void SecureHashAlgorithm::Pad() +{ + M[cursor++] = 0x80; + + if (cursor > 64 - 8) + { + // pad out to next block + while (cursor < 64) + M[cursor++] = 0; + + Process(); + } + + while (cursor < 64 - 8) + M[cursor++] = 0; + + M[cursor++] = (l >> 56) & 0xff; + M[cursor++] = (l >> 48) & 0xff; + M[cursor++] = (l >> 40) & 0xff; + M[cursor++] = (l >> 32) & 0xff; + M[cursor++] = (l >> 24) & 0xff; + M[cursor++] = (l >> 16) & 0xff; + M[cursor++] = (l >> 8) & 0xff; + M[cursor++] = l & 0xff; +} + +void SecureHashAlgorithm::Process() +{ + uint32_t t; + + // Each a...e corresponds to a section in the FIPS 180-3 algorithm. + + // a. + // + // W and M are in a union, so no need to memcpy. + // memcpy(W, M, sizeof(M)); + for (t = 0; t < 16; ++t) + W[t] = ByteSwap(W[t]); + + // b. + for (t = 16; t < 80; ++t) + W[t] = S(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]); + + // c. + A = H[0]; + B = H[1]; + C = H[2]; + D = H[3]; + E = H[4]; + + // d. + for (t = 0; t < 80; ++t) + { + uint32_t TEMP = S(5, A) + f(t, B, C, D) + E + W[t] + K(t); + E = D; + D = C; + C = S(30, B); + B = A; + A = TEMP; + } + + // e. + H[0] += A; + H[1] += B; + H[2] += C; + H[3] += D; + H[4] += E; + + cursor = 0; +} + +std::string SHA1HashString(const std::string &str) +{ + char hash[SecureHashAlgorithm::kDigestSizeBytes]; + SHA1HashBytes(reinterpret_cast(str.c_str()), str.length(), + reinterpret_cast(hash)); + return std::string(hash, SecureHashAlgorithm::kDigestSizeBytes); +} + +void SHA1HashBytes(const unsigned char *data, size_t len, unsigned char *hash) +{ + SecureHashAlgorithm sha; + sha.Update(data, len); + sha.Final(); + + memcpy(hash, sha.Digest(), SecureHashAlgorithm::kDigestSizeBytes); +} + +} // namespace base + +} // namespace angle diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/sha1.h b/src/3rdparty/angle/src/common/third_party/base/anglebase/sha1.h new file mode 100644 index 0000000000..a60908814f --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/sha1.h @@ -0,0 +1,36 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ANGLEBASE_SHA1_H_ +#define ANGLEBASE_SHA1_H_ + +#include + +#include + +#include "anglebase/base_export.h" + +namespace angle +{ + +namespace base +{ + +// These functions perform SHA-1 operations. + +static const size_t kSHA1Length = 20; // Length in bytes of a SHA-1 hash. + +// Computes the SHA-1 hash of the input string |str| and returns the full +// hash. +ANGLEBASE_EXPORT std::string SHA1HashString(const std::string &str); + +// Computes the SHA-1 hash of the |len| bytes in |data| and puts the hash +// in |hash|. |hash| must be kSHA1Length bytes long. +ANGLEBASE_EXPORT void SHA1HashBytes(const unsigned char *data, size_t len, unsigned char *hash); + +} // namespace base + +} // namespace angle + +#endif // ANGLEBASE_SHA1_H_ diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/sys_byteorder.h b/src/3rdparty/angle/src/common/third_party/base/anglebase/sys_byteorder.h new file mode 100644 index 0000000000..43d1777f26 --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/sys_byteorder.h @@ -0,0 +1,49 @@ +// +// Copyright 2017 The ANGLE 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. +// +// sys_byteorder.h: Compatiblity hacks for importing Chromium's base/SHA1. + +#ifndef ANGLEBASE_SYS_BYTEORDER_H_ +#define ANGLEBASE_SYS_BYTEORDER_H_ + +namespace angle +{ + +namespace base +{ + +// Returns a value with all bytes in |x| swapped, i.e. reverses the endianness. +inline uint16_t ByteSwap(uint16_t x) +{ +#if defined(_MSC_VER) + return _byteswap_ushort(x); +#else + return __builtin_bswap16(x); +#endif +} + +inline uint32_t ByteSwap(uint32_t x) +{ +#if defined(_MSC_VER) + return _byteswap_ulong(x); +#else + return __builtin_bswap32(x); +#endif +} + +inline uint64_t ByteSwap(uint64_t x) +{ +#if defined(_MSC_VER) + return _byteswap_uint64(x); +#else + return __builtin_bswap64(x); +#endif +} + +} // namespace base + +} // namespace angle + +#endif // ANGLEBASE_SYS_BYTEORDER_H_ \ No newline at end of file -- cgit v1.2.3