llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Ryosuke Niwa (rniwa)

<details>
<summary>Changes</summary>

TrivialFunctionAnalysisVisitor had no handler for CXXStdInitializerListExpr, so 
a braced list bound to a std::initializer_list fell through to VisitStmt and 
was conservatively treated as non-trivial. This made any nodelete function 
containing e.g. std::min({a, b, c}) report that it "contains code that could 
destruct an object".

The backing array of a std::initializer_list is a temporary whose lifetime ends 
in the enclosing function, so its elements really are destructed there. Accept 
the node when the array's element type is trivially destructible and recurse 
into the initializers, and keep rejecting it otherwise.

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


2 Files Affected:

- (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp 
(+11) 
- (modified) clang/test/Analysis/Checkers/WebKit/nodelete-annotation.cpp (+52) 


``````````diff
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index d8a62db4daee1..196ee4cf99d08 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -1095,6 +1095,17 @@ class TrivialFunctionAnalysisVisitor
     return true;
   }
 
+  bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *ILE) {
+    auto *SubExpr = ILE->getSubExpr();
+    if (!SubExpr)
+      return false;
+    // The backing array of a std::initializer_list is a temporary whose
+    // lifetime ends in this function, so its elements are destructed here.
+    if (!CanTriviallyDestruct(SubExpr->getType()))
+      return false;
+    return Visit(SubExpr);
+  }
+
   bool VisitMemberExpr(const MemberExpr *ME) {
     // Field access is allowed but the base pointer may itself be non-trivial.
     return Visit(ME->getBase());
diff --git a/clang/test/Analysis/Checkers/WebKit/nodelete-annotation.cpp 
b/clang/test/Analysis/Checkers/WebKit/nodelete-annotation.cpp
index 83ec6e704f14a..e1d0ffc05cb77 100644
--- a/clang/test/Analysis/Checkers/WebKit/nodelete-annotation.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/nodelete-annotation.cpp
@@ -795,3 +795,55 @@ void [[clang::annotate_type("webkit.nodelete")]] 
valueInitNew() {
 }
 
 } // namespace trivial_implicit_ctor_in_new_expr
+
+namespace std {
+
+// The compiler only recognises the real ::std::initializer_list, so this mock
+// has to live in the global std namespace.
+template <typename T>
+class initializer_list {
+  const T* m_begin;
+  decltype(sizeof(0)) m_size;
+
+public:
+  constexpr initializer_list() : m_begin(nullptr), m_size(0) { }
+  constexpr const T* begin() const { return m_begin; }
+  constexpr const T* end() const { return m_begin + m_size; }
+  constexpr decltype(sizeof(0)) size() const { return m_size; }
+};
+
+template <typename T>
+constexpr T min(initializer_list<T> list) {
+  const T* first = list.begin();
+  const T* last = list.end();
+  T result = *first;
+  for (++first; first != last; ++first) {
+    if (*first < result)
+      result = *first;
+  }
+  return result;
+}
+
+} // namespace std
+
+namespace std_initializer_list {
+
+// A braced list passed as std::initializer_list materialises a backing array
+// temporary wrapped in a CXXStdInitializerListExpr. That array is destructed 
in
+// this function, so it's only safe when its element type destructs trivially.
+
+unsigned [[clang::annotate_type("webkit.nodelete")]] safeSize();
+
+void [[clang::annotate_type("webkit.nodelete")]] 
callsMinWithInitializerList(unsigned other) {
+  unsigned smallest = std::min({ safeSize(), other, 3u });
+  (void)smallest;
+}
+
+void takesTrackedList(std::initializer_list<ObjectWithNonTrivialDestructor>);
+
+void [[clang::annotate_type("webkit.nodelete")]] passesListOfTrackedObjects() {
+  takesTrackedList({ ObjectWithNonTrivialDestructor(), 
ObjectWithNonTrivialDestructor() });
+  // expected-warning@-1{{A function 'passesListOfTrackedObjects' has 
[[clang::annotate_type("webkit.nodelete")]] but it contains code that could 
destruct an object}}
+}
+
+} // namespace std_initializer_list

``````````

</details>


https://github.com/llvm/llvm-project/pull/224723
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to