From 6abacd8d5f8edeb07bbbfa916cc1e7ba3b29de73 Mon Sep 17 00:00:00 2001 From: Dennis Felsing Date: Thu, 29 Feb 2024 16:11:51 +0000 Subject: [PATCH] Fix undefined behavior in libdecnumber Based on the suggestions from Jakub Jelinek in https://gcc.gnu.org/pipermail/gcc-patches/2024-February/644843.html and https://gcc.gnu.org/pipermail/gcc-patches/2024-February/644844.html and the patch by Ian McCormack in https://gcc.gnu.org/pipermail/gcc-patches/2024-February/644840.html Fixes: https://github.com/MaterializeInc/materialize/issues/25634 Fixes: https://github.com/MaterializeInc/rust-dec/issues/80 --- decnumber-sys/decnumber/decBasic.c | 20 ++++++++++---------- decnumber-sys/decnumber/decCommon.c | 4 ++-- decnumber-sys/decnumber/decNumber.c | 5 +++-- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/decnumber-sys/decnumber/decBasic.c b/decnumber-sys/decnumber/decBasic.c index ac3fcf8..9cd4fa2 100644 --- a/decnumber-sys/decnumber/decBasic.c +++ b/decnumber-sys/decnumber/decBasic.c @@ -331,7 +331,7 @@ static decFloat * decDivide(decFloat *result, const decFloat *dfl, for (;;) { // inner loop -- calculate quotient unit // strip leading zero units from acc (either there initially or // from subtraction below); this may strip all if exactly 0 - for (; *msua==0 && msua>=lsua;) msua--; + for (; msua>=lsua && *msua==0;) msua--; accunits=(Int)(msua-lsua+1); // [maybe 0] // subtraction is only necessary and possible if there are as // least as many units remaining in acc for this iteration as @@ -505,7 +505,7 @@ static decFloat * decDivide(decFloat *result, const decFloat *dfl, // (must also continue to original lsu for correct quotient length) if (lsua>acc+DIVACCLEN-DIVOPLEN) continue; for (; msua>lsua && *msua==0;) msua--; - if (*msua==0 && msua==lsua) break; + if (msua==lsua && *msua==0) break; } // outer loop // all of the original operand in acc has been covered at this point @@ -1533,8 +1533,8 @@ decFloat * decFloatAdd(decFloat *result, umsd=acc+COFF+DECPMAX-1; // so far, so zero if (ulsd>umsd) { // more to check umsd++; // to align after checked area - for (; UBTOUI(umsd)==0 && umsd+3msd)==0 && hi->msd+3lsd;) hi->msd+=4; - for (; *hi->msd==0 && hi->msdlsd;) hi->msd++; - for (; UBTOUI(lo->msd)==0 && lo->msd+3lsd;) lo->msd+=4; - for (; *lo->msd==0 && lo->msdlsd;) lo->msd++; + for (; hi->msd+3lsd && UBTOUI(hi->msd)==0;) hi->msd+=4; + for (; hi->msdlsd && *hi->msd==0;) hi->msd++; + for (; lo->msd+3lsd && UBTOUI(lo->msd)==0;) lo->msd+=4; + for (; lo->msdlsd && *lo->msd==0;) lo->msd++; // if hi is zero then result will be lo (which has the smaller // exponent), which also may need to be tested for zero for the @@ -2242,8 +2242,8 @@ decFloat * decFloatFMA(decFloat *result, const decFloat *dfl, // all done except for the special IEEE 754 exact-zero-result // rule (see above); while testing for zero, strip leading // zeros (which will save decFinalize doing it) - for (; UBTOUI(lo->msd)==0 && lo->msd+3lsd;) lo->msd+=4; - for (; *lo->msd==0 && lo->msdlsd;) lo->msd++; + for (; lo->msd+3lsd && UBTOUI(lo->msd)==0;) lo->msd+=4; + for (; lo->msdlsd && *lo->msd==0;) lo->msd++; if (*lo->msd==0) { // must be true zero (and diffsign) lo->sign=0; // assume + if (set->round==DEC_ROUND_FLOOR) lo->sign=DECFLOAT_Sign; diff --git a/decnumber-sys/decnumber/decCommon.c b/decnumber-sys/decnumber/decCommon.c index 6a0c112..ad3cfda 100644 --- a/decnumber-sys/decnumber/decCommon.c +++ b/decnumber-sys/decnumber/decCommon.c @@ -264,7 +264,7 @@ static decFloat * decFinalize(decFloat *df, bcdnum *num, // [this is quite expensive] if (*umsd==0) { for (; umsd+3exponent); @@ -416,7 +416,7 @@ static decFloat * decFinalize(decFloat *df, bcdnum *num, // if exponent is >=emax may have to clamp, overflow, or fold-down if (num->exponent>DECEMAX-(DECPMAX-1)) { // is edge case // printf("overflow checks...\n"); - if (*ulsd==0 && ulsd==umsd) { // have zero + if (ulsd==umsd && *ulsd==0) { // have zero num->exponent=DECEMAX-(DECPMAX-1); // clamp to max } else if ((num->exponent+length-1)>DECEMAX) { // > Nmax diff --git a/decnumber-sys/decnumber/decNumber.c b/decnumber-sys/decnumber/decNumber.c index 2572fac..c44941b 100644 --- a/decnumber-sys/decnumber/decNumber.c +++ b/decnumber-sys/decnumber/decNumber.c @@ -3467,7 +3467,8 @@ uByte * decNumberGetBCD(const decNumber *dn, uByte *bcd) { cut--; if (cut>0) continue; // more in this unit up++; - u=*up; + if (ub > bcd) + u=*up; cut=DECDPUN; } #endif @@ -4508,7 +4509,7 @@ static decNumber * decDivideOp(decNumber *res, for (;;) { // inner forever loop // strip leading zero units [from either pre-adjust or from // subtract last time around]. Leave at least one unit. - for (; *msu1==0 && msu1>var1; msu1--) var1units--; + for (; msu1>var1 && *msu1==0; msu1--) var1units--; if (var1units