diff mbox series

[1/2,v2] libdecnumber: fixed multiple potential access-out-of bounds errors by moving range conditions before reads.

Message ID 20240203193119.18549-1-icmccorm@andrew.cmu.edu
State New
Headers show
Series [1/2,v2] libdecnumber: fixed multiple potential access-out-of bounds errors by moving range conditions before reads. | expand

Commit Message

Ian McCormack Feb. 3, 2024, 7:31 p.m. UTC
Multiple `for` loops across `libdecnumber` contain boolean expressions where memory is accessed prior to checking if the pointer is still within a valid range, which can lead to out-of-bounds reads.

This patch moves the range conditions to appear before the memory accesses in each conjunction so that these expressions short-circuit instead of performing an invalid read. 

libdecnumber/ChangeLog
       * In each `for` loop and `if` statement, all boolean expressions of the form `*ptr == value && in_range(ptr)` have been changed to `in_range(ptr) && *ptr == value`.

Bootstrapped on x86_64-pc-linux-gnu with no regressions.
---
 libdecnumber/decBasic.c  | 20 ++++++++++----------
 libdecnumber/decCommon.c |  2 +-
 libdecnumber/decNumber.c |  2 +-
 3 files changed, 12 insertions(+), 12 deletions(-)

Comments

Ian McCormack March 27, 2024, 8:48 p.m. UTC | #1
Hello—just pinging again about the following two patches I submitted. Each
fixes small access-out-of-bounds errors in libdecnumber.

https://gcc.gnu.org/pipermail/gcc-patches/2024-February/644840.html
https://gcc.gnu.org/pipermail/gcc-patches/2024-February/644910.html

Also, the documentation indicated that I should mention that I do not have
write access, since I'm a first-time contributor.

On Sat, Feb 3, 2024 at 2:31 PM Ian McCormack <icmccorm@gmail.com> wrote:

> Multiple `for` loops across `libdecnumber` contain boolean expressions
> where memory is accessed prior to checking if the pointer is still within a
> valid range, which can lead to out-of-bounds reads.
>
> This patch moves the range conditions to appear before the memory accesses
> in each conjunction so that these expressions short-circuit instead of
> performing an invalid read.
>
> libdecnumber/ChangeLog
>        * In each `for` loop and `if` statement, all boolean expressions of
> the form `*ptr == value && in_range(ptr)` have been changed to
> `in_range(ptr) && *ptr == value`.
>
> Bootstrapped on x86_64-pc-linux-gnu with no regressions.
> ---
>  libdecnumber/decBasic.c  | 20 ++++++++++----------
>  libdecnumber/decCommon.c |  2 +-
>  libdecnumber/decNumber.c |  2 +-
>  3 files changed, 12 insertions(+), 12 deletions(-)
>
> diff --git a/libdecnumber/decBasic.c b/libdecnumber/decBasic.c
> index 6319f66b25d..04833f2390d 100644
> --- a/libdecnumber/decBasic.c
> +++ b/libdecnumber/decBasic.c
> @@ -341,7 +341,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 */
> @@ -515,7 +515,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 */
> @@ -1543,8 +1543,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+3<ulsd;) umsd+=4;
> -         for (; *umsd==0 && umsd<ulsd;) umsd++;
> +         for (; umsd+3<ulsd && UBTOUI(umsd)==0;) umsd+=4;
> +         for (; umsd<ulsd && *umsd==0;) umsd++;
>           }
>         if (*umsd==0) {            /* must be true zero (and diffsign) */
>           num.sign=0;              /* assume + */
> @@ -2087,10 +2087,10 @@ decFloat * decFloatFMA(decFloat *result, const
> decFloat *dfl,
>    /* remove leading zeros on both operands; this will save time later */
>    /* and make testing for zero trivial (tests are safe because acc */
>    /* and coe are rounded up to uInts) */
> -  for (; UBTOUI(hi->msd)==0 && hi->msd+3<hi->lsd;) hi->msd+=4;
> -  for (; *hi->msd==0 && hi->msd<hi->lsd;) hi->msd++;
> -  for (; UBTOUI(lo->msd)==0 && lo->msd+3<lo->lsd;) lo->msd+=4;
> -  for (; *lo->msd==0 && lo->msd<lo->lsd;) lo->msd++;
> +  for (; hi->msd+3<hi->lsd && UBTOUI(hi->msd)==0;) hi->msd+=4;
> +  for (; hi->msd<hi->lsd && *hi->msd==0;) hi->msd++;
> +  for (; lo->msd+3<lo->lsd && UBTOUI(lo->msd)==0;) lo->msd+=4;
> +  for (; lo->msd<lo->lsd && *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 */
> @@ -2252,8 +2252,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+3<lo->lsd;) lo->msd+=4;
> -      for (; *lo->msd==0 && lo->msd<lo->lsd;) lo->msd++;
> +      for (; lo->msd+3<lo->lsd && UBTOUI(lo->msd)==0;) lo->msd+=4;
> +      for (; lo->msd<lo->lsd && *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/libdecnumber/decCommon.c b/libdecnumber/decCommon.c
> index 6f7563de6e6..1f9fe4a1935 100644
> --- a/libdecnumber/decCommon.c
> +++ b/libdecnumber/decCommon.c
> @@ -276,7 +276,7 @@ static decFloat * decFinalize(decFloat *df, bcdnum
> *num,
>      /* [this is quite expensive] */
>      if (*umsd==0) {
>        for (; umsd+3<ulsd && UBTOUI(umsd)==0;) umsd+=4;
> -      for (; *umsd==0 && umsd<ulsd;) umsd++;
> +      for (; umsd<ulsd && *umsd==0;) umsd++;
>        length=ulsd-umsd+1;                   /* recalculate */
>        }
>      drop=MAXI(length-DECPMAX, DECQTINY-num->exponent);
> diff --git a/libdecnumber/decNumber.c b/libdecnumber/decNumber.c
> index 094bc51c14a..89baef15749 100644
> --- a/libdecnumber/decNumber.c
> +++ b/libdecnumber/decNumber.c
> @@ -4505,7 +4505,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<var2ulen) break;       /* var1 too low for subtract
> */
>         if (var1units==var2ulen) {           /* unit-by-unit compare
> needed */
> --
> 2.39.3 (Apple Git-145)
>
>
diff mbox series

Patch

diff --git a/libdecnumber/decBasic.c b/libdecnumber/decBasic.c
index 6319f66b25d..04833f2390d 100644
--- a/libdecnumber/decBasic.c
+++ b/libdecnumber/decBasic.c
@@ -341,7 +341,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 */
@@ -515,7 +515,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 */
@@ -1543,8 +1543,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+3<ulsd;) umsd+=4;
-	  for (; *umsd==0 && umsd<ulsd;) umsd++;
+	  for (; umsd+3<ulsd && UBTOUI(umsd)==0;) umsd+=4;
+	  for (; umsd<ulsd && *umsd==0;) umsd++;
 	  }
 	if (*umsd==0) { 	   /* must be true zero (and diffsign) */
 	  num.sign=0;		   /* assume + */
@@ -2087,10 +2087,10 @@  decFloat * decFloatFMA(decFloat *result, const decFloat *dfl,
   /* remove leading zeros on both operands; this will save time later */
   /* and make testing for zero trivial (tests are safe because acc */
   /* and coe are rounded up to uInts) */
-  for (; UBTOUI(hi->msd)==0 && hi->msd+3<hi->lsd;) hi->msd+=4;
-  for (; *hi->msd==0 && hi->msd<hi->lsd;) hi->msd++;
-  for (; UBTOUI(lo->msd)==0 && lo->msd+3<lo->lsd;) lo->msd+=4;
-  for (; *lo->msd==0 && lo->msd<lo->lsd;) lo->msd++;
+  for (; hi->msd+3<hi->lsd && UBTOUI(hi->msd)==0;) hi->msd+=4;
+  for (; hi->msd<hi->lsd && *hi->msd==0;) hi->msd++;
+  for (; lo->msd+3<lo->lsd && UBTOUI(lo->msd)==0;) lo->msd+=4;
+  for (; lo->msd<lo->lsd && *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 */
@@ -2252,8 +2252,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+3<lo->lsd;) lo->msd+=4;
-      for (; *lo->msd==0 && lo->msd<lo->lsd;) lo->msd++;
+      for (; lo->msd+3<lo->lsd && UBTOUI(lo->msd)==0;) lo->msd+=4;
+      for (; lo->msd<lo->lsd && *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/libdecnumber/decCommon.c b/libdecnumber/decCommon.c
index 6f7563de6e6..1f9fe4a1935 100644
--- a/libdecnumber/decCommon.c
+++ b/libdecnumber/decCommon.c
@@ -276,7 +276,7 @@  static decFloat * decFinalize(decFloat *df, bcdnum *num,
     /* [this is quite expensive] */
     if (*umsd==0) {
       for (; umsd+3<ulsd && UBTOUI(umsd)==0;) umsd+=4;
-      for (; *umsd==0 && umsd<ulsd;) umsd++;
+      for (; umsd<ulsd && *umsd==0;) umsd++;
       length=ulsd-umsd+1;		     /* recalculate */
       }
     drop=MAXI(length-DECPMAX, DECQTINY-num->exponent);
diff --git a/libdecnumber/decNumber.c b/libdecnumber/decNumber.c
index 094bc51c14a..89baef15749 100644
--- a/libdecnumber/decNumber.c
+++ b/libdecnumber/decNumber.c
@@ -4505,7 +4505,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<var2ulen) break;	     /* var1 too low for subtract */
 	if (var1units==var2ulen) {	     /* unit-by-unit compare needed */