[flang-commits] [flang] [flang] Do not invoke undefined behaviour when parsing format expressions (PR #147539)
David Spickett via flang-commits
flang-commits at lists.llvm.org
Tue Jul 8 07:40:54 PDT 2025
https://github.com/DavidSpickett created https://github.com/llvm/llvm-project/pull/147539
The test flang/test/Semantics/io08.f90 was failing when UBSAN was enabled:
```
/home/david.spickett/llvm-project/flang/include/flang/Common/format.h:224:26: runtime error: signed integer overflow: 10 * 987654321098765432 cannot be represented in type 'int64_t' (aka 'long') SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /home/david.spickett/llvm-project/flang/include/flang/Common/format.h:224:26 error: Semantic errors in /home/david.spickett/llvm-project/flang/test/Semantics/io08.f90 /home/david.spickett/llvm-project/flang/test/Semantics/io08.f90:2:14: error: Integer overflow in format expression
write(*,'(I98765432109876543210)')
^^^^^^^^^^^^^^^^^^^^
```
This is because the code was effectively:
* Take the risk of UB happening
* Check whether it happened or not
Which UBSAN is obviously not going to like. Instead of checking after the fact, use llvm's helpers that catch overflow without actually doing it.
>From d1e410a35bfd788e5062c566b7b031c6758a9c18 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at linaro.org>
Date: Tue, 8 Jul 2025 14:36:35 +0000
Subject: [PATCH] [flang] Do not invoke undefined behaviour when parsing format
expressions
The test flang/test/Semantics/io08.f90 was failing when UBSAN was enabled:
/home/david.spickett/llvm-project/flang/include/flang/Common/format.h:224:26: runtime error: signed integer overflow: 10 * 987654321098765432 cannot be represented in type 'int64_t' (aka 'long')
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /home/david.spickett/llvm-project/flang/include/flang/Common/format.h:224:26
error: Semantic errors in /home/david.spickett/llvm-project/flang/test/Semantics/io08.f90
/home/david.spickett/llvm-project/flang/test/Semantics/io08.f90:2:14: error: Integer overflow in format expression
write(*,'(I98765432109876543210)')
^^^^^^^^^^^^^^^^^^^^
This is because the code was effectively:
* Take the risk of UB happening
* Check whether it happened or not
Which UBSAN is obviously not going to like. Instead of checking after the
fact, use llvm's helpers that catch overflow without actually doing it.
---
flang/include/flang/Common/format.h | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/flang/include/flang/Common/format.h b/flang/include/flang/Common/format.h
index 1650f56140b4d..11aa6f2c07797 100644
--- a/flang/include/flang/Common/format.h
+++ b/flang/include/flang/Common/format.h
@@ -11,6 +11,7 @@
#include "Fortran-consts.h"
#include "enum-set.h"
+#include "llvm/Support/MathExtras.h"
#include <cstring>
// Define a FormatValidator class template to validate a format expression
@@ -214,16 +215,18 @@ template <typename CHAR> void FormatValidator<CHAR>::NextToken() {
case '7':
case '8':
case '9': {
- int64_t lastValue;
const CHAR *lastCursor;
integerValue_ = 0;
bool overflow{false};
do {
- lastValue = integerValue_;
lastCursor = cursor_;
- integerValue_ = 10 * integerValue_ + c - '0';
- if (lastValue > integerValue_) {
- overflow = true;
+ if (LLVM_LIKELY(!overflow)) {
+ overflow = llvm::MulOverflow(
+ static_cast<int64_t>(10), integerValue_, integerValue_);
+ }
+ if (LLVM_LIKELY(!overflow)) {
+ overflow = llvm::AddOverflow(
+ integerValue_, static_cast<int64_t>(c - '0'), integerValue_);
}
c = NextChar();
} while (c >= '0' && c <= '9');
More information about the flang-commits
mailing list