Issue #16096: Fix several occurrences of potential signed integer overflow.  Thanks Serhiy Storchaka.
diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c
index b76125a..9c843fa 100644
--- a/Objects/tupleobject.c
+++ b/Objects/tupleobject.c
@@ -96,15 +96,11 @@
     else
 #endif
     {
-        Py_ssize_t nbytes = size * sizeof(PyObject *);
         /* Check for overflow */
-        if (nbytes / sizeof(PyObject *) != (size_t)size ||
-            (nbytes > PY_SSIZE_T_MAX - sizeof(PyTupleObject) - sizeof(PyObject *)))
-        {
+        if (size > (PY_SSIZE_T_MAX - sizeof(PyTupleObject) -
+                    sizeof(PyObject *)) / sizeof(PyObject *)) {
             return PyErr_NoMemory();
         }
-        /* nbytes += sizeof(PyTupleObject) - sizeof(PyObject *); */
-
         op = PyObject_GC_NewVar(PyTupleObject, &PyTuple_Type, size);
         if (op == NULL)
             return NULL;
@@ -481,9 +477,9 @@
         if (Py_SIZE(a) == 0)
             return PyTuple_New(0);
     }
-    size = Py_SIZE(a) * n;
-    if (size/Py_SIZE(a) != n)
+    if (n > PY_SSIZE_T_MAX / Py_SIZE(a))
         return PyErr_NoMemory();
+    size = Py_SIZE(a) * n;
     np = (PyTupleObject *) PyTuple_New(size);
     if (np == NULL)
         return NULL;
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index e90ee3f..8289580 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -4492,7 +4492,6 @@
     void *data;
     Py_ssize_t len;
     PyObject *v;
-    Py_ssize_t allocated;
     int inShift = 0;
     Py_ssize_t i;
     unsigned int base64bits = 0;
@@ -4510,11 +4509,9 @@
         return PyBytes_FromStringAndSize(NULL, 0);
 
     /* It might be possible to tighten this worst case */
-    allocated = 8 * len;
-    if (allocated / 8 != len)
+    if (len > PY_SSIZE_T_MAX / 8)
         return PyErr_NoMemory();
-
-    v = PyBytes_FromStringAndSize(NULL, allocated);
+    v = PyBytes_FromStringAndSize(NULL, len * 8);
     if (v == NULL)
         return NULL;
 
@@ -5092,7 +5089,7 @@
     Py_ssize_t len;
     PyObject *v;
     unsigned char *p;
-    Py_ssize_t nsize, bytesize, i;
+    Py_ssize_t nsize, i;
     /* Offsets from p for storing byte pairs in the right order. */
 #ifdef BYTEORDER_IS_LITTLE_ENDIAN
     int iorder[] = {0, 1, 2, 3};
@@ -5120,10 +5117,9 @@
     len = PyUnicode_GET_LENGTH(str);
 
     nsize = len + (byteorder == 0);
-    bytesize = nsize * 4;
-    if (bytesize / 4 != nsize)
+    if (nsize > PY_SSIZE_T_MAX / 4)
         return PyErr_NoMemory();
-    v = PyBytes_FromStringAndSize(NULL, bytesize);
+    v = PyBytes_FromStringAndSize(NULL, nsize * 4);
     if (v == NULL)
         return NULL;
 
@@ -10159,7 +10155,7 @@
     }
     else {
         Py_ssize_t n, i, j, ires;
-        Py_ssize_t product, new_size;
+        Py_ssize_t new_size;
         int rkind = skind;
         char *res;
 
@@ -10191,19 +10187,18 @@
         }
         /* new_size = PyUnicode_GET_LENGTH(self) + n * (PyUnicode_GET_LENGTH(str2) -
            PyUnicode_GET_LENGTH(str1))); */
-        product = n * (len2-len1);
-        if ((product / (len2-len1)) != n) {
+        if (len2 > len1 && len2 - len1 > (PY_SSIZE_T_MAX - slen) / n) {
                 PyErr_SetString(PyExc_OverflowError,
                                 "replace string is too long");
                 goto error;
         }
-        new_size = slen + product;
+        new_size = slen + n * (len2 - len1);
         if (new_size == 0) {
             Py_INCREF(unicode_empty);
             u = unicode_empty;
             goto done;
         }
-        if (new_size < 0 || new_size > (PY_SSIZE_T_MAX >> (rkind-1))) {
+        if (new_size > (PY_SSIZE_T_MAX >> (rkind-1))) {
             PyErr_SetString(PyExc_OverflowError,
                             "replace string is too long");
             goto error;