diff options
author | Marc Mutz <marc.mutz@kdab.com> | 2016-03-09 16:27:47 +0100 |
---|---|---|
committer | Marc Mutz <marc.mutz@kdab.com> | 2016-03-10 07:17:55 +0000 |
commit | f64737527559e22783b57d30ce8bab9ee517974d (patch) | |
tree | 1d563dbbcd65e58f2a05d4c8b64a30fb828837e1 /tests | |
parent | 85a57f7a2e85ac61bb65e66b003cb21f58d5a5b7 (diff) |
Fix signed integer overflows in tst_QAtomicInteger
Signed integer overflows and underflows are undefined
behavior. A test that invokes UB tests nothing, because
the standard permits any outcome.
Fix by guarding the respective operations so
they are not executed if they would overflow
or underflow.
Change-Id: I40354ee88f40e4b47b70eac7790dc3a79ac70a57
Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/corelib/thread/qatomicinteger/tst_qatomicinteger.cpp | 88 |
1 files changed, 80 insertions, 8 deletions
diff --git a/tests/auto/corelib/thread/qatomicinteger/tst_qatomicinteger.cpp b/tests/auto/corelib/thread/qatomicinteger/tst_qatomicinteger.cpp index d3c85c54a7..ff41ccf26b 100644 --- a/tests/auto/corelib/thread/qatomicinteger/tst_qatomicinteger.cpp +++ b/tests/auto/corelib/thread/qatomicinteger/tst_qatomicinteger.cpp @@ -362,28 +362,46 @@ void tst_QAtomicIntegerXX::loadAcquireStoreRelease() void tst_QAtomicIntegerXX::refDeref() { QFETCH(LargeInt, value); - T nextValue = T(value + 1); - T prevValue = T(value - 1); + const bool needToPreventOverflow = TypeIsSigned && value == std::numeric_limits<T>::max(); + const bool needToPreventUnderflow = TypeIsSigned && value == std::numeric_limits<T>::min(); + T nextValue = T(value); + if (!needToPreventOverflow) + ++nextValue; + T prevValue = T(value); + if (!needToPreventUnderflow) + --prevValue; QAtomicInteger<T> atomic(value); + if (!needToPreventOverflow) { QCOMPARE(atomic.ref(), (nextValue != 0)); QCOMPARE(atomic.load(), nextValue); QCOMPARE(atomic.deref(), (value != 0)); + } QCOMPARE(atomic.load(), T(value)); + if (!needToPreventUnderflow) { QCOMPARE(atomic.deref(), (prevValue != 0)); QCOMPARE(atomic.load(), prevValue); QCOMPARE(atomic.ref(), (value != 0)); + } QCOMPARE(atomic.load(), T(value)); + if (!needToPreventOverflow) { QCOMPARE(++atomic, nextValue); QCOMPARE(--atomic, T(value)); + } + if (!needToPreventUnderflow) { QCOMPARE(--atomic, prevValue); QCOMPARE(++atomic, T(value)); + } + if (!needToPreventOverflow) { QCOMPARE(atomic++, T(value)); QCOMPARE(atomic--, nextValue); + } + if (!needToPreventUnderflow) { QCOMPARE(atomic--, T(value)); QCOMPARE(atomic++, prevValue); + } QCOMPARE(atomic.load(), T(value)); } @@ -486,53 +504,80 @@ void tst_QAtomicIntegerXX::fetchAndAdd() QFETCH(LargeInt, value); QAtomicInteger<T> atomic(value); - // note: this test has undefined behavior for signed max and min T parcel1 = 42; T parcel2 = T(0-parcel1); - T newValue1 = T(value) + parcel1; - T newValue2 = T(value) + parcel2; + const bool needToPreventOverflow = TypeIsSigned && value > std::numeric_limits<T>::max() + parcel2; + const bool needToPreventUnderflow = TypeIsSigned && value < std::numeric_limits<T>::min() + parcel1; + + T newValue1 = T(value); + if (!needToPreventOverflow) + newValue1 += parcel1; + T newValue2 = T(value); + if (!needToPreventUnderflow) + newValue2 += parcel2; + + if (!needToPreventOverflow) { QCOMPARE(atomic.fetchAndAddRelaxed(parcel1), T(value)); QCOMPARE(atomic.load(), newValue1); QCOMPARE(atomic.fetchAndAddRelaxed(parcel2), newValue1); + } QCOMPARE(atomic.load(), T(value)); + if (!needToPreventUnderflow) { QCOMPARE(atomic.fetchAndAddRelaxed(parcel2), T(value)); QCOMPARE(atomic.load(), newValue2); QCOMPARE(atomic.fetchAndAddRelaxed(parcel1), newValue2); + } QCOMPARE(atomic.load(), T(value)); + if (!needToPreventOverflow) { QCOMPARE(atomic.fetchAndAddAcquire(parcel1), T(value)); QCOMPARE(atomic.load(), newValue1); QCOMPARE(atomic.fetchAndAddAcquire(parcel2), newValue1); + } QCOMPARE(atomic.load(), T(value)); + if (!needToPreventUnderflow) { QCOMPARE(atomic.fetchAndAddAcquire(parcel2), T(value)); QCOMPARE(atomic.load(), newValue2); QCOMPARE(atomic.fetchAndAddAcquire(parcel1), newValue2); + } QCOMPARE(atomic.load(), T(value)); + if (!needToPreventOverflow) { QCOMPARE(atomic.fetchAndAddRelease(parcel1), T(value)); QCOMPARE(atomic.loadAcquire(), newValue1); QCOMPARE(atomic.fetchAndAddRelease(parcel2), newValue1); + } QCOMPARE(atomic.loadAcquire(), T(value)); + if (!needToPreventUnderflow) { QCOMPARE(atomic.fetchAndAddRelease(parcel2), T(value)); QCOMPARE(atomic.loadAcquire(), newValue2); QCOMPARE(atomic.fetchAndAddRelease(parcel1), newValue2); + } QCOMPARE(atomic.loadAcquire(), T(value)); + if (!needToPreventOverflow) { QCOMPARE(atomic.fetchAndAddOrdered(parcel1), T(value)); QCOMPARE(atomic.loadAcquire(), newValue1); QCOMPARE(atomic.fetchAndAddOrdered(parcel2), newValue1); + } QCOMPARE(atomic.loadAcquire(), T(value)); + if (!needToPreventUnderflow) { QCOMPARE(atomic.fetchAndAddOrdered(parcel2), T(value)); QCOMPARE(atomic.loadAcquire(), newValue2); QCOMPARE(atomic.fetchAndAddOrdered(parcel1), newValue2); + } QCOMPARE(atomic.loadAcquire(), T(value)); // operator+= + if (!needToPreventOverflow) { QCOMPARE(atomic += parcel1, newValue1); QCOMPARE(atomic += parcel2, T(value)); + } + if (!needToPreventUnderflow) { QCOMPARE(atomic += parcel2, newValue2); QCOMPARE(atomic += parcel1, T(value)); + } } void tst_QAtomicIntegerXX::fetchAndSub() @@ -540,53 +585,80 @@ void tst_QAtomicIntegerXX::fetchAndSub() QFETCH(LargeInt, value); QAtomicInteger<T> atomic(value); - // note: this test has undefined behavior for signed max and min T parcel1 = 42; T parcel2 = T(0-parcel1); - T newValue1 = T(value) - parcel1; - T newValue2 = T(value) - parcel2; + const bool needToPreventOverflow = TypeIsSigned && value > std::numeric_limits<T>::max() - parcel1; + const bool needToPreventUnderflow = TypeIsSigned && value < std::numeric_limits<T>::min() - parcel2; + + T newValue1 = T(value); + if (!needToPreventUnderflow) + newValue1 -= parcel1; + T newValue2 = T(value); + if (!needToPreventOverflow) + newValue2 -= parcel2; + + if (!needToPreventUnderflow) { QCOMPARE(atomic.fetchAndSubRelaxed(parcel1), T(value)); QCOMPARE(atomic.load(), newValue1); QCOMPARE(atomic.fetchAndSubRelaxed(parcel2), newValue1); + } QCOMPARE(atomic.load(), T(value)); + if (!needToPreventOverflow) { QCOMPARE(atomic.fetchAndSubRelaxed(parcel2), T(value)); QCOMPARE(atomic.load(), newValue2); QCOMPARE(atomic.fetchAndSubRelaxed(parcel1), newValue2); + } QCOMPARE(atomic.load(), T(value)); + if (!needToPreventUnderflow) { QCOMPARE(atomic.fetchAndSubAcquire(parcel1), T(value)); QCOMPARE(atomic.load(), newValue1); QCOMPARE(atomic.fetchAndSubAcquire(parcel2), newValue1); + } QCOMPARE(atomic.load(), T(value)); + if (!needToPreventOverflow) { QCOMPARE(atomic.fetchAndSubAcquire(parcel2), T(value)); QCOMPARE(atomic.load(), newValue2); QCOMPARE(atomic.fetchAndSubAcquire(parcel1), newValue2); + } QCOMPARE(atomic.load(), T(value)); + if (!needToPreventUnderflow) { QCOMPARE(atomic.fetchAndSubRelease(parcel1), T(value)); QCOMPARE(atomic.loadAcquire(), newValue1); QCOMPARE(atomic.fetchAndSubRelease(parcel2), newValue1); + } QCOMPARE(atomic.loadAcquire(), T(value)); + if (!needToPreventOverflow) { QCOMPARE(atomic.fetchAndSubRelease(parcel2), T(value)); QCOMPARE(atomic.loadAcquire(), newValue2); QCOMPARE(atomic.fetchAndSubRelease(parcel1), newValue2); + } QCOMPARE(atomic.loadAcquire(), T(value)); + if (!needToPreventUnderflow) { QCOMPARE(atomic.fetchAndSubOrdered(parcel1), T(value)); QCOMPARE(atomic.loadAcquire(), newValue1); QCOMPARE(atomic.fetchAndSubOrdered(parcel2), newValue1); + } QCOMPARE(atomic.loadAcquire(), T(value)); + if (!needToPreventOverflow) { QCOMPARE(atomic.fetchAndSubOrdered(parcel2), T(value)); QCOMPARE(atomic.loadAcquire(), newValue2); QCOMPARE(atomic.fetchAndSubOrdered(parcel1), newValue2); + } QCOMPARE(atomic.loadAcquire(), T(value)); // operator-= + if (!needToPreventUnderflow) { QCOMPARE(atomic -= parcel1, newValue1); QCOMPARE(atomic -= parcel2, T(value)); + } + if (!needToPreventOverflow) { QCOMPARE(atomic -= parcel2, newValue2); QCOMPARE(atomic -= parcel1, T(value)); + } } void tst_QAtomicIntegerXX::addSub() |