summaryrefslogtreecommitdiff
path: root/mfbt/tests
diff options
context:
space:
mode:
Diffstat (limited to 'mfbt/tests')
-rw-r--r--mfbt/tests/Makefile.in47
-rw-r--r--mfbt/tests/TestAtomics.cpp159
-rw-r--r--mfbt/tests/TestBloomFilter.cpp102
-rw-r--r--mfbt/tests/TestCasting.cpp107
-rw-r--r--mfbt/tests/TestCheckedInt.cpp567
-rw-r--r--mfbt/tests/TestEndian.cpp398
-rw-r--r--mfbt/tests/TestEnumSet.cpp232
-rw-r--r--mfbt/tests/TestPoisonArea.cpp654
-rw-r--r--mfbt/tests/TestSHA1.cpp204
-rw-r--r--mfbt/tests/TestTypeTraits.cpp213
-rw-r--r--mfbt/tests/TestWeakPtr.cpp77
-rw-r--r--mfbt/tests/moz.build6
12 files changed, 2766 insertions, 0 deletions
diff --git a/mfbt/tests/Makefile.in b/mfbt/tests/Makefile.in
new file mode 100644
index 0000000..faac3bc
--- /dev/null
+++ b/mfbt/tests/Makefile.in
@@ -0,0 +1,47 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+# You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DEPTH = @DEPTH@
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+STL_FLAGS =
+
+CPP_UNIT_TESTS = \
+ TestAtomics.cpp \
+ TestBloomFilter.cpp \
+ TestCasting.cpp \
+ TestCheckedInt.cpp \
+ TestEndian.cpp \
+ TestEnumSet.cpp \
+ TestSHA1.cpp \
+ TestTypeTraits.cpp \
+ TestWeakPtr.cpp \
+ $(NULL)
+
+# These tests don't work with AddressSanitizer enabled
+ifndef MOZ_ASAN
+CPP_UNIT_TESTS += \
+ TestPoisonArea.cpp \
+ $(NULL)
+endif
+
+# in order to prevent rules.mk from trying to link to libraries that are
+# not available to MFBT, we have to reset these MOZ_GLUE*_LDFLAGS before including it
+# and LIBS_ after including it. For WRAP_LDFLAGS, it shouldn't matter.
+# See later comments in bug 732875.
+
+MOZ_GLUE_PROGRAM_LDFLAGS=
+MOZ_GLUE_LDFLAGS =
+WRAP_LDFLAGS=
+
+# Since we link directly with MFBT object files, define IMPL_MFBT
+DEFINES += -DIMPL_MFBT
+
+include $(topsrcdir)/config/rules.mk
+
+LIBS= $(call EXPAND_LIBNAME_PATH,mfbt,$(DEPTH)/mfbt)
diff --git a/mfbt/tests/TestAtomics.cpp b/mfbt/tests/TestAtomics.cpp
new file mode 100644
index 0000000..3e05893
--- /dev/null
+++ b/mfbt/tests/TestAtomics.cpp
@@ -0,0 +1,159 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Atomics.h"
+#include "mozilla/DebugOnly.h"
+
+#include <stdint.h>
+
+using mozilla::Atomic;
+using mozilla::DebugOnly;
+using mozilla::MemoryOrdering;
+using mozilla::Relaxed;
+using mozilla::ReleaseAcquire;
+using mozilla::SequentiallyConsistent;
+
+template <typename T, MemoryOrdering Order>
+static void
+TestTypeWithOrdering()
+{
+ Atomic<T, Order> atomic(5);
+ MOZ_ASSERT(atomic == 5, "Atomic variable did not initialize");
+
+ // Test atomic increment
+ MOZ_ASSERT(++atomic == T(6), "Atomic increment did not work");
+ MOZ_ASSERT(atomic++ == T(6), "Atomic post-increment did not work");
+ MOZ_ASSERT(atomic == T(7), "Atomic post-increment did not work");
+
+ // Test atomic decrement
+ MOZ_ASSERT(--atomic == 6, "Atomic decrement did not work");
+ MOZ_ASSERT(atomic-- == 6, "Atomic post-decrement did not work");
+ MOZ_ASSERT(atomic == 5, "Atomic post-decrement did not work");
+
+ // Test other arithmetic.
+ DebugOnly<T> result;
+ result = (atomic += T(5));
+ MOZ_ASSERT(atomic == T(10), "Atomic += did not work");
+ MOZ_ASSERT(result == T(10), "Atomic += returned the wrong value");
+ result = (atomic -= T(3));
+ MOZ_ASSERT(atomic == T(7), "Atomic -= did not work");
+ MOZ_ASSERT(result == T(7), "Atomic -= returned the wrong value");
+
+ // Test assignment
+ result = (atomic = T(5));
+ MOZ_ASSERT(atomic == T(5), "Atomic assignment failed");
+ MOZ_ASSERT(result == T(5), "Atomic assignment returned the wrong value");
+
+ // Test logical operations.
+ result = (atomic ^= T(2));
+ MOZ_ASSERT(atomic == T(7), "Atomic ^= did not work");
+ MOZ_ASSERT(result == T(7), "Atomic ^= returned the wrong value");
+ result = (atomic ^= T(4));
+ MOZ_ASSERT(atomic == T(3), "Atomic ^= did not work");
+ MOZ_ASSERT(result == T(3), "Atomic ^= returned the wrong value");
+ result = (atomic |= T(8));
+ MOZ_ASSERT(atomic == T(11), "Atomic |= did not work");
+ MOZ_ASSERT(result == T(11), "Atomic |= returned the wrong value");
+ result = (atomic |= T(8));
+ MOZ_ASSERT(atomic == T(11), "Atomic |= did not work");
+ MOZ_ASSERT(result == T(11), "Atomic |= returned the wrong value");
+ result = (atomic &= T(12));
+ MOZ_ASSERT(atomic == T(8), "Atomic &= did not work");
+ MOZ_ASSERT(result == T(8), "Atomic &= returned the wrong value");
+
+ // Test exchange.
+ atomic = T(30);
+ result = atomic.exchange(42);
+ MOZ_ASSERT(atomic == T(42), "Atomic exchange did not work");
+ MOZ_ASSERT(result == T(30), "Atomic exchange returned the wrong value");
+
+ // Test CAS.
+ atomic = T(1);
+ DebugOnly<bool> boolResult = atomic.compareExchange(0, 2);
+ MOZ_ASSERT(!boolResult, "CAS should have returned false.");
+ MOZ_ASSERT(atomic == T(1), "CAS shouldn't have done anything.");
+
+ boolResult = atomic.compareExchange(1, 42);
+ MOZ_ASSERT(boolResult, "CAS should have succeeded.");
+ MOZ_ASSERT(atomic == T(42), "CAS should have changed atomic's value.");
+}
+
+template<typename T, MemoryOrdering Order>
+static void
+TestPointerWithOrdering()
+{
+ T array1[10];
+ Atomic<T*, Order> atomic(array1);
+ MOZ_ASSERT(atomic == array1, "Atomic variable did not initialize");
+
+ // Test atomic increment
+ MOZ_ASSERT(++atomic == array1 + 1, "Atomic increment did not work");
+ MOZ_ASSERT(atomic++ == array1 + 1, "Atomic post-increment did not work");
+ MOZ_ASSERT(atomic == array1 + 2, "Atomic post-increment did not work");
+
+ // Test atomic decrement
+ MOZ_ASSERT(--atomic == array1 + 1, "Atomic decrement did not work");
+ MOZ_ASSERT(atomic-- == array1 + 1, "Atomic post-decrement did not work");
+ MOZ_ASSERT(atomic == array1, "Atomic post-decrement did not work");
+
+ // Test other arithmetic operations
+ DebugOnly<T*> result;
+ result = (atomic += 2);
+ MOZ_ASSERT(atomic == array1 + 2, "Atomic += did not work");
+ MOZ_ASSERT(result == array1 + 2, "Atomic += returned the wrong value");
+ result = (atomic -= 1);
+ MOZ_ASSERT(atomic == array1 + 1, "Atomic -= did not work");
+ MOZ_ASSERT(result == array1 + 1, "Atomic -= returned the wrong value");
+
+ // Test stores
+ result = (atomic = array1);
+ MOZ_ASSERT(atomic == array1, "Atomic assignment did not work");
+ MOZ_ASSERT(result == array1, "Atomic assignment returned the wrong value");
+
+ // Test exchange
+ atomic = array1 + 2;
+ result = atomic.exchange(array1);
+ MOZ_ASSERT(atomic == array1, "Atomic exchange did not work");
+ MOZ_ASSERT(result == array1 + 2, "Atomic exchange returned the wrong value");
+
+ atomic = array1;
+ DebugOnly<bool> boolResult = atomic.compareExchange(array1 + 1, array1 + 2);
+ MOZ_ASSERT(!boolResult, "CAS should have returned false.");
+ MOZ_ASSERT(atomic == array1, "CAS shouldn't have done anything.");
+
+ boolResult = atomic.compareExchange(array1, array1 + 3);
+ MOZ_ASSERT(boolResult, "CAS should have succeeded.");
+ MOZ_ASSERT(atomic == array1 + 3, "CAS should have changed atomic's value.");
+}
+
+template <typename T>
+static void
+TestType()
+{
+ TestTypeWithOrdering<T, SequentiallyConsistent>();
+ TestTypeWithOrdering<T, ReleaseAcquire>();
+ TestTypeWithOrdering<T, Relaxed>();
+}
+
+template<typename T>
+static void
+TestPointer()
+{
+ TestPointerWithOrdering<T, SequentiallyConsistent>();
+ TestPointerWithOrdering<T, ReleaseAcquire>();
+ TestPointerWithOrdering<T, Relaxed>();
+}
+
+int main()
+{
+ TestType<uint32_t>();
+ TestType<int32_t>();
+ TestType<intptr_t>();
+ TestType<uintptr_t>();
+ TestPointer<int>();
+ TestPointer<float>();
+ TestPointer<uint16_t*>();
+ TestPointer<uint32_t*>();
+}
diff --git a/mfbt/tests/TestBloomFilter.cpp b/mfbt/tests/TestBloomFilter.cpp
new file mode 100644
index 0000000..7a8a0ec
--- /dev/null
+++ b/mfbt/tests/TestBloomFilter.cpp
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/BloomFilter.h"
+
+#include <stddef.h>
+#include <stdio.h>
+
+using mozilla::BloomFilter;
+
+class FilterChecker
+{
+ public:
+ FilterChecker(uint32_t hash) : mHash(hash) { }
+
+ uint32_t hash() const { return mHash; }
+
+ private:
+ uint32_t mHash;
+};
+
+int
+main()
+{
+ BloomFilter<12, FilterChecker> *filter = new BloomFilter<12, FilterChecker>();
+ MOZ_ASSERT(filter);
+
+ FilterChecker one(1);
+ FilterChecker two(0x20000);
+ FilterChecker many(0x10000);
+ FilterChecker multiple(0x20001);
+
+ filter->add(&one);
+ MOZ_ASSERT(filter->mightContain(&one),
+ "Filter should contain 'one'");
+
+ MOZ_ASSERT(!filter->mightContain(&multiple),
+ "Filter claims to contain 'multiple' when it should not");
+
+ MOZ_ASSERT(filter->mightContain(&many),
+ "Filter should contain 'many' (false positive)");
+
+ filter->add(&two);
+ MOZ_ASSERT(filter->mightContain(&multiple),
+ "Filter should contain 'multiple' (false positive)");
+
+ // Test basic removals
+ filter->remove(&two);
+ MOZ_ASSERT(!filter->mightContain(&multiple),
+ "Filter claims to contain 'multiple' when it should not after two "
+ "was removed");
+
+ // Test multiple addition/removal
+ const size_t FILTER_SIZE = 255;
+ for (size_t i = 0; i < FILTER_SIZE - 1; ++i)
+ filter->add(&two);
+
+ MOZ_ASSERT(filter->mightContain(&multiple),
+ "Filter should contain 'multiple' after 'two' added lots of times "
+ "(false positive)");
+
+ for (size_t i = 0; i < FILTER_SIZE - 1; ++i)
+ filter->remove(&two);
+
+ MOZ_ASSERT(!filter->mightContain(&multiple),
+ "Filter claims to contain 'multiple' when it should not after two "
+ "was removed lots of times");
+
+ // Test overflowing the filter buckets
+ for (size_t i = 0; i < FILTER_SIZE + 1; ++i)
+ filter->add(&two);
+
+ MOZ_ASSERT(filter->mightContain(&multiple),
+ "Filter should contain 'multiple' after 'two' added lots more "
+ "times (false positive)");
+
+ for (size_t i = 0; i < FILTER_SIZE + 1; ++i)
+ filter->remove(&two);
+
+ MOZ_ASSERT(filter->mightContain(&multiple),
+ "Filter claims to not contain 'multiple' even though we should "
+ "have run out of space in the buckets (false positive)");
+ MOZ_ASSERT(filter->mightContain(&two),
+ "Filter claims to not contain 'two' even though we should have "
+ "run out of space in the buckets (false positive)");
+
+ filter->remove(&one);
+
+ MOZ_ASSERT(!filter->mightContain(&one),
+ "Filter should not contain 'one', because we didn't overflow its "
+ "bucket");
+
+ filter->clear();
+
+ MOZ_ASSERT(!filter->mightContain(&multiple),
+ "clear() failed to work");
+
+ return 0;
+}
diff --git a/mfbt/tests/TestCasting.cpp b/mfbt/tests/TestCasting.cpp
new file mode 100644
index 0000000..1e19b07
--- /dev/null
+++ b/mfbt/tests/TestCasting.cpp
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/Casting.h"
+#include "mozilla/StandardInteger.h"
+
+using mozilla::BitwiseCast;
+using mozilla::detail::IsInBounds;
+
+template<typename Uint, typename Ulong, bool = (sizeof(Uint) == sizeof(Ulong))>
+struct UintUlongBitwiseCast;
+
+template<typename Uint, typename Ulong>
+struct UintUlongBitwiseCast<Uint, Ulong, true>
+{
+ static void test() {
+ MOZ_ASSERT(BitwiseCast<Ulong>(Uint(8675309)) == Ulong(8675309));
+ }
+};
+
+template<typename Uint, typename Ulong>
+struct UintUlongBitwiseCast<Uint, Ulong, false>
+{
+ static void test() { }
+};
+
+static void
+TestBitwiseCast()
+{
+ MOZ_ASSERT(BitwiseCast<int>(int(8675309)) == int(8675309));
+ UintUlongBitwiseCast<unsigned int, unsigned long>::test();
+}
+
+static void
+TestSameSize()
+{
+ MOZ_ASSERT((IsInBounds<int16_t, int16_t>(int16_t(0))));
+ MOZ_ASSERT((IsInBounds<int16_t, int16_t>(int16_t(INT16_MIN))));
+ MOZ_ASSERT((IsInBounds<int16_t, int16_t>(int16_t(INT16_MAX))));
+ MOZ_ASSERT((IsInBounds<uint16_t, uint16_t>(uint16_t(UINT16_MAX))));
+ MOZ_ASSERT((IsInBounds<uint16_t, int16_t>(uint16_t(0))));
+ MOZ_ASSERT((!IsInBounds<uint16_t, int16_t>(uint16_t(-1))));
+ MOZ_ASSERT((!IsInBounds<int16_t, uint16_t>(int16_t(-1))));
+ MOZ_ASSERT((IsInBounds<int16_t, uint16_t>(int16_t(INT16_MAX))));
+ MOZ_ASSERT((!IsInBounds<int16_t, uint16_t>(int16_t(INT16_MIN))));
+ MOZ_ASSERT((IsInBounds<int32_t, uint32_t>(int32_t(INT32_MAX))));
+ MOZ_ASSERT((!IsInBounds<int32_t, uint32_t>(int32_t(INT32_MIN))));
+}
+
+static void
+TestToBiggerSize()
+{
+ MOZ_ASSERT((IsInBounds<int16_t, int32_t>(int16_t(0))));
+ MOZ_ASSERT((IsInBounds<int16_t, int32_t>(int16_t(INT16_MIN))));
+ MOZ_ASSERT((IsInBounds<int16_t, int32_t>(int16_t(INT16_MAX))));
+ MOZ_ASSERT((IsInBounds<uint16_t, uint32_t>(uint16_t(UINT16_MAX))));
+ MOZ_ASSERT((IsInBounds<uint16_t, int32_t>(uint16_t(0))));
+ MOZ_ASSERT((IsInBounds<uint16_t, int32_t>(uint16_t(-1))));
+ MOZ_ASSERT((!IsInBounds<int16_t, uint32_t>(int16_t(-1))));
+ MOZ_ASSERT((IsInBounds<int16_t, uint32_t>(int16_t(INT16_MAX))));
+ MOZ_ASSERT((!IsInBounds<int16_t, uint32_t>(int16_t(INT16_MIN))));
+ MOZ_ASSERT((IsInBounds<int32_t, uint64_t>(int32_t(INT32_MAX))));
+ MOZ_ASSERT((!IsInBounds<int32_t, uint64_t>(int32_t(INT32_MIN))));
+}
+
+static void
+TestToSmallerSize()
+{
+ MOZ_ASSERT((IsInBounds<int16_t, int8_t>(int16_t(0))));
+ MOZ_ASSERT((!IsInBounds<int16_t, int8_t>(int16_t(INT16_MIN))));
+ MOZ_ASSERT((!IsInBounds<int16_t, int8_t>(int16_t(INT16_MAX))));
+ MOZ_ASSERT((!IsInBounds<uint16_t, uint8_t>(uint16_t(UINT16_MAX))));
+ MOZ_ASSERT((IsInBounds<uint16_t, int8_t>(uint16_t(0))));
+ MOZ_ASSERT((!IsInBounds<uint16_t, int8_t>(uint16_t(-1))));
+ MOZ_ASSERT((!IsInBounds<int16_t, uint8_t>(int16_t(-1))));
+ MOZ_ASSERT((!IsInBounds<int16_t, uint8_t>(int16_t(INT16_MAX))));
+ MOZ_ASSERT((!IsInBounds<int16_t, uint8_t>(int16_t(INT16_MIN))));
+ MOZ_ASSERT((!IsInBounds<int32_t, uint16_t>(int32_t(INT32_MAX))));
+ MOZ_ASSERT((!IsInBounds<int32_t, uint16_t>(int32_t(INT32_MIN))));
+
+ // Boundary cases
+ MOZ_ASSERT((!IsInBounds<int64_t, int32_t>(int64_t(INT32_MIN) - 1)));
+ MOZ_ASSERT((IsInBounds<int64_t, int32_t>(int64_t(INT32_MIN))));
+ MOZ_ASSERT((IsInBounds<int64_t, int32_t>(int64_t(INT32_MIN) + 1)));
+ MOZ_ASSERT((IsInBounds<int64_t, int32_t>(int64_t(INT32_MAX) - 1)));
+ MOZ_ASSERT((IsInBounds<int64_t, int32_t>(int64_t(INT32_MAX))));
+ MOZ_ASSERT((!IsInBounds<int64_t, int32_t>(int64_t(INT32_MAX) + 1)));
+
+ MOZ_ASSERT((!IsInBounds<int64_t, uint32_t>(int64_t(-1))));
+ MOZ_ASSERT((IsInBounds<int64_t, uint32_t>(int64_t(0))));
+ MOZ_ASSERT((IsInBounds<int64_t, uint32_t>(int64_t(1))));
+ MOZ_ASSERT((IsInBounds<int64_t, uint32_t>(int64_t(UINT32_MAX) - 1)));
+ MOZ_ASSERT((IsInBounds<int64_t, uint32_t>(int64_t(UINT32_MAX))));
+ MOZ_ASSERT((!IsInBounds<int64_t, uint32_t>(int64_t(UINT32_MAX) + 1)));
+}
+
+int
+main()
+{
+ TestBitwiseCast();
+
+ TestSameSize();
+ TestToBiggerSize();
+ TestToSmallerSize();
+}
diff --git a/mfbt/tests/TestCheckedInt.cpp b/mfbt/tests/TestCheckedInt.cpp
new file mode 100644
index 0000000..5a9cba7
--- /dev/null
+++ b/mfbt/tests/TestCheckedInt.cpp
@@ -0,0 +1,567 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/CheckedInt.h"
+
+#include <iostream>
+#include <climits>
+
+#ifndef MOZ_CHECKEDINT_USE_MFBT
+# error "MOZ_CHECKEDINT_USE_MFBT should be defined by CheckedInt.h"
+#endif
+
+using namespace mozilla;
+
+int gIntegerTypesTested = 0;
+int gTestsPassed = 0;
+int gTestsFailed = 0;
+
+void verifyImplFunction(bool x, bool expected,
+ const char* file, int line,
+ int size, bool isTSigned)
+{
+ if (x == expected) {
+ gTestsPassed++;
+ } else {
+ gTestsFailed++;
+ std::cerr << "Test failed at " << file << ":" << line;
+ std::cerr << " with T a ";
+ if (isTSigned)
+ std::cerr << "signed";
+ else
+ std::cerr << "unsigned";
+ std::cerr << " " << CHAR_BIT*size << "-bit integer type" << std::endl;
+ }
+}
+
+#define VERIFY_IMPL(x, expected) \
+ verifyImplFunction((x), \
+ (expected), \
+ __FILE__, \
+ __LINE__, \
+ sizeof(T), \
+ detail::IsSigned<T>::value)
+
+#define VERIFY(x) VERIFY_IMPL(x, true)
+#define VERIFY_IS_FALSE(x) VERIFY_IMPL(x, false)
+#define VERIFY_IS_VALID(x) VERIFY_IMPL((x).isValid(), true)
+#define VERIFY_IS_INVALID(x) VERIFY_IMPL((x).isValid(), false)
+#define VERIFY_IS_VALID_IF(x,condition) VERIFY_IMPL((x).isValid(), (condition))
+
+template<typename T, size_t Size = sizeof(T)>
+struct testTwiceBiggerType
+{
+ static void run()
+ {
+ VERIFY(detail::IsSupported<typename detail::TwiceBiggerType<T>::Type>::value);
+ VERIFY(sizeof(typename detail::TwiceBiggerType<T>::Type)
+ == 2 * sizeof(T));
+ VERIFY(bool(detail::IsSigned<typename detail::TwiceBiggerType<T>::Type>::value)
+ == bool(detail::IsSigned<T>::value));
+ }
+};
+
+template<typename T>
+struct testTwiceBiggerType<T, 8>
+{
+ static void run()
+ {
+ VERIFY_IS_FALSE(detail::IsSupported<
+ typename detail::TwiceBiggerType<T>::Type
+ >::value);
+ }
+};
+
+
+template<typename T>
+void test()
+{
+ static bool alreadyRun = false;
+ // Integer types from different families may just be typedefs for types from other families.
+ // e.g. int32_t might be just a typedef for int. No point re-running the same tests then.
+ if (alreadyRun)
+ return;
+ alreadyRun = true;
+
+ VERIFY(detail::IsSupported<T>::value);
+ const bool isTSigned = detail::IsSigned<T>::value;
+ VERIFY(bool(isTSigned) == !bool(T(-1) > T(0)));
+
+ testTwiceBiggerType<T>::run();
+
+ typedef typename detail::UnsignedType<T>::Type unsignedT;
+
+ VERIFY(sizeof(unsignedT) == sizeof(T));
+ VERIFY(detail::IsSigned<unsignedT>::value == false);
+
+ const CheckedInt<T> max(detail::MaxValue<T>::value);
+ const CheckedInt<T> min(detail::MinValue<T>::value);
+
+ // Check MinValue and MaxValue, since they are custom implementations and a mistake there
+ // could potentially NOT be caught by any other tests... while making everything wrong!
+
+ unsignedT bit = 1;
+ unsignedT unsignedMinValue(min.value());
+ unsignedT unsignedMaxValue(max.value());
+ for (size_t i = 0; i < sizeof(T) * CHAR_BIT - 1; i++)
+ {
+ VERIFY((unsignedMinValue & bit) == 0);
+ bit <<= 1;
+ }
+ VERIFY((unsignedMinValue & bit) == (isTSigned ? bit : unsignedT(0)));
+ VERIFY(unsignedMaxValue == unsignedT(~unsignedMinValue));
+
+ const CheckedInt<T> zero(0);
+ const CheckedInt<T> one(1);
+ const CheckedInt<T> two(2);
+ const CheckedInt<T> three(3);
+ const CheckedInt<T> four(4);
+
+ /* Addition / subtraction checks */
+
+ VERIFY_IS_VALID(zero + zero);
+ VERIFY(zero + zero == zero);
+ VERIFY_IS_FALSE(zero + zero == one); // Check that == doesn't always return true
+ VERIFY_IS_VALID(zero + one);
+ VERIFY(zero + one == one);
+ VERIFY_IS_VALID(one + one);
+ VERIFY(one + one == two);
+
+ const CheckedInt<T> maxMinusOne = max - one;
+ const CheckedInt<T> maxMinusTwo = max - two;
+ VERIFY_IS_VALID(maxMinusOne);
+ VERIFY_IS_VALID(maxMinusTwo);
+ VERIFY_IS_VALID(maxMinusOne + one);
+ VERIFY_IS_VALID(maxMinusTwo + one);
+ VERIFY_IS_VALID(maxMinusTwo + two);
+ VERIFY(maxMinusOne + one == max);
+ VERIFY(maxMinusTwo + one == maxMinusOne);
+ VERIFY(maxMinusTwo + two == max);
+
+ VERIFY_IS_VALID(max + zero);
+ VERIFY_IS_VALID(max - zero);
+ VERIFY_IS_INVALID(max + one);
+ VERIFY_IS_INVALID(max + two);
+ VERIFY_IS_INVALID(max + maxMinusOne);
+ VERIFY_IS_INVALID(max + max);
+
+ const CheckedInt<T> minPlusOne = min + one;
+ const CheckedInt<T> minPlusTwo = min + two;
+ VERIFY_IS_VALID(minPlusOne);
+ VERIFY_IS_VALID(minPlusTwo);
+ VERIFY_IS_VALID(minPlusOne - one);
+ VERIFY_IS_VALID(minPlusTwo - one);
+ VERIFY_IS_VALID(minPlusTwo - two);
+ VERIFY(minPlusOne - one == min);
+ VERIFY(minPlusTwo - one == minPlusOne);
+ VERIFY(minPlusTwo - two == min);
+
+ const CheckedInt<T> minMinusOne = min - one;
+ VERIFY_IS_VALID(min + zero);
+ VERIFY_IS_VALID(min - zero);
+ VERIFY_IS_INVALID(min - one);
+ VERIFY_IS_INVALID(min - two);
+ VERIFY_IS_INVALID(min - minMinusOne);
+ VERIFY_IS_VALID(min - min);
+
+ const CheckedInt<T> maxOverTwo = max / two;
+ VERIFY_IS_VALID(maxOverTwo + maxOverTwo);
+ VERIFY_IS_VALID(maxOverTwo + one);
+ VERIFY((maxOverTwo + one) - one == maxOverTwo);
+ VERIFY_IS_VALID(maxOverTwo - maxOverTwo);
+ VERIFY(maxOverTwo - maxOverTwo == zero);
+
+ const CheckedInt<T> minOverTwo = min / two;
+ VERIFY_IS_VALID(minOverTwo + minOverTwo);
+ VERIFY_IS_VALID(minOverTwo + one);
+ VERIFY((minOverTwo + one) - one == minOverTwo);
+ VERIFY_IS_VALID(minOverTwo - minOverTwo);
+ VERIFY(minOverTwo - minOverTwo == zero);
+
+ VERIFY_IS_INVALID(min - one);
+ VERIFY_IS_INVALID(min - two);
+
+ if (isTSigned) {
+ VERIFY_IS_INVALID(min + min);
+ VERIFY_IS_INVALID(minOverTwo + minOverTwo + minOverTwo);
+ VERIFY_IS_INVALID(zero - min + min);
+ VERIFY_IS_INVALID(one - min + min);
+ }
+
+ /* Modulo checks */
+ VERIFY_IS_INVALID(zero % zero);
+ VERIFY_IS_INVALID(one % zero);
+ VERIFY_IS_VALID(zero % one);
+ VERIFY_IS_VALID(zero % max);
+ VERIFY_IS_VALID(one % max);
+ VERIFY_IS_VALID(max % one);
+ VERIFY_IS_VALID(max % max);
+ if (isTSigned) {
+ const CheckedInt<T> minusOne = zero - one;
+ VERIFY_IS_INVALID(minusOne % minusOne);
+ VERIFY_IS_INVALID(zero % minusOne);
+ VERIFY_IS_INVALID(one % minusOne);
+ VERIFY_IS_INVALID(minusOne % one);
+
+ VERIFY_IS_INVALID(min % min);
+ VERIFY_IS_INVALID(zero % min);
+ VERIFY_IS_INVALID(min % one);
+ }
+
+ /* Unary operator- checks */
+
+ const CheckedInt<T> negOne = -one;
+ const CheckedInt<T> negTwo = -two;
+
+ if (isTSigned) {
+ VERIFY_IS_VALID(-max);
+ VERIFY_IS_INVALID(-min);
+ VERIFY(-max - min == one);
+ VERIFY_IS_VALID(-max - one);
+ VERIFY_IS_VALID(negOne);
+ VERIFY_IS_VALID(-max + negOne);
+ VERIFY_IS_VALID(negOne + one);
+ VERIFY(negOne + one == zero);
+ VERIFY_IS_VALID(negTwo);
+ VERIFY_IS_VALID(negOne + negOne);
+ VERIFY(negOne + negOne == negTwo);
+ } else {
+ VERIFY_IS_INVALID(-max);
+ VERIFY_IS_VALID(-min);
+ VERIFY(min == zero);
+ VERIFY_IS_INVALID(negOne);
+ }
+
+ /* multiplication checks */
+
+ VERIFY_IS_VALID(zero * zero);
+ VERIFY(zero * zero == zero);
+ VERIFY_IS_VALID(zero * one);
+ VERIFY(zero * one == zero);
+ VERIFY_IS_VALID(one * zero);
+ VERIFY(one * zero == zero);
+ VERIFY_IS_VALID(one * one);
+ VERIFY(one * one == one);
+ VERIFY_IS_VALID(one * three);
+ VERIFY(one * three == three);
+ VERIFY_IS_VALID(two * two);
+ VERIFY(two * two == four);
+
+ VERIFY_IS_INVALID(max * max);
+ VERIFY_IS_INVALID(maxOverTwo * max);
+ VERIFY_IS_INVALID(maxOverTwo * maxOverTwo);
+
+ const CheckedInt<T> maxApproxSqrt(T(T(1) << (CHAR_BIT*sizeof(T)/2)));
+
+ VERIFY_IS_VALID(maxApproxSqrt);
+ VERIFY_IS_VALID(maxApproxSqrt * two);
+ VERIFY_IS_INVALID(maxApproxSqrt * maxApproxSqrt);
+ VERIFY_IS_INVALID(maxApproxSqrt * maxApproxSqrt * maxApproxSqrt);
+
+ if (isTSigned) {
+ VERIFY_IS_INVALID(min * min);
+ VERIFY_IS_INVALID(minOverTwo * min);
+ VERIFY_IS_INVALID(minOverTwo * minOverTwo);
+
+ const CheckedInt<T> minApproxSqrt = -maxApproxSqrt;
+
+ VERIFY_IS_VALID(minApproxSqrt);
+ VERIFY_IS_VALID(minApproxSqrt * two);
+ VERIFY_IS_INVALID(minApproxSqrt * maxApproxSqrt);
+ VERIFY_IS_INVALID(minApproxSqrt * minApproxSqrt);
+ }
+
+ // make sure to check all 4 paths in signed multiplication validity check.
+ // test positive * positive
+ VERIFY_IS_VALID(max * one);
+ VERIFY(max * one == max);
+ VERIFY_IS_INVALID(max * two);
+ VERIFY_IS_VALID(maxOverTwo * two);
+ VERIFY((maxOverTwo + maxOverTwo) == (maxOverTwo * two));
+
+ if (isTSigned) {
+ // test positive * negative
+ VERIFY_IS_VALID(max * negOne);
+ VERIFY_IS_VALID(-max);
+ VERIFY(max * negOne == -max);
+ VERIFY_IS_VALID(one * min);
+ VERIFY_IS_INVALID(max * negTwo);
+ VERIFY_IS_VALID(maxOverTwo * negTwo);
+ VERIFY_IS_VALID(two * minOverTwo);
+ VERIFY_IS_VALID((maxOverTwo + one) * negTwo);
+ VERIFY_IS_INVALID((maxOverTwo + two) * negTwo);
+ VERIFY_IS_INVALID(two * (minOverTwo - one));
+
+ // test negative * positive
+ VERIFY_IS_VALID(min * one);
+ VERIFY_IS_VALID(minPlusOne * one);
+ VERIFY_IS_INVALID(min * two);
+ VERIFY_IS_VALID(minOverTwo * two);
+ VERIFY(minOverTwo * two == min);
+ VERIFY_IS_INVALID((minOverTwo - one) * negTwo);
+ VERIFY_IS_INVALID(negTwo * max);
+ VERIFY_IS_VALID(minOverTwo * two);
+ VERIFY(minOverTwo * two == min);
+ VERIFY_IS_VALID(negTwo * maxOverTwo);
+ VERIFY_IS_INVALID((minOverTwo - one) * two);
+ VERIFY_IS_VALID(negTwo * (maxOverTwo + one));
+ VERIFY_IS_INVALID(negTwo * (maxOverTwo + two));
+
+ // test negative * negative
+ VERIFY_IS_INVALID(min * negOne);
+ VERIFY_IS_VALID(minPlusOne * negOne);
+ VERIFY(minPlusOne * negOne == max);
+ VERIFY_IS_INVALID(min * negTwo);
+ VERIFY_IS_INVALID(minOverTwo * negTwo);
+ VERIFY_IS_INVALID(negOne * min);
+ VERIFY_IS_VALID(negOne * minPlusOne);
+ VERIFY(negOne * minPlusOne == max);
+ VERIFY_IS_INVALID(negTwo * min);
+ VERIFY_IS_INVALID(negTwo * minOverTwo);
+ }
+
+ /* Division checks */
+
+ VERIFY_IS_VALID(one / one);
+ VERIFY(one / one == one);
+ VERIFY_IS_VALID(three / three);
+ VERIFY(three / three == one);
+ VERIFY_IS_VALID(four / two);
+ VERIFY(four / two == two);
+ VERIFY((four*three)/four == three);
+
+ // Check that div by zero is invalid
+ VERIFY_IS_INVALID(zero / zero);
+ VERIFY_IS_INVALID(one / zero);
+ VERIFY_IS_INVALID(two / zero);
+ VERIFY_IS_INVALID(negOne / zero);
+ VERIFY_IS_INVALID(max / zero);
+ VERIFY_IS_INVALID(min / zero);
+
+ if (isTSigned) {
+ // Check that min / -1 is invalid
+ VERIFY_IS_INVALID(min / negOne);
+
+ // Check that the test for div by -1 isn't banning other numerators than min
+ VERIFY_IS_VALID(one / negOne);
+ VERIFY_IS_VALID(zero / negOne);
+ VERIFY_IS_VALID(negOne / negOne);
+ VERIFY_IS_VALID(max / negOne);
+ }
+
+ /* Check that invalidity is correctly preserved by arithmetic ops */
+
+ const CheckedInt<T> someInvalid = max + max;
+ VERIFY_IS_INVALID(someInvalid + zero);
+ VERIFY_IS_INVALID(someInvalid - zero);
+ VERIFY_IS_INVALID(zero + someInvalid);
+ VERIFY_IS_INVALID(zero - someInvalid);
+ VERIFY_IS_INVALID(-someInvalid);
+ VERIFY_IS_INVALID(someInvalid * zero);
+ VERIFY_IS_INVALID(someInvalid * one);
+ VERIFY_IS_INVALID(zero * someInvalid);
+ VERIFY_IS_INVALID(one * someInvalid);
+ VERIFY_IS_INVALID(someInvalid / zero);
+ VERIFY_IS_INVALID(someInvalid / one);
+ VERIFY_IS_INVALID(zero / someInvalid);
+ VERIFY_IS_INVALID(one / someInvalid);
+ VERIFY_IS_INVALID(someInvalid % zero);
+ VERIFY_IS_INVALID(someInvalid % one);
+ VERIFY_IS_INVALID(zero % someInvalid);
+ VERIFY_IS_INVALID(one % someInvalid);
+ VERIFY_IS_INVALID(someInvalid + someInvalid);
+ VERIFY_IS_INVALID(someInvalid - someInvalid);
+ VERIFY_IS_INVALID(someInvalid * someInvalid);
+ VERIFY_IS_INVALID(someInvalid / someInvalid);
+ VERIFY_IS_INVALID(someInvalid % someInvalid);
+
+ /* Check that mixing checked integers with plain integers in expressions is allowed */
+
+ VERIFY(one + T(2) == three);
+ VERIFY(2 + one == three);
+ {
+ CheckedInt<T> x = one;
+ x += 2;
+ VERIFY(x == three);
+ }
+ VERIFY(two - 1 == one);
+ VERIFY(2 - one == one);
+ {
+ CheckedInt<T> x = two;
+ x -= 1;
+ VERIFY(x == one);
+ }
+ VERIFY(one * 2 == two);
+ VERIFY(2 * one == two);
+ {
+ CheckedInt<T> x = one;
+ x *= 2;
+ VERIFY(x == two);
+ }
+ VERIFY(four / 2 == two);
+ VERIFY(4 / two == two);
+ {
+ CheckedInt<T> x = four;
+ x /= 2;
+ VERIFY(x == two);
+ }
+ VERIFY(three % 2 == one);
+ VERIFY(3 % two == one);
+ {
+ CheckedInt<T> x = three;
+ x %= 2;
+ VERIFY(x == one);
+ }
+
+ VERIFY(one == 1);
+ VERIFY(1 == one);
+ VERIFY_IS_FALSE(two == 1);
+ VERIFY_IS_FALSE(1 == two);
+ VERIFY_IS_FALSE(someInvalid == 1);
+ VERIFY_IS_FALSE(1 == someInvalid);
+
+ // Check simple casting between different signedness and sizes.
+ {
+ CheckedInt<uint8_t> foo = CheckedInt<uint16_t>(2).toChecked<uint8_t>();
+ VERIFY_IS_VALID(foo);
+ VERIFY(foo == 2);
+ }
+ {
+ CheckedInt<uint8_t> foo = CheckedInt<uint16_t>(255).toChecked<uint8_t>();
+ VERIFY_IS_VALID(foo);
+ VERIFY(foo == 255);
+ }
+ {
+ CheckedInt<uint8_t> foo = CheckedInt<uint16_t>(256).toChecked<uint8_t>();
+ VERIFY_IS_INVALID(foo);
+ }
+ {
+ CheckedInt<uint8_t> foo = CheckedInt<int8_t>(-2).toChecked<uint8_t>();
+ VERIFY_IS_INVALID(foo);
+ }
+
+ // Check that construction of CheckedInt from an integer value of a mismatched type is checked
+ // Also check casting between all types.
+
+ #define VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE2(U,V,PostVExpr) \
+ { \
+ bool isUSigned = detail::IsSigned<U>::value; \
+ VERIFY_IS_VALID(CheckedInt<T>(V( 0)PostVExpr)); \
+ VERIFY_IS_VALID(CheckedInt<T>(V( 1)PostVExpr)); \
+ VERIFY_IS_VALID(CheckedInt<T>(V(100)PostVExpr)); \
+ if (isUSigned) \
+ VERIFY_IS_VALID_IF(CheckedInt<T>(V(-1)PostVExpr), isTSigned); \
+ if (sizeof(U) > sizeof(T)) \
+ VERIFY_IS_INVALID(CheckedInt<T>(V(detail::MaxValue<T>::value)PostVExpr + one.value())); \
+ VERIFY_IS_VALID_IF(CheckedInt<T>(detail::MaxValue<U>::value), \
+ (sizeof(T) > sizeof(U) || ((sizeof(T) == sizeof(U)) && (isUSigned || !isTSigned)))); \
+ VERIFY_IS_VALID_IF(CheckedInt<T>(detail::MinValue<U>::value), \
+ isUSigned == false ? 1 \
+ : bool(isTSigned) == false ? 0 \
+ : sizeof(T) >= sizeof(U)); \
+ }
+ #define VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(U) \
+ VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE2(U,U,+0) \
+ VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE2(U,CheckedInt<U>,.toChecked<T>())
+
+ VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int8_t)
+ VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint8_t)
+ VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int16_t)
+ VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint16_t)
+ VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int32_t)
+ VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint32_t)
+ VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int64_t)
+ VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint64_t)
+
+ typedef signed char signedChar;
+ typedef unsigned char unsignedChar;
+ typedef unsigned short unsignedShort;
+ typedef unsigned int unsignedInt;
+ typedef unsigned long unsignedLong;
+ typedef long long longLong;
+ typedef unsigned long long unsignedLongLong;
+
+ VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(char)
+ VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(signedChar)
+ VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedChar)
+ VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(short)
+ VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedShort)
+ VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int)
+ VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedInt)
+ VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(long)
+ VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedLong)
+ VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(longLong)
+ VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedLongLong)
+
+ /* Test increment/decrement operators */
+
+ CheckedInt<T> x, y;
+ x = one;
+ y = x++;
+ VERIFY(x == two);
+ VERIFY(y == one);
+ x = one;
+ y = ++x;
+ VERIFY(x == two);
+ VERIFY(y == two);
+ x = one;
+ y = x--;
+ VERIFY(x == zero);
+ VERIFY(y == one);
+ x = one;
+ y = --x;
+ VERIFY(x == zero);
+ VERIFY(y == zero);
+ x = max;
+ VERIFY_IS_VALID(x++);
+ x = max;
+ VERIFY_IS_INVALID(++x);
+ x = min;
+ VERIFY_IS_VALID(x--);
+ x = min;
+ VERIFY_IS_INVALID(--x);
+
+ gIntegerTypesTested++;
+}
+
+int main()
+{
+ test<int8_t>();
+ test<uint8_t>();
+ test<int16_t>();
+ test<uint16_t>();
+ test<int32_t>();
+ test<uint32_t>();
+ test<int64_t>();
+ test<uint64_t>();
+
+ test<char>();
+ test<signed char>();
+ test<unsigned char>();
+ test<short>();
+ test<unsigned short>();
+ test<int>();
+ test<unsigned int>();
+ test<long>();
+ test<unsigned long>();
+ test<long long>();
+ test<unsigned long long>();
+
+ const int MIN_TYPES_TESTED = 9;
+ if (gIntegerTypesTested < MIN_TYPES_TESTED) {
+ std::cerr << "Only " << gIntegerTypesTested << " have been tested. "
+ << "This should not be less than " << MIN_TYPES_TESTED << "."
+ << std::endl;
+ gTestsFailed++;
+ }
+
+ std::cerr << gTestsFailed << " tests failed, "
+ << gTestsPassed << " tests passed out of "
+ << gTestsFailed + gTestsPassed
+ << " tests, covering " << gIntegerTypesTested
+ << " distinct integer types." << std::endl;
+
+ return gTestsFailed > 0;
+}
diff --git a/mfbt/tests/TestEndian.cpp b/mfbt/tests/TestEndian.cpp
new file mode 100644
index 0000000..1ec520d
--- /dev/null
+++ b/mfbt/tests/TestEndian.cpp
@@ -0,0 +1,398 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/DebugOnly.h"
+#include "mozilla/Endian.h"
+
+using mozilla::BigEndian;
+using mozilla::DebugOnly;
+using mozilla::LittleEndian;
+using mozilla::NativeEndian;
+
+template<typename T>
+void
+TestSingleSwap(T value, T swappedValue)
+{
+#if MOZ_LITTLE_ENDIAN
+ MOZ_ASSERT(NativeEndian::swapToBigEndian(value) == swappedValue);
+ MOZ_ASSERT(NativeEndian::swapFromBigEndian(value) == swappedValue);
+ MOZ_ASSERT(NativeEndian::swapToNetworkOrder(value) == swappedValue);
+ MOZ_ASSERT(NativeEndian::swapFromNetworkOrder(value) == swappedValue);
+#else
+ MOZ_ASSERT(NativeEndian::swapToLittleEndian(value) == swappedValue);
+ MOZ_ASSERT(NativeEndian::swapFromLittleEndian(value) == swappedValue);
+#endif
+}
+
+template<typename T>
+void
+TestSingleNoSwap(T value, T notSwappedValue)
+{
+#if MOZ_LITTLE_ENDIAN
+ MOZ_ASSERT(NativeEndian::swapToLittleEndian(value) == notSwappedValue);
+ MOZ_ASSERT(NativeEndian::swapFromLittleEndian(value) == notSwappedValue);
+#else
+ MOZ_ASSERT(NativeEndian::swapToBigEndian(value) == notSwappedValue);
+ MOZ_ASSERT(NativeEndian::swapFromBigEndian(value) == notSwappedValue);
+ MOZ_ASSERT(NativeEndian::swapToNetworkOrder(value) == notSwappedValue);
+ MOZ_ASSERT(NativeEndian::swapFromNetworkOrder(value) == notSwappedValue);
+#endif
+}
+
+// Endian.h functions are declared as protected in an base class and
+// then re-exported as public in public derived classes. The
+// standardese around explicit instantiation of templates is not clear
+// in such cases. Provide these wrappers to make things more explicit.
+// For your own enlightenment, you may wish to peruse:
+// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56152 and subsequently
+// http://j.mp/XosS6S .
+#define WRAP_COPYTO(NAME) \
+ template<typename T> \
+ void \
+ NAME(void* dst, const T* src, unsigned int count) \
+ { \
+ NativeEndian::NAME<T>(dst, src, count); \
+ }
+
+WRAP_COPYTO(copyAndSwapToLittleEndian)
+WRAP_COPYTO(copyAndSwapToBigEndian)
+WRAP_COPYTO(copyAndSwapToNetworkOrder)
+
+#define WRAP_COPYFROM(NAME) \
+ template<typename T> \
+ void \
+ NAME(T* dst, const void* src, unsigned int count) \
+ { \
+ NativeEndian::NAME<T>(dst, src, count); \
+ }
+
+WRAP_COPYFROM(copyAndSwapFromLittleEndian)
+WRAP_COPYFROM(copyAndSwapFromBigEndian)
+WRAP_COPYFROM(copyAndSwapFromNetworkOrder)
+
+#define WRAP_IN_PLACE(NAME) \
+ template<typename T> \
+ void \
+ NAME(T* p, unsigned int count) \
+ { \
+ NativeEndian::NAME<T>(p, count); \
+ }
+WRAP_IN_PLACE(swapToLittleEndianInPlace)
+WRAP_IN_PLACE(swapFromLittleEndianInPlace)
+WRAP_IN_PLACE(swapToBigEndianInPlace)
+WRAP_IN_PLACE(swapFromBigEndianInPlace)
+WRAP_IN_PLACE(swapToNetworkOrderInPlace)
+WRAP_IN_PLACE(swapFromNetworkOrderInPlace)
+
+enum SwapExpectation {
+ Swap,
+ NoSwap
+};
+
+template<typename T, size_t count>
+void
+TestBulkSwapToSub(enum SwapExpectation expectSwap,
+ const T (&values)[count],
+ void (*swapperFunc)(void*, const T*, unsigned int),
+ T (*readerFunc)(const void*))
+{
+ const size_t arraySize = 2 * count;
+ const size_t bufferSize = arraySize * sizeof(T);
+ static uint8_t buffer[bufferSize];
+ const uint8_t fillValue = 0xa5;
+ static uint8_t checkBuffer[bufferSize];
+
+ MOZ_ASSERT(bufferSize > 2 * sizeof(T));
+
+ memset(checkBuffer, fillValue, bufferSize);
+
+ for (size_t startPosition = 0; startPosition < sizeof(T); ++startPosition) {
+ for (size_t nValues = 0; nValues < count; ++nValues) {
+ memset(buffer, fillValue, bufferSize);
+ swapperFunc(buffer + startPosition, values, nValues);
+
+ MOZ_ASSERT(memcmp(buffer, checkBuffer, startPosition) == 0);
+ DebugOnly<size_t> valuesEndPosition = startPosition + sizeof(T) * nValues;
+ MOZ_ASSERT(memcmp(buffer + valuesEndPosition,
+ checkBuffer + valuesEndPosition,
+ bufferSize - valuesEndPosition) == 0);
+ if (expectSwap == NoSwap) {
+ MOZ_ASSERT(memcmp(buffer + startPosition, values,
+ nValues * sizeof(T)) == 0);
+ }
+ for (size_t i = 0; i < nValues; ++i) {
+ MOZ_ASSERT(readerFunc(buffer + startPosition + sizeof(T) * i) ==
+ values[i]);
+ }
+ }
+ }
+}
+
+template<typename T, size_t count>
+void
+TestBulkSwapFromSub(enum SwapExpectation expectSwap,
+ const T (&values)[count],
+ void (*swapperFunc)(T*, const void*, unsigned int),
+ T (*readerFunc)(const void*))
+{
+ const size_t arraySize = 2 * count;
+ const size_t bufferSize = arraySize * sizeof(T);
+ static T buffer[arraySize];
+ const uint8_t fillValue = 0xa5;
+ static T checkBuffer[arraySize];
+
+ memset(checkBuffer, fillValue, bufferSize);
+
+ for (size_t startPosition = 0; startPosition < count; ++startPosition) {
+ for (size_t nValues = 0; nValues < (count - startPosition); ++nValues) {
+ memset(buffer, fillValue, bufferSize);
+ swapperFunc(buffer + startPosition, values, nValues);
+
+ MOZ_ASSERT(memcmp(buffer, checkBuffer, startPosition * sizeof(T)) == 0);
+ DebugOnly<size_t> valuesEndPosition = startPosition + nValues;
+ MOZ_ASSERT(memcmp(buffer + valuesEndPosition,
+ checkBuffer + valuesEndPosition,
+ (arraySize - valuesEndPosition) * sizeof(T)) == 0);
+ if (expectSwap == NoSwap) {
+ MOZ_ASSERT(memcmp(buffer + startPosition, values,
+ nValues * sizeof(T)) == 0);
+ }
+ for (size_t i = 0; i < nValues; ++i)
+ MOZ_ASSERT(readerFunc(buffer + startPosition + i) == values[i]);
+ }
+ }
+}
+
+
+template<typename T, size_t count>
+void
+TestBulkInPlaceSub(enum SwapExpectation expectSwap,
+ const T (&values)[count],
+ void (*swapperFunc)(T* p, unsigned int),
+ T (*readerFunc)(const void*))
+{
+ const size_t bufferCount = 4 * count;
+ const size_t bufferSize = bufferCount * sizeof(T);
+ static T buffer[bufferCount];
+ const T fillValue = 0xa5;
+ static T checkBuffer[bufferCount];
+
+ MOZ_ASSERT(bufferSize > 2 * sizeof(T));
+
+ memset(checkBuffer, fillValue, bufferSize);
+
+ for (size_t startPosition = 0; startPosition < count; ++startPosition) {
+ for (size_t nValues = 0; nValues < count; ++nValues) {
+ memset(buffer, fillValue, bufferSize);
+ memcpy(buffer + startPosition, values, nValues * sizeof(T));
+ swapperFunc(buffer + startPosition, nValues);
+
+ MOZ_ASSERT(memcmp(buffer, checkBuffer, startPosition * sizeof(T)) == 0);
+ DebugOnly<size_t> valuesEndPosition = startPosition + nValues;
+ MOZ_ASSERT(memcmp(buffer + valuesEndPosition,
+ checkBuffer + valuesEndPosition,
+ bufferSize - valuesEndPosition * sizeof(T)) == 0);
+ if (expectSwap == NoSwap) {
+ MOZ_ASSERT(memcmp(buffer + startPosition, values,
+ nValues * sizeof(T)) == 0);
+ }
+ for (size_t i = 0; i < nValues; ++i)
+ MOZ_ASSERT(readerFunc(buffer + startPosition + i) == values[i]);
+ }
+ }
+}
+
+template<typename T>
+struct Reader
+{
+};
+
+#define SPECIALIZE_READER(TYPE, READ_FUNC) \
+ template<> \
+ struct Reader<TYPE> \
+ { \
+ static TYPE readLE(const void* p) { return LittleEndian::READ_FUNC(p); } \
+ static TYPE readBE(const void* p) { return BigEndian::READ_FUNC(p); } \
+ };
+
+SPECIALIZE_READER(uint16_t, readUint16)
+SPECIALIZE_READER(uint32_t, readUint32)
+SPECIALIZE_READER(uint64_t, readUint64)
+SPECIALIZE_READER(int16_t, readInt16)
+SPECIALIZE_READER(int32_t, readInt32)
+SPECIALIZE_READER(int64_t, readInt64)
+
+template<typename T, size_t count>
+void
+TestBulkSwap(const T (&bytes)[count])
+{
+#if MOZ_LITTLE_ENDIAN
+ TestBulkSwapToSub(Swap, bytes, copyAndSwapToBigEndian<T>, Reader<T>::readBE);
+ TestBulkSwapFromSub(Swap, bytes, copyAndSwapFromBigEndian<T>, Reader<T>::readBE);
+ TestBulkSwapToSub(Swap, bytes, copyAndSwapToNetworkOrder<T>, Reader<T>::readBE);
+ TestBulkSwapFromSub(Swap, bytes, copyAndSwapFromNetworkOrder<T>, Reader<T>::readBE);
+#else
+ TestBulkSwapToSub(Swap, bytes, copyAndSwapToLittleEndian<T>, Reader<T>::readLE);
+ TestBulkSwapFromSub(Swap, bytes, copyAndSwapFromLittleEndian<T>, Reader<T>::readLE);
+#endif
+}
+
+template<typename T, size_t count>
+void
+TestBulkNoSwap(const T (&bytes)[count])
+{
+#if MOZ_LITTLE_ENDIAN
+ TestBulkSwapToSub(NoSwap, bytes, copyAndSwapToLittleEndian<T>, Reader<T>::readLE);
+ TestBulkSwapFromSub(NoSwap, bytes, copyAndSwapFromLittleEndian<T>, Reader<T>::readLE);
+#else
+ TestBulkSwapToSub(NoSwap, bytes, copyAndSwapToBigEndian<T>, Reader<T>::readBE);
+ TestBulkSwapFromSub(NoSwap, bytes, copyAndSwapFromBigEndian<T>, Reader<T>::readBE);
+ TestBulkSwapToSub(NoSwap, bytes, copyAndSwapToNetworkOrder<T>, Reader<T>::readBE);
+ TestBulkSwapFromSub(NoSwap, bytes, copyAndSwapFromNetworkOrder<T>, Reader<T>::readBE);
+#endif
+}
+
+template<typename T, size_t count>
+void
+TestBulkInPlaceSwap(const T (&bytes)[count])
+{
+#if MOZ_LITTLE_ENDIAN
+ TestBulkInPlaceSub(Swap, bytes, swapToBigEndianInPlace<T>, Reader<T>::readBE);
+ TestBulkInPlaceSub(Swap, bytes, swapFromBigEndianInPlace<T>, Reader<T>::readBE);
+ TestBulkInPlaceSub(Swap, bytes, swapToNetworkOrderInPlace<T>, Reader<T>::readBE);
+ TestBulkInPlaceSub(Swap, bytes, swapFromNetworkOrderInPlace<T>, Reader<T>::readBE);
+#else
+ TestBulkInPlaceSub(Swap, bytes, swapToLittleEndianInPlace<T>, Reader<T>::readLE);
+ TestBulkInPlaceSub(Swap, bytes, swapFromLittleEndianInPlace<T>, Reader<T>::readLE);
+#endif
+}
+
+template<typename T, size_t count>
+void
+TestBulkInPlaceNoSwap(const T (&bytes)[count])
+{
+#if MOZ_LITTLE_ENDIAN
+ TestBulkInPlaceSub(NoSwap, bytes, swapToLittleEndianInPlace<T>, Reader<T>::readLE);
+ TestBulkInPlaceSub(NoSwap, bytes, swapFromLittleEndianInPlace<T>, Reader<T>::readLE);
+#else
+ TestBulkInPlaceSub(NoSwap, bytes, swapToBigEndianInPlace<T>, Reader<T>::readBE);
+ TestBulkInPlaceSub(NoSwap, bytes, swapFromBigEndianInPlace<T>, Reader<T>::readBE);
+ TestBulkInPlaceSub(NoSwap, bytes, swapToNetworkOrderInPlace<T>, Reader<T>::readBE);
+ TestBulkInPlaceSub(NoSwap, bytes, swapFromNetworkOrderInPlace<T>, Reader<T>::readBE);
+#endif
+}
+
+int
+main()
+{
+ static const uint8_t unsigned_bytes[16] = { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8,
+ 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8 };
+ static const int8_t signed_bytes[16] = { -0x0f, -0x0e, -0x0d, -0x0c, -0x0b, -0x0a, -0x09, -0x08,
+ -0x0f, -0x0e, -0x0d, -0x0c, -0x0b, -0x0a, -0x09, -0x08 };
+ static const uint16_t uint16_values[8] = { 0x102, 0x304, 0x506, 0x708, 0x102, 0x304, 0x506, 0x708 };
+ static const int16_t int16_values[8] = { int16_t(0xf1f2), int16_t(0xf3f4), int16_t(0xf5f6), int16_t(0xf7f8),
+ int16_t(0xf1f2), int16_t(0xf3f4), int16_t(0xf5f6), int16_t(0xf7f8) };
+ static const uint32_t uint32_values[4] = { 0x1020304, 0x5060708, 0x1020304, 0x5060708 };
+ static const int32_t int32_values[4] = { int32_t(0xf1f2f3f4), int32_t(0xf5f6f7f8),
+ int32_t(0xf1f2f3f4), int32_t(0xf5f6f7f8) };
+ static const uint64_t uint64_values[2] = { 0x102030405060708, 0x102030405060708 };
+ static const int64_t int64_values[2] = { int64_t(0xf1f2f3f4f5f6f7f8),
+ int64_t(0xf1f2f3f4f5f6f7f8) };
+ uint8_t buffer[8];
+
+ MOZ_ASSERT(LittleEndian::readUint16(&unsigned_bytes[0]) == 0x201);
+ MOZ_ASSERT(BigEndian::readUint16(&unsigned_bytes[0]) == 0x102);
+
+ MOZ_ASSERT(LittleEndian::readUint32(&unsigned_bytes[0]) == 0x4030201U);
+ MOZ_ASSERT(BigEndian::readUint32(&unsigned_bytes[0]) == 0x1020304U);
+
+ MOZ_ASSERT(LittleEndian::readUint64(&unsigned_bytes[0]) == 0x807060504030201ULL);
+ MOZ_ASSERT(BigEndian::readUint64(&unsigned_bytes[0]) == 0x102030405060708ULL);
+
+ LittleEndian::writeUint16(&buffer[0], 0x201);
+ MOZ_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint16_t)) == 0);
+ BigEndian::writeUint16(&buffer[0], 0x102);
+ MOZ_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint16_t)) == 0);
+
+ LittleEndian::writeUint32(&buffer[0], 0x4030201U);
+ MOZ_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint32_t)) == 0);
+ BigEndian::writeUint32(&buffer[0], 0x1020304U);
+ MOZ_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint32_t)) == 0);
+
+ LittleEndian::writeUint64(&buffer[0], 0x807060504030201ULL);
+ MOZ_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint64_t)) == 0);
+ BigEndian::writeUint64(&buffer[0], 0x102030405060708ULL);
+ MOZ_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint64_t)) == 0);
+
+ MOZ_ASSERT(LittleEndian::readInt16(&signed_bytes[0]) == int16_t(0xf2f1));
+ MOZ_ASSERT(BigEndian::readInt16(&signed_bytes[0]) == int16_t(0xf1f2));
+
+ MOZ_ASSERT(LittleEndian::readInt32(&signed_bytes[0]) == int32_t(0xf4f3f2f1));
+ MOZ_ASSERT(BigEndian::readInt32(&signed_bytes[0]) == int32_t(0xf1f2f3f4));
+
+ MOZ_ASSERT(LittleEndian::readInt64(&signed_bytes[0]) == int64_t(0xf8f7f6f5f4f3f2f1LL));
+ MOZ_ASSERT(BigEndian::readInt64(&signed_bytes[0]) == int64_t(0xf1f2f3f4f5f6f7f8LL));
+
+ LittleEndian::writeInt16(&buffer[0], 0xf2f1);
+ MOZ_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int16_t)) == 0);
+ BigEndian::writeInt16(&buffer[0], 0xf1f2);
+ MOZ_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int16_t)) == 0);
+
+ LittleEndian::writeInt32(&buffer[0], 0xf4f3f2f1);
+ MOZ_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int32_t)) == 0);
+ BigEndian::writeInt32(&buffer[0], 0xf1f2f3f4);
+ MOZ_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int32_t)) == 0);
+
+ LittleEndian::writeInt64(&buffer[0], 0xf8f7f6f5f4f3f2f1LL);
+ MOZ_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int64_t)) == 0);
+ BigEndian::writeInt64(&buffer[0], 0xf1f2f3f4f5f6f7f8LL);
+ MOZ_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int64_t)) == 0);
+
+ TestSingleSwap(uint16_t(0xf2f1), uint16_t(0xf1f2));
+ TestSingleSwap(uint32_t(0xf4f3f2f1), uint32_t(0xf1f2f3f4));
+ TestSingleSwap(uint64_t(0xf8f7f6f5f4f3f2f1), uint64_t(0xf1f2f3f4f5f6f7f8));
+
+ TestSingleSwap(int16_t(0xf2f1), int16_t(0xf1f2));
+ TestSingleSwap(int32_t(0xf4f3f2f1), int32_t(0xf1f2f3f4));
+ TestSingleSwap(int64_t(0xf8f7f6f5f4f3f2f1), int64_t(0xf1f2f3f4f5f6f7f8));
+
+ TestSingleNoSwap(uint16_t(0xf2f1), uint16_t(0xf2f1));
+ TestSingleNoSwap(uint32_t(0xf4f3f2f1), uint32_t(0xf4f3f2f1));
+ TestSingleNoSwap(uint64_t(0xf8f7f6f5f4f3f2f1), uint64_t(0xf8f7f6f5f4f3f2f1));
+
+ TestSingleNoSwap(int16_t(0xf2f1), int16_t(0xf2f1));
+ TestSingleNoSwap(int32_t(0xf4f3f2f1), int32_t(0xf4f3f2f1));
+ TestSingleNoSwap(int64_t(0xf8f7f6f5f4f3f2f1), int64_t(0xf8f7f6f5f4f3f2f1));
+
+ TestBulkSwap(uint16_values);
+ TestBulkSwap(int16_values);
+ TestBulkSwap(uint32_values);
+ TestBulkSwap(int32_values);
+ TestBulkSwap(uint64_values);
+ TestBulkSwap(int64_values);
+
+ TestBulkNoSwap(uint16_values);
+ TestBulkNoSwap(int16_values);
+ TestBulkNoSwap(uint32_values);
+ TestBulkNoSwap(int32_values);
+ TestBulkNoSwap(uint64_values);
+ TestBulkNoSwap(int64_values);
+
+ TestBulkInPlaceSwap(uint16_values);
+ TestBulkInPlaceSwap(int16_values);
+ TestBulkInPlaceSwap(uint32_values);
+ TestBulkInPlaceSwap(int32_values);
+ TestBulkInPlaceSwap(uint64_values);
+ TestBulkInPlaceSwap(int64_values);
+
+ TestBulkInPlaceNoSwap(uint16_values);
+ TestBulkInPlaceNoSwap(int16_values);
+ TestBulkInPlaceNoSwap(uint32_values);
+ TestBulkInPlaceNoSwap(int32_values);
+ TestBulkInPlaceNoSwap(uint64_values);
+ TestBulkInPlaceNoSwap(int64_values);
+
+ return 0;
+}
diff --git a/mfbt/tests/TestEnumSet.cpp b/mfbt/tests/TestEnumSet.cpp
new file mode 100644
index 0000000..dc43fe3
--- /dev/null
+++ b/mfbt/tests/TestEnumSet.cpp
@@ -0,0 +1,232 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/EnumSet.h"
+
+using namespace mozilla;
+
+enum SeaBird {
+ PENGUIN,
+ ALBATROSS,
+ FULMAR,
+ PRION,
+ SHEARWATER,
+ GADFLY_PETREL,
+ TRUE_PETREL,
+ DIVING_PETREL,
+ STORM_PETREL,
+ PELICAN,
+ GANNET,
+ BOOBY,
+ CORMORANT,
+ FRIGATEBIRD,
+ TROPICBIRD,
+ SKUA,
+ GULL,
+ TERN,
+ SKIMMER,
+ AUK
+};
+
+class EnumSetSuite {
+ public:
+ EnumSetSuite()
+ : mAlcidae(),
+ mDiomedeidae(ALBATROSS),
+ mPetrelProcellariidae(GADFLY_PETREL, TRUE_PETREL),
+ mNonPetrelProcellariidae(FULMAR, PRION, SHEARWATER),
+ mPetrels(GADFLY_PETREL, TRUE_PETREL, DIVING_PETREL, STORM_PETREL)
+ { }
+
+ void runTests() {
+ testSize();
+ testContains();
+ testAddTo();
+ testAdd();
+ testAddAll();
+ testUnion();
+ testRemoveFrom();
+ testRemove();
+ testRemoveAllFrom();
+ testRemoveAll();
+ testIntersect();
+ testInsersection();
+ testEquality();
+ testDuplicates();
+ }
+
+ private:
+ void testSize() {
+ MOZ_ASSERT(mAlcidae.size() == 0);
+ MOZ_ASSERT(mDiomedeidae.size() == 1);
+ MOZ_ASSERT(mPetrelProcellariidae.size() == 2);
+ MOZ_ASSERT(mNonPetrelProcellariidae.size() == 3);
+ MOZ_ASSERT(mPetrels.size() == 4);
+ }
+
+ void testContains() {
+ MOZ_ASSERT(!mPetrels.contains(PENGUIN));
+ MOZ_ASSERT(!mPetrels.contains(ALBATROSS));
+ MOZ_ASSERT(!mPetrels.contains(FULMAR));
+ MOZ_ASSERT(!mPetrels.contains(PRION));
+ MOZ_ASSERT(!mPetrels.contains(SHEARWATER));
+ MOZ_ASSERT(mPetrels.contains(GADFLY_PETREL));
+ MOZ_ASSERT(mPetrels.contains(TRUE_PETREL));
+ MOZ_ASSERT(mPetrels.contains(DIVING_PETREL));
+ MOZ_ASSERT(mPetrels.contains(STORM_PETREL));
+ MOZ_ASSERT(!mPetrels.contains(PELICAN));
+ MOZ_ASSERT(!mPetrels.contains(GANNET));
+ MOZ_ASSERT(!mPetrels.contains(BOOBY));
+ MOZ_ASSERT(!mPetrels.contains(CORMORANT));
+ MOZ_ASSERT(!mPetrels.contains(FRIGATEBIRD));
+ MOZ_ASSERT(!mPetrels.contains(TROPICBIRD));
+ MOZ_ASSERT(!mPetrels.contains(SKUA));
+ MOZ_ASSERT(!mPetrels.contains(GULL));
+ MOZ_ASSERT(!mPetrels.contains(TERN));
+ MOZ_ASSERT(!mPetrels.contains(SKIMMER));
+ MOZ_ASSERT(!mPetrels.contains(AUK));
+ }
+
+ void testCopy() {
+ EnumSet<SeaBird> likes = mPetrels;
+ likes -= TRUE_PETREL;
+ MOZ_ASSERT(mPetrels.size() == 4);
+ MOZ_ASSERT(mPetrels.contains(TRUE_PETREL));
+
+ MOZ_ASSERT(likes.size() == 3);
+ MOZ_ASSERT(likes.contains(GADFLY_PETREL));
+ MOZ_ASSERT(likes.contains(DIVING_PETREL));
+ MOZ_ASSERT(likes.contains(STORM_PETREL));
+ }
+
+ void testAddTo() {
+ EnumSet<SeaBird> seen = mPetrels;
+ seen += CORMORANT;
+ seen += TRUE_PETREL;
+ MOZ_ASSERT(mPetrels.size() == 4);
+ MOZ_ASSERT(!mPetrels.contains(CORMORANT));
+ MOZ_ASSERT(seen.size() == 5);
+ MOZ_ASSERT(seen.contains(GADFLY_PETREL));
+ MOZ_ASSERT(seen.contains(TRUE_PETREL));
+ MOZ_ASSERT(seen.contains(DIVING_PETREL));
+ MOZ_ASSERT(seen.contains(STORM_PETREL));
+ MOZ_ASSERT(seen.contains(CORMORANT));
+ }
+
+ void testAdd() {
+ EnumSet<SeaBird> seen = mPetrels + CORMORANT +
+ STORM_PETREL;
+ MOZ_ASSERT(mPetrels.size() == 4);
+ MOZ_ASSERT(!mPetrels.contains(CORMORANT));
+ MOZ_ASSERT(seen.size() == 5);
+ MOZ_ASSERT(seen.contains(GADFLY_PETREL));
+ MOZ_ASSERT(seen.contains(TRUE_PETREL));
+ MOZ_ASSERT(seen.contains(DIVING_PETREL));
+ MOZ_ASSERT(seen.contains(STORM_PETREL));
+ MOZ_ASSERT(seen.contains(CORMORANT));
+ }
+
+ void testAddAll() {
+ EnumSet<SeaBird> procellariidae;
+ procellariidae += mPetrelProcellariidae;
+ procellariidae += mNonPetrelProcellariidae;
+ MOZ_ASSERT(procellariidae.size() == 5);
+
+ // Both procellariidae and mPetrels include GADFLY_PERTEL and TRUE_PETREL
+ EnumSet<SeaBird> procellariiformes;
+ procellariiformes += mDiomedeidae;
+ procellariiformes += procellariidae;
+ procellariiformes += mPetrels;
+ MOZ_ASSERT(procellariiformes.size() == 8);
+ }
+
+ void testUnion() {
+ EnumSet<SeaBird> procellariidae = mPetrelProcellariidae +
+ mNonPetrelProcellariidae;
+ MOZ_ASSERT(procellariidae.size() == 5);
+
+ // Both procellariidae and mPetrels include GADFLY_PETREL and TRUE_PETREL
+ EnumSet<SeaBird> procellariiformes = mDiomedeidae + procellariidae +
+ mPetrels;
+ MOZ_ASSERT(procellariiformes.size() == 8);
+ }
+
+ void testRemoveFrom() {
+ EnumSet<SeaBird> likes = mPetrels;
+ likes -= TRUE_PETREL;
+ likes -= DIVING_PETREL;
+ MOZ_ASSERT(likes.size() == 2);
+ MOZ_ASSERT(likes.contains(GADFLY_PETREL));
+ MOZ_ASSERT(likes.contains(STORM_PETREL));
+ }
+
+ void testRemove() {
+ EnumSet<SeaBird> likes = mPetrels - TRUE_PETREL -
+ DIVING_PETREL;
+ MOZ_ASSERT(likes.size() == 2);
+ MOZ_ASSERT(likes.contains(GADFLY_PETREL));
+ MOZ_ASSERT(likes.contains(STORM_PETREL));
+ }
+
+ void testRemoveAllFrom() {
+ EnumSet<SeaBird> likes = mPetrels;
+ likes -= mPetrelProcellariidae;
+ MOZ_ASSERT(likes.size() == 2);
+ MOZ_ASSERT(likes.contains(DIVING_PETREL));
+ MOZ_ASSERT(likes.contains(STORM_PETREL));
+ }
+
+ void testRemoveAll() {
+ EnumSet<SeaBird> likes = mPetrels - mPetrelProcellariidae;
+ MOZ_ASSERT(likes.size() == 2);
+ MOZ_ASSERT(likes.contains(DIVING_PETREL));
+ MOZ_ASSERT(likes.contains(STORM_PETREL));
+ }
+
+ void testIntersect() {
+ EnumSet<SeaBird> likes = mPetrels;
+ likes &= mPetrelProcellariidae;
+ MOZ_ASSERT(likes.size() == 2);
+ MOZ_ASSERT(likes.contains(GADFLY_PETREL));
+ MOZ_ASSERT(likes.contains(TRUE_PETREL));
+ }
+
+ void testInsersection() {
+ EnumSet<SeaBird> likes = mPetrels & mPetrelProcellariidae;
+ MOZ_ASSERT(likes.size() == 2);
+ MOZ_ASSERT(likes.contains(GADFLY_PETREL));
+ MOZ_ASSERT(likes.contains(TRUE_PETREL));
+ }
+
+ void testEquality() {
+ EnumSet<SeaBird> likes = mPetrels & mPetrelProcellariidae;
+ MOZ_ASSERT(likes == EnumSet<SeaBird>(GADFLY_PETREL,
+ TRUE_PETREL));
+ }
+
+ void testDuplicates() {
+ EnumSet<SeaBird> likes = mPetrels;
+ likes += GADFLY_PETREL;
+ likes += TRUE_PETREL;
+ likes += DIVING_PETREL;
+ likes += STORM_PETREL;
+ MOZ_ASSERT(likes.size() == 4);
+ MOZ_ASSERT(likes == mPetrels);
+ }
+
+
+ EnumSet<SeaBird> mAlcidae;
+ EnumSet<SeaBird> mDiomedeidae;
+ EnumSet<SeaBird> mPetrelProcellariidae;
+ EnumSet<SeaBird> mNonPetrelProcellariidae;
+ EnumSet<SeaBird> mPetrels;
+};
+
+int main()
+{
+ EnumSetSuite suite;
+ suite.runTests();
+ return 0;
+}
diff --git a/mfbt/tests/TestPoisonArea.cpp b/mfbt/tests/TestPoisonArea.cpp
new file mode 100644
index 0000000..cf2417a
--- /dev/null
+++ b/mfbt/tests/TestPoisonArea.cpp
@@ -0,0 +1,654 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/* Code in this file needs to be kept in sync with code in nsPresArena.cpp.
+ *
+ * We want to use a fixed address for frame poisoning so that it is readily
+ * identifiable in crash dumps. Whether such an address is available
+ * without any special setup depends on the system configuration.
+ *
+ * All current 64-bit CPUs (with the possible exception of PowerPC64)
+ * reserve the vast majority of the virtual address space for future
+ * hardware extensions; valid addresses must be below some break point
+ * between 2**48 and 2**54, depending on exactly which chip you have. Some
+ * chips (notably amd64) also allow the use of the *highest* 2**48 -- 2**54
+ * addresses. Thus, if user space pointers are 64 bits wide, we can just
+ * use an address outside this range, and no more is required. To
+ * accommodate the chips that allow very high addresses to be valid, the
+ * value chosen is close to 2**63 (that is, in the middle of the space).
+ *
+ * In most cases, a purely 32-bit operating system must reserve some
+ * fraction of the address space for its own use. Contemporary 32-bit OSes
+ * tend to take the high gigabyte or so (0xC000_0000 on up). If we can
+ * prove that high addresses are reserved to the kernel, we can use an
+ * address in that region. Unfortunately, not all 32-bit OSes do this;
+ * OSX 10.4 might not, and it is unclear what mobile OSes are like
+ * (some 32-bit CPUs make it very easy for the kernel to exist in its own
+ * private address space).
+ *
+ * Furthermore, when a 32-bit user space process is running on a 64-bit
+ * kernel, the operating system has no need to reserve any of the space that
+ * the process can see, and generally does not do so. This is the scenario
+ * of greatest concern, since it covers all contemporary OSX iterations
+ * (10.5+) as well as Windows Vista and 7 on newer amd64 hardware. Linux on
+ * amd64 is generally run as a pure 64-bit environment, but its 32-bit
+ * compatibility mode also has this property.
+ *
+ * Thus, when user space pointers are 32 bits wide, we need to validate
+ * our chosen address, and possibly *make* it a good poison address by
+ * allocating a page around it and marking it inaccessible. The algorithm
+ * for this is:
+ *
+ * 1. Attempt to make the page surrounding the poison address a reserved,
+ * inaccessible memory region using OS primitives. On Windows, this is
+ * done with VirtualAlloc(MEM_RESERVE); on Unix, mmap(PROT_NONE).
+ *
+ * 2. If mmap/VirtualAlloc failed, there are two possible reasons: either
+ * the region is reserved to the kernel and no further action is
+ * required, or there is already usable memory in this area and we have
+ * to pick a different address. The tricky part is knowing which case
+ * we have, without attempting to access the region. On Windows, we
+ * rely on GetSystemInfo()'s reported upper and lower bounds of the
+ * application memory area. On Unix, there is nothing devoted to the
+ * purpose, but seeing if madvise() fails is close enough (it *might*
+ * disrupt someone else's use of the memory region, but not by as much
+ * as anything else available).
+ *
+ * Be aware of these gotchas:
+ *
+ * 1. We cannot use mmap() with MAP_FIXED. MAP_FIXED is defined to
+ * _replace_ any existing mapping in the region, if necessary to satisfy
+ * the request. Obviously, as we are blindly attempting to acquire a
+ * page at a constant address, we must not do this, lest we overwrite
+ * someone else's allocation.
+ *
+ * 2. For the same reason, we cannot blindly use mprotect() if mmap() fails.
+ *
+ * 3. madvise() may fail when applied to a 'magic' memory region provided as
+ * a kernel/user interface. Fortunately, the only such case I know about
+ * is the "vsyscall" area (not to be confused with the "vdso" area) for
+ * *64*-bit processes on Linux - and we don't even run this code for
+ * 64-bit processes.
+ *
+ * 4. VirtualQuery() does not produce any useful information if
+ * applied to kernel memory - in fact, it doesn't write its output
+ * at all. Thus, it is not used here.
+ */
+
+// MAP_ANON(YMOUS) is not in any standard, and the C99 PRI* macros are
+// not in C++98. Add defines as necessary.
+#define __STDC_FORMAT_MACROS
+#define _GNU_SOURCE 1
+#define _DARWIN_C_SOURCE 1
+
+#include <stddef.h>
+
+#ifndef _WIN32
+#include <inttypes.h>
+#else
+#define PRIxPTR "Ix"
+typedef unsigned int uint32_t;
+// MSVC defines uintptr_t in <crtdefs.h> which is brought in implicitly
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#elif defined(__OS2__)
+#include <sys/types.h>
+#include <unistd.h>
+#include <setjmp.h>
+#define INCL_DOS
+#include <os2.h>
+#else
+#include <sys/types.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <sys/mman.h>
+#ifndef MAP_ANON
+#ifdef MAP_ANONYMOUS
+#define MAP_ANON MAP_ANONYMOUS
+#else
+#error "Don't know how to get anonymous memory"
+#endif
+#endif
+#endif
+
+#define SIZxPTR ((int)(sizeof(uintptr_t)*2))
+
+/* This program assumes that a whole number of return instructions fit into
+ * 32 bits, and that 32-bit alignment is sufficient for a branch destination.
+ * For architectures where this is not true, fiddling with RETURN_INSTR_TYPE
+ * can be enough.
+ */
+
+#if defined __i386__ || defined __x86_64__ || \
+ defined __i386 || defined __x86_64 || \
+ defined _M_IX86 || defined _M_AMD64
+#define RETURN_INSTR 0xC3C3C3C3 /* ret; ret; ret; ret */
+
+#elif defined __arm__ || defined _M_ARM
+#define RETURN_INSTR 0xE12FFF1E /* bx lr */
+
+// PPC has its own style of CPU-id #defines. There is no Windows for
+// PPC as far as I know, so no _M_ variant.
+#elif defined _ARCH_PPC || defined _ARCH_PWR || defined _ARCH_PWR2
+#define RETURN_INSTR 0x4E800020 /* blr */
+
+#elif defined __sparc || defined __sparcv9
+#define RETURN_INSTR 0x81c3e008 /* retl */
+
+#elif defined __alpha
+#define RETURN_INSTR 0x6bfa8001 /* ret */
+
+#elif defined __hppa
+#define RETURN_INSTR 0xe840c002 /* bv,n r0(rp) */
+
+#elif defined __mips
+#define RETURN_INSTR 0x03e00008 /* jr ra */
+
+#ifdef __MIPSEL
+/* On mipsel, jr ra needs to be followed by a nop.
+ 0x03e00008 as a 64 bits integer just does that */
+#define RETURN_INSTR_TYPE uint64_t
+#endif
+
+#elif defined __s390__
+#define RETURN_INSTR 0x07fe0000 /* br %r14 */
+
+#elif defined __ia64
+struct ia64_instr { uint32_t i[4]; };
+static const ia64_instr _return_instr =
+ {{ 0x00000011, 0x00000001, 0x80000200, 0x00840008 }}; /* br.ret.sptk.many b0 */
+
+#define RETURN_INSTR _return_instr
+#define RETURN_INSTR_TYPE ia64_instr
+
+#else
+#error "Need return instruction for this architecture"
+#endif
+
+#ifndef RETURN_INSTR_TYPE
+#define RETURN_INSTR_TYPE uint32_t
+#endif
+
+// Miscellaneous Windows/Unix portability gumph
+
+#ifdef _WIN32
+// Uses of this function deliberately leak the string.
+static LPSTR
+StrW32Error(DWORD errcode)
+{
+ LPSTR errmsg;
+ FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, errcode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPSTR) &errmsg, 0, NULL);
+
+ // FormatMessage puts an unwanted newline at the end of the string
+ size_t n = strlen(errmsg)-1;
+ while (errmsg[n] == '\r' || errmsg[n] == '\n') n--;
+ errmsg[n+1] = '\0';
+ return errmsg;
+}
+#define LastErrMsg() (StrW32Error(GetLastError()))
+
+// Because we use VirtualAlloc in MEM_RESERVE mode, the "page size" we want
+// is the allocation granularity.
+static SYSTEM_INFO _sinfo;
+#undef PAGESIZE
+#define PAGESIZE (_sinfo.dwAllocationGranularity)
+
+
+static void *
+ReserveRegion(uintptr_t request, bool accessible)
+{
+ return VirtualAlloc((void *)request, PAGESIZE,
+ accessible ? MEM_RESERVE|MEM_COMMIT : MEM_RESERVE,
+ accessible ? PAGE_EXECUTE_READWRITE : PAGE_NOACCESS);
+}
+
+static void
+ReleaseRegion(void *page)
+{
+ VirtualFree(page, PAGESIZE, MEM_RELEASE);
+}
+
+static bool
+ProbeRegion(uintptr_t page)
+{
+ if (page >= (uintptr_t)_sinfo.lpMaximumApplicationAddress &&
+ page + PAGESIZE >= (uintptr_t)_sinfo.lpMaximumApplicationAddress) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static bool
+MakeRegionExecutable(void *)
+{
+ return false;
+}
+
+#undef MAP_FAILED
+#define MAP_FAILED 0
+
+#elif defined(__OS2__)
+
+// page size is always 4k
+#undef PAGESIZE
+#define PAGESIZE 0x1000
+static unsigned long rc = 0;
+
+char * LastErrMsg()
+{
+ char * errmsg = (char *)malloc(16);
+ sprintf(errmsg, "rc= %ld", rc);
+ rc = 0;
+ return errmsg;
+}
+
+static void *
+ReserveRegion(uintptr_t request, bool accessible)
+{
+ // OS/2 doesn't support allocation at an arbitrary address,
+ // so return an address that is known to be invalid.
+ if (request) {
+ return (void*)0xFFFD0000;
+ }
+ void * mem = 0;
+ rc = DosAllocMem(&mem, PAGESIZE,
+ (accessible ? PAG_COMMIT : 0) | PAG_READ | PAG_WRITE);
+ return rc ? 0 : mem;
+}
+
+static void
+ReleaseRegion(void *page)
+{
+ return;
+}
+
+static bool
+ProbeRegion(uintptr_t page)
+{
+ // There's no reliable way to probe an address in the system
+ // arena other than by touching it and seeing if a trap occurs.
+ return false;
+}
+
+static bool
+MakeRegionExecutable(void *page)
+{
+ rc = DosSetMem(page, PAGESIZE, PAG_READ | PAG_WRITE | PAG_EXECUTE);
+ return rc ? true : false;
+}
+
+typedef struct _XCPT {
+ EXCEPTIONREGISTRATIONRECORD regrec;
+ jmp_buf jmpbuf;
+} XCPT;
+
+static unsigned long _System
+ExceptionHandler(PEXCEPTIONREPORTRECORD pReport,
+ PEXCEPTIONREGISTRATIONRECORD pRegRec,
+ PCONTEXTRECORD pContext, PVOID pVoid)
+{
+ if (pReport->fHandlerFlags == 0) {
+ longjmp(((XCPT*)pRegRec)->jmpbuf, pReport->ExceptionNum);
+ }
+ return XCPT_CONTINUE_SEARCH;
+}
+
+#undef MAP_FAILED
+#define MAP_FAILED 0
+
+#else // Unix
+
+#define LastErrMsg() (strerror(errno))
+
+static unsigned long _pagesize;
+#define PAGESIZE _pagesize
+
+static void *
+ReserveRegion(uintptr_t request, bool accessible)
+{
+ return mmap(reinterpret_cast<void*>(request), PAGESIZE,
+ accessible ? PROT_READ|PROT_WRITE : PROT_NONE,
+ MAP_PRIVATE|MAP_ANON, -1, 0);
+}
+
+static void
+ReleaseRegion(void *page)
+{
+ munmap(page, PAGESIZE);
+}
+
+static bool
+ProbeRegion(uintptr_t page)
+{
+ if (madvise(reinterpret_cast<void*>(page), PAGESIZE, MADV_NORMAL)) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static int
+MakeRegionExecutable(void *page)
+{
+ return mprotect((caddr_t)page, PAGESIZE, PROT_READ|PROT_WRITE|PROT_EXEC);
+}
+
+#endif
+
+static uintptr_t
+ReservePoisonArea()
+{
+ if (sizeof(uintptr_t) == 8) {
+ // Use the hardware-inaccessible region.
+ // We have to avoid 64-bit constants and shifts by 32 bits, since this
+ // code is compiled in 32-bit mode, although it is never executed there.
+ uintptr_t result = (((uintptr_t(0x7FFFFFFFu) << 31) << 1 |
+ uintptr_t(0xF0DEAFFFu)) &
+ ~uintptr_t(PAGESIZE-1));
+ printf("INFO | poison area assumed at 0x%.*" PRIxPTR "\n", SIZxPTR, result);
+ return result;
+ } else {
+ // First see if we can allocate the preferred poison address from the OS.
+ uintptr_t candidate = (0xF0DEAFFF & ~(PAGESIZE-1));
+ void *result = ReserveRegion(candidate, false);
+ if (result == (void *)candidate) {
+ // success - inaccessible page allocated
+ printf("INFO | poison area allocated at 0x%.*" PRIxPTR
+ " (preferred addr)\n", SIZxPTR, (uintptr_t)result);
+ return candidate;
+ }
+
+ // That didn't work, so see if the preferred address is within a range
+ // of permanently inacessible memory.
+ if (ProbeRegion(candidate)) {
+ // success - selected page cannot be usable memory
+ if (result != MAP_FAILED)
+ ReleaseRegion(result);
+ printf("INFO | poison area assumed at 0x%.*" PRIxPTR
+ " (preferred addr)\n", SIZxPTR, candidate);
+ return candidate;
+ }
+
+ // The preferred address is already in use. Did the OS give us a
+ // consolation prize?
+ if (result != MAP_FAILED) {
+ printf("INFO | poison area allocated at 0x%.*" PRIxPTR
+ " (consolation prize)\n", SIZxPTR, (uintptr_t)result);
+ return (uintptr_t)result;
+ }
+
+ // It didn't, so try to allocate again, without any constraint on
+ // the address.
+ result = ReserveRegion(0, false);
+ if (result != MAP_FAILED) {
+ printf("INFO | poison area allocated at 0x%.*" PRIxPTR
+ " (fallback)\n", SIZxPTR, (uintptr_t)result);
+ return (uintptr_t)result;
+ }
+
+ printf("ERROR | no usable poison area found\n");
+ return 0;
+ }
+}
+
+/* The "positive control" area confirms that we can allocate a page with the
+ * proper characteristics.
+ */
+static uintptr_t
+ReservePositiveControl()
+{
+
+ void *result = ReserveRegion(0, false);
+ if (result == MAP_FAILED) {
+ printf("ERROR | allocating positive control | %s\n", LastErrMsg());
+ return 0;
+ }
+ printf("INFO | positive control allocated at 0x%.*" PRIxPTR "\n",
+ SIZxPTR, (uintptr_t)result);
+ return (uintptr_t)result;
+}
+
+/* The "negative control" area confirms that our probe logic does detect a
+ * page that is readable, writable, or executable.
+ */
+static uintptr_t
+ReserveNegativeControl()
+{
+ void *result = ReserveRegion(0, true);
+ if (result == MAP_FAILED) {
+ printf("ERROR | allocating negative control | %s\n", LastErrMsg());
+ return 0;
+ }
+
+ // Fill the page with return instructions.
+ RETURN_INSTR_TYPE *p = (RETURN_INSTR_TYPE *)result;
+ RETURN_INSTR_TYPE *limit = (RETURN_INSTR_TYPE *)(((char *)result) + PAGESIZE);
+ while (p < limit)
+ *p++ = RETURN_INSTR;
+
+ // Now mark it executable as well as readable and writable.
+ // (mmap(PROT_EXEC) may fail when applied to anonymous memory.)
+
+ if (MakeRegionExecutable(result)) {
+ printf("ERROR | making negative control executable | %s\n", LastErrMsg());
+ return 0;
+ }
+
+ printf("INFO | negative control allocated at 0x%.*" PRIxPTR "\n",
+ SIZxPTR, (uintptr_t)result);
+ return (uintptr_t)result;
+}
+
+static void
+JumpTo(uintptr_t opaddr)
+{
+#ifdef __ia64
+ struct func_call {
+ uintptr_t func;
+ uintptr_t gp;
+ } call = { opaddr, };
+ ((void (*)())&call)();
+#else
+ ((void (*)())opaddr)();
+#endif
+}
+
+#ifdef _WIN32
+static BOOL
+IsBadExecPtr(uintptr_t ptr)
+{
+ BOOL ret = false;
+
+#ifdef _MSC_VER
+ __try {
+ JumpTo(ptr);
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ ret = true;
+ }
+#else
+ printf("INFO | exec test not supported on MinGW build\n");
+ // We do our best
+ ret = IsBadReadPtr((const void*)ptr, 1);
+#endif
+ return ret;
+}
+#endif
+
+/* Test each page. */
+static bool
+TestPage(const char *pagelabel, uintptr_t pageaddr, int should_succeed)
+{
+ const char *oplabel;
+ uintptr_t opaddr;
+
+ bool failed = false;
+ for (unsigned int test = 0; test < 3; test++) {
+ switch (test) {
+ // The execute test must be done before the write test, because the
+ // write test will clobber memory at the target address.
+ case 0: oplabel = "reading"; opaddr = pageaddr + PAGESIZE/2 - 1; break;
+ case 1: oplabel = "executing"; opaddr = pageaddr + PAGESIZE/2; break;
+ case 2: oplabel = "writing"; opaddr = pageaddr + PAGESIZE/2 - 1; break;
+ default: abort();
+ }
+
+#ifdef _WIN32
+ BOOL badptr;
+
+ switch (test) {
+ case 0: badptr = IsBadReadPtr((const void*)opaddr, 1); break;
+ case 1: badptr = IsBadExecPtr(opaddr); break;
+ case 2: badptr = IsBadWritePtr((void*)opaddr, 1); break;
+ default: abort();
+ }
+
+ if (badptr) {
+ if (should_succeed) {
+ printf("TEST-UNEXPECTED-FAIL | %s %s\n", oplabel, pagelabel);
+ failed = true;
+ } else {
+ printf("TEST-PASS | %s %s\n", oplabel, pagelabel);
+ }
+ } else {
+ // if control reaches this point the probe succeeded
+ if (should_succeed) {
+ printf("TEST-PASS | %s %s\n", oplabel, pagelabel);
+ } else {
+ printf("TEST-UNEXPECTED-FAIL | %s %s\n", oplabel, pagelabel);
+ failed = true;
+ }
+ }
+#elif defined(__OS2__)
+ XCPT xcpt;
+ volatile int code = setjmp(xcpt.jmpbuf);
+
+ if (!code) {
+ xcpt.regrec.prev_structure = 0;
+ xcpt.regrec.ExceptionHandler = ExceptionHandler;
+ DosSetExceptionHandler(&xcpt.regrec);
+ unsigned char scratch;
+ switch (test) {
+ case 0: scratch = *(volatile unsigned char *)opaddr; break;
+ case 1: ((void (*)())opaddr)(); break;
+ case 2: *(volatile unsigned char *)opaddr = 0; break;
+ default: abort();
+ }
+ }
+
+ if (code) {
+ if (should_succeed) {
+ printf("TEST-UNEXPECTED-FAIL | %s %s | exception code %x\n",
+ oplabel, pagelabel, code);
+ failed = true;
+ } else {
+ printf("TEST-PASS | %s %s | exception code %x\n",
+ oplabel, pagelabel, code);
+ }
+ } else {
+ if (should_succeed) {
+ printf("TEST-PASS | %s %s\n", oplabel, pagelabel);
+ } else {
+ printf("TEST-UNEXPECTED-FAIL | %s %s\n", oplabel, pagelabel);
+ failed = true;
+ }
+ DosUnsetExceptionHandler(&xcpt.regrec);
+ }
+#else
+ pid_t pid = fork();
+ if (pid == -1) {
+ printf("ERROR | %s %s | fork=%s\n", oplabel, pagelabel,
+ LastErrMsg());
+ exit(2);
+ } else if (pid == 0) {
+ volatile unsigned char scratch;
+ switch (test) {
+ case 0: scratch = *(volatile unsigned char *)opaddr; break;
+ case 1: JumpTo(opaddr); break;
+ case 2: *(volatile unsigned char *)opaddr = 0; break;
+ default: abort();
+ }
+ (void)scratch;
+ _exit(0);
+ } else {
+ int status;
+ if (waitpid(pid, &status, 0) != pid) {
+ printf("ERROR | %s %s | wait=%s\n", oplabel, pagelabel,
+ LastErrMsg());
+ exit(2);
+ }
+
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+ if (should_succeed) {
+ printf("TEST-PASS | %s %s\n", oplabel, pagelabel);
+ } else {
+ printf("TEST-UNEXPECTED-FAIL | %s %s | unexpected successful exit\n",
+ oplabel, pagelabel);
+ failed = true;
+ }
+ } else if (WIFEXITED(status)) {
+ printf("ERROR | %s %s | unexpected exit code %d\n",
+ oplabel, pagelabel, WEXITSTATUS(status));
+ exit(2);
+ } else if (WIFSIGNALED(status)) {
+ if (should_succeed) {
+ printf("TEST-UNEXPECTED-FAIL | %s %s | unexpected signal %d\n",
+ oplabel, pagelabel, WTERMSIG(status));
+ failed = true;
+ } else {
+ printf("TEST-PASS | %s %s | signal %d (as expected)\n",
+ oplabel, pagelabel, WTERMSIG(status));
+ }
+ } else {
+ printf("ERROR | %s %s | unexpected exit status %d\n",
+ oplabel, pagelabel, status);
+ exit(2);
+ }
+ }
+#endif
+ }
+ return failed;
+}
+
+int
+main()
+{
+#ifdef _WIN32
+ GetSystemInfo(&_sinfo);
+#elif !defined(__OS2__)
+ _pagesize = sysconf(_SC_PAGESIZE);
+#endif
+
+ uintptr_t ncontrol = ReserveNegativeControl();
+ uintptr_t pcontrol = ReservePositiveControl();
+ uintptr_t poison = ReservePoisonArea();
+
+ if (!ncontrol || !pcontrol || !poison)
+ return 2;
+
+ bool failed = false;
+ failed |= TestPage("negative control", ncontrol, 1);
+ failed |= TestPage("positive control", pcontrol, 0);
+ failed |= TestPage("poison area", poison, 0);
+
+ return failed ? 1 : 0;
+}
diff --git a/mfbt/tests/TestSHA1.cpp b/mfbt/tests/TestSHA1.cpp
new file mode 100644
index 0000000..0d30dbe
--- /dev/null
+++ b/mfbt/tests/TestSHA1.cpp
@@ -0,0 +1,204 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/SHA1.h"
+
+using mozilla::SHA1Sum;
+
+static unsigned int testV[1024] = {
+ 0x048edc1a, 0x4345588c, 0x0ef03cbf, 0x1d6438f5, 0x094e0a1e, 0x68535f60,
+ 0x14e8c927, 0x60190043, 0x5d640ab7, 0x73dc7c62, 0x364223f9, 0x47320292,
+ 0x3924cae0, 0x5f6b26d3, 0x5efa04ef, 0x7aab361e, 0x2773b1aa, 0x1631b07d,
+ 0x385b5dd1, 0x26c809b0, 0x28ad3a9f, 0x0315292a, 0x1a544e67, 0x1e79dcb9,
+ 0x787683e8, 0x3a591c75, 0x1dd338c7, 0x01c539e5, 0x1c15b23e, 0x0697c25c,
+ 0x4df5fd45, 0x672aa324, 0x39f74e6e, 0x269cdd5f, 0x087b6fce, 0x293509db,
+ 0x0aef54a9, 0x210c4cc5, 0x29d6dc4a, 0x16320825, 0x3ab7b181, 0x56d6fd25,
+ 0x6837fda2, 0x3e7994c2, 0x37f77529, 0x48c85472, 0x424fd84d, 0x00aba7fa,
+ 0x6d8475de, 0x354634a7, 0x0c73bb49, 0x0a335de6, 0x0a9ea542, 0x5ffb31f1,
+ 0x00a6a3f2, 0x76b14a03, 0x1e436a37, 0x173b766a, 0x33cf3ca0, 0x34eb0f1a,
+ 0x4ca073ee, 0x27591fe6, 0x5eaf3356, 0x10c24493, 0x1bad88b6, 0x676f2309,
+ 0x7f5e2d91, 0x74bd4c83, 0x66549b43, 0x52ffdf24, 0x2dfa0a83, 0x7c3e1cbf,
+ 0x1edf87fc, 0x1f6fa930, 0x7c29bc74, 0x374bcd2f, 0x5b43de94, 0x0d09a3a6,
+ 0x7437ecb0, 0x635117f8, 0x2aa78f65, 0x2c788958, 0x098cb9f3, 0x13ed5b3f,
+ 0x41b7c7ba, 0x696b2d88, 0x42e20d63, 0x69585b1d, 0x4a9b027c, 0x0c761cba,
+ 0x563bdbc4, 0x3bde2f5b, 0x0bab9730, 0x7740104c, 0x11641702, 0x26f03c32,
+ 0x011a87c6, 0x2c5e4e6c, 0x46c34200, 0x6a167e84, 0x34205728, 0x0e8a6152,
+ 0x0014604b, 0x6793bacd, 0x442bca9c, 0x6f2018ce, 0x4313e07e, 0x77f2c69c,
+ 0x62621441, 0x47bf6358, 0x59c45e04, 0x16ba3426, 0x6ac0c19d, 0x20218c6b,
+ 0x510b4ddc, 0x585f6c9d, 0x1ed02b0c, 0x366bf0a9, 0x131c7f59, 0x0ebcd320,
+ 0x00ca858a, 0x5efbcb77, 0x2a7a1859, 0x64bb5afd, 0x76258886, 0x6505c895,
+ 0x602cfa32, 0x17040942, 0x783df744, 0x3838e0ae, 0x6a021e39, 0x4c8c9c5a,
+ 0x4a5e96b6, 0x10f4477d, 0x247fda4f, 0x4c390400, 0x0cbe048c, 0x7b547d26,
+ 0x1e2e6897, 0x4ba7e01b, 0x5cfea1bb, 0x39a2d199, 0x45aee64a, 0x12615500,
+ 0x0151615f, 0x1a9f5d33, 0x4542ed44, 0x101357eb, 0x35a16b1f, 0x3420b3e1,
+ 0x6442bac7, 0x1c0f2a8c, 0x68d642f1, 0x45744fc4, 0x048e60cb, 0x5f217f44,
+ 0x6cc7d151, 0x27f41984, 0x2d01eb09, 0x2bb15aea, 0x6dda49f8, 0x590dd6bc,
+ 0x280cc20b, 0x7e2592b5, 0x043642f0, 0x292b5d29, 0x2e0a9b69, 0x41162471,
+ 0x1e55db6b, 0x648b96fe, 0x05f8f9d1, 0x4a9d4cbb, 0x38517039, 0x2b0f8917,
+ 0x4d1e67bb, 0x713e0974, 0x64fdf214, 0x11223963, 0x2bd09d24, 0x19924092,
+ 0x4b4a70f0, 0x1ece6b03, 0x1780c9c1, 0x09b4c3ac, 0x58ac7e73, 0x5c9a4747,
+ 0x321f943b, 0x41167667, 0x3a19cf8c, 0x53f4144d, 0x03a498de, 0x6fb4b742,
+ 0x54d793cb, 0x7ee164e2, 0x501af74c, 0x43201e7f, 0x0ad581be, 0x497f046a,
+ 0x3b1d2a9f, 0x53b88eb0, 0x2c3a26c5, 0x5ae970ba, 0x7d7ee4ff, 0x471366c5,
+ 0x46119703, 0x3bfc2e58, 0x456d6c4f, 0x4b6bb181, 0x45d7c872, 0x0d023221,
+ 0x021176d1, 0x4195ad44, 0x4621ec90, 0x3ae68279, 0x57952f71, 0x1796080c,
+ 0x228077bb, 0x5e2b7fee, 0x3d71dd88, 0x4a651849, 0x7f1c8081, 0x04c333fc,
+ 0x1f99bff6, 0x11b7754c, 0x740be324, 0x069bf2e2, 0x0802f3e0, 0x371cf30e,
+ 0x1d44dda5, 0x6033b9e5, 0x5639a9b0, 0x6526bfff, 0x14d7d9b7, 0x4182b6a7,
+ 0x01a5fa76, 0x7aa5e581, 0x762465e6, 0x386b3a2e, 0x495a3ab0, 0x04421b2e,
+ 0x46e04591, 0x472af458, 0x6a007dd3, 0x2e8be484, 0x18660abe, 0x7969af82,
+ 0x5a242a83, 0x581b5f72, 0x5f0eff6d, 0x38aea98c, 0x2acb5853, 0x6d650b35,
+ 0x10b750d7, 0x18fdcd14, 0x09b4816c, 0x3ceef016, 0x6957153c, 0x27cf39fb,
+ 0x60e3495d, 0x381e1da6, 0x4b5be02d, 0x14b6f309, 0x6380c589, 0x1a31f436,
+ 0x4b5e50c1, 0x493ac048, 0x314baad1, 0x71e24ab7, 0x718af49c, 0x022f4658,
+ 0x1a419d5b, 0x1854610d, 0x2ec4e99a, 0x7096ce50, 0x5467ba00, 0x404aab4c,
+ 0x1a5ab015, 0x217580f7, 0x2d50071e, 0x71a9f437, 0x27f758b5, 0x11cd8b3f,
+ 0x63b089c9, 0x53c860c1, 0x2fa6b7d7, 0x61e54771, 0x5c0ba6b9, 0x3138f796,
+ 0x5c7359cd, 0x4c2c5654, 0x549d581c, 0x3129ebf7, 0x4958a248, 0x1a460541,
+ 0x68e64964, 0x597c0609, 0x57afcbab, 0x2f1c6479, 0x57a0ad5c, 0x5936938f,
+ 0x536a5cbe, 0x29aacf0b, 0x43eca70d, 0x6e7a3e4e, 0x563c1e3b, 0x32f23909,
+ 0x12faa42d, 0x28b0bbde, 0x797e2842, 0x1b827bdf, 0x0df96a6e, 0x542ef7f4,
+ 0x6226d368, 0x01cb4258, 0x77bcba08, 0x7e6dc041, 0x0571eda3, 0x0fdf5065,
+ 0x5c9b9f7a, 0x2b496dd6, 0x02d3b40b, 0x3a5752db, 0x4843a293, 0x6fdc9c3f,
+ 0x42963996, 0x39c9e4eb, 0x01db58ad, 0x7e79381c, 0x5bb207bb, 0x2df5de51,
+ 0x1549ec82, 0x64f01e70, 0x536eb0d0, 0x10fa6e03, 0x5b7f9a20, 0x2d8b625d,
+ 0x397410c7, 0x7778284e, 0x1ab75170, 0x254f304e, 0x395ba877, 0x0c2e2815,
+ 0x5c723dec, 0x63b91327, 0x7c5954b5, 0x67dd69a3, 0x21d220c7, 0x5a287fcd,
+ 0x0d0b9c59, 0x22444c9f, 0x6305cb43, 0x12f717cc, 0x77c11945, 0x0e79bda8,
+ 0x6e014391, 0x441d0179, 0x5e17dd2f, 0x53e57a5c, 0x692f4b9a, 0x76c1e94b,
+ 0x5a872d81, 0x044f7e7e, 0x0970844f, 0x25e34e73, 0x57865d3c, 0x640771d2,
+ 0x12d410ed, 0x1424e079, 0x3e1c7fd7, 0x0e89295a, 0x48dcf262, 0x55a29550,
+ 0x0fd4d360, 0x7494d449, 0x41e6f260, 0x2230d4e7, 0x5ad1cd49, 0x7f8dd428,
+ 0x7722b48a, 0x7a14848d, 0x2a83335a, 0x548c0d9b, 0x24f5d43b, 0x33a417cb,
+ 0x3061e078, 0x1a1bc935, 0x5aedb5df, 0x6755f3e4, 0x795e4cdb, 0x64dfcd1c,
+ 0x6d5164fc, 0x34a3df0e, 0x2cc92142, 0x2569127d, 0x130f3d86, 0x43617cc2,
+ 0x25eaf1fa, 0x044ae792, 0x4b47ee17, 0x6879ea87, 0x7eb455fa, 0x54481e19,
+ 0x13bba2f0, 0x6da3fe79, 0x19c306ff, 0x42591e38, 0x2b0e205d, 0x60bd48bc,
+ 0x550aa0ce, 0x2296a6ef, 0x551eb052, 0x76df1b8e, 0x242a2d22, 0x0ada0b06,
+ 0x58b661ec, 0x490bec94, 0x20bd7c59, 0x760de8c3, 0x7a048ee8, 0x44ba6dcd,
+ 0x3816abd9, 0x47e8527e, 0x2194a188, 0x6967a480, 0x7f7e2083, 0x0ec455f3,
+ 0x78198eab, 0x3d710773, 0x05969198, 0x76ffcffe, 0x54be4797, 0x11105781,
+ 0x3a851719, 0x516284b8, 0x4295de1c, 0x3905be43, 0x6d4e7d6a, 0x0877796d,
+ 0x0b9e986a, 0x5e2b853f, 0x7e6c79cd, 0x4a44a54c, 0x1e28b9a2, 0x5b1e408e,
+ 0x6a1c8eac, 0x62a87929, 0x4f075dac, 0x5c030e8c, 0x3df73ce9, 0x321c3c69,
+ 0x2325cc45, 0x4eaf0759, 0x486a31fb, 0x12d04b94, 0x714e15d5, 0x420d1910,
+ 0x092dc45b, 0x0119beac, 0x68b2bfdb, 0x74863a17, 0x3c7ab8e5, 0x035bc2df,
+ 0x4e7a7965, 0x017f58d6, 0x6414074e, 0x3a1e64ae, 0x2d6725d8, 0x0f22f82a,
+ 0x0a0affa0, 0x4159f31e, 0x4002cb9d, 0x234e393f, 0x6028169f, 0x3b804078,
+ 0x0c16e2e1, 0x0e198020, 0x24b13c40, 0x1ceb2143, 0x38dd4246, 0x6f483590,
+ 0x69b20a6e, 0x105580b1, 0x5d60f184, 0x065d18eb, 0x09a28739, 0x70345728,
+ 0x595a5934, 0x14a78a43, 0x449f05c7, 0x6556fcfc, 0x260bc0b2, 0x3afb600e,
+ 0x1f47bb91, 0x145c14b6, 0x541832fe, 0x54f10f23, 0x3013650e, 0x6c0d32ba,
+ 0x4f202c8d, 0x66bcc661, 0x6131dc7f, 0x04828b25, 0x1737565d, 0x520e967f,
+ 0x16cf0438, 0x6f2bc19e, 0x553c3dda, 0x356906b0, 0x333916d5, 0x2887c195,
+ 0x11e7440b, 0x6354f182, 0x06b2f977, 0x6d2c9a5c, 0x2d02bfb7, 0x74fafcf6,
+ 0x2b955161, 0x74035c38, 0x6e9bc991, 0x09a3a5b9, 0x460f416a, 0x11afabfc,
+ 0x66e32d10, 0x4a56ac6e, 0x6448afa8, 0x680b0044, 0x05d0e296, 0x49569eac,
+ 0x0adb563b, 0x4a9da168, 0x4f857004, 0x0f234600, 0x6db386ec, 0x280b94bf,
+ 0x7cd258a5, 0x6165fd88, 0x3bf2aac9, 0x2cb47c44, 0x2381c2a4, 0x4fe42552,
+ 0x21d4c81e, 0x24baa9af, 0x365231cb, 0x11b7fc81, 0x419748fb, 0x38ff637e,
+ 0x065f3365, 0x21f1aba8, 0x2df41ace, 0x5cec1d95, 0x22c078a8, 0x7bb894fc,
+ 0x2d66fc53, 0x7ed82ccc, 0x4485c9d7, 0x1af210fc, 0x5d2faa09, 0x3b33412e,
+ 0x79d12ea8, 0x7bb8103b, 0x5cea1a7b, 0x2779db45, 0x1250ed5b, 0x0c4d8964,
+ 0x6c18e9f5, 0x501ddc60, 0x3de43ae4, 0x6c0e8577, 0x0adfb426, 0x7ec718f5,
+ 0x1991f387, 0x101ccb9c, 0x632360b4, 0x7d52ce4d, 0x0b58c91c, 0x1fa59d53,
+ 0x0b0b48b0, 0x297315d0, 0x7f3132ff, 0x323b85d1, 0x2f852141, 0x23e84bdc,
+ 0x3732cb25, 0x1274eb57, 0x21a882c3, 0x095288a9, 0x2120e253, 0x617799ce,
+ 0x5e4926b3, 0x52575363, 0x696722e0, 0x509c9117, 0x3b60f14f, 0x423310fa,
+ 0x4e694e80, 0x000a647e, 0x453e283a, 0x3f1d21ef, 0x527c91f0, 0x7ac2e88a,
+ 0x1ba3b840, 0x1c3f253a, 0x04c40280, 0x437dc361, 0x7247859c, 0x61e5b34c,
+ 0x20746a53, 0x58cfc2df, 0x79edf48e, 0x5b48e723, 0x7b08baac, 0x1d1035ea,
+ 0x023fc918, 0x2de0427c, 0x71540904, 0x4030e8f5, 0x2b0961f6, 0x4ec98ef0,
+ 0x781076ee, 0x0dac959b, 0x16f66214, 0x273411e5, 0x02334297, 0x3b568cd1,
+ 0x7cf4e8c0, 0x0f4c2c91, 0x2d8dd28e, 0x4a7b3fb0, 0x237969ae, 0x363d6cb6,
+ 0x75fee60a, 0x5825f4df, 0x29f79f9d, 0x22de4f33, 0x2309590e, 0x1977c2bd,
+ 0x67f7bebe, 0x452b8330, 0x5dc70832, 0x5cddbea4, 0x59091e0b, 0x4d287830,
+ 0x2bbc2ce6, 0x420ee023, 0x02d6e086, 0x228a7a14, 0x48207207, 0x1d5ccc5a,
+ 0x37d32cdc, 0x50dc6508, 0x0b795304, 0x5b9fd543, 0x2a3f2925, 0x72e71606,
+ 0x0dc8ba42, 0x3279a910, 0x6bd2c2e2, 0x775065d8, 0x547c59a6, 0x4b5374cf,
+ 0x0c45cd18, 0x532096d6, 0x351c9bd1, 0x107fdce0, 0x3ae69075, 0x5dddd5de,
+ 0x3bb0ba8b, 0x0b1a0019, 0x6c226525, 0x109e9002, 0x312191be, 0x16fa3de8,
+ 0x4a5197aa, 0x0931b2d2, 0x79ee6e1b, 0x657a142b, 0x6ab74d38, 0x77440cff,
+ 0x11e37956, 0x5c335799, 0x269d3be3, 0x18923cfd, 0x4dd71b00, 0x77c58014,
+ 0x07145324, 0x1678546a, 0x5dfd4f6a, 0x207f4e13, 0x6b0a98c0, 0x015bc2cf,
+ 0x1636d8fe, 0x7bc5f038, 0x183a0661, 0x573ec5f3, 0x54cf2255, 0x2fcc905c,
+ 0x71bb70b9, 0x2b122a89, 0x59f86e5b, 0x5528273d, 0x464cf857, 0x27efdeec,
+ 0x1d0bcfcc, 0x64d7837f, 0x1e7a659a, 0x02aa611c, 0x53969ad5, 0x0e83f59f,
+ 0x50a6d11b, 0x79513c59, 0x0e5c3c98, 0x2ed7bbcf, 0x117de9d9, 0x375ec696,
+ 0x19c830aa, 0x66950511, 0x2b6dbbaa, 0x5ca18c9b, 0x0a487514, 0x6f44a887,
+ 0x6921bc6e, 0x3ef8130b, 0x26f6cde3, 0x686d7605, 0x6583553a, 0x29bcf7cc,
+ 0x55d42201, 0x1c93497c, 0x64c53231, 0x32088f6e, 0x381c5770, 0x617574d8,
+ 0x09757952, 0x1a616eb0, 0x1140e8aa, 0x0ff66ffb, 0x32039001, 0x5a455e7c,
+ 0x0027b906, 0x21cf154c, 0x67d3527f, 0x56fd7602, 0x150f8b25, 0x2ae8e4c8,
+ 0x0bf10aec, 0x3d26a40f, 0x5c4c8ffc, 0x3c291322, 0x737fd02c, 0x4b506209,
+ 0x484ddaa4, 0x00b44669, 0x5974bdd1, 0x7d39d617, 0x12995404, 0x48f00bbe,
+ 0x44f7c59a, 0x23cb9292, 0x6476f20b, 0x034fbd59, 0x2893161c, 0x1dbae8c0,
+ 0x50348c2e, 0x797f0957, 0x685ddeaf, 0x36fb8a2e, 0x0fceb6f4, 0x10347ab4,
+ 0x72720bfc, 0x292a4304, 0x0cbf8a27, 0x3cea6db7, 0x4b0c6b15, 0x57e8e716,
+ 0x4e9c54cc, 0x4fc7f7ca, 0x49a6d3e2, 0x10fc2df3, 0x73db387e, 0x72cb89c3,
+ 0x71dba437, 0x4b14048c, 0x6e1af265, 0x1084b213, 0x3842107d, 0x6ecdc171,
+ 0x647919b2, 0x41a80841, 0x7b387c76, 0x46bc094b, 0x331b312a, 0x2f140cc4,
+ 0x355d0a11, 0x19390200, 0x69b05263, 0x582963fa, 0x44897e31, 0x66a473f0,
+ 0x0374f08d, 0x35879e45, 0x5e1dd7ef, 0x34d6a311, 0x6e4e18eb, 0x7b44734b,
+ 0x0e421333, 0x3da026d8, 0x5becbf4b, 0x56db4a1f, 0x1f2089bc, 0x28c733f2,
+ 0x04b0975d, 0x6156f224, 0x12d1f40f, 0x7f4d30f4, 0x2c0b9861, 0x769a083b,
+ 0x739544fb, 0x1dbd1067, 0x0e8cd717, 0x4c246fb2, 0x115eff39, 0x19e22f2a,
+ 0x4563ba61, 0x5d33a617, 0x54af83cf, 0x030bde73, 0x54b4736d, 0x0f01dfec,
+ 0x08869c01, 0x4e9e4d7b, 0x4739855a, 0x62d964a3, 0x26948fde, 0x30adf212,
+ 0x1f57b400, 0x3766c914, 0x1e7f9d1c, 0x33258b59, 0x522ab2c2, 0x3dc99798,
+ 0x15f53fe2, 0x05636669, 0x354b59c3, 0x1c37ebd4, 0x0bb7ebf9, 0x0e4e87f9,
+ 0x680d3124, 0x2770d549, 0x0c5e112e, 0x74aaa7ed, 0x06c0b550, 0x342b5922,
+ 0x4532ab5b, 0x4257dbee, 0x087f32a9, 0x45ada3e3, 0x7a854272, 0x061625f2,
+ 0x47c85a91, 0x25ad375d, 0x2809bd9d, 0x168b9348, 0x4381b0a3, 0x6f2dc6ca,
+ 0x122e54f6, 0x6c3228a6, 0x653c1652, 0x60b60584, 0x1d304b77, 0x4cc74c58,
+ 0x087e3dd5, 0x79bd540e, 0x79ab7a70, 0x26fcd1c9, 0x342abaaf, 0x644716b0,
+ 0x01f076cb, 0x73628937, 0x20b01ff8, 0x5832b80b, 0x2f77fc92, 0x4468d962,
+ 0x2bac2679, 0x7f850778, 0x47d2997c, 0x02690cb7, 0x7de54951, 0x54d80b14,
+ 0x5e0c6854, 0x313cc749, 0x622b86ba, 0x38dbf6d3, 0x045d3e52, 0x574f87fd,
+ 0x09f1b078, 0x31784f71, 0x4f01dd2f, 0x1874c9f9, 0x5837c7af, 0x2372f768,
+ 0x531bd1e8, 0x61816c0b, 0x4592995f, 0x156463c0, 0x250c5afe, 0x40c83178,
+ 0x4396f6b7, 0x29bdbec0, 0x43ea8ca5, 0x5c474696, 0x2c869192, 0x2ff2f51a,
+ 0x7c963fe5, 0x294319c1, 0x019fbe26, 0x72fa8e68, 0x245ca463, 0x4ca88208,
+ 0x72ac845a, 0x25307181, 0x2cdf88f7, 0x0adbfebd, 0x2eea465b, 0x52e4eee0,
+ 0x084daacd, 0x717ce67e, 0x594087c2, 0x2b8ee5c7, 0x4558f811, 0x76b65ba4,
+ 0x5de05e09, 0x3db76e27, 0x3c75110d, 0x04ca67e7, 0x51cd6d09, 0x7b4e9c3e,
+ 0x7cdda4d2, 0x674fb021, 0x7d372d2d, 0x13f7978b, 0x5fb106b1, 0x034377d1,
+ 0x2e5336f3, 0x099bb17d, 0x04e6755e, 0x34f73c1e, 0x004e0a0d, 0x7f2c32e2,
+ 0x1fc8f910, 0x67d0859d, 0x76462b25, 0x59fa9a17, 0x028e53ef, 0x3d6d5fdd,
+ 0x79a4671e, 0x5cbec506, 0x2c23ee6d, 0x628a2c1e, 0x4dae87bd, 0x07a189ea,
+ 0x3a414a96, 0x5915f622, 0x6bea011e, 0x412674cf, 0x07ecc314, 0x6a7dbce8,
+ 0x7e176f10, 0x68e60d47, 0x079ea970, 0x79f3b55c, 0x65a46098, 0x56155533,
+ 0x7e5d0272, 0x795bfad5, 0x094da770, 0x05ba427c, 0x152e430e, 0x187d8470,
+ 0x08e607bc, 0x45ce5ef9, 0x654231ae, 0x38d8cb48, 0x605632f8, 0x25cf8ee9,
+ 0x11497170, 0x171a3b00, 0x0f103d49, 0x24826483, 0x2848e187, 0x7498919b,
+ 0x1bb788cb, 0x791ad5c7, 0x5129330e, 0x016c4436, 0x430f05bf, 0x1f06b5cd,
+ 0x62df1378, 0x0423b9b4, 0x0341acaf, 0x3189543c, 0x7b96b2ea, 0x6c4865c3,
+ 0x4cc7adc3, 0x78a2bff6, 0x642db7c7, 0x70d02300, 0x7cd43ac0, 0x4f5fe414,
+ 0x333b52c2, 0x500d3c74, 0x65782c01, 0x3f72a2c5, 0x278f59d8, 0x493bf7f8,
+ 0x16bf51a0, 0x6cc70ced, 0x6ed15979, 0x1a77abae, 0x08cadbb7, 0x2f2e0bc0,
+ 0x236f5e8d, 0x1a4b4495, 0x360bd008, 0x32227d40
+};
+
+int
+main()
+{
+ SHA1Sum sum;
+ SHA1Sum::Hash hash;
+ sum.update(reinterpret_cast<const uint8_t*>(testV), sizeof(testV));
+ sum.finish(hash);
+
+ static const uint8_t expected[20] =
+ { 0xc8, 0xf2, 0x09, 0x59, 0x4e, 0x64, 0x40, 0xaa, 0x7b, 0xf7, 0xb8, 0xe0,
+ 0xfa, 0x44, 0xb2, 0x31, 0x95, 0xad, 0x94, 0x81 };
+
+ MOZ_STATIC_ASSERT(sizeof(expected) == sizeof(SHA1Sum::Hash),
+ "expected-data size should be the same as the actual hash "
+ "size");
+
+ for (size_t i = 0; i < SHA1Sum::HashSize; i++)
+ MOZ_ASSERT(hash[i] == expected[i]);
+
+ return 0;
+}
diff --git a/mfbt/tests/TestTypeTraits.cpp b/mfbt/tests/TestTypeTraits.cpp
new file mode 100644
index 0000000..6c424ed
--- /dev/null
+++ b/mfbt/tests/TestTypeTraits.cpp
@@ -0,0 +1,213 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/TypeTraits.h"
+
+using mozilla::IsBaseOf;
+using mozilla::IsConvertible;
+using mozilla::IsSame;
+using mozilla::IsSigned;
+using mozilla::IsUnsigned;
+using mozilla::MakeSigned;
+using mozilla::MakeUnsigned;
+
+MOZ_STATIC_ASSERT(!IsSigned<bool>::value, "bool shouldn't be signed");
+MOZ_STATIC_ASSERT(IsUnsigned<bool>::value, "bool should be unsigned");
+
+MOZ_STATIC_ASSERT(!IsSigned<const bool>::value, "const bool shouldn't be signed");
+MOZ_STATIC_ASSERT(IsUnsigned<const bool>::value, "const bool should be unsigned");
+
+MOZ_STATIC_ASSERT(!IsSigned<volatile bool>::value, "volatile bool shouldn't be signed");
+MOZ_STATIC_ASSERT(IsUnsigned<volatile bool>::value, "volatile bool should be unsigned");
+
+MOZ_STATIC_ASSERT(!IsSigned<unsigned char>::value, "unsigned char shouldn't be signed");
+MOZ_STATIC_ASSERT(IsUnsigned<unsigned char>::value, "unsigned char should be unsigned");
+MOZ_STATIC_ASSERT(IsSigned<signed char>::value, "signed char should be signed");
+MOZ_STATIC_ASSERT(!IsUnsigned<signed char>::value, "signed char shouldn't be unsigned");
+
+MOZ_STATIC_ASSERT(!IsSigned<unsigned short>::value, "unsigned short shouldn't be signed");
+MOZ_STATIC_ASSERT(IsUnsigned<unsigned short>::value, "unsigned short should be unsigned");
+MOZ_STATIC_ASSERT(IsSigned<short>::value, "short should be signed");
+MOZ_STATIC_ASSERT(!IsUnsigned<short>::value, "short shouldn't be unsigned");
+
+MOZ_STATIC_ASSERT(!IsSigned<unsigned int>::value, "unsigned int shouldn't be signed");
+MOZ_STATIC_ASSERT(IsUnsigned<unsigned int>::value, "unsigned int should be unsigned");
+MOZ_STATIC_ASSERT(IsSigned<int>::value, "int should be signed");
+MOZ_STATIC_ASSERT(!IsUnsigned<int>::value, "int shouldn't be unsigned");
+
+MOZ_STATIC_ASSERT(!IsSigned<unsigned long>::value, "unsigned long shouldn't be signed");
+MOZ_STATIC_ASSERT(IsUnsigned<unsigned long>::value, "unsigned long should be unsigned");
+MOZ_STATIC_ASSERT(IsSigned<long>::value, "long should be signed");
+MOZ_STATIC_ASSERT(!IsUnsigned<long>::value, "long shouldn't be unsigned");
+
+MOZ_STATIC_ASSERT(IsSigned<float>::value, "float should be signed");
+MOZ_STATIC_ASSERT(!IsUnsigned<float>::value, "float shouldn't be unsigned");
+
+MOZ_STATIC_ASSERT(IsSigned<const float>::value, "const float should be signed");
+MOZ_STATIC_ASSERT(!IsUnsigned<const float>::value, "const float shouldn't be unsigned");
+
+MOZ_STATIC_ASSERT(IsSigned<double>::value, "double should be signed");
+MOZ_STATIC_ASSERT(!IsUnsigned<double>::value, "double shouldn't be unsigned");
+
+MOZ_STATIC_ASSERT(IsSigned<volatile double>::value, "volatile double should be signed");
+MOZ_STATIC_ASSERT(!IsUnsigned<volatile double>::value, "volatile double shouldn't be unsigned");
+
+MOZ_STATIC_ASSERT(IsSigned<long double>::value, "long double should be signed");
+MOZ_STATIC_ASSERT(!IsUnsigned<long double>::value, "long double shouldn't be unsigned");
+
+MOZ_STATIC_ASSERT(IsSigned<const volatile long double>::value,
+ "const volatile long double should be signed");
+MOZ_STATIC_ASSERT(!IsUnsigned<const volatile long double>::value,
+ "const volatile long double shouldn't be unsigned");
+
+namespace CPlusPlus11IsBaseOf {
+
+// Adapted from C++11 ยง 20.9.6.
+struct B {};
+struct B1 : B {};
+struct B2 : B {};
+struct D : private B1, private B2 {};
+
+static void
+StandardIsBaseOfTests()
+{
+ MOZ_ASSERT((IsBaseOf<B, D>::value) == true);
+ MOZ_ASSERT((IsBaseOf<const B, D>::value) == true);
+ MOZ_ASSERT((IsBaseOf<B, const D>::value) == true);
+ MOZ_ASSERT((IsBaseOf<B, const B>::value) == true);
+ MOZ_ASSERT((IsBaseOf<D, B>::value) == false);
+ MOZ_ASSERT((IsBaseOf<B&, D&>::value) == false);
+ MOZ_ASSERT((IsBaseOf<B[3], D[3]>::value) == false);
+ // We fail at the following test. To fix it, we need to specialize IsBaseOf
+ // for all built-in types.
+ // MOZ_ASSERT((IsBaseOf<int, int>::value) == false);
+}
+
+} /* namespace CPlusPlus11IsBaseOf */
+
+class A { };
+class B : public A { };
+class C : private A { };
+class D { };
+class E : public A { };
+class F : public B, public E { };
+
+static void
+TestIsBaseOf()
+{
+ MOZ_ASSERT((IsBaseOf<A, B>::value),
+ "A is a base of B");
+ MOZ_ASSERT((!IsBaseOf<B, A>::value),
+ "B is not a base of A");
+ MOZ_ASSERT((IsBaseOf<A, C>::value),
+ "A is a base of C");
+ MOZ_ASSERT((!IsBaseOf<C, A>::value),
+ "C is not a base of A");
+ MOZ_ASSERT((IsBaseOf<A, F>::value),
+ "A is a base of F");
+ MOZ_ASSERT((!IsBaseOf<F, A>::value),
+ "F is not a base of A");
+ MOZ_ASSERT((!IsBaseOf<A, D>::value),
+ "A is not a base of D");
+ MOZ_ASSERT((!IsBaseOf<D, A>::value),
+ "D is not a base of A");
+ MOZ_ASSERT((IsBaseOf<B, B>::value),
+ "B is the same as B (and therefore, a base of B)");
+}
+
+static void
+TestIsConvertible()
+{
+ // Pointer type convertibility
+ MOZ_ASSERT((IsConvertible<A*, A*>::value),
+ "A* should convert to A*");
+ MOZ_ASSERT((IsConvertible<B*, A*>::value),
+ "B* should convert to A*");
+ MOZ_ASSERT((!IsConvertible<A*, B*>::value),
+ "A* shouldn't convert to B*");
+ MOZ_ASSERT((!IsConvertible<A*, C*>::value),
+ "A* shouldn't convert to C*");
+ MOZ_ASSERT((!IsConvertible<A*, D*>::value),
+ "A* shouldn't convert to unrelated D*");
+ MOZ_ASSERT((!IsConvertible<D*, A*>::value),
+ "D* shouldn't convert to unrelated A*");
+
+ // Instance type convertibility
+ MOZ_ASSERT((IsConvertible<A, A>::value),
+ "A is A");
+ MOZ_ASSERT((IsConvertible<B, A>::value),
+ "B converts to A");
+ MOZ_ASSERT((!IsConvertible<D, A>::value),
+ "D and A are unrelated");
+ MOZ_ASSERT((!IsConvertible<A, D>::value),
+ "A and D are unrelated");
+
+ // These cases seem to require C++11 support to properly implement them, so
+ // for now just disable them.
+ //MOZ_ASSERT((!IsConvertible<C*, A*>::value),
+ // "C* shouldn't convert to A* (private inheritance)");
+ //MOZ_ASSERT((!IsConvertible<C, A>::value),
+ // "C doesn't convert to A (private inheritance)");
+}
+
+MOZ_STATIC_ASSERT((IsSame<MakeSigned<const unsigned char>::Type, const signed char>::value),
+ "const unsigned char won't signify correctly");
+MOZ_STATIC_ASSERT((IsSame<MakeSigned<volatile unsigned short>::Type, volatile signed short>::value),
+ "volatile unsigned short won't signify correctly");
+MOZ_STATIC_ASSERT((IsSame<MakeSigned<const volatile unsigned int>::Type, const volatile signed int>::value),
+ "const volatile unsigned int won't signify correctly");
+MOZ_STATIC_ASSERT((IsSame<MakeSigned<unsigned long>::Type, signed long>::value),
+ "unsigned long won't signify correctly");
+MOZ_STATIC_ASSERT((IsSame<MakeSigned<const signed char>::Type, const signed char>::value),
+ "const signed char won't signify correctly");
+
+MOZ_STATIC_ASSERT((IsSame<MakeSigned<volatile signed short>::Type, volatile signed short>::value),
+ "volatile signed short won't signify correctly");
+MOZ_STATIC_ASSERT((IsSame<MakeSigned<const volatile signed int>::Type, const volatile signed int>::value),
+ "const volatile signed int won't signify correctly");
+MOZ_STATIC_ASSERT((IsSame<MakeSigned<signed long>::Type, signed long>::value),
+ "signed long won't signify correctly");
+
+MOZ_STATIC_ASSERT((IsSame<MakeSigned<char>::Type, signed char>::value),
+ "char won't signify correctly");
+MOZ_STATIC_ASSERT((IsSame<MakeSigned<volatile char>::Type, volatile signed char>::value),
+ "volatile char won't signify correctly");
+MOZ_STATIC_ASSERT((IsSame<MakeSigned<const char>::Type, const signed char>::value),
+ "const char won't signify correctly");
+
+MOZ_STATIC_ASSERT((IsSame<MakeUnsigned<const signed char>::Type, const unsigned char>::value),
+ "const signed char won't unsignify correctly");
+MOZ_STATIC_ASSERT((IsSame<MakeUnsigned<volatile signed short>::Type, volatile unsigned short>::value),
+ "volatile signed short won't unsignify correctly");
+MOZ_STATIC_ASSERT((IsSame<MakeUnsigned<const volatile signed int>::Type, const volatile unsigned int>::value),
+ "const volatile signed int won't unsignify correctly");
+MOZ_STATIC_ASSERT((IsSame<MakeUnsigned<signed long>::Type, unsigned long>::value),
+ "signed long won't unsignify correctly");
+
+MOZ_STATIC_ASSERT((IsSame<MakeUnsigned<const unsigned char>::Type, const unsigned char>::value),
+ "const unsigned char won't unsignify correctly");
+
+MOZ_STATIC_ASSERT((IsSame<MakeUnsigned<volatile unsigned short>::Type, volatile unsigned short>::value),
+ "volatile unsigned short won't unsignify correctly");
+MOZ_STATIC_ASSERT((IsSame<MakeUnsigned<const volatile unsigned int>::Type, const volatile unsigned int>::value),
+ "const volatile unsigned int won't unsignify correctly");
+MOZ_STATIC_ASSERT((IsSame<MakeUnsigned<unsigned long>::Type, unsigned long>::value),
+ "signed long won't unsignify correctly");
+
+MOZ_STATIC_ASSERT((IsSame<MakeUnsigned<char>::Type, unsigned char>::value),
+ "char won't unsignify correctly");
+MOZ_STATIC_ASSERT((IsSame<MakeUnsigned<volatile char>::Type, volatile unsigned char>::value),
+ "volatile char won't unsignify correctly");
+MOZ_STATIC_ASSERT((IsSame<MakeUnsigned<const char>::Type, const unsigned char>::value),
+ "const char won't unsignify correctly");
+
+int
+main()
+{
+ CPlusPlus11IsBaseOf::StandardIsBaseOfTests();
+ TestIsBaseOf();
+ TestIsConvertible();
+}
diff --git a/mfbt/tests/TestWeakPtr.cpp b/mfbt/tests/TestWeakPtr.cpp
new file mode 100644
index 0000000..510dd06
--- /dev/null
+++ b/mfbt/tests/TestWeakPtr.cpp
@@ -0,0 +1,77 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/WeakPtr.h"
+
+using mozilla::SupportsWeakPtr;
+using mozilla::WeakPtr;
+
+// To have a class C support weak pointers, inherit from SupportsWeakPtr<C>.
+class C : public SupportsWeakPtr<C>
+{
+ public:
+ int num;
+ void act() {}
+};
+
+static void
+Example()
+{
+
+ C* ptr = new C();
+
+ // Get weak pointers to ptr. The first time asWeakPtr is called
+ // a reference counted WeakReference object is created that
+ // can live beyond the lifetime of 'ptr'. The WeakReference
+ // object will be notified of 'ptr's destruction.
+ WeakPtr<C> weak = ptr->asWeakPtr();
+ WeakPtr<C> other = ptr->asWeakPtr();
+
+ // Test a weak pointer for validity before using it.
+ if (weak) {
+ weak->num = 17;
+ weak->act();
+ }
+
+ // Destroying the underlying object clears weak pointers to it.
+ delete ptr;
+
+ MOZ_ASSERT(!weak, "Deleting |ptr| clears weak pointers to it.");
+ MOZ_ASSERT(!other, "Deleting |ptr| clears all weak pointers to it.");
+}
+
+struct A : public SupportsWeakPtr<A>
+{
+ int data;
+};
+
+
+int
+main()
+{
+
+ A* a = new A;
+
+ // a2 is unused to test the case when we haven't initialized
+ // the internal WeakReference pointer.
+ A* a2 = new A;
+
+ a->data = 5;
+ WeakPtr<A> ptr = a->asWeakPtr();
+ {
+ WeakPtr<A> ptr2 = a->asWeakPtr();
+ MOZ_ASSERT(ptr->data == 5);
+ WeakPtr<A> ptr3 = a->asWeakPtr();
+ MOZ_ASSERT(ptr->data == 5);
+ }
+
+ delete a;
+ MOZ_ASSERT(!ptr);
+
+ delete a2;
+
+ Example();
+
+ return 0;
+}
diff --git a/mfbt/tests/moz.build b/mfbt/tests/moz.build
new file mode 100644
index 0000000..895d119
--- /dev/null
+++ b/mfbt/tests/moz.build
@@ -0,0 +1,6 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+