summaryrefslogtreecommitdiff
path: root/absl/algorithm/container.h
diff options
context:
space:
mode:
authorGravatar Derek Mauro <761129+derekmauro@users.noreply.github.com>2020-10-09 14:48:48 -0400
committerGravatar GitHub <noreply@github.com>2020-10-09 14:48:48 -0400
commitf1dad1e9b277066d676034d8f2a982b9e64310de (patch)
treec3fe5c74b1e8800491709b4ad9492e600fd51bf9 /absl/algorithm/container.h
parentc51510d1d87ebce8615ae1752fd5aca912f6cf4c (diff)
Adds bounds-checking to the second range of absl container algorithms (#811)20200225.3
The APIs for the two-range `absl::c_mismatch`, `absl::c_swap_ranges`, and `absl::c_transform` are misleading as they do not check the bounds of the second range against the first one. This commit cleans up ensures that buggy calls are not exploitable; non-buggy calls are unaffected. This is consistent with both C++14's two-range `std::` equivalents and C++20's `std::ranges::` equivalents. http://wg21.link/mismatch http://wg21.link/alg.swap http://wg21.link/alg.transform
Diffstat (limited to 'absl/algorithm/container.h')
-rw-r--r--absl/algorithm/container.h74
1 files changed, 55 insertions, 19 deletions
diff --git a/absl/algorithm/container.h b/absl/algorithm/container.h
index d72532de..a2f936c4 100644
--- a/absl/algorithm/container.h
+++ b/absl/algorithm/container.h
@@ -340,24 +340,45 @@ container_algorithm_internal::ContainerDifferenceType<const C> c_count_if(
// c_mismatch()
//
// Container-based version of the <algorithm> `std::mismatch()` function to
-// return the first element where two ordered containers differ.
+// return the first element where two ordered containers differ. Applies `==` to
+// the first N elements of `c1` and `c2`, where N = min(size(c1), size(c2)).
template <typename C1, typename C2>
container_algorithm_internal::ContainerIterPairType<C1, C2>
c_mismatch(C1& c1, C2& c2) {
- return std::mismatch(container_algorithm_internal::c_begin(c1),
- container_algorithm_internal::c_end(c1),
- container_algorithm_internal::c_begin(c2));
+ auto first1 = container_algorithm_internal::c_begin(c1);
+ auto last1 = container_algorithm_internal::c_end(c1);
+ auto first2 = container_algorithm_internal::c_begin(c2);
+ auto last2 = container_algorithm_internal::c_end(c2);
+
+ for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) {
+ // Negates equality because Cpp17EqualityComparable doesn't require clients
+ // to overload both `operator==` and `operator!=`.
+ if (!(*first1 == *first2)) {
+ break;
+ }
+ }
+
+ return std::make_pair(first1, first2);
}
// Overload of c_mismatch() for using a predicate evaluation other than `==` as
-// the function's test condition.
+// the function's test condition. Applies `pred`to the first N elements of `c1`
+// and `c2`, where N = min(size(c1), size(c2)).
template <typename C1, typename C2, typename BinaryPredicate>
container_algorithm_internal::ContainerIterPairType<C1, C2>
-c_mismatch(C1& c1, C2& c2, BinaryPredicate&& pred) {
- return std::mismatch(container_algorithm_internal::c_begin(c1),
- container_algorithm_internal::c_end(c1),
- container_algorithm_internal::c_begin(c2),
- std::forward<BinaryPredicate>(pred));
+c_mismatch(C1& c1, C2& c2, BinaryPredicate pred) {
+ auto first1 = container_algorithm_internal::c_begin(c1);
+ auto last1 = container_algorithm_internal::c_end(c1);
+ auto first2 = container_algorithm_internal::c_begin(c2);
+ auto last2 = container_algorithm_internal::c_end(c2);
+
+ for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) {
+ if (!pred(*first1, *first2)) {
+ break;
+ }
+ }
+
+ return std::make_pair(first1, first2);
}
// c_equal()
@@ -539,12 +560,20 @@ BidirectionalIterator c_move_backward(C&& src, BidirectionalIterator dest) {
// c_swap_ranges()
//
// Container-based version of the <algorithm> `std::swap_ranges()` function to
-// swap a container's elements with another container's elements.
+// swap a container's elements with another container's elements. Swaps the
+// first N elements of `c1` and `c2`, where N = min(size(c1), size(c2)).
template <typename C1, typename C2>
container_algorithm_internal::ContainerIter<C2> c_swap_ranges(C1& c1, C2& c2) {
- return std::swap_ranges(container_algorithm_internal::c_begin(c1),
- container_algorithm_internal::c_end(c1),
- container_algorithm_internal::c_begin(c2));
+ auto first1 = container_algorithm_internal::c_begin(c1);
+ auto last1 = container_algorithm_internal::c_end(c1);
+ auto first2 = container_algorithm_internal::c_begin(c2);
+ auto last2 = container_algorithm_internal::c_end(c2);
+
+ using std::swap;
+ for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) {
+ swap(*first1, *first2);
+ }
+ return first2;
}
// c_transform()
@@ -562,16 +591,23 @@ OutputIterator c_transform(const InputSequence& input, OutputIterator output,
}
// Overload of c_transform() for performing a transformation using a binary
-// predicate.
+// predicate. Applies `binary_op` to the first N elements of `c1` and `c2`,
+// where N = min(size(c1), size(c2)).
template <typename InputSequence1, typename InputSequence2,
typename OutputIterator, typename BinaryOp>
OutputIterator c_transform(const InputSequence1& input1,
const InputSequence2& input2, OutputIterator output,
BinaryOp&& binary_op) {
- return std::transform(container_algorithm_internal::c_begin(input1),
- container_algorithm_internal::c_end(input1),
- container_algorithm_internal::c_begin(input2), output,
- std::forward<BinaryOp>(binary_op));
+ auto first1 = container_algorithm_internal::c_begin(input1);
+ auto last1 = container_algorithm_internal::c_end(input1);
+ auto first2 = container_algorithm_internal::c_begin(input2);
+ auto last2 = container_algorithm_internal::c_end(input2);
+ for (; first1 != last1 && first2 != last2;
+ ++first1, (void)++first2, ++output) {
+ *output = binary_op(*first1, *first2);
+ }
+
+ return output;
}
// c_replace()