Skip to content

[analyzer] Handle [[assume(cond)]] as __builtin_assume(cond) #116462

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 21 commits into from
Dec 19, 2024

Conversation

vinay-deshmukh
Copy link
Contributor

@vinay-deshmukh vinay-deshmukh commented Nov 16, 2024

Resolves #100762

Gist of the change:

  1. All the symbol analysis, constraint manager and expression parsing logic was already present, but the previous code didn't "visit" the expressions within assume() by parsing those expressions, all of the code "just works" by evaluating the SVals, and hence leaning on the same logic that makes the code with __builtin_assume work
  2. "Ignore" an expression from adding in CFG if it has side-effects ( similar to CGStmt.cpp (todo add link))
  3. Add additional test case for ternary operator handling and modify CFG.cpp's VisitGuardedExpr code for continue-ing if the ProgramPoint is a StmtPoint

Copy link

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@vinay-deshmukh
Copy link
Contributor Author

@steakhal

Can you take a look at this PR when you have a chance?
Thanks!

@vinay-deshmukh vinay-deshmukh force-pushed the vinay-issue-100762 branch 2 times, most recently from d4ba202 to 336eb74 Compare November 16, 2024 02:37
@vinay-deshmukh vinay-deshmukh marked this pull request as ready for review November 16, 2024 02:37
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:static analyzer clang:analysis labels Nov 16, 2024
@llvmbot
Copy link
Member

llvmbot commented Nov 16, 2024

@llvm/pr-subscribers-clang-codegen
@llvm/pr-subscribers-clang-static-analyzer-1

@llvm/pr-subscribers-clang

Author: Vinay Deshmukh (vinay-deshmukh)

Changes

Resolves #100762

Gist of the change:

  1. All the symbol analysis, constraint manager and expression parsing logic was already present, but the previous code didn't "visit" the expressions within assume() by parsing those expressions, all of the code "just works" by evaluating the SVals, and hence leaning on the same logic that makes the code with __builtin_assume work

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

5 Files Affected:

  • (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (+4)
  • (modified) clang/lib/Analysis/CFG.cpp (+43)
  • (modified) clang/lib/StaticAnalyzer/Core/ExprEngine.cpp (+7-1)
  • (modified) clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (+27)
  • (modified) clang/test/Analysis/out-of-bounds-new.cpp (+16)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 8c7493e27fcaa6..078a1d840d0516 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -498,6 +498,10 @@ class ExprEngine {
   void VisitInitListExpr(const InitListExpr *E, ExplodedNode *Pred,
                          ExplodedNodeSet &Dst);
 
+  /// VisitAttributedStmt - Transfer function logic for AttributedStmt
+  void VisitAttributedStmt(const AttributedStmt *A, ExplodedNode *Pred,
+                           ExplodedNodeSet &Dst);
+
   /// VisitLogicalExpr - Transfer function logic for '&&', '||'
   void VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
                         ExplodedNodeSet &Dst);
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index f678ac6f2ff36a..fab10f51cf5cfc 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -456,6 +456,36 @@ reverse_children::reverse_children(Stmt *S) {
                                 IE->getNumInits());
       return;
     }
+    case Stmt::AttributedStmtClass: {
+      AttributedStmt *attrStmt = cast<AttributedStmt>(S);
+      assert(attrStmt);
+
+      {
+        // for an attributed stmt, the "children()" returns only the NullStmt
+        // (;) but semantically the "children" are supposed to be the
+        // expressions _within_ i.e. the two square brackets i.e. [[ HERE ]]
+        // so we add the subexpressions first, _then_ add the "children"
+
+        for (const Attr *attr : attrStmt->getAttrs()) {
+
+          // i.e. one `assume()`
+          CXXAssumeAttr const *assumeAttr = llvm::dyn_cast<CXXAssumeAttr>(attr);
+          if (!assumeAttr) {
+            continue;
+          }
+          // Only handles [[ assume(<assumption>) ]] right now
+          Expr *assumption = assumeAttr->getAssumption();
+          childrenBuf.push_back(assumption);
+        }
+
+        // children() for an AttributedStmt is NullStmt(;)
+        llvm::append_range(childrenBuf, attrStmt->children());
+
+        // This needs to be done *after* childrenBuf has been populated.
+        children = childrenBuf;
+      }
+      return;
+    }
     default:
       break;
   }
@@ -2475,6 +2505,14 @@ static bool isFallthroughStatement(const AttributedStmt *A) {
   return isFallthrough;
 }
 
+static bool isCXXAssumeAttr(const AttributedStmt *A) {
+  bool hasAssumeAttr = hasSpecificAttr<CXXAssumeAttr>(A->getAttrs());
+
+  assert((!hasAssumeAttr || isa<NullStmt>(A->getSubStmt())) &&
+         "expected [[assume]] not to have children");
+  return hasAssumeAttr;
+}
+
 CFGBlock *CFGBuilder::VisitAttributedStmt(AttributedStmt *A,
                                           AddStmtChoice asc) {
   // AttributedStmts for [[likely]] can have arbitrary statements as children,
@@ -2490,6 +2528,11 @@ CFGBlock *CFGBuilder::VisitAttributedStmt(AttributedStmt *A,
     appendStmt(Block, A);
   }
 
+  if (isCXXAssumeAttr(A) && asc.alwaysAdd(*this, A)) {
+    autoCreateBlock();
+    appendStmt(Block, A);
+  }
+
   return VisitChildren(A);
 }
 
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 22eab9f66418d4..cbc83f1dbda145 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1946,7 +1946,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
     // to be explicitly evaluated.
     case Stmt::PredefinedExprClass:
     case Stmt::AddrLabelExprClass:
-    case Stmt::AttributedStmtClass:
     case Stmt::IntegerLiteralClass:
     case Stmt::FixedPointLiteralClass:
     case Stmt::CharacterLiteralClass:
@@ -1977,6 +1976,13 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
       break;
     }
 
+    case Stmt::AttributedStmtClass: {
+      Bldr.takeNodes(Pred);
+      VisitAttributedStmt(cast<AttributedStmt>(S), Pred, Dst);
+      Bldr.addNodes(Dst);
+      break;
+    }
+
     case Stmt::CXXDefaultArgExprClass:
     case Stmt::CXXDefaultInitExprClass: {
       Bldr.takeNodes(Pred);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index f7020da2e6da20..1a211d1adc44f7 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -1200,3 +1200,30 @@ void ExprEngine::VisitLambdaExpr(const LambdaExpr *LE, ExplodedNode *Pred,
   // FIXME: Move all post/pre visits to ::Visit().
   getCheckerManager().runCheckersForPostStmt(Dst, Tmp, LE, *this);
 }
+
+void ExprEngine::VisitAttributedStmt(const AttributedStmt *A,
+                                     ExplodedNode *Pred, ExplodedNodeSet &Dst) {
+
+  ExplodedNodeSet CheckerPreStmt;
+  getCheckerManager().runCheckersForPreStmt(CheckerPreStmt, Pred, A, *this);
+
+  ExplodedNodeSet EvalSet;
+  StmtNodeBuilder Bldr(CheckerPreStmt, EvalSet, *currBldrCtx);
+
+  {
+    for (const auto *attr : A->getAttrs()) {
+
+      CXXAssumeAttr const *assumeAttr = llvm::dyn_cast<CXXAssumeAttr>(attr);
+      if (!assumeAttr) {
+        continue;
+      }
+      Expr *AssumeExpr = assumeAttr->getAssumption();
+
+      for (auto *node : CheckerPreStmt) {
+        Visit(AssumeExpr, node, EvalSet);
+      }
+    }
+  }
+
+  getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, A, *this);
+}
diff --git a/clang/test/Analysis/out-of-bounds-new.cpp b/clang/test/Analysis/out-of-bounds-new.cpp
index f541bdf810d79c..4db351b10055b1 100644
--- a/clang/test/Analysis/out-of-bounds-new.cpp
+++ b/clang/test/Analysis/out-of-bounds-new.cpp
@@ -180,3 +180,19 @@ int test_reference_that_might_be_after_the_end(int idx) {
   return ref;
 }
 
+// From: https://github.com/llvm/llvm-project/issues/100762
+extern int arr[10];
+void using_builtin(int x) {
+    __builtin_assume(x > 101); // CallExpr
+    arr[x] = 404; // expected-warning{{Out of bound access to memory}}
+}
+
+void using_assume_attr(int ax) {
+    [[assume(ax > 100)]]; // NullStmt with an attribute
+    arr[ax] = 405; // expected-warning{{Out of bound access to memory}}
+}
+
+void using_many_assume_attr(int yx) {
+    [[assume(yx > 104), assume(yx > 200), assume(yx < 300)]]; // NullStmt with an attribute
+    arr[yx] = 406; // expected-warning{{Out of bound access to memory}}
+}

@llvmbot
Copy link
Member

llvmbot commented Nov 16, 2024

@llvm/pr-subscribers-clang-analysis

Author: Vinay Deshmukh (vinay-deshmukh)

Changes

Resolves #100762

Gist of the change:

  1. All the symbol analysis, constraint manager and expression parsing logic was already present, but the previous code didn't "visit" the expressions within assume() by parsing those expressions, all of the code "just works" by evaluating the SVals, and hence leaning on the same logic that makes the code with __builtin_assume work

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

5 Files Affected:

  • (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (+4)
  • (modified) clang/lib/Analysis/CFG.cpp (+43)
  • (modified) clang/lib/StaticAnalyzer/Core/ExprEngine.cpp (+7-1)
  • (modified) clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (+27)
  • (modified) clang/test/Analysis/out-of-bounds-new.cpp (+16)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 8c7493e27fcaa6..078a1d840d0516 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -498,6 +498,10 @@ class ExprEngine {
   void VisitInitListExpr(const InitListExpr *E, ExplodedNode *Pred,
                          ExplodedNodeSet &Dst);
 
+  /// VisitAttributedStmt - Transfer function logic for AttributedStmt
+  void VisitAttributedStmt(const AttributedStmt *A, ExplodedNode *Pred,
+                           ExplodedNodeSet &Dst);
+
   /// VisitLogicalExpr - Transfer function logic for '&&', '||'
   void VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
                         ExplodedNodeSet &Dst);
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index f678ac6f2ff36a..fab10f51cf5cfc 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -456,6 +456,36 @@ reverse_children::reverse_children(Stmt *S) {
                                 IE->getNumInits());
       return;
     }
+    case Stmt::AttributedStmtClass: {
+      AttributedStmt *attrStmt = cast<AttributedStmt>(S);
+      assert(attrStmt);
+
+      {
+        // for an attributed stmt, the "children()" returns only the NullStmt
+        // (;) but semantically the "children" are supposed to be the
+        // expressions _within_ i.e. the two square brackets i.e. [[ HERE ]]
+        // so we add the subexpressions first, _then_ add the "children"
+
+        for (const Attr *attr : attrStmt->getAttrs()) {
+
+          // i.e. one `assume()`
+          CXXAssumeAttr const *assumeAttr = llvm::dyn_cast<CXXAssumeAttr>(attr);
+          if (!assumeAttr) {
+            continue;
+          }
+          // Only handles [[ assume(<assumption>) ]] right now
+          Expr *assumption = assumeAttr->getAssumption();
+          childrenBuf.push_back(assumption);
+        }
+
+        // children() for an AttributedStmt is NullStmt(;)
+        llvm::append_range(childrenBuf, attrStmt->children());
+
+        // This needs to be done *after* childrenBuf has been populated.
+        children = childrenBuf;
+      }
+      return;
+    }
     default:
       break;
   }
@@ -2475,6 +2505,14 @@ static bool isFallthroughStatement(const AttributedStmt *A) {
   return isFallthrough;
 }
 
+static bool isCXXAssumeAttr(const AttributedStmt *A) {
+  bool hasAssumeAttr = hasSpecificAttr<CXXAssumeAttr>(A->getAttrs());
+
+  assert((!hasAssumeAttr || isa<NullStmt>(A->getSubStmt())) &&
+         "expected [[assume]] not to have children");
+  return hasAssumeAttr;
+}
+
 CFGBlock *CFGBuilder::VisitAttributedStmt(AttributedStmt *A,
                                           AddStmtChoice asc) {
   // AttributedStmts for [[likely]] can have arbitrary statements as children,
@@ -2490,6 +2528,11 @@ CFGBlock *CFGBuilder::VisitAttributedStmt(AttributedStmt *A,
     appendStmt(Block, A);
   }
 
+  if (isCXXAssumeAttr(A) && asc.alwaysAdd(*this, A)) {
+    autoCreateBlock();
+    appendStmt(Block, A);
+  }
+
   return VisitChildren(A);
 }
 
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 22eab9f66418d4..cbc83f1dbda145 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1946,7 +1946,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
     // to be explicitly evaluated.
     case Stmt::PredefinedExprClass:
     case Stmt::AddrLabelExprClass:
-    case Stmt::AttributedStmtClass:
     case Stmt::IntegerLiteralClass:
     case Stmt::FixedPointLiteralClass:
     case Stmt::CharacterLiteralClass:
@@ -1977,6 +1976,13 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
       break;
     }
 
+    case Stmt::AttributedStmtClass: {
+      Bldr.takeNodes(Pred);
+      VisitAttributedStmt(cast<AttributedStmt>(S), Pred, Dst);
+      Bldr.addNodes(Dst);
+      break;
+    }
+
     case Stmt::CXXDefaultArgExprClass:
     case Stmt::CXXDefaultInitExprClass: {
       Bldr.takeNodes(Pred);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index f7020da2e6da20..1a211d1adc44f7 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -1200,3 +1200,30 @@ void ExprEngine::VisitLambdaExpr(const LambdaExpr *LE, ExplodedNode *Pred,
   // FIXME: Move all post/pre visits to ::Visit().
   getCheckerManager().runCheckersForPostStmt(Dst, Tmp, LE, *this);
 }
+
+void ExprEngine::VisitAttributedStmt(const AttributedStmt *A,
+                                     ExplodedNode *Pred, ExplodedNodeSet &Dst) {
+
+  ExplodedNodeSet CheckerPreStmt;
+  getCheckerManager().runCheckersForPreStmt(CheckerPreStmt, Pred, A, *this);
+
+  ExplodedNodeSet EvalSet;
+  StmtNodeBuilder Bldr(CheckerPreStmt, EvalSet, *currBldrCtx);
+
+  {
+    for (const auto *attr : A->getAttrs()) {
+
+      CXXAssumeAttr const *assumeAttr = llvm::dyn_cast<CXXAssumeAttr>(attr);
+      if (!assumeAttr) {
+        continue;
+      }
+      Expr *AssumeExpr = assumeAttr->getAssumption();
+
+      for (auto *node : CheckerPreStmt) {
+        Visit(AssumeExpr, node, EvalSet);
+      }
+    }
+  }
+
+  getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, A, *this);
+}
diff --git a/clang/test/Analysis/out-of-bounds-new.cpp b/clang/test/Analysis/out-of-bounds-new.cpp
index f541bdf810d79c..4db351b10055b1 100644
--- a/clang/test/Analysis/out-of-bounds-new.cpp
+++ b/clang/test/Analysis/out-of-bounds-new.cpp
@@ -180,3 +180,19 @@ int test_reference_that_might_be_after_the_end(int idx) {
   return ref;
 }
 
+// From: https://github.com/llvm/llvm-project/issues/100762
+extern int arr[10];
+void using_builtin(int x) {
+    __builtin_assume(x > 101); // CallExpr
+    arr[x] = 404; // expected-warning{{Out of bound access to memory}}
+}
+
+void using_assume_attr(int ax) {
+    [[assume(ax > 100)]]; // NullStmt with an attribute
+    arr[ax] = 405; // expected-warning{{Out of bound access to memory}}
+}
+
+void using_many_assume_attr(int yx) {
+    [[assume(yx > 104), assume(yx > 200), assume(yx < 300)]]; // NullStmt with an attribute
+    arr[yx] = 406; // expected-warning{{Out of bound access to memory}}
+}

@steakhal
Copy link
Contributor

This looks really good. I'll come back and push some changes to your branch to make it more similar with our coding style.
And maybe adding a few more tests. I'll expect you to then have a look at the commits I push and report back if you agree with those.
Once that is done, we can probably merge this PR.

Thank you for the PR.

@llvmbot llvmbot added clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:codegen IR generation bugs: mangling, exceptions, etc. labels Nov 18, 2024
@steakhal
Copy link
Contributor

I simplified your implementation, and also identified a shortcoming of the getSpecificAttr that it didn't work with const attributes. I'll submit a fix for it separately to this PR.

The implementation looks pretty but there is a catch. And this is unfortunately a blocker issue.
Quoting https://eel.is/c++draft/dcl.attr.assume:

int divide_by_32(int x) {
  [[assume(x >= 0)]];
  return x/32;                  // The instructions produced for the division
                                // may omit handling of negative values.
}
int f(int y) {
  [[assume(++y == 43)]];        // y is not incremented
  return y;                     // statement may be replaced with return 42;
}

Because we eval the subexpressions of the assume arguments, their sideeffects sneaks in to the ExplodedGraph.
So after all, this approach might not work out that well.

We should have a look at what the codegen does with this attribute, or even with the builtin assume call - because we should do something very similar. We should gather the constraints and apply them, just like codegen does (I assume).
I think a suitable place to start reading would be CGStmt.cpp CodeGenFunction::EmitAttributedStmt().

Basically, my idea now is more like: don't eval the expressions of the assume in the CFG, but only visit the AttributedStmt in the ExprEngine. When we would reach that, "do the same as codegen to get the constraints" and apply these constraints.

Alternatively, we could take a snapshot of the Store and Environment before we would evaluate any expressions of the assume attribute and "restore" those after we finished with the AttributedStmt. If we would do this, we would be careful of sinking/"merging" all the paths we ended up creating while evaluating this Stmt. This is a lot more complicated, so I'd definitely try the previous approach before even considering this.

@vinay-deshmukh
Copy link
Contributor Author

We should have a look at what the codegen does with this attribute, or even with the builtin assume call - because we should do something very similar. We should gather the constraints and apply them, just like codegen does (I assume).
I think a suitable place to start reading would be CGStmt.cpp CodeGenFunction::EmitAttributedStmt().
Basically, my idea now is more like: don't eval the expressions of the assume in the CFG, but only visit the AttributedStmt in the ExprEngine. When we would reach that, "do the same as codegen to get the constraints" and apply these constraints.

CodeGen seems to be doing a NOOP operation when encountering an attribute with side-effects in void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) {. This can be mirrored within this PR by "ignore"-ing/(not adding those expressions as children) the assumption attributes (in CFG.cpp) that have side effects.

I've checked the debug.ViewCFG output and it looks like this is similar to what __builtin_assume does if it's assumptions encounter expressions with side-effects.

Furthermore, it appears to me that clang specifically NEVER evaluates assumptions that can have side-effects (See section at the end that compares GCC/clang behavior). We know it doesn't for codegen as per the above function, and given the DiagnosticSemaKind.td's warn_assume_side_effects occurrence unconditionally, it would appear they aren't evaluated at all. (compliant with the standard).

Once the other comments regarding for vs if is answered, I can raise a cleaned up PR with the necessary changes, that way it can be one commit.

Comparison of GCC vs clang for compiler for pre-C++23 ASSUME macro and `[[assume()]]`

Noting the current "real" behavior of clang and gcc NOT considering static analysis/checkers:
https://godbolt.org/z/nM6PccseK

This godbolt link shows the output of with the following scenarios, where the assumption argument is an expression with side-effects (++y == 43):

  1. with the compiler builtin-assume equivalent (as per each compiler) as:
// From: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1774r8.pdf
#if defined(__clang__)
#define ASSUME(expr) __builtin_assume(expr)
#elif defined(__GNUC__) && !defined(__ICC)
#define ASSUME(expr) if (expr) {} else { __builtin_unreachable(); }
#endif

a. U.B. (as per standard) i.e. f(20) takes y != 42

  • Clang: returns 20, (DOES NOT EVALUATE the assumption as it has side-effects) (via DiagnosticsSemaKinds.td)
If the condition is violated during execution, the behavior is undefined. The argument itself is never evaluated, so any side effects of the expression will be discarded.

from
https://clang.llvm.org/docs/LanguageExtensions.html#builtin-assume

Note: int f(int)'s assembly output contains 20, as clang didn't evaluate ++y

  • GCC: returns 139, terminates with SIGSEGV

Note: int f(int)'s assembly output contains 43 since GCC evaluates ++y

If control flow reaches the point of the __builtin_unreachable, the program is undefined.

from
https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-_005f_005fbuiltin_005funreachable

b. Defined Behavior i.e. f() takes 42 as input

  • Clang: returns 42, asm output has 42, since clagn does NOT evaluate ++y
  • GCC: returns 43, asm output has 43, since GCC evaluates ++y
  1. with [[assume]] (by setting the preprocessor directive CXX23_ASSUME at the start of the code)

a. U.B. (as per standard) i.e. f(20) takes y != 42
U.B. so no behavior is guaranteed anyway.

  • Clang: f()'s ASM is reading from the parameter, main() returns 20
  • GCC: f() 's ASM has 42, but main() returns 20

b. Defined Behavior i.e. f() takes 42 as input

Clang: f()'s ASM is reading from the parameter, main() returns 42
GCC: f()'s ASM has 42, main() returns 42

@steakhal
Copy link
Contributor

I wanted to come back with another example:

int ternary_in_assume(int a, int b) {
  [[assume(a > 10 ? b == 4 : b == 10)]];
  if (a > 20)
    return b + 100; // expecting 104
  if (a > 10)
    return b + 200; // expecting 204
  return b + 300; // expecting 310
}

Actually, neither gcc, clang, msvc, or icc optimizes the return paths to constants - even though I think they would be allowed to. https://compiler-explorer.com/z/1ajvcvG9h

I'd need to think about of the implications for us though. I think it should be safe to eval these subexpressions and do state splits if and only if none of those expressions have sideeffects. In that case, they wouldn't be emitted into the CFG, so they shouldn't be a problem.

@steakhal steakhal removed clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:codegen IR generation bugs: mangling, exceptions, etc. clang:analysis labels Dec 18, 2024
@steakhal steakhal self-requested a review December 18, 2024 16:04
Copy link
Contributor

@steakhal steakhal left a comment

Choose a reason for hiding this comment

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

As far as I know, to eliminate the warning emitted corresponding to the FIXME comment, we need to implement a new Checker for attributes; we can do this in a second PR to avoid scope creep for this issue/PR.

Agreed. I had a look at the exploded graph and look correct to me.

I think I'll come back to this PR, apply some really minor recommendations and I think we can land it.
Thank you so much for pushing for this so hard. I really appreciate it.

Expect me back on this in a couple of days.

@steakhal
Copy link
Contributor

@vinay-deshmukh WDYT of the current shape? Can we merge it?

Copy link
Contributor

@steakhal steakhal left a comment

Choose a reason for hiding this comment

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

For me it looks good.

@vinay-deshmukh
Copy link
Contributor Author

Looks good to me @steakhal ! Thanks for the review!

@steakhal steakhal merged commit 89da344 into llvm:main Dec 19, 2024
5 of 7 checks passed
Copy link

@vinay-deshmukh Congratulations on having your first Pull Request (PR) merged into the LLVM Project!

Your changes will be combined with recent changes from other authors, then tested by our build bots. If there is a problem with a build, you may receive a report in an email or a comment on this PR.

Please check whether problems have been caused by your change specifically, as the builds can include changes from many authors. It is not uncommon for your change to be included in a build that fails due to someone else's changes, or infrastructure issues.

How to do this, and the rest of the post-merge process, is covered in detail here.

If your change does cause a problem, it may be reverted, or you can revert it yourself. This is a normal part of LLVM development. You can fix your changes and open a new PR to merge them again.

If you don't get any reports, no action is required from you. Your changes are working as expected, well done!

@steakhal
Copy link
Contributor

I made the followup for this one in #120572

@llvm-ci
Copy link
Collaborator

llvm-ci commented Dec 19, 2024

LLVM Buildbot has detected a new failure on builder sanitizer-aarch64-linux-bootstrap-hwasan running on sanitizer-buildbot12 while building clang at step 2 "annotate".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/55/builds/4556

Here is the relevant piece of the build log for the reference
Step 2 (annotate) failure: 'python ../sanitizer_buildbot/sanitizers/zorg/buildbot/builders/sanitizers/buildbot_selector.py' (failure)
...
llvm-lit: /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/utils/libcxx/test/config.py:24: note: (llvm-libc++-shared.cfg.in) Using %{cxx} substitution: '/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang++'
llvm-lit: /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/utils/libcxx/test/config.py:24: note: (llvm-libc++-shared.cfg.in) Using %{flags} substitution: '-pthread --target=aarch64-unknown-linux-gnu -g -fno-omit-frame-pointer -fsanitize=hwaddress'
llvm-lit: /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/utils/libcxx/test/config.py:24: note: (llvm-libc++-shared.cfg.in) Using %{compile_flags} substitution: '-nostdinc++ -I %{target-include-dir} -I %{include-dir} -I %{libcxx-dir}/test/support -std=c++26 -Werror -Wall -Wctad-maybe-unsupported -Wextra -Wshadow -Wundef -Wunused-template -Wno-unused-command-line-argument -Wno-attributes -Wno-pessimizing-move -Wno-noexcept-type -Wno-atomic-alignment -Wno-reserved-module-identifier -Wdeprecated-copy -Wdeprecated-copy-dtor -Wno-user-defined-literals -Wno-tautological-compare -Wsign-compare -Wunused-variable -Wunused-parameter -Wunreachable-code -Wno-unused-local-typedef -Wno-local-type-template-args -Wno-c++11-extensions -Wno-unknown-pragmas -Wno-pass-failed -Wno-mismatched-new-delete -Wno-redundant-move -Wno-self-move -D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -D_LIBCPP_ENABLE_EXPERIMENTAL -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE -Werror=thread-safety -Wuser-defined-warnings'
llvm-lit: /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/utils/libcxx/test/config.py:24: note: (llvm-libc++-shared.cfg.in) Using %{link_flags} substitution: '-lc++experimental -nostdlib++ -L %{lib-dir} -Wl,-rpath,%{lib-dir} -lc++ -latomic'
llvm-lit: /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/utils/libcxx/test/config.py:24: note: (llvm-libc++-shared.cfg.in) Using %{benchmark_flags} substitution: '-I /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test/benchmarks/google-benchmark/include -L /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test/benchmarks/google-benchmark/lib -L /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test/benchmarks/google-benchmark/lib64 -l benchmark'
llvm-lit: /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/utils/libcxx/test/config.py:24: note: (llvm-libc++-shared.cfg.in) Using %{exec} substitution: '%{executor} --execdir %T -- '
llvm-lit: /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/utils/libcxx/test/config.py:24: note: (llvm-libc++-shared.cfg.in) All available features: add-latomic-workaround, buildhost=linux, c++26, c++experimental, can-create-symlinks, clang, clang-20, clang-20.0, clang-20.0.0, diagnose-if-support, enable-benchmarks=no, gcc-style-warnings, glibc-old-ru_RU-decimal-point, has-1024-bit-atomics, has-64-bit-atomics, has-fblocks, has-fconstexpr-steps, has-unix-headers, hwasan, large_tests, libcpp-abi-version=1, libcpp-hardening-mode=none, libcpp-has-no-availability-markup, libcpp-has-thread-api-pthread, linux, lsan, objective-c++, optimization=none, sanitizer-new-delete, stdlib=libc++, stdlib=llvm-libc++, target=aarch64-unknown-linux-gnu, thread-safety, verify-support
llvm-lit: /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/llvm/utils/lit/lit/main.py:72: note: The test suite configuration requested an individual test timeout of 0 seconds but a timeout of 1500 seconds was requested on the command line. Forcing timeout to be 1500 seconds.
-- Testing: 9977 of 9996 tests, 72 workers --
Testing:  0.. 10..
FAIL: llvm-libc++-shared.cfg.in :: std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp (1904 of 9977)
******************** TEST 'llvm-libc++-shared.cfg.in :: std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp' FAILED ********************
Exit Code: 1

Command Output (stdout):
--
# COMPILED WITH
/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang++ /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp -pthread --target=aarch64-unknown-linux-gnu -g -fno-omit-frame-pointer -fsanitize=hwaddress -nostdinc++ -I /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/include/c++/v1 -I /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/include/c++/v1 -I /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/test/support -std=c++26 -Werror -Wall -Wctad-maybe-unsupported -Wextra -Wshadow -Wundef -Wunused-template -Wno-unused-command-line-argument -Wno-attributes -Wno-pessimizing-move -Wno-noexcept-type -Wno-atomic-alignment -Wno-reserved-module-identifier -Wdeprecated-copy -Wdeprecated-copy-dtor -Wno-user-defined-literals -Wno-tautological-compare -Wsign-compare -Wunused-variable -Wunused-parameter -Wunreachable-code -Wno-unused-local-typedef -Wno-local-type-template-args -Wno-c++11-extensions -Wno-unknown-pragmas -Wno-pass-failed -Wno-mismatched-new-delete -Wno-redundant-move -Wno-self-move -D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -D_LIBCPP_ENABLE_EXPERIMENTAL -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE -Werror=thread-safety -Wuser-defined-warnings  -lc++experimental -nostdlib++ -L /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/lib -Wl,-rpath,/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/lib -lc++ -latomic -o /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/Output/pstl.fill_n.pass.cpp.dir/t.tmp.exe
# executed command: /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang++ /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp -pthread --target=aarch64-unknown-linux-gnu -g -fno-omit-frame-pointer -fsanitize=hwaddress -nostdinc++ -I /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/include/c++/v1 -I /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/include/c++/v1 -I /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/test/support -std=c++26 -Werror -Wall -Wctad-maybe-unsupported -Wextra -Wshadow -Wundef -Wunused-template -Wno-unused-command-line-argument -Wno-attributes -Wno-pessimizing-move -Wno-noexcept-type -Wno-atomic-alignment -Wno-reserved-module-identifier -Wdeprecated-copy -Wdeprecated-copy-dtor -Wno-user-defined-literals -Wno-tautological-compare -Wsign-compare -Wunused-variable -Wunused-parameter -Wunreachable-code -Wno-unused-local-typedef -Wno-local-type-template-args -Wno-c++11-extensions -Wno-unknown-pragmas -Wno-pass-failed -Wno-mismatched-new-delete -Wno-redundant-move -Wno-self-move -D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -D_LIBCPP_ENABLE_EXPERIMENTAL -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE -Werror=thread-safety -Wuser-defined-warnings -lc++experimental -nostdlib++ -L /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/lib -Wl,-rpath,/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/lib -lc++ -latomic -o /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/Output/pstl.fill_n.pass.cpp.dir/t.tmp.exe
# .---command stderr------------
# | clang-20: /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/lib/Analysis/ThreadSafety.cpp:529: Context (anonymous namespace)::LocalVariableMap::addDefinition(const NamedDecl *, const Expr *, Context): Assertion `!Ctx.contains(D)' failed.
# | PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
# | Stack dump:
# | 0.	Program arguments: /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang-20 -cc1 -triple aarch64-unknown-linux-gnu -emit-obj -dumpdir /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/Output/pstl.fill_n.pass.cpp.dir/t.tmp.exe- -disable-free -clear-ast-before-backend -main-file-name pstl.fill_n.pass.cpp -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=non-leaf -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu generic -target-feature +v8a -target-feature +fp-armv8 -target-feature +neon -target-abi aapcs -debug-info-kind=constructor -dwarf-version=5 -debugger-tuning=gdb -fdebug-compilation-dir=/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill -fcoverage-compilation-dir=/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill -nostdinc++ -resource-dir /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/lib/clang/20 -I /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/include/c++/v1 -I /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/include/c++/v1 -I /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/test/support -D _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -D _LIBCPP_ENABLE_EXPERIMENTAL -D _LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE -internal-isystem /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/lib/clang/20/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/include -internal-externc-isystem /usr/include/aarch64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Werror -Wall -Wctad-maybe-unsupported -Wextra -Wshadow -Wundef -Wunused-template -Wno-unused-command-line-argument -Wno-attributes -Wno-pessimizing-move -Wno-noexcept-type -Wno-atomic-alignment -Wno-reserved-module-identifier -Wdeprecated-copy -Wdeprecated-copy-dtor -Wno-user-defined-literals -Wno-tautological-compare -Wsign-compare -Wunused-variable -Wunused-parameter -Wunreachable-code -Wno-unused-local-typedef -Wno-local-type-template-args -Wno-c++11-extensions -Wno-unknown-pragmas -Wno-pass-failed -Wno-mismatched-new-delete -Wno-redundant-move -Wno-self-move -Werror=thread-safety -Wuser-defined-warnings -std=c++26 -fdeprecated-macro -ferror-limit 19 -pthread -fno-signed-char -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -fsanitize=hwaddress -fsanitize-system-ignorelist=/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/lib/clang/20/share/hwasan_ignorelist.txt -fno-sanitize-memory-param-retval -fno-sanitize-address-use-odr-indicator -default-function-attr hwasan-abi=interceptor -target-feature +tagged-globals -target-feature +outline-atomics -target-feature -fmv -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/lit-tmp-hracwbro/pstl-891ea7.o -x c++ /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp
# | 1.	<eof> parser at end of file
# | 2.	/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/test/support/test_execution_policies.h:46:8: instantiating function definition 'TestIteratorWithPolicies<Test>::operator()<int *>'
# | 3.	/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/test/support/test_execution_policies.h:32:6: instantiating function definition 'test_execution_policies<Test<int *>>'
# | 4.	/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp:35:8: instantiating function definition 'Test<int *>::operator()<const std::execution::unsequenced_policy &>'
# | 5.	/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/include/c++/v1/__algorithm/pstl.h:250:1: instantiating function definition 'std::fill_n<const std::execution::unsequenced_policy &, int *, unsigned long, int, std::execution::unsequenced_policy, 0>'
# | 6.	/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/include/c++/v1/__pstl/backends/default.h:216:3: instantiating function definition 'std::__pstl::__fill_n<std::__pstl::__default_backend_tag, std::execution::unsequenced_policy>::operator()<const std::execution::unsequenced_policy &, int *, unsigned long, int>'
# | 7.	/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/include/c++/v1/__pstl/cpu_algos/fill.h:44:3: instantiating function definition 'std::__pstl::__cpu_parallel_fill<std::__pstl::__std_thread_backend_tag, std::execution::unsequenced_policy>::operator()<const std::execution::unsequenced_policy &, int *, int>'
# | 8.	/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/include/c++/v1/__pstl/cpu_algos/fill.h:32:30: instantiating function definition 'std::__pstl::__simd_fill_n<int *, long, int>'
# |  #0 0x0000b660378dad88 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang-20+0x810ad88)
# |  #1 0x0000b660378d8c30 llvm::sys::RunSignalHandlers() (/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang-20+0x8108c30)
# |  #2 0x0000b660378db498 SignalHandler(int) Signals.cpp:0:0
# |  #3 0x0000f5b72dd4a8f8 (linux-vdso.so.1+0x8f8)
# |  #4 0x0000f5b72d6c7628 (/lib/aarch64-linux-gnu/libc.so.6+0x87628)
# |  #5 0x0000f5b72d67cb3c raise (/lib/aarch64-linux-gnu/libc.so.6+0x3cb3c)
# |  #6 0x0000f5b72d667e00 abort (/lib/aarch64-linux-gnu/libc.so.6+0x27e00)
# |  #7 0x0000f5b72d675cbc (/lib/aarch64-linux-gnu/libc.so.6+0x35cbc)
# |  #8 0x0000f5b72d675d2c (/lib/aarch64-linux-gnu/libc.so.6+0x35d2c)
# |  #9 0x0000b6603a66731c (anonymous namespace)::ThreadSafetyAnalyzer::runAnalysis(clang::AnalysisDeclContext&) ThreadSafety.cpp:0:0
# | #10 0x0000b6603a663844 clang::threadSafety::runThreadSafetyAnalysis(clang::AnalysisDeclContext&, clang::threadSafety::ThreadSafetyHandler&, clang::threadSafety::BeforeSet**) (/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang-20+0xae93844)
# | #11 0x0000b66039d6e518 clang::sema::AnalysisBasedWarnings::IssueWarnings(clang::sema::AnalysisBasedWarnings::Policy, clang::sema::FunctionScopeInfo*, clang::Decl const*, clang::QualType) (/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang-20+0xa59e518)
# | #12 0x0000b66039d62904 clang::Sema::PopFunctionScopeInfo(clang::sema::AnalysisBasedWarnings::Policy const*, clang::Decl const*, clang::QualType) (/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang-20+0xa592904)
# | #13 0x0000b66039edd4ec clang::Sema::ActOnFinishFunctionBody(clang::Decl*, clang::Stmt*, bool) (/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang-20+0xa70d4ec)
# | #14 0x0000b6603a585278 clang::Sema::InstantiateFunctionDefinition(clang::SourceLocation, clang::FunctionDecl*, bool, bool, bool) (/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang-20+0xadb5278)
# | #15 0x0000b6603a587ea4 clang::Sema::PerformPendingInstantiations(bool) (/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang-20+0xadb7ea4)
# | #16 0x0000b6603a585310 clang::Sema::InstantiateFunctionDefinition(clang::SourceLocation, clang::FunctionDecl*, bool, bool, bool) (/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang-20+0xadb5310)
Step 10 (stage2/hwasan check-cxx) failure: stage2/hwasan check-cxx (failure)
...
llvm-lit: /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/utils/libcxx/test/config.py:24: note: (llvm-libc++-shared.cfg.in) Using %{cxx} substitution: '/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang++'
llvm-lit: /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/utils/libcxx/test/config.py:24: note: (llvm-libc++-shared.cfg.in) Using %{flags} substitution: '-pthread --target=aarch64-unknown-linux-gnu -g -fno-omit-frame-pointer -fsanitize=hwaddress'
llvm-lit: /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/utils/libcxx/test/config.py:24: note: (llvm-libc++-shared.cfg.in) Using %{compile_flags} substitution: '-nostdinc++ -I %{target-include-dir} -I %{include-dir} -I %{libcxx-dir}/test/support -std=c++26 -Werror -Wall -Wctad-maybe-unsupported -Wextra -Wshadow -Wundef -Wunused-template -Wno-unused-command-line-argument -Wno-attributes -Wno-pessimizing-move -Wno-noexcept-type -Wno-atomic-alignment -Wno-reserved-module-identifier -Wdeprecated-copy -Wdeprecated-copy-dtor -Wno-user-defined-literals -Wno-tautological-compare -Wsign-compare -Wunused-variable -Wunused-parameter -Wunreachable-code -Wno-unused-local-typedef -Wno-local-type-template-args -Wno-c++11-extensions -Wno-unknown-pragmas -Wno-pass-failed -Wno-mismatched-new-delete -Wno-redundant-move -Wno-self-move -D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -D_LIBCPP_ENABLE_EXPERIMENTAL -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE -Werror=thread-safety -Wuser-defined-warnings'
llvm-lit: /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/utils/libcxx/test/config.py:24: note: (llvm-libc++-shared.cfg.in) Using %{link_flags} substitution: '-lc++experimental -nostdlib++ -L %{lib-dir} -Wl,-rpath,%{lib-dir} -lc++ -latomic'
llvm-lit: /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/utils/libcxx/test/config.py:24: note: (llvm-libc++-shared.cfg.in) Using %{benchmark_flags} substitution: '-I /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test/benchmarks/google-benchmark/include -L /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test/benchmarks/google-benchmark/lib -L /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test/benchmarks/google-benchmark/lib64 -l benchmark'
llvm-lit: /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/utils/libcxx/test/config.py:24: note: (llvm-libc++-shared.cfg.in) Using %{exec} substitution: '%{executor} --execdir %T -- '
llvm-lit: /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/utils/libcxx/test/config.py:24: note: (llvm-libc++-shared.cfg.in) All available features: add-latomic-workaround, buildhost=linux, c++26, c++experimental, can-create-symlinks, clang, clang-20, clang-20.0, clang-20.0.0, diagnose-if-support, enable-benchmarks=no, gcc-style-warnings, glibc-old-ru_RU-decimal-point, has-1024-bit-atomics, has-64-bit-atomics, has-fblocks, has-fconstexpr-steps, has-unix-headers, hwasan, large_tests, libcpp-abi-version=1, libcpp-hardening-mode=none, libcpp-has-no-availability-markup, libcpp-has-thread-api-pthread, linux, lsan, objective-c++, optimization=none, sanitizer-new-delete, stdlib=libc++, stdlib=llvm-libc++, target=aarch64-unknown-linux-gnu, thread-safety, verify-support
llvm-lit: /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/llvm/utils/lit/lit/main.py:72: note: The test suite configuration requested an individual test timeout of 0 seconds but a timeout of 1500 seconds was requested on the command line. Forcing timeout to be 1500 seconds.
-- Testing: 9977 of 9996 tests, 72 workers --
Testing:  0.. 10..
FAIL: llvm-libc++-shared.cfg.in :: std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp (1904 of 9977)
******************** TEST 'llvm-libc++-shared.cfg.in :: std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp' FAILED ********************
Exit Code: 1

Command Output (stdout):
--
# COMPILED WITH
/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang++ /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp -pthread --target=aarch64-unknown-linux-gnu -g -fno-omit-frame-pointer -fsanitize=hwaddress -nostdinc++ -I /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/include/c++/v1 -I /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/include/c++/v1 -I /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/test/support -std=c++26 -Werror -Wall -Wctad-maybe-unsupported -Wextra -Wshadow -Wundef -Wunused-template -Wno-unused-command-line-argument -Wno-attributes -Wno-pessimizing-move -Wno-noexcept-type -Wno-atomic-alignment -Wno-reserved-module-identifier -Wdeprecated-copy -Wdeprecated-copy-dtor -Wno-user-defined-literals -Wno-tautological-compare -Wsign-compare -Wunused-variable -Wunused-parameter -Wunreachable-code -Wno-unused-local-typedef -Wno-local-type-template-args -Wno-c++11-extensions -Wno-unknown-pragmas -Wno-pass-failed -Wno-mismatched-new-delete -Wno-redundant-move -Wno-self-move -D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -D_LIBCPP_ENABLE_EXPERIMENTAL -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE -Werror=thread-safety -Wuser-defined-warnings  -lc++experimental -nostdlib++ -L /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/lib -Wl,-rpath,/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/lib -lc++ -latomic -o /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/Output/pstl.fill_n.pass.cpp.dir/t.tmp.exe
# executed command: /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang++ /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp -pthread --target=aarch64-unknown-linux-gnu -g -fno-omit-frame-pointer -fsanitize=hwaddress -nostdinc++ -I /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/include/c++/v1 -I /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/include/c++/v1 -I /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/test/support -std=c++26 -Werror -Wall -Wctad-maybe-unsupported -Wextra -Wshadow -Wundef -Wunused-template -Wno-unused-command-line-argument -Wno-attributes -Wno-pessimizing-move -Wno-noexcept-type -Wno-atomic-alignment -Wno-reserved-module-identifier -Wdeprecated-copy -Wdeprecated-copy-dtor -Wno-user-defined-literals -Wno-tautological-compare -Wsign-compare -Wunused-variable -Wunused-parameter -Wunreachable-code -Wno-unused-local-typedef -Wno-local-type-template-args -Wno-c++11-extensions -Wno-unknown-pragmas -Wno-pass-failed -Wno-mismatched-new-delete -Wno-redundant-move -Wno-self-move -D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -D_LIBCPP_ENABLE_EXPERIMENTAL -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE -Werror=thread-safety -Wuser-defined-warnings -lc++experimental -nostdlib++ -L /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/lib -Wl,-rpath,/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/lib -lc++ -latomic -o /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/Output/pstl.fill_n.pass.cpp.dir/t.tmp.exe
# .---command stderr------------
# | clang-20: /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/clang/lib/Analysis/ThreadSafety.cpp:529: Context (anonymous namespace)::LocalVariableMap::addDefinition(const NamedDecl *, const Expr *, Context): Assertion `!Ctx.contains(D)' failed.
# | PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
# | Stack dump:
# | 0.	Program arguments: /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang-20 -cc1 -triple aarch64-unknown-linux-gnu -emit-obj -dumpdir /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/Output/pstl.fill_n.pass.cpp.dir/t.tmp.exe- -disable-free -clear-ast-before-backend -main-file-name pstl.fill_n.pass.cpp -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=non-leaf -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu generic -target-feature +v8a -target-feature +fp-armv8 -target-feature +neon -target-abi aapcs -debug-info-kind=constructor -dwarf-version=5 -debugger-tuning=gdb -fdebug-compilation-dir=/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill -fcoverage-compilation-dir=/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill -nostdinc++ -resource-dir /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/lib/clang/20 -I /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/include/c++/v1 -I /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/include/c++/v1 -I /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/test/support -D _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -D _LIBCPP_ENABLE_EXPERIMENTAL -D _LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE -internal-isystem /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/lib/clang/20/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/include -internal-externc-isystem /usr/include/aarch64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Werror -Wall -Wctad-maybe-unsupported -Wextra -Wshadow -Wundef -Wunused-template -Wno-unused-command-line-argument -Wno-attributes -Wno-pessimizing-move -Wno-noexcept-type -Wno-atomic-alignment -Wno-reserved-module-identifier -Wdeprecated-copy -Wdeprecated-copy-dtor -Wno-user-defined-literals -Wno-tautological-compare -Wsign-compare -Wunused-variable -Wunused-parameter -Wunreachable-code -Wno-unused-local-typedef -Wno-local-type-template-args -Wno-c++11-extensions -Wno-unknown-pragmas -Wno-pass-failed -Wno-mismatched-new-delete -Wno-redundant-move -Wno-self-move -Werror=thread-safety -Wuser-defined-warnings -std=c++26 -fdeprecated-macro -ferror-limit 19 -pthread -fno-signed-char -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -fsanitize=hwaddress -fsanitize-system-ignorelist=/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/lib/clang/20/share/hwasan_ignorelist.txt -fno-sanitize-memory-param-retval -fno-sanitize-address-use-odr-indicator -default-function-attr hwasan-abi=interceptor -target-feature +tagged-globals -target-feature +outline-atomics -target-feature -fmv -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/lit-tmp-hracwbro/pstl-891ea7.o -x c++ /home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp
# | 1.	<eof> parser at end of file
# | 2.	/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/test/support/test_execution_policies.h:46:8: instantiating function definition 'TestIteratorWithPolicies<Test>::operator()<int *>'
# | 3.	/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/test/support/test_execution_policies.h:32:6: instantiating function definition 'test_execution_policies<Test<int *>>'
# | 4.	/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm-project/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp:35:8: instantiating function definition 'Test<int *>::operator()<const std::execution::unsequenced_policy &>'
# | 5.	/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/include/c++/v1/__algorithm/pstl.h:250:1: instantiating function definition 'std::fill_n<const std::execution::unsequenced_policy &, int *, unsigned long, int, std::execution::unsequenced_policy, 0>'
# | 6.	/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/include/c++/v1/__pstl/backends/default.h:216:3: instantiating function definition 'std::__pstl::__fill_n<std::__pstl::__default_backend_tag, std::execution::unsequenced_policy>::operator()<const std::execution::unsequenced_policy &, int *, unsigned long, int>'
# | 7.	/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/include/c++/v1/__pstl/cpu_algos/fill.h:44:3: instantiating function definition 'std::__pstl::__cpu_parallel_fill<std::__pstl::__std_thread_backend_tag, std::execution::unsequenced_policy>::operator()<const std::execution::unsequenced_policy &, int *, int>'
# | 8.	/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/libcxx_build_hwasan/libcxx/test-suite-install/include/c++/v1/__pstl/cpu_algos/fill.h:32:30: instantiating function definition 'std::__pstl::__simd_fill_n<int *, long, int>'
# |  #0 0x0000b660378dad88 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang-20+0x810ad88)
# |  #1 0x0000b660378d8c30 llvm::sys::RunSignalHandlers() (/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang-20+0x8108c30)
# |  #2 0x0000b660378db498 SignalHandler(int) Signals.cpp:0:0
# |  #3 0x0000f5b72dd4a8f8 (linux-vdso.so.1+0x8f8)
# |  #4 0x0000f5b72d6c7628 (/lib/aarch64-linux-gnu/libc.so.6+0x87628)
# |  #5 0x0000f5b72d67cb3c raise (/lib/aarch64-linux-gnu/libc.so.6+0x3cb3c)
# |  #6 0x0000f5b72d667e00 abort (/lib/aarch64-linux-gnu/libc.so.6+0x27e00)
# |  #7 0x0000f5b72d675cbc (/lib/aarch64-linux-gnu/libc.so.6+0x35cbc)
# |  #8 0x0000f5b72d675d2c (/lib/aarch64-linux-gnu/libc.so.6+0x35d2c)
# |  #9 0x0000b6603a66731c (anonymous namespace)::ThreadSafetyAnalyzer::runAnalysis(clang::AnalysisDeclContext&) ThreadSafety.cpp:0:0
# | #10 0x0000b6603a663844 clang::threadSafety::runThreadSafetyAnalysis(clang::AnalysisDeclContext&, clang::threadSafety::ThreadSafetyHandler&, clang::threadSafety::BeforeSet**) (/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang-20+0xae93844)
# | #11 0x0000b66039d6e518 clang::sema::AnalysisBasedWarnings::IssueWarnings(clang::sema::AnalysisBasedWarnings::Policy, clang::sema::FunctionScopeInfo*, clang::Decl const*, clang::QualType) (/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang-20+0xa59e518)
# | #12 0x0000b66039d62904 clang::Sema::PopFunctionScopeInfo(clang::sema::AnalysisBasedWarnings::Policy const*, clang::Decl const*, clang::QualType) (/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang-20+0xa592904)
# | #13 0x0000b66039edd4ec clang::Sema::ActOnFinishFunctionBody(clang::Decl*, clang::Stmt*, bool) (/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang-20+0xa70d4ec)
# | #14 0x0000b6603a585278 clang::Sema::InstantiateFunctionDefinition(clang::SourceLocation, clang::FunctionDecl*, bool, bool, bool) (/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang-20+0xadb5278)
# | #15 0x0000b6603a587ea4 clang::Sema::PerformPendingInstantiations(bool) (/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang-20+0xadb7ea4)
# | #16 0x0000b6603a585310 clang::Sema::InstantiateFunctionDefinition(clang::SourceLocation, clang::FunctionDecl*, bool, bool, bool) (/home/b/sanitizer-aarch64-linux-bootstrap-hwasan/build/llvm_build0/bin/clang-20+0xadb5310)

@vitalybuka
Copy link
Collaborator

vitalybuka commented Dec 19, 2024

I made the followup for this one in #120572

Please revert and reland with followup. Followup is good way to go for trivial cases which can be landed with quick or no review

thurstond added a commit that referenced this pull request Dec 19, 2024
…116462)"

This reverts commit 89da344.

Reason: buildbot breakages e.g., https://lab.llvm.org/buildbot/#/builders/55/builds/4556 (for which the reverted patch is the only code change)
@thurstond
Copy link
Contributor

I've reverted it in 2b9abf0 to clear up some buildbots

@steakhal
Copy link
Contributor

I've reverted it in 2b9abf0 to clear up some buildbots

Thanks! Ill have a look later.

@vinay-deshmukh
Copy link
Contributor Author

Thanks @thurstond for the revert! Let me know if there's anything I can do here to help fix the issue!

@steakhal
Copy link
Contributor

So we had the following assertion failure:

clang/lib/Analysis/ThreadSafety.cpp:529: LocalVariableMap::addDefinition: Assertion `!Ctx.contains(D)' failed.

On libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp.

I wish I could come back to this to see why that assert fails. I don't have the bandwidth. Maybe at some point in January.

steakhal added a commit to steakhal/llvm-project that referenced this pull request Feb 28, 2025
steakhal added a commit that referenced this pull request Mar 6, 2025
#129234)

This is the second attempt to bring initial support for [[assume()]] in
the Clang Static Analyzer.
The first attempt (#116462) was reverted in
2b9abf0 due to some weird failure in a
libcxx test involving `#pragma clang loop vectorize(enable)
interleave(enable)`.

The failure could be reduced into:
```c++
template <class ExecutionPolicy>
void transform(ExecutionPolicy) {
  #pragma clang loop vectorize(enable) interleave(enable)
  for (int i = 0; 0;) { // The DeclStmt of "i" would be added twice in the ThreadSafety analysis.
    // empty
  }
}
void entrypoint() {
  transform(1);
}
```

As it turns out, the problem with the initial patch was this:
```c++
for (const auto *Attr : AS->getAttrs()) {
  if (const auto *AssumeAttr = dyn_cast<CXXAssumeAttr>(Attr)) {
    Expr *AssumeExpr = AssumeAttr->getAssumption();
    if (!AssumeExpr->HasSideEffects(Ctx)) {
      childrenBuf.push_back(AssumeExpr);
    }
  }
  // Visit the actual children AST nodes.
  // For CXXAssumeAttrs, this is always a NullStmt.
  llvm::append_range(childrenBuf, AS->children()); // <--- This was not meant to be part of the "for" loop.
  children = childrenBuf;
}
return;
 ```

The solution was simple. Just hoist it from the loop.

I also had a closer look at `CFGBuilder::VisitAttributedStmt`, where I also spotted another bug.
We would have added the CFG blocks twice if the AttributedStmt would have both the `[[fallthrough]]` and the `[[assume()]]` attributes. With my fix, it will only once add the blocks. Added a regression test for this.

Co-authored-by: Vinay Deshmukh <vinay_deshmukh AT outlook DOT com>
jph-13 pushed a commit to jph-13/llvm-project that referenced this pull request Mar 21, 2025
llvm#129234)

This is the second attempt to bring initial support for [[assume()]] in
the Clang Static Analyzer.
The first attempt (llvm#116462) was reverted in
2b9abf0 due to some weird failure in a
libcxx test involving `#pragma clang loop vectorize(enable)
interleave(enable)`.

The failure could be reduced into:
```c++
template <class ExecutionPolicy>
void transform(ExecutionPolicy) {
  #pragma clang loop vectorize(enable) interleave(enable)
  for (int i = 0; 0;) { // The DeclStmt of "i" would be added twice in the ThreadSafety analysis.
    // empty
  }
}
void entrypoint() {
  transform(1);
}
```

As it turns out, the problem with the initial patch was this:
```c++
for (const auto *Attr : AS->getAttrs()) {
  if (const auto *AssumeAttr = dyn_cast<CXXAssumeAttr>(Attr)) {
    Expr *AssumeExpr = AssumeAttr->getAssumption();
    if (!AssumeExpr->HasSideEffects(Ctx)) {
      childrenBuf.push_back(AssumeExpr);
    }
  }
  // Visit the actual children AST nodes.
  // For CXXAssumeAttrs, this is always a NullStmt.
  llvm::append_range(childrenBuf, AS->children()); // <--- This was not meant to be part of the "for" loop.
  children = childrenBuf;
}
return;
 ```

The solution was simple. Just hoist it from the loop.

I also had a closer look at `CFGBuilder::VisitAttributedStmt`, where I also spotted another bug.
We would have added the CFG blocks twice if the AttributedStmt would have both the `[[fallthrough]]` and the `[[assume()]]` attributes. With my fix, it will only once add the blocks. Added a regression test for this.

Co-authored-by: Vinay Deshmukh <vinay_deshmukh AT outlook DOT com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[analyzer] Handle [[assume(cond)]] as __builtin_assume(cond)
6 participants