summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tclStrToD.c85
1 files changed, 69 insertions, 16 deletions
diff --git a/generic/tclStrToD.c b/generic/tclStrToD.c
index 3cee154..e87f714 100644
--- a/generic/tclStrToD.c
+++ b/generic/tclStrToD.c
@@ -721,9 +721,9 @@ TclParseNumber(
if (!octalSignificandOverflow) {
/*
- * Shifting by more bits than are in the value being
- * shifted is at least de facto nonportable. Check for
- * too large shifts first.
+ * Shifting by as many or more bits than are in the
+ * value being shifted is undefined behavior. Check
+ * for too large shifts first.
*/
if ((octalSignificandWide != 0)
@@ -737,8 +737,17 @@ TclParseNumber(
}
}
if (!octalSignificandOverflow) {
- octalSignificandWide =
- (octalSignificandWide << shift) + (c - '0');
+ /*
+ * When the significand is 0, it is possible for the
+ * amount to be shifted to equal or exceed the width
+ * of the significand. Do not shift when the
+ * significand is 0 to avoid undefined behavior.
+ */
+
+ if (octalSignificandWide != 0) {
+ octalSignificandWide <<= shift;
+ }
+ octalSignificandWide += c - '0';
} else {
if (err == MP_OKAY) {
err = mp_mul_2d(&octalSignificandBig, shift,
@@ -863,9 +872,9 @@ TclParseNumber(
shift = 4 * (numTrailZeros + 1);
if (!significandOverflow) {
/*
- * Shifting by more bits than are in the value being
- * shifted is at least de facto nonportable. Check for too
- * large shifts first.
+ * Shifting by as many or more bits than are in the
+ * value being shifted is undefined behavior. Check
+ * for too large shifts first.
*/
if (significandWide != 0 &&
@@ -877,7 +886,17 @@ TclParseNumber(
}
}
if (!significandOverflow) {
- significandWide = (significandWide << shift) + d;
+ /*
+ * When the significand is 0, it is possible for the
+ * amount to be shifted to equal or exceed the width
+ * of the significand. Do not shift when the
+ * significand is 0 to avoid undefined behavior.
+ */
+
+ if (significandWide != 0) {
+ significandWide <<= shift;
+ }
+ significandWide += d;
} else if (err == MP_OKAY) {
err = mp_mul_2d(&significandBig, shift, &significandBig);
if (err == MP_OKAY) {
@@ -917,9 +936,9 @@ TclParseNumber(
shift = numTrailZeros + 1;
if (!significandOverflow) {
/*
- * Shifting by more bits than are in the value being
- * shifted is at least de facto nonportable. Check for too
- * large shifts first.
+ * Shifting by as many or more bits than are in the
+ * value being shifted is undefined behavior. Check
+ * for too large shifts first.
*/
if (significandWide != 0 &&
@@ -931,7 +950,17 @@ TclParseNumber(
}
}
if (!significandOverflow) {
- significandWide = (significandWide << shift) + 1;
+ /*
+ * When the significand is 0, it is possible for the
+ * amount to be shifted to equal or exceed the width
+ * of the significand. Do not shift when the
+ * significand is 0 to avoid undefined behavior.
+ */
+
+ if (significandWide != 0) {
+ significandWide <<= shift;
+ }
+ significandWide += 1;
} else if (err == MP_OKAY) {
err = mp_mul_2d(&significandBig, shift, &significandBig);
if (err == MP_OKAY) {
@@ -1330,7 +1359,15 @@ TclParseNumber(
}
if (shift) {
if (!significandOverflow) {
- significandWide <<= shift;
+ /*
+ * When the significand is 0, it is possible for the
+ * amount to be shifted to equal or exceed the width
+ * of the significand. Do not shift when the
+ * significand is 0 to avoid undefined behavior.
+ */
+ if (significandWide != 0) {
+ significandWide <<= shift;
+ }
} else if (err == MP_OKAY) {
err = mp_mul_2d(&significandBig, shift, &significandBig);
}
@@ -1354,7 +1391,15 @@ TclParseNumber(
}
if (shift) {
if (!significandOverflow) {
- significandWide <<= shift;
+ /*
+ * When the significand is 0, it is possible for the
+ * amount to be shifted to equal or exceed the width
+ * of the significand. Do not shift when the
+ * significand is 0 to avoid undefined behavior.
+ */
+ if (significandWide != 0) {
+ significandWide <<= shift;
+ }
} else if (err == MP_OKAY) {
err = mp_mul_2d(&significandBig, shift, &significandBig);
}
@@ -1379,7 +1424,15 @@ TclParseNumber(
}
if (shift) {
if (!octalSignificandOverflow) {
- octalSignificandWide <<= shift;
+ /*
+ * When the significand is 0, it is possible for the
+ * amount to be shifted to equal or exceed the width
+ * of the significand. Do not shift when the
+ * significand is 0 to avoid undefined behavior.
+ */
+ if (octalSignificandWide != 0) {
+ octalSignificandWide <<= shift;
+ }
} else if (err == MP_OKAY) {
err = mp_mul_2d(&octalSignificandBig, shift,
&octalSignificandBig);