|
12 | 12 | #include "Fortran-consts.h"
|
13 | 13 | #include "enum-set.h"
|
14 | 14 | #include <cstring>
|
| 15 | +#include <limits> |
15 | 16 |
|
16 | 17 | // Define a FormatValidator class template to validate a format expression
|
17 | 18 | // of a given CHAR type. To enable use in runtime library code as well as
|
|
28 | 29 |
|
29 | 30 | namespace Fortran::common {
|
30 | 31 |
|
| 32 | +// AddOverflow and MulOverflow are copied from |
| 33 | +// llvm/include/llvm/Support/MathExtras.h and specialised to int64_t. |
| 34 | + |
| 35 | +/// Add two signed integers, computing the two's complement truncated result, |
| 36 | +/// returning true if overflow occurred. |
| 37 | +static inline bool AddOverflow(int64_t X, int64_t Y, int64_t &Result) { |
| 38 | +#if __has_builtin(__builtin_add_overflow) |
| 39 | + return __builtin_add_overflow(X, Y, &Result); |
| 40 | +#else |
| 41 | + // Perform the unsigned addition. |
| 42 | + const uint64_t UX = static_cast<uint64_t>(X); |
| 43 | + const uint64_t UY = static_cast<uint64_t>(Y); |
| 44 | + const uint64_t UResult = UX + UY; |
| 45 | + |
| 46 | + // Convert to signed. |
| 47 | + Result = static_cast<int64_t>(UResult); |
| 48 | + |
| 49 | + // Adding two positive numbers should result in a positive number. |
| 50 | + if (X > 0 && Y > 0) { |
| 51 | + return Result <= 0; |
| 52 | + } |
| 53 | + // Adding two negatives should result in a negative number. |
| 54 | + if (X < 0 && Y < 0) { |
| 55 | + return Result >= 0; |
| 56 | + } |
| 57 | + return false; |
| 58 | +#endif |
| 59 | +} |
| 60 | + |
| 61 | +/// Multiply two signed integers, computing the two's complement truncated |
| 62 | +/// result, returning true if an overflow occurred. |
| 63 | +static inline bool MulOverflow(int64_t X, int64_t Y, int64_t &Result) { |
| 64 | +#if __has_builtin(__builtin_mul_overflow) |
| 65 | + return __builtin_mul_overflow(X, Y, &Result); |
| 66 | +#else |
| 67 | + // Perform the unsigned multiplication on absolute values. |
| 68 | + const uint64_t UX = |
| 69 | + X < 0 ? (0 - static_cast<uint64_t>(X)) : static_cast<uint64_t>(X); |
| 70 | + const uint64_t UY = |
| 71 | + Y < 0 ? (0 - static_cast<uint64_t>(Y)) : static_cast<uint64_t>(Y); |
| 72 | + const uint64_t UResult = UX * UY; |
| 73 | + |
| 74 | + // Convert to signed. |
| 75 | + const bool IsNegative = (X < 0) ^ (Y < 0); |
| 76 | + Result = IsNegative ? (0 - UResult) : UResult; |
| 77 | + |
| 78 | + // If any of the args was 0, result is 0 and no overflow occurs. |
| 79 | + if (UX == 0 || UY == 0) { |
| 80 | + return false; |
| 81 | + } |
| 82 | + |
| 83 | + // UX and UY are in [1, 2^n], where n is the number of digits. |
| 84 | + // Check how the max allowed absolute value (2^n for negative, 2^(n-1) for |
| 85 | + // positive) divided by an argument compares to the other. |
| 86 | + if (IsNegative) { |
| 87 | + return UX > (static_cast<uint64_t>(std::numeric_limits<int64_t>::max()) + |
| 88 | + uint64_t(1)) / |
| 89 | + UY; |
| 90 | + } else { |
| 91 | + return UX > |
| 92 | + (static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) / UY; |
| 93 | + } |
| 94 | +#endif |
| 95 | +} |
| 96 | + |
31 | 97 | struct FormatMessage {
|
32 | 98 | const char *text; // message text; may have one %s argument
|
33 | 99 | const char *arg; // optional %s argument value
|
@@ -214,16 +280,18 @@ template <typename CHAR> void FormatValidator<CHAR>::NextToken() {
|
214 | 280 | case '7':
|
215 | 281 | case '8':
|
216 | 282 | case '9': {
|
217 |
| - int64_t lastValue; |
218 | 283 | const CHAR *lastCursor;
|
219 | 284 | integerValue_ = 0;
|
220 | 285 | bool overflow{false};
|
221 | 286 | do {
|
222 |
| - lastValue = integerValue_; |
223 | 287 | lastCursor = cursor_;
|
224 |
| - integerValue_ = 10 * integerValue_ + c - '0'; |
225 |
| - if (lastValue > integerValue_) { |
226 |
| - overflow = true; |
| 288 | + if (!overflow) { |
| 289 | + overflow = |
| 290 | + MulOverflow(static_cast<int64_t>(10), integerValue_, integerValue_); |
| 291 | + } |
| 292 | + if (!overflow) { |
| 293 | + overflow = AddOverflow( |
| 294 | + integerValue_, static_cast<int64_t>(c - '0'), integerValue_); |
227 | 295 | }
|
228 | 296 | c = NextChar();
|
229 | 297 | } while (c >= '0' && c <= '9');
|
|
0 commit comments