Bug 2070249: Prevent unsigned values in binary search. r=mfbt-reviewers,glandium
It is relatively easy for unsigned values to sneak into a binary search, in which case `result < 0` will always return false. Statically asserting that the result is not unsigned prevents this. Technically this condition is a little bit loose, in that things like `bool` still slip through. There are probably some nasty ways of getting a very precise type assertion using concepts or something, but unsigned seems like the biggest and most obvious footgun. Differential Revision: https://phabricator.services.mozilla.com/D324362
This commit is contained in:
committed by
bvisness@mozilla.com
parent
8c2245fa4a
commit
f16e730a7e
+13
-3
@@ -6,6 +6,7 @@
|
||||
#define mozilla_BinarySearch_h
|
||||
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
@@ -32,8 +33,8 @@ namespace mozilla {
|
||||
*
|
||||
* The BinarySearchIf() version behaves similarly, but takes |aComparator|, a
|
||||
* functor to compare the values with, instead of a value to find.
|
||||
* That functor should take one argument - the value to compare - and return an
|
||||
* |int| with the comparison result:
|
||||
* That functor should take one argument - the value to compare - and return a
|
||||
* signed integer with the comparison result:
|
||||
*
|
||||
* * 0, if the argument is equal to,
|
||||
* * less than 0, if the argument is greater than,
|
||||
@@ -57,7 +58,8 @@ namespace mozilla {
|
||||
*
|
||||
* size_t match;
|
||||
* if (BinarySearchIf(sortedInts, 0, sortedInts.length(), Comparator(13),
|
||||
* &match)) { printf("found 13 at %lu\n", match);
|
||||
* &match)) {
|
||||
* printf("found 13 at %lu\n", match);
|
||||
* }
|
||||
*
|
||||
*/
|
||||
@@ -76,6 +78,8 @@ bool BinarySearchIf(const Container& aContainer, size_t aBegin, size_t aEnd,
|
||||
// Allow any intermediate type so long as it provides a suitable ordering
|
||||
// relation.
|
||||
const auto result = aCompare(aContainer[middle]);
|
||||
static_assert(!std::is_unsigned_v<decltype(result)>,
|
||||
"comparator result must allow negative values");
|
||||
|
||||
if (result == 0) {
|
||||
*aMatchOrInsertionPoint = middle;
|
||||
@@ -174,6 +178,8 @@ size_t LowerBound(const Container& aContainer, size_t aBegin, size_t aEnd,
|
||||
// Allow any intermediate type so long as it provides a suitable ordering
|
||||
// relation.
|
||||
const auto result = aCompare(aContainer[middle]);
|
||||
static_assert(!std::is_unsigned_v<decltype(result)>,
|
||||
"comparator result must allow negative values");
|
||||
|
||||
// The range returning from LowerBound does include elements
|
||||
// equivalent to the given value i.e. aCompare(element) == 0
|
||||
@@ -200,6 +206,8 @@ size_t UpperBound(const Container& aContainer, size_t aBegin, size_t aEnd,
|
||||
// Allow any intermediate type so long as it provides a suitable ordering
|
||||
// relation.
|
||||
const auto result = aCompare(aContainer[middle]);
|
||||
static_assert(!std::is_unsigned_v<decltype(result)>,
|
||||
"comparator result must allow negative values");
|
||||
|
||||
// The range returning from UpperBound does NOT include elements
|
||||
// equivalent to the given value i.e. aCompare(element) == 0
|
||||
@@ -226,6 +234,8 @@ std::pair<size_t, size_t> EqualRange(const Container& aContainer, size_t aBegin,
|
||||
// Allow any intermediate type so long as it provides a suitable ordering
|
||||
// relation.
|
||||
const auto result = aCompare(aContainer[middle]);
|
||||
static_assert(!std::is_unsigned_v<decltype(result)>,
|
||||
"comparator result must allow negative values");
|
||||
|
||||
if (result < 0) {
|
||||
high = middle;
|
||||
|
||||
Reference in New Issue
Block a user