Make core/fxcrt/css compile under nounsafe_buffer_usage. Change-Id: Ib7bc494cc688b077de12e2d6056cc51162c73c05 Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/117030 Reviewed-by: Lei Zhang <thestig@chromium.org> Commit-Queue: Tom Sepez <tsepez@chromium.org> Reviewed-by: Thomas Sepez <tsepez@google.com>
diff --git a/core/fxcrt/css/BUILD.gn b/core/fxcrt/css/BUILD.gn index cd138b6..3482f71 100644 --- a/core/fxcrt/css/BUILD.gn +++ b/core/fxcrt/css/BUILD.gn
@@ -54,6 +54,7 @@ configs += [ "../../../:pdfium_strict_config", "../../../:pdfium_noshorten_config", + "../../../:pdfium_nounsafe_buffer_usage_config", ] deps = [ "../",
diff --git a/core/fxcrt/css/cfx_cssdata.cpp b/core/fxcrt/css/cfx_cssdata.cpp index 40aacf3..99c3e60 100644 --- a/core/fxcrt/css/cfx_cssdata.cpp +++ b/core/fxcrt/css/cfx_cssdata.cpp
@@ -9,6 +9,8 @@ #include <algorithm> #include <utility> +#include "core/fxcrt/check_op.h" +#include "core/fxcrt/compiler_specific.h" #include "core/fxcrt/css/cfx_cssstyleselector.h" #include "core/fxcrt/css/cfx_cssvaluelistparser.h" #include "core/fxcrt/fx_codepage.h" @@ -73,7 +75,10 @@ const CFX_CSSData::Property* CFX_CSSData::GetPropertyByEnum( CFX_CSSProperty property) { - return &kPropertyTable[static_cast<uint8_t>(property)]; + auto index = static_cast<size_t>(property); + CHECK_LT(index, std::size(kPropertyTable)); + // SAFETY: CHECK() on previous line ensures index is in bounds. + return UNSAFE_BUFFERS(&kPropertyTable[index]); } const CFX_CSSData::PropertyValue* CFX_CSSData::GetPropertyValueByName( @@ -102,13 +107,12 @@ WideString lowerName = WideString(wsName); lowerName.MakeLower(); - for (auto* iter = std::begin(kLengthUnitTable); - iter != std::end(kLengthUnitTable); ++iter) { - if (lowerName == iter->value) - return iter; - } - - return nullptr; + auto* iter = + std::find_if(std::begin(kLengthUnitTable), std::end(kLengthUnitTable), + [lowerName](const CFX_CSSData::LengthUnit& unit) { + return lowerName == unit.value; + }); + return iter != std::end(kLengthUnitTable) ? iter : nullptr; } const CFX_CSSData::Color* CFX_CSSData::GetColorByName(WideStringView wsName) { @@ -118,10 +122,9 @@ WideString lowerName = WideString(wsName); lowerName.MakeLower(); - for (auto* iter = std::begin(kColorTable); iter != std::end(kColorTable); - ++iter) { - if (lowerName == iter->name) - return iter; - } - return nullptr; + auto* iter = std::find_if(std::begin(kColorTable), std::end(kColorTable), + [lowerName](const CFX_CSSData::Color& color) { + return lowerName == color.name; + }); + return iter != std::end(kColorTable) ? iter : nullptr; }
diff --git a/core/fxcrt/css/cfx_cssdeclaration.cpp b/core/fxcrt/css/cfx_cssdeclaration.cpp index 87aee28..3e4f67a 100644 --- a/core/fxcrt/css/cfx_cssdeclaration.cpp +++ b/core/fxcrt/css/cfx_cssdeclaration.cpp
@@ -8,6 +8,7 @@ #include <math.h> +#include <array> #include <utility> #include "core/fxcrt/check.h" @@ -96,9 +97,9 @@ if (!value.First(4).EqualsASCIINoCase("rgb(") || value.Back() != ')') { return std::nullopt; } - uint8_t rgb[3] = {0}; + std::array<uint8_t, 3> rgb = {}; CFX_CSSValueListParser list(value.Substr(4, value.GetLength() - 5), ','); - for (int32_t i = 0; i < 3; ++i) { + for (auto& component : rgb) { auto maybe_value = list.NextValue(); if (!maybe_value.has_value() || maybe_value.value().type != CFX_CSSValue::PrimitiveType::kNumber) { @@ -108,9 +109,9 @@ if (!maybe_number.has_value()) { return std::nullopt; } - rgb[i] = maybe_number.value().unit == CFX_CSSNumber::Unit::kPercent - ? FXSYS_roundf(maybe_number.value().value * 2.55f) - : FXSYS_roundf(maybe_number.value().value); + component = maybe_number.value().unit == CFX_CSSNumber::Unit::kPercent + ? FXSYS_roundf(maybe_number.value().value * 2.55f) + : FXSYS_roundf(maybe_number.value().value); } return ArgbEncode(255, rgb[0], rgb[1], rgb[2]); }
diff --git a/core/fxcrt/css/cfx_cssvaluelistparser.cpp b/core/fxcrt/css/cfx_cssvaluelistparser.cpp index ac5471e..4fcd7be 100644 --- a/core/fxcrt/css/cfx_cssvaluelistparser.cpp +++ b/core/fxcrt/css/cfx_cssvaluelistparser.cpp
@@ -8,29 +8,31 @@ #include "core/fxcrt/check.h" #include "core/fxcrt/check_op.h" +#include "core/fxcrt/compiler_specific.h" #include "core/fxcrt/fx_extension.h" #include "core/fxcrt/fx_system.h" CFX_CSSValueListParser::CFX_CSSValueListParser(WideStringView list, wchar_t separator) - : m_Separator(separator), - m_pCur(list.unterminated_c_str()), - m_pEnd(list.unterminated_c_str() + list.GetLength()) { - DCHECK_NE(m_pCur, m_pEnd); + : m_Cur(list), m_Separator(separator) { + DCHECK(CharsRemain()); } +CFX_CSSValueListParser::~CFX_CSSValueListParser() = default; + std::optional<CFX_CSSValueListParser::Result> CFX_CSSValueListParser::NextValue() { - while (m_pCur < m_pEnd && (*m_pCur <= ' ' || *m_pCur == m_Separator)) { - ++m_pCur; + while (CharsRemain() && + (CurrentChar() <= ' ' || CurrentChar() == m_Separator)) { + Advance(); } - if (m_pCur >= m_pEnd) { + if (!CharsRemain()) { return std::nullopt; } auto eType = CFX_CSSValue::PrimitiveType::kUnknown; - const wchar_t* pStart = m_pCur; + WideStringView start = m_Cur; size_t nLength = 0; - wchar_t wch = *m_pCur; + wchar_t wch = CurrentChar(); if (wch == '#') { nLength = SkipToChar(' '); if (nLength == 4 || nLength == 7) { @@ -38,57 +40,63 @@ } } else if (FXSYS_IsDecimalDigit(wch) || wch == '.' || wch == '-' || wch == '+') { - while (m_pCur < m_pEnd && (*m_pCur > ' ' && *m_pCur != m_Separator)) { - ++m_pCur; + while (CharsRemain() && + (CurrentChar() > ' ' && CurrentChar() != m_Separator)) { + ++nLength; + Advance(); } - nLength = m_pCur - pStart; eType = CFX_CSSValue::PrimitiveType::kNumber; } else if (wch == '\"' || wch == '\'') { - ++pStart; - ++m_pCur; + start = start.Substr(1); + Advance(); nLength = SkipToChar(wch); - ++m_pCur; + Advance(); eType = CFX_CSSValue::PrimitiveType::kString; - } else if (m_pEnd - m_pCur > 5 && m_pCur[3] == '(') { - if (FXSYS_wcsnicmp(L"rgb", m_pCur, 3) == 0) { - nLength = SkipToChar(')') + 1; - ++m_pCur; - eType = CFX_CSSValue::PrimitiveType::kRGB; - } + } else if (m_Cur.First(4).EqualsASCIINoCase( + "rgb(")) { // First() always safe. + nLength = SkipToChar(')') + 1; + Advance(); + eType = CFX_CSSValue::PrimitiveType::kRGB; } else { nLength = SkipToCharMatchingParens(m_Separator); eType = CFX_CSSValue::PrimitiveType::kString; } - if (m_pCur <= m_pEnd && nLength > 0) { - return Result{eType, WideStringView(pStart, nLength)}; + if (nLength == 0) { + return std::nullopt; } - return std::nullopt; + return Result{eType, start.First(nLength)}; } size_t CFX_CSSValueListParser::SkipToChar(wchar_t wch) { - const wchar_t* pStart = m_pCur; - while (m_pCur < m_pEnd && *m_pCur != wch) { - m_pCur++; + size_t count = 0; + while (CharsRemain() && CurrentChar() != wch) { + Advance(); + ++count; } - return m_pCur - pStart; + return count; } size_t CFX_CSSValueListParser::SkipToCharMatchingParens(wchar_t wch) { - const wchar_t* pStart = m_pCur; + size_t nLength = 0; int64_t bracketCount = 0; - while (m_pCur < m_pEnd && *m_pCur != wch) { - if (*m_pCur <= ' ') + while (CharsRemain() && CurrentChar() != wch) { + if (CurrentChar() <= ' ') { break; - if (*m_pCur == '(') + } + if (CurrentChar() == '(') { bracketCount++; - else if (*m_pCur == ')') + } else if (CurrentChar() == ')') { bracketCount--; - m_pCur++; + } + ++nLength; + Advance(); } - while (bracketCount > 0 && m_pCur < m_pEnd) { - if (*m_pCur == ')') + while (bracketCount > 0 && CharsRemain()) { + if (CurrentChar() == ')') { bracketCount--; - m_pCur++; + } + ++nLength; + Advance(); } - return m_pCur - pStart; + return nLength; }
diff --git a/core/fxcrt/css/cfx_cssvaluelistparser.h b/core/fxcrt/css/cfx_cssvaluelistparser.h index e6deb88..2673520 100644 --- a/core/fxcrt/css/cfx_cssvaluelistparser.h +++ b/core/fxcrt/css/cfx_cssvaluelistparser.h
@@ -22,17 +22,25 @@ }; CFX_CSSValueListParser(WideStringView list, wchar_t separator); + ~CFX_CSSValueListParser(); std::optional<Result> NextValue(); void UseCommaSeparator() { m_Separator = ','; } private: + bool CharsRemain() const { return !m_Cur.IsEmpty(); } + + // Safe to call even when input exhausted, stays unchanged. + void Advance() { m_Cur = m_Cur.Substr(1); } + + // Safe to call even when input exhausted, returns NUL. + wchar_t CurrentChar() const { return static_cast<wchar_t>(m_Cur.Front()); } + size_t SkipToChar(wchar_t wch); size_t SkipToCharMatchingParens(wchar_t wch); + WideStringView m_Cur; wchar_t m_Separator; - const wchar_t* m_pCur; - const wchar_t* m_pEnd; }; #endif // CORE_FXCRT_CSS_CFX_CSSVALUELISTPARSER_H_