Fix some signed overflow errors causing undefined behavior (in theory).

BUG=webrtc:5491

Review URL: https://codereview.webrtc.org/1744183002

Cr-Commit-Position: refs/heads/master@{#11832}
This commit is contained in:
terelius 2016-03-01 11:07:34 -08:00 committed by Commit bot
parent 5711c8d1f8
commit d802b5b7c3
4 changed files with 30 additions and 8 deletions

View File

@ -412,7 +412,9 @@ int CountIPMaskBits(IPAddress mask) {
// http://graphics.stanford.edu/~seander/bithacks.html
// Counts the trailing 0s in the word.
unsigned int zeroes = 32;
word_to_count &= -static_cast<int32_t>(word_to_count);
// This could also be written word_to_count &= -word_to_count, but
// MSVC emits warning C4146 when negating an unsigned number.
word_to_count &= ~word_to_count + 1; // Isolate lowest set bit.
if (word_to_count) zeroes--;
if (word_to_count & 0x0000FFFF) zeroes -= 16;
if (word_to_count & 0x00FF00FF) zeroes -= 8;
@ -522,4 +524,4 @@ IPAddress GetAnyIP(int family) {
return rtc::IPAddress();
}
} // Namespace rtc
} // namespace rtc

View File

@ -12,9 +12,28 @@
#define WEBRTC_BASE_MATHUTILS_H_
#include <math.h>
#include <type_traits>
#include "webrtc/base/checks.h"
#ifndef M_PI
#define M_PI 3.14159265359f
#endif
// Given two numbers |x| and |y| such that x >= y, computes the difference
// x - y without causing undefined behavior due to signed overflow.
template <typename T>
typename std::make_unsigned<T>::type unsigned_difference(T x, T y) {
static_assert(
std::is_signed<T>::value,
"Function unsigned_difference is only meaningful for signed types.");
RTC_DCHECK_GE(x, y);
typedef typename std::make_unsigned<T>::type unsigned_type;
// int -> unsigned conversion repeatedly adds UINT_MAX + 1 until the number
// can be represented as an unsigned. Since we know that the actual
// difference x - y can be represented as an unsigned, it is sufficient to
// compute the difference modulo UINT_MAX + 1, i.e using unsigned arithmetic.
return static_cast<unsigned_type>(x) - static_cast<unsigned_type>(y);
}
#endif // WEBRTC_BASE_MATHUTILS_H_

View File

@ -14,6 +14,7 @@
#include <vector>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/mathutils.h" // unsigned difference
#include "webrtc/base/random.h"
namespace webrtc {
@ -118,7 +119,7 @@ void BucketTestSignedInterval(unsigned int bucket_count,
ASSERT_GE(high, low);
ASSERT_GE(bucket_count, 2u);
uint32_t interval = static_cast<uint32_t>(high - low + 1);
uint32_t interval = unsigned_difference<int32_t>(high, low) + 1;
uint32_t numbers_per_bucket;
if (interval == 0) {
// The computation high - low + 1 should be 2^32 but overflowed
@ -134,7 +135,7 @@ void BucketTestSignedInterval(unsigned int bucket_count,
int32_t sample = prng->Rand(low, high);
EXPECT_LE(low, sample);
EXPECT_GE(high, sample);
buckets[static_cast<uint32_t>(sample - low) / numbers_per_bucket]++;
buckets[unsigned_difference<int32_t>(sample, low) / numbers_per_bucket]++;
}
for (unsigned int i = 0; i < bucket_count; i++) {
@ -158,7 +159,7 @@ void BucketTestUnsignedInterval(unsigned int bucket_count,
ASSERT_GE(high, low);
ASSERT_GE(bucket_count, 2u);
uint32_t interval = static_cast<uint32_t>(high - low + 1);
uint32_t interval = high - low + 1;
uint32_t numbers_per_bucket;
if (interval == 0) {
// The computation high - low + 1 should be 2^32 but overflowed
@ -174,7 +175,7 @@ void BucketTestUnsignedInterval(unsigned int bucket_count,
uint32_t sample = prng->Rand(low, high);
EXPECT_LE(low, sample);
EXPECT_GE(high, sample);
buckets[static_cast<uint32_t>(sample - low) / numbers_per_bucket]++;
buckets[(sample - low) / numbers_per_bucket]++;
}
for (unsigned int i = 0; i < bucket_count; i++) {

View File

@ -56,7 +56,7 @@ class RollingAccumulator {
// Remove oldest sample.
T sample_to_remove = samples_[next_index_];
sum_ -= sample_to_remove;
sum_2_ -= sample_to_remove * sample_to_remove;
sum_2_ -= static_cast<double>(sample_to_remove) * sample_to_remove;
if (sample_to_remove >= max_) {
max_stale_ = true;
}
@ -70,7 +70,7 @@ class RollingAccumulator {
// Add new sample.
samples_[next_index_] = sample;
sum_ += sample;
sum_2_ += sample * sample;
sum_2_ += static_cast<double>(sample) * sample;
if (count_ == 1 || sample >= max_) {
max_ = sample;
max_stale_ = false;