diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h
index f8f306f6147414c87ec9cf805af32c903dc6d3f6..6ee3e37ce632e353b55e7e45fd6dbd61d8e3c0d8 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -448,6 +448,9 @@ template <>    struct QIntegerForSize<1> { typedef quint8  Unsigned; typedef qin
 template <>    struct QIntegerForSize<2> { typedef quint16 Unsigned; typedef qint16 Signed; };
 template <>    struct QIntegerForSize<4> { typedef quint32 Unsigned; typedef qint32 Signed; };
 template <>    struct QIntegerForSize<8> { typedef quint64 Unsigned; typedef qint64 Signed; };
+#if defined(Q_CC_GNU) && defined(__SIZEOF_INT128__)
+template <>    struct QIntegerForSize<16> { __extension__ typedef unsigned __int128 Unsigned; __extension__ typedef __int128 Signed; };
+#endif
 template <class T> struct QIntegerForSizeof: QIntegerForSize<sizeof(T)> { };
 typedef QIntegerForSize<Q_PROCESSOR_WORDSIZE>::Signed qregisterint;
 typedef QIntegerForSize<Q_PROCESSOR_WORDSIZE>::Unsigned qregisteruint;
diff --git a/src/corelib/global/qnumeric_p.h b/src/corelib/global/qnumeric_p.h
index 5fa0a881a37836fdb9dfbc89ef4d9cf3fd6e14ae..e5f9d8e13e116da0ae3560c1ed9884e15354fc93 100644
--- a/src/corelib/global/qnumeric_p.h
+++ b/src/corelib/global/qnumeric_p.h
@@ -1,6 +1,7 @@
 /****************************************************************************
 **
 ** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2015 Intel Corporation.
 ** Contact: http://www.qt.io/licensing/
 **
 ** This file is part of the QtCore module of the Qt Toolkit.
@@ -47,6 +48,18 @@
 
 #include "QtCore/qglobal.h"
 
+#include <limits>
+
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+#  include <intrin.h>
+#elif defined(Q_CC_INTEL)
+#  include <immintrin.h>    // for _addcarry_u<nn>
+#endif
+
+#ifndef __has_builtin
+#  define __has_builtin(x)  0
+#endif
+
 QT_BEGIN_NAMESPACE
 
 #if !defined(Q_CC_MIPS)
@@ -188,6 +201,110 @@ static inline bool qt_is_finite(float d)
     }
 }
 
+//
+// Overflow math
+//
+namespace {
+template <typename T> inline typename QtPrivate::QEnableIf<QtPrivate::is_unsigned<T>::value, bool>::Type
+add_overflow(T v1, T v2, T *r)
+{
+    // unsigned additions are well-defined
+    *r = v1 + v2;
+    return v1 > T(v1 + v2);
+}
+
+template <typename T> inline typename QtPrivate::QEnableIf<QtPrivate::is_unsigned<T>::value, bool>::Type
+mul_overflow(T v1, T v2, T *r)
+{
+    // use the next biggest type
+    // Note: for 64-bit systems where __int128 isn't supported, this will cause an error.
+    // A fallback is present below.
+    typedef typename QIntegerForSize<sizeof(T) * 2>::Unsigned Larger;
+    Larger lr = Larger(v1) * Larger(v2);
+    *r = T(lr);
+    return lr > std::numeric_limits<T>::max();
+}
+
+#if defined(__SIZEOF_INT128__)
+#  define HAVE_MUL64_OVERFLOW
+#endif
+
+// GCC 5 and Clang have builtins to detect overflows
+#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 500) || __has_builtin(__builtin_uadd_overflow)
+template <> inline bool add_overflow(unsigned v1, unsigned v2, unsigned *r)
+{ return __builtin_uadd_overflow(v1, v2, r); }
+#endif
+#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 500) || __has_builtin(__builtin_uaddl_overflow)
+template <> inline bool add_overflow(unsigned long v1, unsigned long v2, unsigned long *r)
+{ return __builtin_uaddl_overflow(v1, v2, r); }
+#endif
+#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 500) || __has_builtin(__builtin_uaddll_overflow)
+template <> inline bool add_overflow(unsigned long long v1, unsigned long long v2, unsigned long long *r)
+{ return __builtin_uaddll_overflow(v1, v2, r); }
+#endif
+
+#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 500) || __has_builtin(__builtin_umul_overflow)
+template <> inline bool mul_overflow(unsigned v1, unsigned v2, unsigned *r)
+{ return __builtin_umul_overflow(v1, v2, r); }
+#endif
+#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 500) || __has_builtin(__builtin_umull_overflow)
+template <> inline bool mul_overflow(unsigned long v1, unsigned long v2, unsigned long *r)
+{ return __builtin_umull_overflow(v1, v2, r); }
+#endif
+#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 500) || __has_builtin(__builtin_umulll_overflow)
+template <> inline bool mul_overflow(unsigned long long v1, unsigned long long v2, unsigned long long *r)
+{ return __builtin_umulll_overflow(v1, v2, r); }
+#  define HAVE_MUL64_OVERFLOW
+#endif
+
+#if ((defined(Q_CC_MSVC) && _MSC_VER >= 1800) || defined(Q_CC_INTEL)) && defined(Q_PROCESSOR_X86)
+template <> inline bool add_overflow(unsigned v1, unsigned v2, unsigned *r)
+{ return _addcarry_u32(0, v1, v2, r); }
+#  ifdef Q_CC_MSVC      // longs are 32-bit
+template <> inline bool add_overflow(unsigned long v1, unsigned long v2, unsigned long *r)
+{ return _addcarry_u32(0, v1, v2, reinterpret_cast<unsigned *>(r)); }
+#  endif
+#endif
+#if ((defined(Q_CC_MSVC) && _MSC_VER >= 1800) || defined(Q_CC_INTEL)) && defined(Q_PROCESSOR_X86_64)
+template <> inline bool add_overflow(quint64 v1, quint64 v2, quint64 *r)
+{ return _addcarry_u64(0, v1, v2, reinterpret_cast<unsigned __int64 *>(r)); }
+#  ifndef Q_CC_MSVC      // longs are 64-bit
+template <> inline bool add_overflow(unsigned long v1, unsigned long v2, unsigned long *r)
+{ return _addcarry_u64(0, v1, v2, reinterpret_cast<unsigned __int64 *>(r)); }
+#  endif
+#endif
+
+#if defined(Q_CC_MSVC) && (defined(Q_PROCESSOR_X86_64) || defined(Q_PROCESSOR_IA64))
+#pragma intrinsic(_umul128)
+template <> inline bool mul_overflow(quint64 v1, quint64 v2, quint64 *r)
+{
+    // use 128-bit multiplication with the _umul128 intrinsic
+    // https://msdn.microsoft.com/en-us/library/3dayytw9.aspx
+    quint64 high;
+    *r = _umul128(v1, v2, &high);
+    return high;
+}
+#  define HAVE_MUL64_OVERFLOW
+#endif
+
+#if !defined(HAVE_MUL64_OVERFLOW) && defined(__LP64__)
+// no 128-bit multiplication, we need to figure out with a slow division
+template <> inline bool mul_overflow(quint64 v1, quint64 v2, quint64 *r)
+{
+    if (v2 && v1 > std::numeric_limits<quint64>::max() / v2)
+        return true;
+    *r = v1 * v2;
+    return false;
+}
+template <> inline bool mul_overflow(unsigned long v1, unsigned long v2, unsigned long *r)
+{
+    return mul_overflow<quint64>(v1, v2, reinterpret_cast<quint64 *>(r));
+}
+#else
+#  undef HAVE_MUL64_OVERFLOW
+#endif
+}
+
 QT_END_NAMESPACE
 
 #endif // QNUMERIC_P_H
diff --git a/tests/auto/corelib/global/qnumeric/qnumeric.pro b/tests/auto/corelib/global/qnumeric/qnumeric.pro
index 00f3635be956d9770cfefac978d53d99248e27fe..0772ce6aab27a80457984ce97f6a4445c6c7b476 100644
--- a/tests/auto/corelib/global/qnumeric/qnumeric.pro
+++ b/tests/auto/corelib/global/qnumeric/qnumeric.pro
@@ -1,6 +1,6 @@
 CONFIG += testcase parallel_test
 TARGET = tst_qnumeric
-QT = core testlib
+QT = core-private testlib
 SOURCES = tst_qnumeric.cpp
 DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
 intel_icc: QMAKE_CXXFLAGS += -fp-model strict
diff --git a/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp b/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp
index fdc8bc6aabc7748ff14a0e09ec8d086ab86df9bc..59a536ed25b16cdf90f7ed699e5b59a026eb39b8 100644
--- a/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp
+++ b/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp
@@ -34,6 +34,7 @@
 
 #include <QtTest/QtTest>
 #include <QtGlobal>
+#include "private/qnumeric_p.h"
 
 #include <math.h>
 #include <float.h>
@@ -50,6 +51,10 @@ private slots:
     void floatDistance();
     void floatDistance_double_data();
     void floatDistance_double();
+    void addOverflow_data();
+    void addOverflow();
+    void mulOverflow_data();
+    void mulOverflow();
 };
 
 void tst_QNumeric::fuzzyCompare_data()
@@ -206,5 +211,160 @@ void tst_QNumeric::floatDistance_double()
     QCOMPARE(qFloatDistance(val1, val2), expectedDistance);
 }
 
+void tst_QNumeric::addOverflow_data()
+{
+    QTest::addColumn<int>("size");
+    QTest::newRow("quint8") << 8;
+    QTest::newRow("quint16") << 16;
+    QTest::newRow("quint32") << 32;
+    QTest::newRow("quint64") << 64;
+    QTest::newRow("ulong") << 48;   // it's either 32- or 64-bit, so on average it's 48 :-)
+}
+
+// Note: in release mode, all the tests may be statically determined and only the calls
+// to QTest::toString and QTest::qCompare will remain.
+template <typename Int> static void addOverflow_template()
+{
+#if defined(Q_CC_MSVC) && Q_CC_MSVC < 1900
+    QSKIP("Test disabled, this test generates an Internal Compiler Error compiling");
+#else
+    const Int max = std::numeric_limits<Int>::max();
+    Int r;
+
+    // basic values
+    QCOMPARE(add_overflow(Int(0), Int(0), &r), false);
+    QCOMPARE(r, Int(0));
+    QCOMPARE(add_overflow(Int(1), Int(0), &r), false);
+    QCOMPARE(r, Int(1));
+    QCOMPARE(add_overflow(Int(0), Int(1), &r), false);
+    QCOMPARE(r, Int(1));
+
+    // half-way through max
+    QCOMPARE(add_overflow(Int(max/2), Int(max/2), &r), false);
+    QCOMPARE(r, Int(max / 2 * 2));
+    QCOMPARE(add_overflow(Int(max/2 - 1), Int(max/2 + 1), &r), false);
+    QCOMPARE(r, Int(max / 2 * 2));
+    QCOMPARE(add_overflow(Int(max/2 + 1), Int(max/2), &r), false);
+    QCOMPARE(r, max);
+    QCOMPARE(add_overflow(Int(max/2), Int(max/2 + 1), &r), false);
+    QCOMPARE(r, max);
+
+    // more than half
+    QCOMPARE(add_overflow(Int(max/4 * 3), Int(max/4), &r), false);
+    QCOMPARE(r, Int(max / 4 * 4));
+
+    // max
+    QCOMPARE(add_overflow(max, Int(0), &r), false);
+    QCOMPARE(r, max);
+    QCOMPARE(add_overflow(Int(0), max, &r), false);
+    QCOMPARE(r, max);
+
+    // 64-bit issues
+    if (max > std::numeric_limits<uint>::max()) {
+        QCOMPARE(add_overflow(Int(std::numeric_limits<uint>::max()), Int(std::numeric_limits<uint>::max()), &r), false);
+        QCOMPARE(r, Int(2 * Int(std::numeric_limits<uint>::max())));
+    }
+
+    // overflows
+    QCOMPARE(add_overflow(max, Int(1), &r), true);
+    QCOMPARE(add_overflow(Int(1), max, &r), true);
+    QCOMPARE(add_overflow(Int(max/2 + 1), Int(max/2 + 1), &r), true);
+#endif
+}
+
+void tst_QNumeric::addOverflow()
+{
+    QFETCH(int, size);
+    if (size == 8)
+        addOverflow_template<quint8>();
+    if (size == 16)
+        addOverflow_template<quint16>();
+    if (size == 32)
+        addOverflow_template<quint32>();
+    if (size == 48)
+        addOverflow_template<ulong>();  // not really 48-bit
+    if (size == 64)
+        addOverflow_template<quint64>();
+}
+
+void tst_QNumeric::mulOverflow_data()
+{
+    addOverflow_data();
+}
+
+// Note: in release mode, all the tests may be statically determined and only the calls
+// to QTest::toString and QTest::qCompare will remain.
+template <typename Int> static void mulOverflow_template()
+{
+#if defined(Q_CC_MSVC) && Q_CC_MSVC < 1900
+    QSKIP("Test disabled, this test generates an Internal Compiler Error compiling");
+#else
+    const Int max = std::numeric_limits<Int>::max();
+    const Int middle = Int(max >> (sizeof(Int) * CHAR_BIT / 2));
+    Int r;
+
+    // basic multiplications
+    QCOMPARE(mul_overflow(Int(0), Int(0), &r), false);
+    QCOMPARE(r, Int(0));
+    QCOMPARE(mul_overflow(Int(1), Int(0), &r), false);
+    QCOMPARE(r, Int(0));
+    QCOMPARE(mul_overflow(Int(0), Int(1), &r), false);
+    QCOMPARE(r, Int(0));
+    QCOMPARE(mul_overflow(max, Int(0), &r), false);
+    QCOMPARE(r, Int(0));
+    QCOMPARE(mul_overflow(Int(0), max, &r), false);
+    QCOMPARE(r, Int(0));
+
+    QCOMPARE(mul_overflow(Int(1), Int(1), &r), false);
+    QCOMPARE(r, Int(1));
+    QCOMPARE(mul_overflow(Int(1), max, &r), false);
+    QCOMPARE(r, max);
+    QCOMPARE(mul_overflow(max, Int(1), &r), false);
+    QCOMPARE(r, max);
+
+    // almost max
+    QCOMPARE(mul_overflow(middle, middle, &r), false);
+    QCOMPARE(r, Int(max - 2 * middle));
+    QCOMPARE(mul_overflow(Int(middle + 1), middle, &r), false);
+    QCOMPARE(r, Int(middle << (sizeof(Int) * CHAR_BIT / 2)));
+    QCOMPARE(mul_overflow(middle, Int(middle + 1), &r), false);
+    QCOMPARE(r, Int(middle << (sizeof(Int) * CHAR_BIT / 2)));
+    QCOMPARE(mul_overflow(Int(max / 2), Int(2), &r), false);
+    QCOMPARE(r, Int(max & ~Int(1)));
+    QCOMPARE(mul_overflow(Int(max / 4), Int(4), &r), false);
+    QCOMPARE(r, Int(max & ~Int(3)));
+
+    // overflows
+    QCOMPARE(mul_overflow(max, Int(2), &r), true);
+    QCOMPARE(mul_overflow(Int(max / 2), Int(3), &r), true);
+    QCOMPARE(mul_overflow(Int(middle + 1), Int(middle + 1), &r), true);
+#endif
+}
+
+template <typename Int, bool enabled = sizeof(Int) <= sizeof(void*)> struct MulOverflowDispatch;
+template <typename Int> struct MulOverflowDispatch<Int, true>
+{
+    void operator()() { mulOverflow_template<Int>(); }
+};
+template <typename Int> struct MulOverflowDispatch<Int, false>
+{
+    void operator()() { QSKIP("This type is too big for this architecture"); }
+};
+
+void tst_QNumeric::mulOverflow()
+{
+    QFETCH(int, size);
+    if (size == 8)
+        MulOverflowDispatch<quint8>()();
+    if (size == 16)
+        MulOverflowDispatch<quint16>()();
+    if (size == 32)
+        MulOverflowDispatch<quint32>()();
+    if (size == 48)
+        MulOverflowDispatch<ulong>()();     // not really 48-bit
+    if (size == 64)
+        MulOverflowDispatch<quint64>()();
+}
+
 QTEST_APPLESS_MAIN(tst_QNumeric)
 #include "tst_qnumeric.moc"