summaryrefslogtreecommitdiff
path: root/pp_hot.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_hot.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_hot.c')
-rw-r--r--pp_hot.c9
1 files changed, 5 insertions, 4 deletions
diff --git a/pp_hot.c b/pp_hot.c
index 3ee48180d3..4072ab11e1 100644
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -647,8 +647,8 @@ PP(pp_add)
if (aiv >= 0) {
auv = aiv;
auvok = 1; /* Now acting as a sign flag. */
- } else { /* 2s complement assumption for IV_MIN */
- auv = (UV)-aiv;
+ } else {
+ auv = (aiv == IV_MIN) ? (UV)aiv : (UV)(-aiv);
}
}
a_valid = 1;
@@ -668,7 +668,7 @@ PP(pp_add)
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.
@@ -709,7 +709,8 @@ PP(pp_add)
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 );