summaryrefslogtreecommitdiff
path: root/pp.c
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2014-12-20 16:40:52 +0000
committerDavid Mitchell <davem@iabyn.com>2014-12-31 11:28:51 +0000
commit53e2bfb7c6a2e8a3171dabe7dbdc24eba77e4bf0 (patch)
tree0581d4da5f1bccbd72d0632eaa006e972800445d /pp.c
parent382a7a77501a1e25895d78eca9cb6838c6d7e6a3 (diff)
downloadperl-53e2bfb7c6a2e8a3171dabe7dbdc24eba77e4bf0.tar.gz
fix -IV_MIN negations
Doing uv = -iv is undefined behaviour if iv happens to be IV_MIN. This occurs in several places in the perl sources. Found by -fsanitize=undefined. Here's a typical message: sv.c:2864:7: runtime error: negation of -9223372036854775808 cannot be represented in type 'IV' (aka 'long'); cast to an unsigned type to negate this value to itself
Diffstat (limited to 'pp.c')
-rw-r--r--pp.c16
1 files changed, 10 insertions, 6 deletions
diff --git a/pp.c b/pp.c
index 08e0999f3e..e24b5714fe 100644
--- a/pp.c
+++ b/pp.c
@@ -1298,7 +1298,8 @@ PP(pp_multiply)
alow = aiv;
auvok = TRUE; /* effectively it's a UV now */
} else {
- alow = -aiv; /* abs, auvok == false records sign */
+ /* abs, auvok == false records sign */
+ alow = (aiv == IV_MIN) ? (UV)aiv : (UV)(-aiv);
}
}
if (buvok) {
@@ -1309,7 +1310,8 @@ PP(pp_multiply)
blow = biv;
buvok = TRUE; /* effectively it's a UV now */
} else {
- blow = -biv; /* abs, buvok == false records sign */
+ /* abs, buvok == false records sign */
+ blow = (biv == IV_MIN) ? (UV)biv : (UV)(-biv);
}
}
@@ -1372,7 +1374,8 @@ PP(pp_multiply)
/* 2s complement assumption again */
/* -ve result, which could overflow an IV */
SP--;
- SETi( -(IV)product_low );
+ SETi(product_low == (UV)IV_MIN
+ ? IV_MIN : -(IV)product_low);
RETURN;
} /* else drop to NVs below. */
}
@@ -1797,7 +1800,7 @@ PP(pp_subtract)
auv = aiv;
auvok = 1; /* Now acting as a sign flag. */
} else { /* 2s complement assumption for IV_MIN */
- auv = (UV)-aiv;
+ auv = (aiv == IV_MIN) ? (UV)aiv : (UV)-aiv;
}
}
a_valid = 1;
@@ -1817,7 +1820,7 @@ PP(pp_subtract)
buv = biv;
buvok = 1;
} else
- buv = (UV)-biv;
+ buv = (biv == IV_MIN) ? (UV)biv : (UV)-biv;
}
/* ?uvok if value is >= 0. basically, flagged as UV if it's +ve,
else "IV" now, independent of how it came in.
@@ -1858,7 +1861,8 @@ PP(pp_subtract)
else {
/* Negate result */
if (result <= (UV)IV_MIN)
- SETi( -(IV)result );
+ SETi(result == (UV)IV_MIN
+ ? IV_MIN : -(IV)result);
else {
/* result valid, but out of range for IV. */
SETn( -(NV)result );