--- util.c.orig	2007-12-18 10:47:08.000000000 +0000
+++ util.c	2022-08-05 12:39:09.280213666 +0000
@@ -1611,6 +1611,36 @@ Perl_new_warnings_bitfield(pTHX_ STRLEN
    *(s+(nlen+1+vlen)) = '\0'
 
 #ifdef USE_ENVIRON_ARRAY
+
+/* small wrapper for use by Perl_my_setenv that mallocs, or reallocs if
+ * 'current' is non-null, with up to three sizes that are added together.
+ * It handles integer overflow.
+ */
+static char *
+S_env_alloc(void *current, Size_t l1, Size_t l2, Size_t l3, Size_t size)
+{
+    void *p;
+    Size_t sl, l = l1 + l2;
+
+    if (l < l2)
+        goto panic;
+    l += l3;
+    if (l < l3)
+        goto panic;
+    sl = l * size;
+    if (sl < l)
+        goto panic;
+
+    p = current
+            ? safesysrealloc(current, sl)
+            : safesysmalloc(sl);
+    if (p)
+        return (char*)p;
+
+  panic:
+    Perl_croak_nocontext(PL_memory_wrap);
+}
+
        /* VMS' my_setenv() is in vms.c */
 #if !defined(WIN32) && !defined(NETWARE)
 void
@@ -1625,21 +1655,27 @@ Perl_my_setenv(pTHX_ const char *nam, co
 #ifndef PERL_USE_SAFE_PUTENV
     if (!PL_use_safe_putenv) {
     /* most putenv()s leak, so we manipulate environ directly */
-    register I32 i=setenv_getix(nam);          /* where does it go? */
-    int nlen, vlen;
+    UV i;
+    Size_t vlen, nlen = strlen(nam);
+
+    /* where does it go? */
+    for (i = 0; environ[i]; i++) {
+	if (strnEQ(environ[i],nam,nlen) && environ[i][nlen] == '=')
+	    break;
+    }
 
     if (environ == PL_origenviron) {   /* need we copy environment? */
-       I32 j;
-       I32 max;
+       UV j, max;
        char **tmpenv;
 
        max = i;
        while (environ[max])
            max++;
-       tmpenv = (char**)safesysmalloc((max+2) * sizeof(char*));
+       /* XXX shouldn't that be max+1 rather than max+2 ??? - DAPM */
+       tmpenv = (char**)S_env_alloc(NULL, max, 2, 0, sizeof(char*));
        for (j=0; j<max; j++) {         /* copy environment */
-           const int len = strlen(environ[j]);
-           tmpenv[j] = (char*)safesysmalloc((len+1)*sizeof(char));
+	   const Size_t len = strlen(environ[j]);
+           tmpenv[j] = S_env_alloc(NULL, len, 1, 0, 1);
            Copy(environ[j], tmpenv[j], len+1, char);
        }
        tmpenv[max] = NULL;
@@ -1654,15 +1690,15 @@ Perl_my_setenv(pTHX_ const char *nam, co
        return;
     }
     if (!environ[i]) {                 /* does not exist yet */
-       environ = (char**)safesysrealloc(environ, (i+2) * sizeof(char*));
+       environ = (char**)S_env_alloc(environ, i, 2, 0, sizeof(char*));
        environ[i+1] = NULL;    /* make sure it's null terminated */
     }
     else
        safesysfree(environ[i]);
-       nlen = strlen(nam);
+
        vlen = strlen(val);
 
-       environ[i] = (char*)safesysmalloc((nlen+vlen+2) * sizeof(char));
+       environ[i] = S_env_alloc(NULL, nlen, vlen, 2, 1);
        /* all that work just for this */
        my_setenv_format(environ[i], nam, nlen, val, vlen);
     } else {
@@ -1682,22 +1718,21 @@ Perl_my_setenv(pTHX_ const char *nam, co
         if (val == NULL) {
             (void)unsetenv(nam);
         } else {
-	    const int nlen = strlen(nam);
-	    const int vlen = strlen(val);
-	    char * const new_env =
-                (char*)safesysmalloc((nlen + vlen + 2) * sizeof(char));
+	    const Size_t nlen = strlen(nam);
+	    const Size_t vlen = strlen(val);
+	    char * const new_env = S_env_alloc(NULL, nlen, vlen, 2, 1);
             my_setenv_format(new_env, nam, nlen, val, vlen);
             (void)putenv(new_env);
         }
 #       else /* ! HAS_UNSETENV */
         char *new_env;
-	const int nlen = strlen(nam);
-	int vlen;
+	const Size_t nlen = strlen(nam);
+	Size_t vlen;
         if (!val) {
 	   val = "";
         }
         vlen = strlen(val);
-        new_env = (char*)safesysmalloc((nlen + vlen + 2) * sizeof(char));
+        new_env = S_env_alloc(NULL, nlen, vlen, 2, 1);
         /* all that work just for this */
         my_setenv_format(new_env, nam, nlen, val, vlen);
         (void)putenv(new_env);
@@ -1716,14 +1751,14 @@ Perl_my_setenv(pTHX_ const char *nam, co
 {
     dVAR;
     register char *envstr;
-    const int nlen = strlen(nam);
-    int vlen;
+    const Size_t nlen = strlen(nam);
+    Size_t vlen;
 
     if (!val) {
        val = "";
     }
     vlen = strlen(val);
-    Newx(envstr, nlen+vlen+2, char);
+    envstr = S_env_alloc(NULL, nlen, vlen, 2, 1);
     my_setenv_format(envstr, nam, nlen, val, vlen);
     (void)PerlEnv_putenv(envstr);
     Safefree(envstr);
