[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