Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(312)

Unified Diff: third_party/WebKit/Source/core/xml/XPathFunctions.cpp

Issue 2424453002: Handle overflow, underflow in XPath substring position, length. (Closed)
Patch Set: Address nit. Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/xml/XPathFunctions.cpp
diff --git a/third_party/WebKit/Source/core/xml/XPathFunctions.cpp b/third_party/WebKit/Source/core/xml/XPathFunctions.cpp
index 8fe6c2a563024496d1667ab559ea5a7ff1642203..90f18471351ac9406a19af49712317a06370a21f 100644
--- a/third_party/WebKit/Source/core/xml/XPathFunctions.cpp
+++ b/third_party/WebKit/Source/core/xml/XPathFunctions.cpp
@@ -37,6 +37,9 @@
#include "wtf/MathExtras.h"
#include "wtf/text/StringBuilder.h"
+#include <algorithm>
+#include <limits>
+
namespace blink {
namespace XPath {
@@ -530,34 +533,47 @@ Value FunSubstringAfter::evaluate(EvaluationContext& context) const {
return s1.substring(i + s2.length());
}
+// Returns |value| clamped to the range [lo, hi].
+// TODO(dominicc): Replace with std::clamp when C++17 is allowed
+// per <https://chromium-cpp.appspot.com/>
+static double clamp(const double value, const double lo, const double hi) {
+ return std::min(hi, std::max(lo, value));
+}
+
+// Computes the 1-based start and end (exclusive) string indices for
+// substring. This is all the positions [1, maxLen (inclusive)] where
+// start <= position < start + len
+static std::pair<unsigned, unsigned> computeSubstringStartEnd(double start,
+ double len,
+ double maxLen) {
+ DCHECK(std::isfinite(maxLen));
+ const double end = start + len;
+ if (std::isnan(start) || std::isnan(end))
+ return std::make_pair(1, 1);
+ // Neither start nor end are NaN, but may still be +/- Inf
+ const double clampedStart = clamp(start, 1, maxLen + 1);
+ const double clampedEnd = clamp(end, clampedStart, maxLen + 1);
+ return std::make_pair(static_cast<unsigned>(clampedStart),
+ static_cast<unsigned>(clampedEnd));
+}
+
+// substring(string, number pos, number? len)
+//
+// Characters in string are indexed from 1. Numbers are doubles and
+// substring is specified to work with IEEE-754 infinity, NaN, and
+// XPath's bespoke rounding function, round.
+//
+// <https://www.w3.org/TR/xpath/#function-substring>
Value FunSubstring::evaluate(EvaluationContext& context) const {
- String s = arg(0)->evaluate(context).toString();
- double doublePos = arg(1)->evaluate(context).toNumber();
- if (std::isnan(doublePos))
- return "";
- long pos = static_cast<long>(FunRound::round(doublePos));
- bool haveLength = argCount() == 3;
- long len = -1;
- if (haveLength) {
- double doubleLen = arg(2)->evaluate(context).toNumber();
- if (std::isnan(doubleLen))
- return "";
- len = static_cast<long>(FunRound::round(doubleLen));
- }
-
- if (pos > long(s.length()))
+ String sourceString = arg(0)->evaluate(context).toString();
+ const double pos = FunRound::round(arg(1)->evaluate(context).toNumber());
+ const double len = argCount() == 3
+ ? FunRound::round(arg(2)->evaluate(context).toNumber())
+ : std::numeric_limits<double>::infinity();
+ const auto bounds = computeSubstringStartEnd(pos, len, sourceString.length());
+ if (bounds.second <= bounds.first)
return "";
-
- if (pos < 1) {
- if (haveLength) {
- len -= 1 - pos;
- if (len < 1)
- return "";
- }
- pos = 1;
- }
-
- return s.substring(pos - 1, len);
+ return sourceString.substring(bounds.first - 1, bounds.second - bounds.first);
}
Value FunStringLength::evaluate(EvaluationContext& context) const {
« no previous file with comments | « third_party/WebKit/Source/core/xml/XPathFunctions.h ('k') | third_party/WebKit/Source/core/xml/XPathFunctionsTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698