From ca3027e1badf760ead0693b7164f2ceb6118c5dd Mon Sep 17 00:00:00 2001 From: ChudaykinAlex Date: Wed, 6 May 2026 11:11:33 +0300 Subject: [PATCH 1/2] Suggestions for fixing the problem. --- extern/decNumber/decBasic.c | 2 +- extern/decNumber/decCommon.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/extern/decNumber/decBasic.c b/extern/decNumber/decBasic.c index 56396f8da7f..7645d6e658a 100644 --- a/extern/decNumber/decBasic.c +++ b/extern/decNumber/decBasic.c @@ -1120,7 +1120,7 @@ decFloat * decFloatAdd(decFloat *result, // the following buffers hold coefficients with various alignments // (see commentary and diagrams below) uByte acc[4+2+DECPMAX*3+8]; - uByte buf[4+2+DECPMAX*2]; + uByte buf[4+2+DECPMAX*2+4]; uByte *umsd, *ulsd; // local MSD and LSD pointers #if DECLITEND diff --git a/extern/decNumber/decCommon.c b/extern/decNumber/decCommon.c index e16d6ee2d1d..1a5df969d45 100644 --- a/extern/decNumber/decCommon.c +++ b/extern/decNumber/decCommon.c @@ -461,7 +461,8 @@ static decFloat * decFinalize(decFloat *df, bcdnum *num, uByte *t=buffer; // safe target uByte *tlsd=buffer+(ulsd-umsd)+shift; // target LSD // printf("folddown shift=%ld\n", (LI)shift); - for (; s<=ulsd; s+=4, t+=4) UBFROMUI(t, UBTOUI(s)); + for (; s+3<=ulsd; s+=4, t+=4) UBFROMUI(t, UBTOUI(s)); + for (; s<=ulsd; s++, t++) *t=*s; for (t=tlsd-shift+1; t<=tlsd; t+=4) UBFROMUI(t, 0); // pad 0s num->exponent-=shift; umsd=buffer; From 46142e2204ad20153bd5f4fd2f84b04cf52a89c3 Mon Sep 17 00:00:00 2001 From: "alexey.chudaykin" Date: Fri, 10 Jul 2026 12:09:12 +0300 Subject: [PATCH 2/2] Fix decNumber OOB reads and UB found by ASan+UBSan fuzzing Follow-up to the earlier stack-buffer-overflow fix. Adds 8 fixes: - decBasic.c: unsigned DPD shift in decFloatAdd (UB); break out of outer loop in decQuadCompareTotal (OOB read); bounds-check before UBTOUI in strip-leading-zeros loops (decQuadFMA and 3 others, OOB read) - decCommon.c: unsigned exponent accumulation in decFloatFromString (overflow) - decNumber.c: unsigned X10 in decNumberFromString (overflow/shift); unsigned n<<1 in decNumberPower and decNumberLn (UB) --- extern/decNumber/decBasic.c | 17 +++++++++-------- extern/decNumber/decCommon.c | 2 +- extern/decNumber/decNumber.c | 6 +++--- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/extern/decNumber/decBasic.c b/extern/decNumber/decBasic.c index 7645d6e658a..9fbcec09614 100644 --- a/extern/decNumber/decBasic.c +++ b/extern/decNumber/decBasic.c @@ -1186,8 +1186,8 @@ decFloat * decFloatAdd(decFloat *result, // construct the result; low word is the same for both formats encode =BIN2DPD[tac[0]]; encode|=BIN2DPD[tac[1]]<<10; - encode|=BIN2DPD[tac[2]]<<20; - encode|=BIN2DPD[tac[3]]<<30; + encode|=(uInt)BIN2DPD[tac[2]]<<20; + encode|=(uInt)BIN2DPD[tac[3]]<<30; DFWORD(result, (DECBYTES/4)-1)=encode; // collect next two declets (all that remains, for Double) @@ -1197,13 +1197,13 @@ decFloat * decFloatAdd(decFloat *result, #if QUAD // complete and lay out middling words encode|=BIN2DPD[tac[5]]<<18; - encode|=BIN2DPD[tac[6]]<<28; + encode|=(uInt)BIN2DPD[tac[6]]<<28; DFWORD(result, 2)=encode; encode =BIN2DPD[tac[6]]>>4; encode|=BIN2DPD[tac[7]]<<6; encode|=BIN2DPD[tac[8]]<<16; - encode|=BIN2DPD[tac[9]]<<26; + encode|=(uInt)BIN2DPD[tac[9]]<<26; DFWORD(result, 1)=encode; // and final two declets @@ -1533,7 +1533,7 @@ 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+3lsd && UBTOUI(hi->msd)==0;) 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+3lsd && UBTOUI(lo->msd)==0;) lo->msd+=4; for (; *lo->msd==0 && lo->msdlsd;) lo->msd++; // if hi is zero then result will be lo (which has the smaller @@ -2242,7 +2243,7 @@ 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+3lsd && UBTOUI(lo->msd)==0;) lo->msd+=4; for (; *lo->msd==0 && lo->msdlsd;) lo->msd++; if (*lo->msd==0) { // must be true zero (and diffsign) lo->sign=0; // assume + diff --git a/extern/decNumber/decCommon.c b/extern/decNumber/decCommon.c index 1a5df969d45..b74a31690eb 100644 --- a/extern/decNumber/decCommon.c +++ b/extern/decNumber/decCommon.c @@ -842,7 +842,7 @@ decFloat * decFloatFromString(decFloat *result, const char *string, for (;; c++) { edig=(uInt)*c-(uInt)'0'; if (edig>9) break; - exp=exp*10+edig; + exp=(Int)((uInt)exp*10+edig); // unsigned to avoid signed overflow (clipped below) } } // if not now on the '\0', *c must not be a digit diff --git a/extern/decNumber/decNumber.c b/extern/decNumber/decNumber.c index 2572fac5b17..76e2d043d53 100644 --- a/extern/decNumber/decNumber.c +++ b/extern/decNumber/decNumber.c @@ -595,7 +595,7 @@ decNumber * decNumberFromString(decNumber *dn, const char chars[], firstexp=c; // save exponent digit place for (; ;c++) { if (*c<'0' || *c>'9') break; // not a digit - exponent=X10(exponent)+(Int)*c-(Int)'0'; + exponent=(Int)(X10((uInt)exponent)+(uInt)((Int)*c-(Int)'0')); // unsigned to avoid signed overflow (clipped below) } // c // if not now on a '\0', *c must not be a digit if (*c!='\0') break; @@ -2199,7 +2199,7 @@ decNumber * decNumberPower(decNumber *res, const decNumber *lhs, } // [the following two lines revealed an optimizer bug in a C++ // compiler, with symptom: 5**3 -> 25, when n=n+n was used] - n=n<<1; // move next bit to testable position + n=(Int)((uInt)n<<1); // move next bit to testable position if (n<0) { // top bit is set seenbit=1; // OK, significant bit seen decMultiplyOp(dac, dac, lhs, &aset, &status); // dac=dac*x @@ -5466,7 +5466,7 @@ decNumber * decExpOp(decNumber *res, const decNumber *rhs, // abandon if have had overflow or terminal underflow if (*status & (DEC_Overflow|DEC_Underflow)) { // interesting? if (*status&DEC_Overflow || ISZERO(t)) break;} - n=n<<1; // move next bit to testable position + n=(Int)((uInt)n<<1); // move next bit to testable position if (n<0) { // top bit is set seenbit=1; // OK, have a significant bit decMultiplyOp(t, t, a, &aset, status); // acc=acc*x