{static_,}range_map: fix overflows under ubsan

Explicitly call out where overflows are expected, and add appropriate
checking for them.

BUG=b:235999011
TEST=Unittests on CrOS and Linux

Change-Id: I999a6996183c2f4afc16a1c0188dee3bd64d7f09
Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/3759630
Reviewed-by: Mike Frysinger <vapier@chromium.org>
This commit is contained in:
George Burgess IV 2022-07-12 21:35:52 -07:00 committed by George Burgess
parent eb087c3383
commit 335e61656f
8 changed files with 242 additions and 15 deletions

View file

@ -163,6 +163,7 @@
'memory_range.h',
'module.cc',
'module.h',
'safe_math.h',
'scoped_ptr.h',
'simple_string_dictionary.cc',
'simple_string_dictionary.h',
@ -233,6 +234,7 @@
'memory_allocator_unittest.cc',
'memory_range_unittest.cc',
'module_unittest.cc',
'safe_math_unittest.cc',
'simple_string_dictionary_unittest.cc',
'stabs_reader_unittest.cc',
'stabs_to_module_unittest.cc',

82
src/common/safe_math.h Normal file
View file

@ -0,0 +1,82 @@
// Copyright (c) 2022, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// safe_math.h: Helpful math functions.
#ifndef SAFE_MATH_H__
#define SAFE_MATH_H__
#include <utility>
namespace google_breakpad {
// Adds `a` and `b`, returning a pair of:
// - The result after any truncation.
// - Whether an overflow/underflow occurred.
template <typename T>
std::pair<T, bool> AddWithOverflowCheck(T a, T b) {
#ifdef _WIN32
// Since C++11, unsigned overflow is well-defined; do everything unsigned,
// assuming 2's complement.
if (std::is_unsigned<T>::value) {
T result = a + b;
// Since we're adding two values >= 0, having a smaller value implies
// overflow.
bool overflow = result < a;
return {result, overflow};
}
using TUnsigned = typename std::make_unsigned<T>::type;
T result = TUnsigned(a) + TUnsigned(b);
bool overflow;
if ((a >= 0) == (b >= 0)) {
if (a >= 0) {
overflow = result < a;
} else {
overflow = result > a;
}
} else {
// If signs are different, it's impossible for overflow to happen.
overflow = false;
}
return {result, overflow};
#else
T result;
bool overflow = __builtin_add_overflow(a, b, &result);
return {result, overflow};
#endif
}
template <typename T>
T AddIgnoringOverflow(T a, T b) {
return AddWithOverflowCheck(a, b).first;
}
} // namespace google_breakpad
#endif // SAFE_MATH_H__

View file

@ -0,0 +1,73 @@
// Copyright (c) 2022 Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// safe_math_unittest.cc: Unit tests for SafeMath
#include "safe_math.h"
#include "breakpad_googletest_includes.h"
namespace {
using google_breakpad::AddIgnoringOverflow;
using google_breakpad::AddWithOverflowCheck;
TEST(SafeMath, AddOverflowWorksAsIntended) {
EXPECT_EQ(AddWithOverflowCheck<uint8_t>(0, 0),
std::make_pair<uint8_t>(0, false));
EXPECT_EQ(AddWithOverflowCheck<uint8_t>(0, 255),
std::make_pair<uint8_t>(255, false));
EXPECT_EQ(AddWithOverflowCheck<uint8_t>(1, 255),
std::make_pair<uint8_t>(0, true));
EXPECT_EQ(AddWithOverflowCheck<int8_t>(-128, 127),
std::make_pair<int8_t>(-1, false));
EXPECT_EQ(AddWithOverflowCheck<int8_t>(127, -128),
std::make_pair<int8_t>(-1, false));
EXPECT_EQ(AddWithOverflowCheck<int8_t>(1, -128),
std::make_pair<int8_t>(-127, false));
EXPECT_EQ(AddWithOverflowCheck<int8_t>(127, -1),
std::make_pair<int8_t>(126, false));
EXPECT_EQ(AddWithOverflowCheck<int8_t>(-128, -1),
std::make_pair<int8_t>(127, true));
EXPECT_EQ(AddWithOverflowCheck<int8_t>(-128, -128),
std::make_pair<int8_t>(0, true));
EXPECT_EQ(AddWithOverflowCheck<int8_t>(127, 1),
std::make_pair<int8_t>(-128, true));
EXPECT_EQ(AddWithOverflowCheck<int8_t>(127, 127),
std::make_pair<int8_t>(-2, true));
}
TEST(SafeMath, AddIgnoringOverflowWorksAsIntended) {
EXPECT_EQ(AddIgnoringOverflow<uint8_t>(0, 0), 0);
EXPECT_EQ(AddIgnoringOverflow<uint8_t>(0, 255), 255);
EXPECT_EQ(AddIgnoringOverflow<uint8_t>(1, 255), 0);
}
} // namespace