Skip to content

[flang] Avoid left shifts of negative signed values #84786

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 11, 2024

Conversation

kparzysz
Copy link
Contributor

Shifting left a signed, negative value is an undefined behavior in C++.

This was detected by the undefined behavior sanitizer.

Shifting left a signed, negative value is an undefined behavior in C++.

This was detected by the undefined behavior sanitizer.
@kparzysz kparzysz requested review from tskeith and klausler March 11, 2024 16:24
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:semantics labels Mar 11, 2024
@llvmbot
Copy link
Member

llvmbot commented Mar 11, 2024

@llvm/pr-subscribers-flang-semantics

Author: Krzysztof Parzyszek (kparzysz)

Changes

Shifting left a signed, negative value is an undefined behavior in C++.

This was detected by the undefined behavior sanitizer.


Full diff: https://github.com/llvm/llvm-project/pull/84786.diff

1 Files Affected:

  • (modified) flang/include/flang/Evaluate/integer.h (+10-2)
diff --git a/flang/include/flang/Evaluate/integer.h b/flang/include/flang/Evaluate/integer.h
index 977d35c7eecf48..1e5f68104f72bf 100644
--- a/flang/include/flang/Evaluate/integer.h
+++ b/flang/include/flang/Evaluate/integer.h
@@ -150,7 +150,10 @@ class Integer {
           }
         }
       } else {
-        INT signExtension{-(n < 0)};
+        // Avoid left shifts of negative signed values (that's an undefined
+        // behavior in C++).
+        auto signExtension = std::make_unsigned_t<INT>(n < 0);
+        signExtension = ~signExtension + 1;
         static_assert(nBits >= partBits);
         if constexpr (nBits > partBits) {
           signExtension <<= nBits - partBits;
@@ -474,7 +477,12 @@ class Integer {
     SINT n = ToUInt<UINT>();
     constexpr std::size_t maxBits{CHAR_BIT * sizeof n};
     if constexpr (bits < maxBits) {
-      n |= -(n >> (bits - 1)) << bits;
+      // Avoid left shifts of negative signed values (that's an undefined
+      // behavior in C++).
+      auto u = std::make_unsigned_t<SINT>(ToUInt());
+      u = (u >> (bits - 1)) << (bits - 1); // Get the sign bit only.
+      u = ~u + 1;                          // Negate top bits if not 0.
+      n |= static_cast<SINT>(u);
     }
     return n;
   }

Copy link

github-actions bot commented Mar 11, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

INT signExtension{-(n < 0)};
// Avoid left shifts of negative signed values (that's an undefined
// behavior in C++).
auto signExtension = std::make_unsigned_t<INT>(n < 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use braced initialization in Flang front-end code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@kparzysz kparzysz merged commit a70d729 into llvm:main Mar 11, 2024
@kparzysz kparzysz deleted the users/kparzysz/ubsan-02 branch March 11, 2024 19:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:semantics flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants