From dabc5d57bf473708295800a7991bc1fafdf76288 Mon Sep 17 00:00:00 2001 From: Tom Sepez Date: Thu, 5 Feb 2015 09:46:23 -0800 Subject: Add namespace and-re-arrange PDFium's local copy of chromium /base. Any projects DEPS'd into chromium and requiring a /base subset should have a local copy of that subset in a separate namespace. This will avoid future naming conflicts. Re-arrange the directory structure to better identify what came from chromium's base, and to make drop-in replacement easier for files that contain hard-coded "base/" in their #include directives. R=jam@chromium.org Review URL: https://codereview.chromium.org/900753002 --- BUILD.gn | 2 +- core/src/fpdfapi/fpdf_page/fpdf_page_func.cpp | 2 +- .../src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp | 12 +- core/src/fxcrt/fx_basic_array.cpp | 8 +- core/src/fxcrt/fx_basic_bstring.cpp | 4 +- core/src/fxcrt/fx_basic_wstring.cpp | 6 +- core/src/fxcrt/fx_safe_types.h | 10 +- fpdfsdk/src/fpdfview.cpp | 6 +- fpdfsdk/src/javascript/Document.cpp | 6 +- pdfium.gyp | 2 +- third_party/BUILD.gn | 18 +- third_party/base/logging.h | 18 + third_party/base/macros.h | 31 ++ third_party/base/numerics/OWNERS | 3 + third_party/base/numerics/safe_conversions.h | 66 +++ third_party/base/numerics/safe_conversions_impl.h | 219 +++++++++ third_party/base/numerics/safe_math.h | 272 +++++++++++ third_party/base/numerics/safe_math_impl.h | 504 +++++++++++++++++++++ third_party/base/template_util.h | 35 ++ third_party/logging.h | 18 - third_party/macros.h | 31 -- third_party/numerics/OWNERS | 3 - third_party/numerics/safe_conversions.h | 64 --- third_party/numerics/safe_conversions_impl.h | 217 --------- third_party/numerics/safe_math.h | 271 ----------- third_party/numerics/safe_math_impl.h | 502 -------------------- third_party/template_util.h | 33 -- third_party/third_party.gyp | 16 +- 28 files changed, 1194 insertions(+), 1185 deletions(-) create mode 100644 third_party/base/logging.h create mode 100644 third_party/base/macros.h create mode 100644 third_party/base/numerics/OWNERS create mode 100644 third_party/base/numerics/safe_conversions.h create mode 100644 third_party/base/numerics/safe_conversions_impl.h create mode 100644 third_party/base/numerics/safe_math.h create mode 100644 third_party/base/numerics/safe_math_impl.h create mode 100644 third_party/base/template_util.h delete mode 100644 third_party/logging.h delete mode 100644 third_party/macros.h delete mode 100644 third_party/numerics/OWNERS delete mode 100644 third_party/numerics/safe_conversions.h delete mode 100644 third_party/numerics/safe_conversions_impl.h delete mode 100644 third_party/numerics/safe_math.h delete mode 100644 third_party/numerics/safe_math_impl.h delete mode 100644 third_party/template_util.h diff --git a/BUILD.gn b/BUILD.gn index b657836bdc..bb369eb786 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -95,7 +95,7 @@ static_library("pdfium") { deps = [ "third_party:bigint", - "third_party:safemath", + "third_party:pdfium_base", ":fdrm", ":formfiller", ":fpdfapi", diff --git a/core/src/fpdfapi/fpdf_page/fpdf_page_func.cpp b/core/src/fpdfapi/fpdf_page/fpdf_page_func.cpp index 7d727f37fb..b112540356 100644 --- a/core/src/fpdfapi/fpdf_page/fpdf_page_func.cpp +++ b/core/src/fpdfapi/fpdf_page/fpdf_page_func.cpp @@ -9,7 +9,7 @@ #include "../../../include/fpdfapi/fpdf_page.h" #include "../../../include/fpdfapi/fpdf_module.h" #include "../../../src/fxcrt/fx_safe_types.h" -#include "../../../third_party/numerics/safe_conversions_impl.h" +#include "../../../third_party/base/numerics/safe_conversions_impl.h" #include "pageint.h" class CPDF_PSEngine; diff --git a/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp b/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp index 340da6f66b..16274088c0 100644 --- a/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp +++ b/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp @@ -1072,8 +1072,8 @@ FX_BOOL CPDF_Parser::LoadCrossRefV5(FX_FILESIZE pos, FX_FILESIZE& prev, FX_BOOL if (startnum < 0) { continue; } - m_dwXrefStartObjNum = base::checked_cast (startnum); - FX_DWORD count = base::checked_cast (arrIndex[i].second); + m_dwXrefStartObjNum = pdfium::base::checked_cast (startnum); + FX_DWORD count = pdfium::base::checked_cast (arrIndex[i].second); FX_SAFE_DWORD dwCaculatedSize = segindex; dwCaculatedSize += count; dwCaculatedSize *= totalWidth; @@ -1083,7 +1083,7 @@ FX_BOOL CPDF_Parser::LoadCrossRefV5(FX_FILESIZE pos, FX_FILESIZE& prev, FX_BOOL FX_LPCBYTE segstart = pData + segindex * totalWidth; FX_SAFE_DWORD dwMaxObjNum = startnum; dwMaxObjNum += count; - FX_DWORD dwV5Size = base::checked_cast (m_V5Type.GetSize()); + FX_DWORD dwV5Size = pdfium::base::checked_cast (m_V5Type.GetSize()); if (!dwMaxObjNum.IsValid() || dwMaxObjNum.ValueOrDie() > dwV5Size) { continue; } @@ -2439,7 +2439,7 @@ CPDF_Stream* CPDF_SyntaxParser::ReadStream(CPDF_Dictionary* pDict, PARSE_CONTEXT CPDF_CryptoHandler* pCryptoHandler = objnum == (FX_DWORD)m_MetadataObjnum ? NULL : m_pCryptoHandler; if (pCryptoHandler == NULL) { - base::CheckedNumeric pos = m_Pos; + pdfium::base::CheckedNumeric pos = m_Pos; pos += len; if (pos.IsValid() && pos.ValueOrDie() < m_FileLen) { m_Pos = pos.ValueOrDie(); @@ -3076,7 +3076,7 @@ FX_BOOL CPDF_DataAvail::IsObjectsAvail(CFX_PtrArray& obj_array, FX_BOOL bParsePa FX_DWORD dwNum = pRef->GetRefObjNum(); FX_FILESIZE offset; FX_DWORD original_size = GetObjectSize(dwNum, offset); - base::CheckedNumeric size = original_size; + pdfium::base::CheckedNumeric size = original_size; if (size.ValueOrDefault(0) == 0 || offset < 0 || offset >= m_dwFileLen) { break; } @@ -3303,7 +3303,7 @@ CPDF_Object* CPDF_DataAvail::GetObject(FX_DWORD objnum, IFX_DownloadHints* pHint pParser = (CPDF_Parser *)(m_pDocument->GetParser()); } - base::CheckedNumeric size = original_size; + pdfium::base::CheckedNumeric size = original_size; if (size.ValueOrDefault(0) == 0 || offset < 0 || offset >= m_dwFileLen) { if (pExistInFile) *pExistInFile = FALSE; diff --git a/core/src/fxcrt/fx_basic_array.cpp b/core/src/fxcrt/fx_basic_array.cpp index 0694cf9cbd..9bdc607bfe 100644 --- a/core/src/fxcrt/fx_basic_array.cpp +++ b/core/src/fxcrt/fx_basic_array.cpp @@ -5,7 +5,7 @@ // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #include "../../include/fxcrt/fx_basic.h" -#include "../../../third_party/numerics/safe_math.h" +#include "../../../third_party/base/numerics/safe_math.h" CFX_BasicArray::CFX_BasicArray(int unit_size) : m_pData(NULL) @@ -32,7 +32,7 @@ FX_BOOL CFX_BasicArray::SetSize(int nNewSize) } if (m_pData == NULL) { - base::CheckedNumeric totalSize = nNewSize; + pdfium::base::CheckedNumeric totalSize = nNewSize; totalSize *= m_nUnitSize; if (!totalSize.IsValid()) { m_nSize = m_nMaxSize = 0; @@ -51,7 +51,7 @@ FX_BOOL CFX_BasicArray::SetSize(int nNewSize) m_nSize = nNewSize; } else { int nNewMax = nNewSize < m_nMaxSize ? m_nMaxSize : nNewSize; - base::CheckedNumeric totalSize = nNewMax; + pdfium::base::CheckedNumeric totalSize = nNewMax; totalSize *= m_nUnitSize; if (!totalSize.IsValid() || nNewMax < m_nSize) { return FALSE; @@ -70,7 +70,7 @@ FX_BOOL CFX_BasicArray::SetSize(int nNewSize) FX_BOOL CFX_BasicArray::Append(const CFX_BasicArray& src) { int nOldSize = m_nSize; - base::CheckedNumeric newSize = m_nSize; + pdfium::base::CheckedNumeric newSize = m_nSize; newSize += src.m_nSize; if (m_nUnitSize != src.m_nUnitSize || !newSize.IsValid() || !SetSize(newSize.ValueOrDie())) { return FALSE; diff --git a/core/src/fxcrt/fx_basic_bstring.cpp b/core/src/fxcrt/fx_basic_bstring.cpp index 0d4f860b32..39104e29f6 100644 --- a/core/src/fxcrt/fx_basic_bstring.cpp +++ b/core/src/fxcrt/fx_basic_bstring.cpp @@ -5,7 +5,7 @@ // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #include "../../include/fxcrt/fx_basic.h" -#include "../../../third_party/numerics/safe_math.h" +#include "../../../third_party/base/numerics/safe_math.h" static int _Buffer_itoa(char* buf, int i, FX_DWORD flags) { @@ -52,7 +52,7 @@ static CFX_StringData* FX_AllocString(int nLen) if (nLen == 0 || nLen < 0) { return NULL; } - base::CheckedNumeric nSize = nLen; + pdfium::base::CheckedNumeric nSize = nLen; nSize += sizeof(long) * 3 + 1; CFX_StringData* pData = (CFX_StringData*)FX_Alloc(FX_BYTE, nSize.ValueOrDie()); if (!pData) { diff --git a/core/src/fxcrt/fx_basic_wstring.cpp b/core/src/fxcrt/fx_basic_wstring.cpp index 0945d2f1c5..dfdbef8bd6 100644 --- a/core/src/fxcrt/fx_basic_wstring.cpp +++ b/core/src/fxcrt/fx_basic_wstring.cpp @@ -5,7 +5,7 @@ // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #include "../../include/fxcrt/fx_basic.h" -#include "../../../third_party/numerics/safe_math.h" +#include "../../../third_party/base/numerics/safe_math.h" static CFX_StringDataW* FX_AllocStringW(int nLen) { @@ -13,7 +13,7 @@ static CFX_StringDataW* FX_AllocStringW(int nLen) return NULL; } - base::CheckedNumeric iSize = static_cast(sizeof(FX_WCHAR)); + pdfium::base::CheckedNumeric iSize = static_cast(sizeof(FX_WCHAR)); iSize *= nLen + 1; iSize += sizeof(long) * 3; CFX_StringDataW* pData = (CFX_StringDataW*)FX_Alloc(FX_BYTE, iSize.ValueOrDie()); @@ -435,7 +435,7 @@ void CFX_WideString::AllocCopy(CFX_WideString& dest, FX_STRSIZE nCopyLen, FX_STR if (nCopyLen == 0 || nCopyLen < 0) { return; } - base::CheckedNumeric iSize = static_cast(sizeof(FX_WCHAR)); + pdfium::base::CheckedNumeric iSize = static_cast(sizeof(FX_WCHAR)); iSize *= nCopyLen; ASSERT(dest.m_pData == NULL); dest.m_pData = FX_AllocStringW(nCopyLen); diff --git a/core/src/fxcrt/fx_safe_types.h b/core/src/fxcrt/fx_safe_types.h index 794e1f19dc..5772fd0e3c 100644 --- a/core/src/fxcrt/fx_safe_types.h +++ b/core/src/fxcrt/fx_safe_types.h @@ -7,11 +7,11 @@ #include // For size_t. -#include "../../../third_party/numerics/safe_math.h" +#include "../../../third_party/base/numerics/safe_math.h" -typedef base::CheckedNumeric FX_SAFE_DWORD; -typedef base::CheckedNumeric FX_SAFE_INT32; -typedef base::CheckedNumeric FX_SAFE_SIZE_T; -typedef base::CheckedNumeric FX_SAFE_FILESIZE; +typedef pdfium::base::CheckedNumeric FX_SAFE_DWORD; +typedef pdfium::base::CheckedNumeric FX_SAFE_INT32; +typedef pdfium::base::CheckedNumeric FX_SAFE_SIZE_T; +typedef pdfium::base::CheckedNumeric FX_SAFE_FILESIZE; #endif // FX_SAFE_TYPES_H_ diff --git a/fpdfsdk/src/fpdfview.cpp b/fpdfsdk/src/fpdfview.cpp index b751091a99..401f817be2 100644 --- a/fpdfsdk/src/fpdfview.cpp +++ b/fpdfsdk/src/fpdfview.cpp @@ -11,7 +11,7 @@ #include "../include/fpdf_progressive.h" #include "../include/fpdf_ext.h" #include "../../../core/src/fxcrt/fx_safe_types.h" -#include "../../third_party/numerics/safe_conversions_impl.h" +#include "../../third_party/base/numerics/safe_conversions_impl.h" CPDF_CustomAccess::CPDF_CustomAccess(FPDF_FILEACCESS* pFileAccess) { @@ -24,7 +24,7 @@ FX_BOOL CPDF_CustomAccess::ReadBlock(void* buffer, FX_FILESIZE offset, size_t si if (offset < 0) { return FALSE; } - FX_SAFE_FILESIZE newPos = base::checked_cast(size); + FX_SAFE_FILESIZE newPos = pdfium::base::checked_cast(size); newPos += offset; if (!newPos.IsValid() || newPos.ValueOrDie() > m_FileAccess.m_FileLen) { return FALSE; @@ -210,7 +210,7 @@ public: if (offset < 0) { return FALSE; } - FX_SAFE_FILESIZE newPos = base::checked_cast(size); + FX_SAFE_FILESIZE newPos = pdfium::base::checked_cast(size); newPos += offset; if (!newPos.IsValid() || newPos.ValueOrDie() > (FX_DWORD)m_size) { return FALSE; diff --git a/fpdfsdk/src/javascript/Document.cpp b/fpdfsdk/src/javascript/Document.cpp index 96cec474c2..8f7a8f29e3 100644 --- a/fpdfsdk/src/javascript/Document.cpp +++ b/fpdfsdk/src/javascript/Document.cpp @@ -18,7 +18,7 @@ #include "../../include/javascript/Icon.h" #include "../../include/javascript/Field.h" -#include "../../../third_party/numerics/safe_math.h" +#include "../../../third_party/base/numerics/safe_math.h" static v8::Isolate* GetIsolate(IFXJS_Context* cc) { @@ -1428,7 +1428,7 @@ FX_BOOL Document::documentFileName(OBJ_PROP_PARAMS) CFX_WideString Document::ReversalStr(CFX_WideString cbFrom) { size_t iLength = cbFrom.GetLength(); - base::CheckedNumeric iSize = sizeof(wchar_t); + pdfium::base::CheckedNumeric iSize = sizeof(wchar_t); iSize *= (iLength + 1); wchar_t* pResult = (wchar_t*)malloc(iSize.ValueOrDie()); wchar_t* pFrom = (wchar_t*)cbFrom.GetBuffer(iLength); @@ -1449,7 +1449,7 @@ CFX_WideString Document::ReversalStr(CFX_WideString cbFrom) CFX_WideString Document::CutString(CFX_WideString cbFrom) { size_t iLength = cbFrom.GetLength(); - base::CheckedNumeric iSize = sizeof(wchar_t); + pdfium::base::CheckedNumeric iSize = sizeof(wchar_t); iSize *= (iLength + 1); wchar_t* pResult = (wchar_t*)malloc(iSize.ValueOrDie()); wchar_t* pFrom = (wchar_t*)cbFrom.GetBuffer(iLength); diff --git a/pdfium.gyp b/pdfium.gyp index c23059d6f3..dbe1b525f5 100644 --- a/pdfium.gyp +++ b/pdfium.gyp @@ -45,7 +45,7 @@ 'type': 'static_library', 'dependencies': [ 'third_party/third_party.gyp:bigint', - 'third_party/third_party.gyp:safemath', + 'third_party/third_party.gyp:pdfium_base', 'fdrm', 'fpdfdoc', 'fpdfapi', diff --git a/third_party/BUILD.gn b/third_party/BUILD.gn index df02938a93..fcb09c4b47 100644 --- a/third_party/BUILD.gn +++ b/third_party/BUILD.gn @@ -6,7 +6,7 @@ group("third_party") { deps = [ ":bigint", ":freetype", - ":safemath", + ":pdfium_base", ] } @@ -69,20 +69,20 @@ static_library("freetype") { ] } -component("safemath") { +component("pdfium_base") { configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//third_party/pdfium:pdfium_config", "//build/config/compiler:no_chromium_code", ] sources = [ - "logging.h", - "macros.h", - "template_util.h", - "numerics/safe_conversions.h", - "numerics/safe_conversions_impl.h", - "numerics/safe_math.h", - "numerics/safe_math_impl.h", + "base/logging.h", + "base/macros.h", + "base/template_util.h", + "base/numerics/safe_conversions.h", + "base/numerics/safe_conversions_impl.h", + "base/numerics/safe_math.h", + "base/numerics/safe_math_impl.h", ] } diff --git a/third_party/base/logging.h b/third_party/base/logging.h new file mode 100644 index 0000000000..d24f93b2a1 --- /dev/null +++ b/third_party/base/logging.h @@ -0,0 +1,18 @@ +// Copyright (c) 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 PDFIUM_THIRD_PARTY_BASE_LOGGING_H_ +#define PDFIUM_THIRD_PARTY_BASE_LOGGING_H_ + +#include + +#define CHECK(condition) \ + if (!(condition)) { \ + abort(); \ + *(reinterpret_cast(NULL) + 42) = 0x42; \ + } + +#define NOTREACHED() abort() + +#endif // PDFIUM_THIRD_PARTY_BASE_LOGGING_H_ diff --git a/third_party/base/macros.h b/third_party/base/macros.h new file mode 100644 index 0000000000..05c3132e46 --- /dev/null +++ b/third_party/base/macros.h @@ -0,0 +1,31 @@ +// 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. + +// This file contains macros and macro-like constructs (e.g., templates) that +// are commonly used throughout Chromium source. (It may also contain things +// that are closely related to things that are commonly used that belong in this +// file.) + +#ifndef PDFIUM_THIRD_PARTY_BASE_MACROS_H_ +#define PDFIUM_THIRD_PARTY_BASE_MACROS_H_ + +// The COMPILE_ASSERT macro can be used to verify that a compile time +// expression is true. For example, you could use it to verify the +// size of a static array: +// +// COMPILE_ASSERT(ARRAYSIZE_UNSAFE(content_type_names) == CONTENT_NUM_TYPES, +// content_type_names_incorrect_size); +// +// or to make sure a struct is smaller than a certain size: +// +// COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large); +// +// The second argument to the macro is the name of the variable. If +// the expression is false, most compilers will issue a warning/error +// containing the name of the variable. + +#undef COMPILE_ASSERT +#define COMPILE_ASSERT(expr, msg) static_assert(expr, #msg) + +#endif // PDFIUM_THIRD_PARTY_BASE_MACROS_H_ diff --git a/third_party/base/numerics/OWNERS b/third_party/base/numerics/OWNERS new file mode 100644 index 0000000000..f7816afe81 --- /dev/null +++ b/third_party/base/numerics/OWNERS @@ -0,0 +1,3 @@ +jschuh@chromium.org +tsepez@chromium.org +palmer@chromium.org diff --git a/third_party/base/numerics/safe_conversions.h b/third_party/base/numerics/safe_conversions.h new file mode 100644 index 0000000000..e95608e0a5 --- /dev/null +++ b/third_party/base/numerics/safe_conversions.h @@ -0,0 +1,66 @@ +// 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 PDFIUM_THIRD_PARTY_BASE_SAFE_CONVERSIONS_H_ +#define PDFIUM_THIRD_PARTY_BASE_SAFE_CONVERSIONS_H_ + +#include + +#include "../logging.h" +#include "safe_conversions_impl.h" + +namespace pdfium { +namespace base { + +// Convenience function that returns true if the supplied value is in range +// for the destination type. +template +inline bool IsValueInRangeForNumericType(Src value) { + return internal::DstRangeRelationToSrcRange(value) == + internal::RANGE_VALID; +} + +// 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); +} + +// saturated_cast<> is analogous to static_cast<> for numeric types, except +// that the specified numeric conversion will saturate rather than overflow or +// underflow. NaN assignment to an integral will trigger a CHECK condition. +template +inline Dst saturated_cast(Src value) { + // Optimization for floating point values, which already saturate. + if (std::numeric_limits::is_iec559) + return static_cast(value); + + switch (internal::DstRangeRelationToSrcRange(value)) { + case internal::RANGE_VALID: + return static_cast(value); + + case internal::RANGE_UNDERFLOW: + return std::numeric_limits::min(); + + case internal::RANGE_OVERFLOW: + return std::numeric_limits::max(); + + // Should fail only on attempting to assign NaN to a saturated integer. + case internal::RANGE_INVALID: + CHECK(false); + return std::numeric_limits::max(); + } + + NOTREACHED(); + return static_cast(value); +} + +} // namespace base +} // namespace pdfium + +#endif // PDFIUM_THIRD_PARTY_BASE_SAFE_CONVERSIONS_H_ + diff --git a/third_party/base/numerics/safe_conversions_impl.h b/third_party/base/numerics/safe_conversions_impl.h new file mode 100644 index 0000000000..7c88dda0a8 --- /dev/null +++ b/third_party/base/numerics/safe_conversions_impl.h @@ -0,0 +1,219 @@ +// 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 PDFIUM_THIRD_PARTY_BASE_SAFE_CONVERSIONS_IMPL_H_ +#define PDFIUM_THIRD_PARTY_BASE_SAFE_CONVERSIONS_IMPL_H_ + +#include + +#include "../macros.h" +#include "../template_util.h" + +namespace pdfium { +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 const int value = std::numeric_limits::is_iec559 + ? std::numeric_limits::max_exponent + : (sizeof(NumericType) * 8 + 1 - + std::numeric_limits::is_signed); +}; + +enum IntegerRepresentation { + INTEGER_REPRESENTATION_UNSIGNED, + INTEGER_REPRESENTATION_SIGNED +}; + +// A range for a given nunmeric Src type is contained for a given numeric Dst +// type if both numeric_limits::max() <= numeric_limits::max() and +// numeric_limits::min() >= numeric_limits::min() are true. +// We implement this as template specializations rather than simple static +// comparisons to ensure type correctness in our comparisons. +enum NumericRangeRepresentation { + NUMERIC_RANGE_NOT_CONTAINED, + NUMERIC_RANGE_CONTAINED +}; + +// Helper templates to statically determine if our destination type can contain +// maximum and minimum values represented by the source type. + +template < + typename Dst, + typename Src, + IntegerRepresentation DstSign = std::numeric_limits::is_signed + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED, + IntegerRepresentation SrcSign = + std::numeric_limits::is_signed + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED > +struct StaticDstRangeRelationToSrcRange; + +// Same sign: Dst is guaranteed to contain Src only if its range is equal or +// larger. +template +struct StaticDstRangeRelationToSrcRange { + static const NumericRangeRepresentation value = + MaxExponent::value >= MaxExponent::value + ? NUMERIC_RANGE_CONTAINED + : NUMERIC_RANGE_NOT_CONTAINED; +}; + +// Unsigned to signed: Dst is guaranteed to contain source only if its range is +// larger. +template +struct StaticDstRangeRelationToSrcRange { + static const NumericRangeRepresentation value = + MaxExponent::value > MaxExponent::value + ? NUMERIC_RANGE_CONTAINED + : NUMERIC_RANGE_NOT_CONTAINED; +}; + +// Signed to unsigned: Dst cannot be statically determined to contain Src. +template +struct StaticDstRangeRelationToSrcRange { + static const NumericRangeRepresentation value = NUMERIC_RANGE_NOT_CONTAINED; +}; + +enum RangeConstraint { + RANGE_VALID = 0x0, // Value can be represented by the destination type. + RANGE_UNDERFLOW = 0x1, // Value would overflow. + RANGE_OVERFLOW = 0x2, // Value would underflow. + RANGE_INVALID = RANGE_UNDERFLOW | RANGE_OVERFLOW // Invalid (i.e. NaN). +}; + +// Helper function for coercing an int back to a RangeContraint. +inline RangeConstraint GetRangeConstraint(int integer_range_constraint) { + 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. +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)); +} + +template < + typename Dst, + typename Src, + IntegerRepresentation DstSign = std::numeric_limits::is_signed + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED, + IntegerRepresentation SrcSign = std::numeric_limits::is_signed + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED, + NumericRangeRepresentation DstRange = + StaticDstRangeRelationToSrcRange::value > +struct DstRangeRelationToSrcRangeImpl; + +// The following templates are for ranges that must be verified at runtime. We +// split it into checks based on signedness to avoid confusing casts and +// compiler warnings on signed an unsigned comparisons. + +// Dst range is statically determined to contain Src: Nothing to check. +template +struct DstRangeRelationToSrcRangeImpl { + static RangeConstraint Check(Src value) { return RANGE_VALID; } +}; + +// Signed to signed narrowing: Both the upper and lower boundaries may be +// exceeded. +template +struct DstRangeRelationToSrcRangeImpl { + static RangeConstraint Check(Src value) { + return std::numeric_limits::is_iec559 + ? GetRangeConstraint(value <= std::numeric_limits::max(), + value >= -std::numeric_limits::max()) + : GetRangeConstraint(value <= std::numeric_limits::max(), + value >= std::numeric_limits::min()); + } +}; + +// Unsigned to unsigned narrowing: Only the upper boundary can be exceeded. +template +struct DstRangeRelationToSrcRangeImpl { + static RangeConstraint Check(Src value) { + return GetRangeConstraint(value <= std::numeric_limits::max(), true); + } +}; + +// Unsigned to signed: The upper boundary may be exceeded. +template +struct DstRangeRelationToSrcRangeImpl { + static RangeConstraint Check(Src value) { + return sizeof(Dst) > sizeof(Src) + ? RANGE_VALID + : GetRangeConstraint( + value <= static_cast(std::numeric_limits::max()), + true); + } +}; + +// Signed to unsigned: The upper boundary may be exceeded for a narrower Dst, +// and any negative value exceeds the lower boundary. +template +struct DstRangeRelationToSrcRangeImpl { + static RangeConstraint Check(Src value) { + return (MaxExponent::value >= MaxExponent::value) + ? GetRangeConstraint(true, value >= static_cast(0)) + : GetRangeConstraint( + value <= static_cast(std::numeric_limits::max()), + value >= static_cast(0)); + } +}; + +template +inline RangeConstraint DstRangeRelationToSrcRange(Src value) { + COMPILE_ASSERT(std::numeric_limits::is_specialized, + argument_must_be_numeric); + COMPILE_ASSERT(std::numeric_limits::is_specialized, + result_must_be_numeric); + return DstRangeRelationToSrcRangeImpl::Check(value); +} + +} // namespace internal +} // namespace base +} // namespace pdfium + +#endif // PDFIUM_THIRD_PARTY_BASE_SAFE_CONVERSIONS_IMPL_H_ + diff --git a/third_party/base/numerics/safe_math.h b/third_party/base/numerics/safe_math.h new file mode 100644 index 0000000000..9540e83321 --- /dev/null +++ b/third_party/base/numerics/safe_math.h @@ -0,0 +1,272 @@ +// 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 PDFIUM_THIRD_PARTY_BASE_SAFE_MATH_H_ +#define PDFIUM_THIRD_PARTY_BASE_SAFE_MATH_H_ + +#include "safe_math_impl.h" + +namespace pdfium { +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; +// CheckedNumeric checked_size = untrusted_input_value; +// checked_size = checked_size + HEADER LENGTH; +// if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size) +// Do stuff... +template +class CheckedNumeric { + public: + typedef T type; + + CheckedNumeric() {} + + // Copy constructor. + template + CheckedNumeric(const CheckedNumeric& rhs) + : state_(rhs.ValueUnsafe(), rhs.validity()) {} + + template + CheckedNumeric(Src value, RangeConstraint validity) + : state_(value, validity) {} + + // This is not an explicit constructor because we implicitly upgrade regular + // numerics to CheckedNumerics to make them easier to use. + template + CheckedNumeric(Src value) + : state_(value) { + COMPILE_ASSERT(std::numeric_limits::is_specialized, + argument_must_be_numeric); + } + + // 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 { + COMPILE_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); + } + + 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 enable_if::is_specialized, int>::type = + 0) { + return u; + } + + template + static CheckedNumeric cast( + const CheckedNumeric& u, + typename enable_if::value, int>::type = 0) { + return u; + } + + static const CheckedNumeric& cast(const CheckedNumeric& u) { return u; } + + private: + CheckedNumericState state_; +}; + +// This is the boilerplate for the standard arithmetic operator overloads. A +// macro isn't the prettiest solution, but it beats rewriting these five times. +// Some details worth noting are: +// * We apply the standard arithmetic promotions. +// * We skip range checks for floating points. +// * We skip range checks for destination integers with sufficient range. +// TODO(jschuh): extract these out into templates. +#define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP) \ + /* Binary arithmetic operator for CheckedNumerics of the same type. */ \ + template \ + CheckedNumeric::type> operator OP( \ + const CheckedNumeric& lhs, const CheckedNumeric& rhs) { \ + typedef typename ArithmeticPromotion::type Promotion; \ + /* Floating point always takes the fast path */ \ + if (std::numeric_limits::is_iec559) \ + return CheckedNumeric(lhs.ValueUnsafe() OP rhs.ValueUnsafe()); \ + if (IsIntegerArithmeticSafe::value) \ + return CheckedNumeric( \ + lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \ + GetRangeConstraint(rhs.validity() | lhs.validity())); \ + RangeConstraint validity = RANGE_VALID; \ + T result = 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::cast(rhs); \ + return *this; \ + } \ + /* Binary arithmetic operator for CheckedNumeric of different type. */ \ + template \ + CheckedNumeric::type> operator OP( \ + const CheckedNumeric& lhs, const CheckedNumeric& rhs) { \ + typedef typename ArithmeticPromotion::type Promotion; \ + if (IsIntegerArithmeticSafe::value) \ + return CheckedNumeric( \ + lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \ + GetRangeConstraint(rhs.validity() | lhs.validity())); \ + return CheckedNumeric::cast(lhs) \ + OP CheckedNumeric::cast(rhs); \ + } \ + /* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \ + template \ + CheckedNumeric::type> operator OP( \ + const CheckedNumeric& lhs, Src rhs) { \ + typedef typename ArithmeticPromotion::type Promotion; \ + if (IsIntegerArithmeticSafe::value) \ + return CheckedNumeric(lhs.ValueUnsafe() OP rhs, \ + lhs.validity()); \ + return CheckedNumeric::cast(lhs) \ + OP CheckedNumeric::cast(rhs); \ + } \ + /* Binary arithmetic operator for right numeric and left CheckedNumeric. */ \ + template \ + CheckedNumeric::type> operator OP( \ + Src lhs, const CheckedNumeric& rhs) { \ + typedef typename ArithmeticPromotion::type Promotion; \ + if (IsIntegerArithmeticSafe::value) \ + return CheckedNumeric(lhs OP rhs.ValueUnsafe(), \ + rhs.validity()); \ + return CheckedNumeric::cast(lhs) \ + OP CheckedNumeric::cast(rhs); \ + } + +BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, += ) +BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -= ) +BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *= ) +BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /= ) +BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %= ) + +#undef BASE_NUMERIC_ARITHMETIC_OPERATORS + +} // namespace internal + +using internal::CheckedNumeric; + +} // namespace base +} // namespace pdfium + +#endif // PDFIUM_THIRD_PARTY_BASE_SAFE_MATH_H_ diff --git a/third_party/base/numerics/safe_math_impl.h b/third_party/base/numerics/safe_math_impl.h new file mode 100644 index 0000000000..f9a4a71570 --- /dev/null +++ b/third_party/base/numerics/safe_math_impl.h @@ -0,0 +1,504 @@ +// 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 PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_ +#define PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_ + +#include + +#include +#include +#include + +#include "../macros.h" +#include "../template_util.h" +#include "safe_conversions.h" + +namespace pdfium { +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 enable_if< + std::numeric_limits::is_integer, + typename IntegerForSizeAndSign::type>::type type; +}; + +template +struct SignedIntegerForSize { + typedef typename enable_if< + std::numeric_limits::is_integer, + typename IntegerForSizeAndSign::type>::type type; +}; + +template +struct TwiceWiderInteger { + typedef typename enable_if< + std::numeric_limits::is_integer, + typename IntegerForSizeAndSign< + sizeof(Integer) * 2, + std::numeric_limits::is_signed>::type>::type type; +}; + +template +struct PositionOfSignBit { + static const typename enable_if::is_integer, + size_t>::type value = 8 * sizeof(Integer) - 1; +}; + +// Helper templates for integer manipulations. + +template +bool HasSignBit(T x) { + // Cast to unsigned since right shift on signed is undefined. + return !!(static_cast::type>(x) >> + PositionOfSignBit::value); +} + +// This wrapper undoes the standard integer promotions. +template +T BinaryComplement(T x) { + return ~x; +} + +// Here are the actual portable checked integer math implementations. +// TODO(jschuh): Break this code out from the enable_if pattern and find a clean +// way to coalesce things into the CheckedNumericState specializations below. + +template +typename enable_if::is_integer, T>::type +CheckedAdd(T x, T y, RangeConstraint* validity) { + // Since the value of x+y is undefined if we have a signed type, we compute + // it using the unsigned type of the same size. + typedef typename UnsignedIntegerForSize::type UnsignedDst; + UnsignedDst ux = static_cast(x); + UnsignedDst uy = static_cast(y); + UnsignedDst uresult = ux + uy; + // Addition is valid if the sign of (x + y) is equal to either that of x or + // that of y. + if (std::numeric_limits::is_signed) { + if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy)))) + *validity = RANGE_VALID; + else // Direction of wrap is inverse of result sign. + *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; + + } else { // Unsigned is either valid or overflow. + *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW; + } + return static_cast(uresult); +} + +template +typename enable_if::is_integer, T>::type +CheckedSub(T x, T y, RangeConstraint* validity) { + // Since the value of x+y is undefined if we have a signed type, we compute + // it using the unsigned type of the same size. + typedef typename UnsignedIntegerForSize::type UnsignedDst; + UnsignedDst ux = static_cast(x); + UnsignedDst uy = static_cast(y); + UnsignedDst uresult = ux - uy; + // Subtraction is valid if either x and y have same sign, or (x-y) and x have + // the same sign. + if (std::numeric_limits::is_signed) { + if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy)))) + *validity = RANGE_VALID; + else // Direction of wrap is inverse of result sign. + *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; + + } else { // Unsigned is either valid or underflow. + *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW; + } + return static_cast(uresult); +} + +// Integer multiplication is a bit complicated. In the fast case we just +// we just promote to a twice wider type, and range check the result. In the +// slow case we need to manually check that the result won't be truncated by +// checking with division against the appropriate bound. +template +typename enable_if< + std::numeric_limits::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 enable_if::is_integer&& std::numeric_limits< + T>::is_signed&&(sizeof(T) * 2 > sizeof(uintmax_t)), + T>::type +CheckedMul(T x, T y, RangeConstraint* validity) { + // if either side is zero then the result will be zero. + if (!(x || y)) { + return RANGE_VALID; + + } else if (x > 0) { + if (y > 0) + *validity = + x <= std::numeric_limits::max() / y ? RANGE_VALID : RANGE_OVERFLOW; + else + *validity = y >= std::numeric_limits::min() / x ? RANGE_VALID + : RANGE_UNDERFLOW; + + } else { + if (y > 0) + *validity = x >= std::numeric_limits::min() / y ? RANGE_VALID + : RANGE_UNDERFLOW; + else + *validity = + y >= std::numeric_limits::max() / x ? RANGE_VALID : RANGE_OVERFLOW; + } + + return x * y; +} + +template +typename enable_if::is_integer && + !std::numeric_limits::is_signed && + (sizeof(T) * 2 > sizeof(uintmax_t)), + T>::type +CheckedMul(T x, T y, RangeConstraint* validity) { + *validity = (y == 0 || x <= std::numeric_limits::max() / y) + ? RANGE_VALID + : RANGE_OVERFLOW; + return x * y; +} + +// Division just requires a check for an invalid negation on signed min/-1. +template +T CheckedDiv( + T x, + T y, + RangeConstraint* validity, + typename enable_if::is_integer, int>::type = 0) { + if (std::numeric_limits::is_signed && x == std::numeric_limits::min() && + y == static_cast(-1)) { + *validity = RANGE_OVERFLOW; + return std::numeric_limits::min(); + } + + *validity = RANGE_VALID; + return x / y; +} + +template +typename enable_if< + std::numeric_limits::is_integer&& std::numeric_limits::is_signed, + T>::type +CheckedMod(T x, T y, RangeConstraint* validity) { + *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; + return x % y; +} + +template +typename enable_if< + std::numeric_limits::is_integer && !std::numeric_limits::is_signed, + T>::type +CheckedMod(T x, T y, RangeConstraint* validity) { + *validity = RANGE_VALID; + return x % y; +} + +template +typename enable_if< + std::numeric_limits::is_integer&& std::numeric_limits::is_signed, + T>::type +CheckedNeg(T value, RangeConstraint* validity) { + *validity = + value != std::numeric_limits::min() ? RANGE_VALID : RANGE_OVERFLOW; + // The negation of signed min is min, so catch that one. + return -value; +} + +template +typename enable_if< + std::numeric_limits::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 enable_if< + std::numeric_limits::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 std::abs(value); +} + +template +typename enable_if< + std::numeric_limits::is_integer && !std::numeric_limits::is_signed, + T>::type +CheckedAbs(T value, RangeConstraint* validity) { + // Absolute value of a positive is just its identiy. + *validity = RANGE_VALID; + return value; +} + +// These are the floating point stubs that the compiler needs to see. Only the +// negation operation is ever called. +#define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ + template \ + typename enable_if::is_iec559, T>::type \ + Checked##NAME(T, T, RangeConstraint*) { \ + NOTREACHED(); \ + return 0; \ + } + +BASE_FLOAT_ARITHMETIC_STUBS(Add) +BASE_FLOAT_ARITHMETIC_STUBS(Sub) +BASE_FLOAT_ARITHMETIC_STUBS(Mul) +BASE_FLOAT_ARITHMETIC_STUBS(Div) +BASE_FLOAT_ARITHMETIC_STUBS(Mod) + +#undef BASE_FLOAT_ARITHMETIC_STUBS + +template +typename enable_if::is_iec559, T>::type CheckedNeg( + T value, + RangeConstraint*) { + return -value; +} + +template +typename enable_if::is_iec559, T>::type CheckedAbs( + T value, + RangeConstraint*) { + return std::abs(value); +} + +// Floats carry around their validity state with them, but integers do not. So, +// we wrap the underlying value in a specialization in order to hide that detail +// and expose an interface via accessors. +enum NumericRepresentation { + NUMERIC_INTEGER, + NUMERIC_FLOATING, + NUMERIC_UNKNOWN +}; + +template +struct GetNumericRepresentation { + static const NumericRepresentation value = + std::numeric_limits::is_integer + ? NUMERIC_INTEGER + : (std::numeric_limits::is_iec559 ? NUMERIC_FLOATING + : NUMERIC_UNKNOWN); +}; + +template ::value> +class CheckedNumericState {}; + +// Integrals require quite a bit of additional housekeeping to manage state. +template +class CheckedNumericState { + private: + T value_; + RangeConstraint validity_; + + public: + template + friend class CheckedNumericState; + + CheckedNumericState() : value_(0), validity_(RANGE_VALID) {} + + template + CheckedNumericState(Src value, RangeConstraint validity) + : value_(value), + validity_(GetRangeConstraint(validity | + DstRangeRelationToSrcRange(value))) { + COMPILE_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 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 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 enable_if::is_specialized, int>::type = + 0) + : value_(static_cast(value)) {} + + // Copy constructor. + template + CheckedNumericState(const CheckedNumericState& rhs) + : value_(static_cast(rhs.value())) {} + + RangeConstraint validity() const { + return GetRangeConstraint(value_ <= std::numeric_limits::max(), + value_ >= -std::numeric_limits::max()); + } + T value() const { return value_; } +}; + +// For integers less than 128-bit and floats 32-bit or larger, we can distil +// C/C++ arithmetic promotions down to two simple rules: +// 1. The type with the larger maximum exponent always takes precedence. +// 2. The resulting type must be promoted to at least an int. +// The following template specializations implement that promotion logic. +enum ArithmeticPromotionCategory { + LEFT_PROMOTION, + RIGHT_PROMOTION, + DEFAULT_PROMOTION +}; + +template ::value > MaxExponent::value) + ? (MaxExponent::value > MaxExponent::value + ? LEFT_PROMOTION + : DEFAULT_PROMOTION) + : (MaxExponent::value > MaxExponent::value + ? RIGHT_PROMOTION + : DEFAULT_PROMOTION) > +struct ArithmeticPromotion; + +template +struct ArithmeticPromotion { + typedef Lhs type; +}; + +template +struct ArithmeticPromotion { + typedef Rhs type; +}; + +template +struct ArithmeticPromotion { + typedef int type; +}; + +// We can statically check if operations on the provided types can wrap, so we +// can skip the checked operations if they're not needed. So, for an integer we +// care if the destination type preserves the sign and is twice the width of +// the source. +template +struct IsIntegerArithmeticSafe { + static const bool value = !std::numeric_limits::is_iec559 && + StaticDstRangeRelationToSrcRange::value == + NUMERIC_RANGE_CONTAINED && + sizeof(T) >= (2 * sizeof(Lhs)) && + StaticDstRangeRelationToSrcRange::value != + NUMERIC_RANGE_CONTAINED && + sizeof(T) >= (2 * sizeof(Rhs)); +}; + +} // namespace internal +} // namespace base +} // namespace pdfium + +#endif // PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_ diff --git a/third_party/base/template_util.h b/third_party/base/template_util.h new file mode 100644 index 0000000000..ab660940f0 --- /dev/null +++ b/third_party/base/template_util.h @@ -0,0 +1,35 @@ +// 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 PDFIUM_THIRD_PARTY_BASE_TEMPLATE_UTIL_H_ +#define PDFIUM_THIRD_PARTY_BASE_TEMPLATE_UTIL_H_ + +#include // For size_t. + +namespace pdfium { +namespace base { + +template +struct integral_constant { + static const T value = v; + typedef T value_type; + typedef integral_constant type; +}; + +typedef integral_constant true_type; +typedef integral_constant false_type; + +template struct is_same : public false_type {}; +template struct is_same : true_type {}; + +template +struct enable_if {}; + +template +struct enable_if { typedef T type; }; + +} // namespace base +} // namespace pdfium + +#endif // PDFIUM_THIRD_PARTY_BASE_TEMPLATE_UTIL_H_ diff --git a/third_party/logging.h b/third_party/logging.h deleted file mode 100644 index 3629e84d4a..0000000000 --- a/third_party/logging.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) 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 BASE_LOGGING_H_ -#define BASE_LOGGING_H_ - -#include - -#define CHECK(condition) \ - if (!(condition)) { \ - abort(); \ - *(reinterpret_cast(NULL) + 42) = 0x42; \ - } - -#define NOTREACHED() abort() - -#endif // BASE_LOGGING_H_ diff --git a/third_party/macros.h b/third_party/macros.h deleted file mode 100644 index b1b8c10888..0000000000 --- a/third_party/macros.h +++ /dev/null @@ -1,31 +0,0 @@ -// 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. - -// This file contains macros and macro-like constructs (e.g., templates) that -// are commonly used throughout Chromium source. (It may also contain things -// that are closely related to things that are commonly used that belong in this -// file.) - -#ifndef BASE_MACROS_H_ -#define BASE_MACROS_H_ - -// The COMPILE_ASSERT macro can be used to verify that a compile time -// expression is true. For example, you could use it to verify the -// size of a static array: -// -// COMPILE_ASSERT(ARRAYSIZE_UNSAFE(content_type_names) == CONTENT_NUM_TYPES, -// content_type_names_incorrect_size); -// -// or to make sure a struct is smaller than a certain size: -// -// COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large); -// -// The second argument to the macro is the name of the variable. If -// the expression is false, most compilers will issue a warning/error -// containing the name of the variable. - -#undef COMPILE_ASSERT -#define COMPILE_ASSERT(expr, msg) static_assert(expr, #msg) - -#endif // BASE_MACROS_H_ diff --git a/third_party/numerics/OWNERS b/third_party/numerics/OWNERS deleted file mode 100644 index f7816afe81..0000000000 --- a/third_party/numerics/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -jschuh@chromium.org -tsepez@chromium.org -palmer@chromium.org diff --git a/third_party/numerics/safe_conversions.h b/third_party/numerics/safe_conversions.h deleted file mode 100644 index 681dc0a9cc..0000000000 --- a/third_party/numerics/safe_conversions.h +++ /dev/null @@ -1,64 +0,0 @@ -// 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 BASE_SAFE_CONVERSIONS_H_ -#define BASE_SAFE_CONVERSIONS_H_ - -#include - -#include "../logging.h" -#include "safe_conversions_impl.h" - -namespace base { - -// Convenience function that returns true if the supplied value is in range -// for the destination type. -template -inline bool IsValueInRangeForNumericType(Src value) { - return internal::DstRangeRelationToSrcRange(value) == - internal::RANGE_VALID; -} - -// 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); -} - -// saturated_cast<> is analogous to static_cast<> for numeric types, except -// that the specified numeric conversion will saturate rather than overflow or -// underflow. NaN assignment to an integral will trigger a CHECK condition. -template -inline Dst saturated_cast(Src value) { - // Optimization for floating point values, which already saturate. - if (std::numeric_limits::is_iec559) - return static_cast(value); - - switch (internal::DstRangeRelationToSrcRange(value)) { - case internal::RANGE_VALID: - return static_cast(value); - - case internal::RANGE_UNDERFLOW: - return std::numeric_limits::min(); - - case internal::RANGE_OVERFLOW: - return std::numeric_limits::max(); - - // Should fail only on attempting to assign NaN to a saturated integer. - case internal::RANGE_INVALID: - CHECK(false); - return std::numeric_limits::max(); - } - - NOTREACHED(); - return static_cast(value); -} - -} // namespace base - -#endif // BASE_SAFE_CONVERSIONS_H_ - diff --git a/third_party/numerics/safe_conversions_impl.h b/third_party/numerics/safe_conversions_impl.h deleted file mode 100644 index a357e518d1..0000000000 --- a/third_party/numerics/safe_conversions_impl.h +++ /dev/null @@ -1,217 +0,0 @@ -// 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 BASE_SAFE_CONVERSIONS_IMPL_H_ -#define BASE_SAFE_CONVERSIONS_IMPL_H_ - -#include - -#include "../macros.h" -#include "../template_util.h" - -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 const int value = std::numeric_limits::is_iec559 - ? std::numeric_limits::max_exponent - : (sizeof(NumericType) * 8 + 1 - - std::numeric_limits::is_signed); -}; - -enum IntegerRepresentation { - INTEGER_REPRESENTATION_UNSIGNED, - INTEGER_REPRESENTATION_SIGNED -}; - -// A range for a given nunmeric Src type is contained for a given numeric Dst -// type if both numeric_limits::max() <= numeric_limits::max() and -// numeric_limits::min() >= numeric_limits::min() are true. -// We implement this as template specializations rather than simple static -// comparisons to ensure type correctness in our comparisons. -enum NumericRangeRepresentation { - NUMERIC_RANGE_NOT_CONTAINED, - NUMERIC_RANGE_CONTAINED -}; - -// Helper templates to statically determine if our destination type can contain -// maximum and minimum values represented by the source type. - -template < - typename Dst, - typename Src, - IntegerRepresentation DstSign = std::numeric_limits::is_signed - ? INTEGER_REPRESENTATION_SIGNED - : INTEGER_REPRESENTATION_UNSIGNED, - IntegerRepresentation SrcSign = - std::numeric_limits::is_signed - ? INTEGER_REPRESENTATION_SIGNED - : INTEGER_REPRESENTATION_UNSIGNED > -struct StaticDstRangeRelationToSrcRange; - -// Same sign: Dst is guaranteed to contain Src only if its range is equal or -// larger. -template -struct StaticDstRangeRelationToSrcRange { - static const NumericRangeRepresentation value = - MaxExponent::value >= MaxExponent::value - ? NUMERIC_RANGE_CONTAINED - : NUMERIC_RANGE_NOT_CONTAINED; -}; - -// Unsigned to signed: Dst is guaranteed to contain source only if its range is -// larger. -template -struct StaticDstRangeRelationToSrcRange { - static const NumericRangeRepresentation value = - MaxExponent::value > MaxExponent::value - ? NUMERIC_RANGE_CONTAINED - : NUMERIC_RANGE_NOT_CONTAINED; -}; - -// Signed to unsigned: Dst cannot be statically determined to contain Src. -template -struct StaticDstRangeRelationToSrcRange { - static const NumericRangeRepresentation value = NUMERIC_RANGE_NOT_CONTAINED; -}; - -enum RangeConstraint { - RANGE_VALID = 0x0, // Value can be represented by the destination type. - RANGE_UNDERFLOW = 0x1, // Value would overflow. - RANGE_OVERFLOW = 0x2, // Value would underflow. - RANGE_INVALID = RANGE_UNDERFLOW | RANGE_OVERFLOW // Invalid (i.e. NaN). -}; - -// Helper function for coercing an int back to a RangeContraint. -inline RangeConstraint GetRangeConstraint(int integer_range_constraint) { - 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. -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)); -} - -template < - typename Dst, - typename Src, - IntegerRepresentation DstSign = std::numeric_limits::is_signed - ? INTEGER_REPRESENTATION_SIGNED - : INTEGER_REPRESENTATION_UNSIGNED, - IntegerRepresentation SrcSign = std::numeric_limits::is_signed - ? INTEGER_REPRESENTATION_SIGNED - : INTEGER_REPRESENTATION_UNSIGNED, - NumericRangeRepresentation DstRange = - StaticDstRangeRelationToSrcRange::value > -struct DstRangeRelationToSrcRangeImpl; - -// The following templates are for ranges that must be verified at runtime. We -// split it into checks based on signedness to avoid confusing casts and -// compiler warnings on signed an unsigned comparisons. - -// Dst range is statically determined to contain Src: Nothing to check. -template -struct DstRangeRelationToSrcRangeImpl { - static RangeConstraint Check(Src value) { return RANGE_VALID; } -}; - -// Signed to signed narrowing: Both the upper and lower boundaries may be -// exceeded. -template -struct DstRangeRelationToSrcRangeImpl { - static RangeConstraint Check(Src value) { - return std::numeric_limits::is_iec559 - ? GetRangeConstraint(value <= std::numeric_limits::max(), - value >= -std::numeric_limits::max()) - : GetRangeConstraint(value <= std::numeric_limits::max(), - value >= std::numeric_limits::min()); - } -}; - -// Unsigned to unsigned narrowing: Only the upper boundary can be exceeded. -template -struct DstRangeRelationToSrcRangeImpl { - static RangeConstraint Check(Src value) { - return GetRangeConstraint(value <= std::numeric_limits::max(), true); - } -}; - -// Unsigned to signed: The upper boundary may be exceeded. -template -struct DstRangeRelationToSrcRangeImpl { - static RangeConstraint Check(Src value) { - return sizeof(Dst) > sizeof(Src) - ? RANGE_VALID - : GetRangeConstraint( - value <= static_cast(std::numeric_limits::max()), - true); - } -}; - -// Signed to unsigned: The upper boundary may be exceeded for a narrower Dst, -// and any negative value exceeds the lower boundary. -template -struct DstRangeRelationToSrcRangeImpl { - static RangeConstraint Check(Src value) { - return (MaxExponent::value >= MaxExponent::value) - ? GetRangeConstraint(true, value >= static_cast(0)) - : GetRangeConstraint( - value <= static_cast(std::numeric_limits::max()), - value >= static_cast(0)); - } -}; - -template -inline RangeConstraint DstRangeRelationToSrcRange(Src value) { - COMPILE_ASSERT(std::numeric_limits::is_specialized, - argument_must_be_numeric); - COMPILE_ASSERT(std::numeric_limits::is_specialized, - result_must_be_numeric); - return DstRangeRelationToSrcRangeImpl::Check(value); -} - -} // namespace internal -} // namespace base - -#endif // BASE_SAFE_CONVERSIONS_IMPL_H_ - diff --git a/third_party/numerics/safe_math.h b/third_party/numerics/safe_math.h deleted file mode 100644 index 4b38ff2b1f..0000000000 --- a/third_party/numerics/safe_math.h +++ /dev/null @@ -1,271 +0,0 @@ -// 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 BASE_SAFE_MATH_H_ -#define BASE_SAFE_MATH_H_ - -#include "safe_math_impl.h" - -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; -// CheckedNumeric checked_size = untrusted_input_value; -// checked_size = checked_size + HEADER LENGTH; -// if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size) -// Do stuff... -template -class CheckedNumeric { - public: - typedef T type; - - CheckedNumeric() {} - - // Copy constructor. - template - CheckedNumeric(const CheckedNumeric& rhs) - : state_(rhs.ValueUnsafe(), rhs.validity()) {} - - template - CheckedNumeric(Src value, RangeConstraint validity) - : state_(value, validity) {} - - // This is not an explicit constructor because we implicitly upgrade regular - // numerics to CheckedNumerics to make them easier to use. - template - CheckedNumeric(Src value) - : state_(value) { - COMPILE_ASSERT(std::numeric_limits::is_specialized, - argument_must_be_numeric); - } - - // 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 { - COMPILE_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); - } - - 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 enable_if::is_specialized, int>::type = - 0) { - return u; - } - - template - static CheckedNumeric cast( - const CheckedNumeric& u, - typename enable_if::value, int>::type = 0) { - return u; - } - - static const CheckedNumeric& cast(const CheckedNumeric& u) { return u; } - - private: - CheckedNumericState state_; -}; - -// This is the boilerplate for the standard arithmetic operator overloads. A -// macro isn't the prettiest solution, but it beats rewriting these five times. -// Some details worth noting are: -// * We apply the standard arithmetic promotions. -// * We skip range checks for floating points. -// * We skip range checks for destination integers with sufficient range. -// TODO(jschuh): extract these out into templates. -#define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP) \ - /* Binary arithmetic operator for CheckedNumerics of the same type. */ \ - template \ - CheckedNumeric::type> operator OP( \ - const CheckedNumeric& lhs, const CheckedNumeric& rhs) { \ - typedef typename ArithmeticPromotion::type Promotion; \ - /* Floating point always takes the fast path */ \ - if (std::numeric_limits::is_iec559) \ - return CheckedNumeric(lhs.ValueUnsafe() OP rhs.ValueUnsafe()); \ - if (IsIntegerArithmeticSafe::value) \ - return CheckedNumeric( \ - lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \ - GetRangeConstraint(rhs.validity() | lhs.validity())); \ - RangeConstraint validity = RANGE_VALID; \ - T result = 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::cast(rhs); \ - return *this; \ - } \ - /* Binary arithmetic operator for CheckedNumeric of different type. */ \ - template \ - CheckedNumeric::type> operator OP( \ - const CheckedNumeric& lhs, const CheckedNumeric& rhs) { \ - typedef typename ArithmeticPromotion::type Promotion; \ - if (IsIntegerArithmeticSafe::value) \ - return CheckedNumeric( \ - lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \ - GetRangeConstraint(rhs.validity() | lhs.validity())); \ - return CheckedNumeric::cast(lhs) \ - OP CheckedNumeric::cast(rhs); \ - } \ - /* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \ - template \ - CheckedNumeric::type> operator OP( \ - const CheckedNumeric& lhs, Src rhs) { \ - typedef typename ArithmeticPromotion::type Promotion; \ - if (IsIntegerArithmeticSafe::value) \ - return CheckedNumeric(lhs.ValueUnsafe() OP rhs, \ - lhs.validity()); \ - return CheckedNumeric::cast(lhs) \ - OP CheckedNumeric::cast(rhs); \ - } \ - /* Binary arithmetic operator for right numeric and left CheckedNumeric. */ \ - template \ - CheckedNumeric::type> operator OP( \ - Src lhs, const CheckedNumeric& rhs) { \ - typedef typename ArithmeticPromotion::type Promotion; \ - if (IsIntegerArithmeticSafe::value) \ - return CheckedNumeric(lhs OP rhs.ValueUnsafe(), \ - rhs.validity()); \ - return CheckedNumeric::cast(lhs) \ - OP CheckedNumeric::cast(rhs); \ - } - -BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, += ) -BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -= ) -BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *= ) -BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /= ) -BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %= ) - -#undef BASE_NUMERIC_ARITHMETIC_OPERATORS - -} // namespace internal - -using internal::CheckedNumeric; - -} // namespace base - -#endif // BASE_SAFE_MATH_H_ diff --git a/third_party/numerics/safe_math_impl.h b/third_party/numerics/safe_math_impl.h deleted file mode 100644 index 4bf59e64e0..0000000000 --- a/third_party/numerics/safe_math_impl.h +++ /dev/null @@ -1,502 +0,0 @@ -// 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 SAFE_MATH_IMPL_H_ -#define SAFE_MATH_IMPL_H_ - -#include - -#include -#include -#include - -#include "../macros.h" -#include "../template_util.h" -#include "safe_conversions.h" - -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 enable_if< - std::numeric_limits::is_integer, - typename IntegerForSizeAndSign::type>::type type; -}; - -template -struct SignedIntegerForSize { - typedef typename enable_if< - std::numeric_limits::is_integer, - typename IntegerForSizeAndSign::type>::type type; -}; - -template -struct TwiceWiderInteger { - typedef typename enable_if< - std::numeric_limits::is_integer, - typename IntegerForSizeAndSign< - sizeof(Integer) * 2, - std::numeric_limits::is_signed>::type>::type type; -}; - -template -struct PositionOfSignBit { - static const typename enable_if::is_integer, - size_t>::type value = 8 * sizeof(Integer) - 1; -}; - -// Helper templates for integer manipulations. - -template -bool HasSignBit(T x) { - // Cast to unsigned since right shift on signed is undefined. - return !!(static_cast::type>(x) >> - PositionOfSignBit::value); -} - -// This wrapper undoes the standard integer promotions. -template -T BinaryComplement(T x) { - return ~x; -} - -// Here are the actual portable checked integer math implementations. -// TODO(jschuh): Break this code out from the enable_if pattern and find a clean -// way to coalesce things into the CheckedNumericState specializations below. - -template -typename enable_if::is_integer, T>::type -CheckedAdd(T x, T y, RangeConstraint* validity) { - // Since the value of x+y is undefined if we have a signed type, we compute - // it using the unsigned type of the same size. - typedef typename UnsignedIntegerForSize::type UnsignedDst; - UnsignedDst ux = static_cast(x); - UnsignedDst uy = static_cast(y); - UnsignedDst uresult = ux + uy; - // Addition is valid if the sign of (x + y) is equal to either that of x or - // that of y. - if (std::numeric_limits::is_signed) { - if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy)))) - *validity = RANGE_VALID; - else // Direction of wrap is inverse of result sign. - *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; - - } else { // Unsigned is either valid or overflow. - *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW; - } - return static_cast(uresult); -} - -template -typename enable_if::is_integer, T>::type -CheckedSub(T x, T y, RangeConstraint* validity) { - // Since the value of x+y is undefined if we have a signed type, we compute - // it using the unsigned type of the same size. - typedef typename UnsignedIntegerForSize::type UnsignedDst; - UnsignedDst ux = static_cast(x); - UnsignedDst uy = static_cast(y); - UnsignedDst uresult = ux - uy; - // Subtraction is valid if either x and y have same sign, or (x-y) and x have - // the same sign. - if (std::numeric_limits::is_signed) { - if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy)))) - *validity = RANGE_VALID; - else // Direction of wrap is inverse of result sign. - *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; - - } else { // Unsigned is either valid or underflow. - *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW; - } - return static_cast(uresult); -} - -// Integer multiplication is a bit complicated. In the fast case we just -// we just promote to a twice wider type, and range check the result. In the -// slow case we need to manually check that the result won't be truncated by -// checking with division against the appropriate bound. -template -typename enable_if< - std::numeric_limits::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 enable_if::is_integer&& std::numeric_limits< - T>::is_signed&&(sizeof(T) * 2 > sizeof(uintmax_t)), - T>::type -CheckedMul(T x, T y, RangeConstraint* validity) { - // if either side is zero then the result will be zero. - if (!(x || y)) { - return RANGE_VALID; - - } else if (x > 0) { - if (y > 0) - *validity = - x <= std::numeric_limits::max() / y ? RANGE_VALID : RANGE_OVERFLOW; - else - *validity = y >= std::numeric_limits::min() / x ? RANGE_VALID - : RANGE_UNDERFLOW; - - } else { - if (y > 0) - *validity = x >= std::numeric_limits::min() / y ? RANGE_VALID - : RANGE_UNDERFLOW; - else - *validity = - y >= std::numeric_limits::max() / x ? RANGE_VALID : RANGE_OVERFLOW; - } - - return x * y; -} - -template -typename enable_if::is_integer && - !std::numeric_limits::is_signed && - (sizeof(T) * 2 > sizeof(uintmax_t)), - T>::type -CheckedMul(T x, T y, RangeConstraint* validity) { - *validity = (y == 0 || x <= std::numeric_limits::max() / y) - ? RANGE_VALID - : RANGE_OVERFLOW; - return x * y; -} - -// Division just requires a check for an invalid negation on signed min/-1. -template -T CheckedDiv( - T x, - T y, - RangeConstraint* validity, - typename enable_if::is_integer, int>::type = 0) { - if (std::numeric_limits::is_signed && x == std::numeric_limits::min() && - y == static_cast(-1)) { - *validity = RANGE_OVERFLOW; - return std::numeric_limits::min(); - } - - *validity = RANGE_VALID; - return x / y; -} - -template -typename enable_if< - std::numeric_limits::is_integer&& std::numeric_limits::is_signed, - T>::type -CheckedMod(T x, T y, RangeConstraint* validity) { - *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; - return x % y; -} - -template -typename enable_if< - std::numeric_limits::is_integer && !std::numeric_limits::is_signed, - T>::type -CheckedMod(T x, T y, RangeConstraint* validity) { - *validity = RANGE_VALID; - return x % y; -} - -template -typename enable_if< - std::numeric_limits::is_integer&& std::numeric_limits::is_signed, - T>::type -CheckedNeg(T value, RangeConstraint* validity) { - *validity = - value != std::numeric_limits::min() ? RANGE_VALID : RANGE_OVERFLOW; - // The negation of signed min is min, so catch that one. - return -value; -} - -template -typename enable_if< - std::numeric_limits::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 enable_if< - std::numeric_limits::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 std::abs(value); -} - -template -typename enable_if< - std::numeric_limits::is_integer && !std::numeric_limits::is_signed, - T>::type -CheckedAbs(T value, RangeConstraint* validity) { - // Absolute value of a positive is just its identiy. - *validity = RANGE_VALID; - return value; -} - -// These are the floating point stubs that the compiler needs to see. Only the -// negation operation is ever called. -#define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ - template \ - typename enable_if::is_iec559, T>::type \ - Checked##NAME(T, T, RangeConstraint*) { \ - NOTREACHED(); \ - return 0; \ - } - -BASE_FLOAT_ARITHMETIC_STUBS(Add) -BASE_FLOAT_ARITHMETIC_STUBS(Sub) -BASE_FLOAT_ARITHMETIC_STUBS(Mul) -BASE_FLOAT_ARITHMETIC_STUBS(Div) -BASE_FLOAT_ARITHMETIC_STUBS(Mod) - -#undef BASE_FLOAT_ARITHMETIC_STUBS - -template -typename enable_if::is_iec559, T>::type CheckedNeg( - T value, - RangeConstraint*) { - return -value; -} - -template -typename enable_if::is_iec559, T>::type CheckedAbs( - T value, - RangeConstraint*) { - return std::abs(value); -} - -// Floats carry around their validity state with them, but integers do not. So, -// we wrap the underlying value in a specialization in order to hide that detail -// and expose an interface via accessors. -enum NumericRepresentation { - NUMERIC_INTEGER, - NUMERIC_FLOATING, - NUMERIC_UNKNOWN -}; - -template -struct GetNumericRepresentation { - static const NumericRepresentation value = - std::numeric_limits::is_integer - ? NUMERIC_INTEGER - : (std::numeric_limits::is_iec559 ? NUMERIC_FLOATING - : NUMERIC_UNKNOWN); -}; - -template ::value> -class CheckedNumericState {}; - -// Integrals require quite a bit of additional housekeeping to manage state. -template -class CheckedNumericState { - private: - T value_; - RangeConstraint validity_; - - public: - template - friend class CheckedNumericState; - - CheckedNumericState() : value_(0), validity_(RANGE_VALID) {} - - template - CheckedNumericState(Src value, RangeConstraint validity) - : value_(value), - validity_(GetRangeConstraint(validity | - DstRangeRelationToSrcRange(value))) { - COMPILE_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 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 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 enable_if::is_specialized, int>::type = - 0) - : value_(static_cast(value)) {} - - // Copy constructor. - template - CheckedNumericState(const CheckedNumericState& rhs) - : value_(static_cast(rhs.value())) {} - - RangeConstraint validity() const { - return GetRangeConstraint(value_ <= std::numeric_limits::max(), - value_ >= -std::numeric_limits::max()); - } - T value() const { return value_; } -}; - -// For integers less than 128-bit and floats 32-bit or larger, we can distil -// C/C++ arithmetic promotions down to two simple rules: -// 1. The type with the larger maximum exponent always takes precedence. -// 2. The resulting type must be promoted to at least an int. -// The following template specializations implement that promotion logic. -enum ArithmeticPromotionCategory { - LEFT_PROMOTION, - RIGHT_PROMOTION, - DEFAULT_PROMOTION -}; - -template ::value > MaxExponent::value) - ? (MaxExponent::value > MaxExponent::value - ? LEFT_PROMOTION - : DEFAULT_PROMOTION) - : (MaxExponent::value > MaxExponent::value - ? RIGHT_PROMOTION - : DEFAULT_PROMOTION) > -struct ArithmeticPromotion; - -template -struct ArithmeticPromotion { - typedef Lhs type; -}; - -template -struct ArithmeticPromotion { - typedef Rhs type; -}; - -template -struct ArithmeticPromotion { - typedef int type; -}; - -// We can statically check if operations on the provided types can wrap, so we -// can skip the checked operations if they're not needed. So, for an integer we -// care if the destination type preserves the sign and is twice the width of -// the source. -template -struct IsIntegerArithmeticSafe { - static const bool value = !std::numeric_limits::is_iec559 && - StaticDstRangeRelationToSrcRange::value == - NUMERIC_RANGE_CONTAINED && - sizeof(T) >= (2 * sizeof(Lhs)) && - StaticDstRangeRelationToSrcRange::value != - NUMERIC_RANGE_CONTAINED && - sizeof(T) >= (2 * sizeof(Rhs)); -}; - -} // namespace internal -} // namespace base - -#endif // SAFE_MATH_IMPL_H_ diff --git a/third_party/template_util.h b/third_party/template_util.h deleted file mode 100644 index d4508dd696..0000000000 --- a/third_party/template_util.h +++ /dev/null @@ -1,33 +0,0 @@ -// 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 BASE_TEMPLATE_UTIL_H_ -#define BASE_TEMPLATE_UTIL_H_ - -#include // For size_t. - -namespace base { - -template -struct integral_constant { - static const T value = v; - typedef T value_type; - typedef integral_constant type; -}; - -typedef integral_constant true_type; -typedef integral_constant false_type; - -template struct is_same : public false_type {}; -template struct is_same : true_type {}; - -template -struct enable_if {}; - -template -struct enable_if { typedef T type; }; - -} // namespace base - -#endif // BASE_TEMPLATE_UTIL_H_ diff --git a/third_party/third_party.gyp b/third_party/third_party.gyp index ac7fb7792a..d54905c022 100644 --- a/third_party/third_party.gyp +++ b/third_party/third_party.gyp @@ -61,16 +61,16 @@ ], }, { - 'target_name': 'safemath', + 'target_name': 'pdfium_base', 'type': 'none', 'sources': [ - 'logging.h', - 'macros.h', - 'template_util.h', - 'numerics/safe_conversions.h', - 'numerics/safe_conversions_impl.h', - 'numerics/safe_math.h', - 'numerics/safe_math_impl.h', + 'base/logging.h', + 'base/macros.h', + 'base/template_util.h', + 'base/numerics/safe_conversions.h', + 'base/numerics/safe_conversions_impl.h', + 'base/numerics/safe_math.h', + 'base/numerics/safe_math_impl.h', ], }, ], -- cgit v1.2.3