Attachment "fix-ubsan-shift-exponent.diff" to
ticket [cea2c63928]
added by
chrstphrchvz
2021-12-06 08:18:43.
diff --git generic/tclStrToD.c generic/tclStrToD.c
index 35848f7d8..9a62eedcb 100644
--- generic/tclStrToD.c
+++ generic/tclStrToD.c
@@ -694,9 +694,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)
@@ -710,8 +710,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 (0 != octalSignificandWide) {
+ octalSignificandWide <<= shift;
+ }
+ octalSignificandWide += c - '0';
} else {
mp_mul_2d(&octalSignificandBig, shift,
&octalSignificandBig);
@@ -813,9 +822,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 &&
@@ -827,7 +836,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 (0 != significandWide) {
+ significandWide <<= shift;
+ }
+ significandWide += d;
} else {
mp_mul_2d(&significandBig, shift, &significandBig);
mp_add_d(&significandBig, (mp_digit) d, &significandBig);
@@ -855,9 +874,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 &&
@@ -869,7 +888,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 (0 != significandWide) {
+ significandWide <<= shift;
+ }
+ significandWide += 1;
} else {
mp_mul_2d(&significandBig, shift, &significandBig);
mp_add_d(&significandBig, (mp_digit) 1, &significandBig);
@@ -1202,7 +1231,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 (0 != significandWide) {
+ significandWide <<= shift;
+ }
} else {
mp_mul_2d(&significandBig, shift, &significandBig);
}
@@ -1223,7 +1260,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 (0 != significandWide) {
+ significandWide <<= shift;
+ }
} else {
mp_mul_2d(&significandBig, shift, &significandBig);
}
@@ -1245,7 +1290,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 (0 != octalSignificandWide) {
+ octalSignificandWide <<= shift;
+ }
} else {
mp_mul_2d(&octalSignificandBig, shift,
&octalSignificandBig);