Skip to content

Commit cdd54cb

Browse files
committed
[flang][runtime] Catch decimal integer input overflow
B/O/Z input overflow is already caught, and real input overflow is signalled as an IEEE arithmetic exception, but regular decimal integer overflow was silent. Differential Revision: https://reviews.llvm.org/D126155
1 parent 0a79113 commit cdd54cb

File tree

3 files changed

+21
-1
lines changed

3 files changed

+21
-1
lines changed

flang/include/flang/Runtime/iostat.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ enum Iostat {
7272
IostatBadScaleFactor,
7373
IostatBadAsynchronous,
7474
IostatBadWaitUnit,
75+
IostatBOZInputOverflow,
76+
IostatIntegerInputOverflow,
7577
};
7678

7779
const char *IostatErrorString(int);

flang/runtime/edit-input.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ static bool EditBOZInput(
4747
}
4848
auto significantBytes{static_cast<std::size_t>(digits * LOG2_BASE + 7) / 8};
4949
if (significantBytes > bytes) {
50-
io.GetIoErrorHandler().SignalError(
50+
io.GetIoErrorHandler().SignalError(IostatBOZInputOverflow,
5151
"B/O/Z input of %d digits overflows %zd-byte variable", digits, bytes);
5252
return false;
5353
}
@@ -140,6 +140,7 @@ bool EditIntegerInput(
140140
bool negate{ScanNumericPrefix(io, edit, next, remaining)};
141141
common::UnsignedInt128 value{0};
142142
bool any{negate};
143+
bool overflow{false};
143144
for (; next; next = io.NextInField(remaining, edit)) {
144145
char32_t ch{*next};
145146
if (ch == ' ' || ch == '\t') {
@@ -157,10 +158,23 @@ bool EditIntegerInput(
157158
"Bad character '%lc' in INTEGER input field", ch);
158159
return false;
159160
}
161+
static constexpr auto maxu128{~common::UnsignedInt128{0}};
162+
static constexpr auto maxu128OverTen{maxu128 / 10};
163+
static constexpr int maxLastDigit{
164+
static_cast<int>(maxu128 - (maxu128OverTen * 10))};
165+
overflow |= value >= maxu128OverTen &&
166+
(value > maxu128OverTen || digit > maxLastDigit);
160167
value *= 10;
161168
value += digit;
162169
any = true;
163170
}
171+
auto maxForKind{common::UnsignedInt128{1} << ((8 * kind) - 1)};
172+
overflow |= value >= maxForKind && (value > maxForKind || !negate);
173+
if (overflow) {
174+
io.GetIoErrorHandler().SignalError(IostatIntegerInputOverflow,
175+
"Decimal input overflows INTEGER(%d) variable", kind);
176+
return false;
177+
}
164178
if (negate) {
165179
value = -value;
166180
}

flang/runtime/iostat.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ const char *IostatErrorString(int iostat) {
8888
"OPEN(ASYNCHRONOUS='YES')";
8989
case IostatBadWaitUnit:
9090
return "WAIT(ID=nonzero) for a bad unit number";
91+
case IostatBOZInputOverflow:
92+
return "B/O/Z input value overflows variable";
93+
case IostatIntegerInputOverflow:
94+
return "Integer input value overflows variable";
9195
default:
9296
return nullptr;
9397
}

0 commit comments

Comments
 (0)