Skip to content

Introduce a new WebKit checker for a unchecked local variable #113708

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 3 commits into from
Nov 1, 2024

Conversation

rniwa
Copy link
Contributor

@rniwa rniwa commented Oct 25, 2024

This PR introduces alpha.webkit.UncheckedLocalVarsChecker which detects a raw reference or a raw pointer local, static, or global variable to a CheckedPtr capable object without a guardian variable in an outer scope.

This PR introduces alpha.webkit.UncheckedLocalVarsChecker which detects a raw reference or a raw pointer
local, static, or global variable to a CheckedPtr capable object without a guardian variable in an outer scope.
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:static analyzer labels Oct 25, 2024
@llvmbot
Copy link
Member

llvmbot commented Oct 25, 2024

@llvm/pr-subscribers-clang

Author: Ryosuke Niwa (rniwa)

Changes

This PR introduces alpha.webkit.UncheckedLocalVarsChecker which detects a raw reference or a raw pointer local, static, or global variable to a CheckedPtr capable object without a guardian variable in an outer scope.


Patch is 20.33 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/113708.diff

9 Files Affected:

  • (modified) clang/docs/analyzer/checkers.rst (+42-5)
  • (modified) clang/include/clang/StaticAnalyzer/Checkers/Checkers.td (+4)
  • (modified) clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt (+1-1)
  • (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp (+9)
  • (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h (+4)
  • (renamed) clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp (+44-10)
  • (modified) clang/test/Analysis/Checkers/WebKit/mock-types.h (+2)
  • (added) clang/test/Analysis/Checkers/WebKit/unchecked-local-vars.cpp (+342)
  • (modified) llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/BUILD.gn (+1-1)
diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst
index 58dbd686a6dc9f..f56f603a8f6eab 100644
--- a/clang/docs/analyzer/checkers.rst
+++ b/clang/docs/analyzer/checkers.rst
@@ -3615,7 +3615,7 @@ These are examples of cases that we consider safe:
       RefCountable* uncounted = this; // ok
     }
 
-Here are some examples of situations that we warn about as they *might* be potentially unsafe. The logic is that either we're able to guarantee that an argument is safe or it's considered if not a bug then bug-prone.
+Here are some examples of situations that we warn about as they *might* be potentially unsafe. The logic is that either we're able to guarantee that a local variable is safe or it's considered unsafe.
 
   .. code-block:: cpp
 
@@ -3634,11 +3634,48 @@ Here are some examples of situations that we warn about as they *might* be poten
       RefCountable* uncounted = counted.get(); // warn
     }
 
-We don't warn about these cases - we don't consider them necessarily safe but since they are very common and usually safe we'd introduce a lot of false positives otherwise:
-- variable defined in condition part of an ```if``` statement
-- variable defined in init statement condition of a ```for``` statement
+alpha.webkit.UncheckedLocalVarsChecker
+""""""""""""""""""""""""""""""""""""""
+The goal of this rule is to make sure that any unchecked local variable is backed by a CheckedPtr or CheckedRef with lifetime that is strictly larger than the scope of the unchecked local variable. To be on the safe side we require the scope of an unchecked variable to be embedded in the scope of CheckedPtr/CheckRef object that backs it.
+
+These are examples of cases that we consider safe:
+
+  .. code-block:: cpp
 
-For the time being we also don't warn about uninitialized uncounted local variables.
+    void foo1() {
+      CheckedPtr<RefCountable> counted;
+      // The scope of uncounted is EMBEDDED in the scope of counted.
+      {
+        RefCountable* uncounted = counted.get(); // ok
+      }
+    }
+
+    void foo2(CheckedPtr<RefCountable> counted_param) {
+      RefCountable* uncounted = counted_param.get(); // ok
+    }
+
+    void FooClass::foo_method() {
+      RefCountable* uncounted = this; // ok
+    }
+
+Here are some examples of situations that we warn about as they *might* be potentially unsafe. The logic is that either we're able to guarantee that a local variable is safe or it's considered unsafe.
+
+  .. code-block:: cpp
+
+    void foo1() {
+      RefCountable* uncounted = new RefCountable; // warn
+    }
+
+    RefCountable* global_uncounted;
+    void foo2() {
+      RefCountable* uncounted = global_uncounted; // warn
+    }
+
+    void foo3() {
+      RefPtr<RefCountable> counted;
+      // The scope of uncounted is not EMBEDDED in the scope of counted.
+      RefCountable* uncounted = counted.get(); // warn
+    }
 
 Debug Checkers
 ---------------
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 349040c15eeb83..2685d194482123 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -1782,4 +1782,8 @@ def UncountedLocalVarsChecker : Checker<"UncountedLocalVarsChecker">,
   HelpText<"Check uncounted local variables.">,
   Documentation<HasDocumentation>;
 
+def UncheckedLocalVarsChecker : Checker<"UncheckedLocalVarsChecker">,
+  HelpText<"Check unchecked local variables.">,
+  Documentation<HasDocumentation>;
+
 } // end alpha.webkit
diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 6da3665ab9a4df..4f2806593aaa30 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -138,7 +138,7 @@ add_clang_library(clangStaticAnalyzerCheckers
   WebKit/RefCntblBaseVirtualDtorChecker.cpp
   WebKit/UncountedCallArgsChecker.cpp
   WebKit/UncountedLambdaCapturesChecker.cpp
-  WebKit/UncountedLocalVarsChecker.cpp
+  WebKit/RawPtrRefLocalVarsChecker.cpp
 
   LINK_LIBS
   clangAST
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index 2293dcf1d4bd64..5d39d02a2f40f7 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -200,6 +200,15 @@ std::optional<bool> isUncountedPtr(const QualType T) {
   return false;
 }
 
+std::optional<bool> isUncheckedPtr(const QualType T)
+{
+  if (T->isPointerType() || T->isReferenceType()) {
+    if (auto *CXXRD = T->getPointeeCXXRecordDecl())
+      return isUnchecked(CXXRD);
+  }
+  return false;
+}
+
 std::optional<bool> isUnsafePtr(const QualType T) {
   if (T->isPointerType() || T->isReferenceType()) {
     if (auto *CXXRD = T->getPointeeCXXRecordDecl()) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
index 4b41ca96e1df1d..30bdaed706bb53 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
@@ -63,6 +63,10 @@ std::optional<bool> isUncounted(const clang::CXXRecordDecl* Class);
 /// class, false if not, std::nullopt if inconclusive.
 std::optional<bool> isUncountedPtr(const clang::QualType T);
 
+/// \returns true if \p T is either a raw pointer or reference to an unchecked
+/// class, false if not, std::nullopt if inconclusive.
+std::optional<bool> isUncheckedPtr(const clang::QualType T);
+
 /// \returns true if \p T is a RefPtr, Ref, CheckedPtr, CheckedRef, or its
 /// variant, false if not.
 bool isSafePtrType(const clang::QualType T);
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
similarity index 85%
rename from clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp
rename to clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
index 5cdf047738abcb..0842cdbc4037b7 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
@@ -103,15 +103,18 @@ bool isGuardedScopeEmbeddedInGuardianScope(const VarDecl *Guarded,
   return false;
 }
 
-class UncountedLocalVarsChecker
+class RawPtrRefLocalVarsChecker
     : public Checker<check::ASTDecl<TranslationUnitDecl>> {
-  BugType Bug{this,
-              "Uncounted raw pointer or reference not provably backed by "
-              "ref-counted variable",
-              "WebKit coding guidelines"};
+  BugType Bug;
   mutable BugReporter *BR;
 
 public:
+  RawPtrRefLocalVarsChecker(const char* description)
+      : Bug(this, description, "WebKit coding guidelines") {}
+
+  virtual std::optional<bool> isUnsafePtr(const QualType T) const = 0;
+  virtual const char *ptrKind() const = 0;
+
   void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR,
                     BugReporter &BRArg) const {
     BR = &BRArg;
@@ -120,14 +123,14 @@ class UncountedLocalVarsChecker
     // visit template instantiations or lambda classes. We
     // want to visit those, so we make our own RecursiveASTVisitor.
     struct LocalVisitor : public RecursiveASTVisitor<LocalVisitor> {
-      const UncountedLocalVarsChecker *Checker;
+      const RawPtrRefLocalVarsChecker *Checker;
       Decl *DeclWithIssue{nullptr};
 
       TrivialFunctionAnalysis TFA;
 
       using Base = RecursiveASTVisitor<LocalVisitor>;
 
-      explicit LocalVisitor(const UncountedLocalVarsChecker *Checker)
+      explicit LocalVisitor(const RawPtrRefLocalVarsChecker *Checker)
           : Checker(Checker) {
         assert(Checker);
       }
@@ -199,7 +202,7 @@ class UncountedLocalVarsChecker
     if (shouldSkipVarDecl(V))
       return;
 
-    std::optional<bool> IsUncountedPtr = isUncountedPtr(V->getType());
+    std::optional<bool> IsUncountedPtr = isUnsafePtr(V->getType());
     if (IsUncountedPtr && *IsUncountedPtr) {
       if (tryToFindPtrOrigin(
               Value, /*StopAtFirstRefCountedObj=*/false,
@@ -262,7 +265,7 @@ class UncountedLocalVarsChecker
     llvm::raw_svector_ostream Os(Buf);
 
     if (dyn_cast<ParmVarDecl>(V)) {
-      Os << "Assignment to an uncounted parameter ";
+      Os << "Assignment to an " << ptrKind() << " parameter ";
       printQuotedQualifiedName(Os, V);
       Os << " is unsafe.";
 
@@ -280,7 +283,7 @@ class UncountedLocalVarsChecker
       else
         Os << "Variable ";
       printQuotedQualifiedName(Os, V);
-      Os << " is uncounted and unsafe.";
+      Os << " is " << ptrKind() << " and unsafe.";
 
       PathDiagnosticLocation BSLoc(V->getLocation(), BR->getSourceManager());
       auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
@@ -290,6 +293,29 @@ class UncountedLocalVarsChecker
     }
   }
 };
+
+class UncountedLocalVarsChecker final : public RawPtrRefLocalVarsChecker {
+public:
+  UncountedLocalVarsChecker()
+      : RawPtrRefLocalVarsChecker("Uncounted raw pointer or reference not "
+                                  "provably backed by ref-counted variable") {}
+  std::optional<bool> isUnsafePtr(const QualType T) const final {
+    return isUncountedPtr(T);
+  }
+  const char *ptrKind() const final { return "uncounted"; }
+};
+
+class UncheckedLocalVarsChecker final : public RawPtrRefLocalVarsChecker {
+public:
+  UncheckedLocalVarsChecker()
+      : RawPtrRefLocalVarsChecker("Unchecked raw pointer or reference not "
+                                  "provably backed by checked variable") {}
+  std::optional<bool> isUnsafePtr(const QualType T) const final {
+    return isUncheckedPtr(T);
+  }
+  const char *ptrKind() const final { return "unchecked"; }
+};
+
 } // namespace
 
 void ento::registerUncountedLocalVarsChecker(CheckerManager &Mgr) {
@@ -299,3 +325,11 @@ void ento::registerUncountedLocalVarsChecker(CheckerManager &Mgr) {
 bool ento::shouldRegisterUncountedLocalVarsChecker(const CheckerManager &) {
   return true;
 }
+
+void ento::registerUncheckedLocalVarsChecker(CheckerManager &Mgr) {
+  Mgr.registerChecker<UncheckedLocalVarsChecker>();
+}
+
+bool ento::shouldRegisterUncheckedLocalVarsChecker(const CheckerManager &) {
+  return true;
+}
diff --git a/clang/test/Analysis/Checkers/WebKit/mock-types.h b/clang/test/Analysis/Checkers/WebKit/mock-types.h
index 8d8a90f0afae0e..5aed6a403fe8f4 100644
--- a/clang/test/Analysis/Checkers/WebKit/mock-types.h
+++ b/clang/test/Analysis/Checkers/WebKit/mock-types.h
@@ -154,6 +154,8 @@ class CheckedObj {
 public:
   void incrementPtrCount();
   void decrementPtrCount();
+  void method();
+  int trivial() { return 123; }
 };
 
 class RefCountableAndCheckable {
diff --git a/clang/test/Analysis/Checkers/WebKit/unchecked-local-vars.cpp b/clang/test/Analysis/Checkers/WebKit/unchecked-local-vars.cpp
new file mode 100644
index 00000000000000..3bc75230fcf821
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/unchecked-local-vars.cpp
@@ -0,0 +1,342 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncheckedLocalVarsChecker -verify %s
+
+#include "mock-types.h"
+#include "mock-system-header.h"
+
+void someFunction();
+
+namespace raw_ptr {
+void foo() {
+  CheckedObj *bar;
+  // FIXME: later on we might warn on uninitialized vars too
+}
+
+void bar(CheckedObj *) {}
+} // namespace raw_ptr
+
+namespace reference {
+void foo_ref() {
+  CheckedObj automatic;
+  CheckedObj &bar = automatic;
+  // expected-warning@-1{{Local variable 'bar' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+  someFunction();
+  bar.method();
+}
+
+void foo_ref_trivial() {
+  CheckedObj automatic;
+  CheckedObj &bar = automatic;
+}
+
+void bar_ref(CheckedObj &) {}
+} // namespace reference
+
+namespace guardian_scopes {
+void foo1() {
+  CheckedPtr<CheckedObj> foo;
+  { CheckedObj *bar = foo.get(); }
+}
+
+void foo2() {
+  CheckedPtr<CheckedObj> foo;
+  // missing embedded scope here
+  CheckedObj *bar = foo.get();
+  // expected-warning@-1{{Local variable 'bar' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+  someFunction();
+  bar->method();
+}
+
+void foo3() {
+  CheckedPtr<CheckedObj> foo;
+  {
+    { CheckedObj *bar = foo.get(); }
+  }
+}
+
+void foo4() {
+  {
+    CheckedPtr<CheckedObj> foo;
+    { CheckedObj *bar = foo.get(); }
+  }
+}
+
+void foo5() {
+  CheckedPtr<CheckedObj> foo;
+  auto* bar = foo.get();
+  bar->trivial();
+}
+
+void foo6() {
+  CheckedPtr<CheckedObj> foo;
+  auto* bar = foo.get();
+  // expected-warning@-1{{Local variable 'bar' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+  bar->method();
+}
+
+struct SelfReferencingStruct {
+  SelfReferencingStruct* ptr;
+  CheckedObj* obj { nullptr };
+};
+
+void foo7(CheckedObj* obj) {
+  SelfReferencingStruct bar = { &bar, obj };
+  bar.obj->method();
+}
+
+} // namespace guardian_scopes
+
+namespace auto_keyword {
+class Foo {
+  CheckedObj *provide_ref_ctnbl();
+
+  void evil_func() {
+    CheckedObj *bar = provide_ref_ctnbl();
+    // expected-warning@-1{{Local variable 'bar' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    auto *baz = provide_ref_ctnbl();
+    // expected-warning@-1{{Local variable 'baz' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    auto *baz2 = this->provide_ref_ctnbl();
+    // expected-warning@-1{{Local variable 'baz2' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    [[clang::suppress]] auto *baz_suppressed = provide_ref_ctnbl(); // no-warning
+  }
+
+  void func() {
+    CheckedObj *bar = provide_ref_ctnbl();
+    // expected-warning@-1{{Local variable 'bar' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    if (bar)
+      bar->method();
+  }
+};
+} // namespace auto_keyword
+
+namespace guardian_casts {
+void foo1() {
+  CheckedPtr<CheckedObj> foo;
+  {
+    CheckedObj *bar = downcast<CheckedObj>(foo.get());
+    bar->method();
+  }
+  foo->method();
+}
+
+void foo2() {
+  CheckedPtr<CheckedObj> foo;
+  {
+    CheckedObj *bar =
+        static_cast<CheckedObj *>(downcast<CheckedObj>(foo.get()));
+    someFunction();
+  }
+}
+} // namespace guardian_casts
+
+namespace guardian_ref_conversion_operator {
+void foo() {
+  CheckedRef<CheckedObj> rc;
+  {
+    CheckedObj &rr = rc;
+    rr.method();
+    someFunction();
+  }
+}
+} // namespace guardian_ref_conversion_operator
+
+namespace ignore_for_if {
+CheckedObj *provide_ref_ctnbl() { return nullptr; }
+
+void foo() {
+  // no warnings
+  if (CheckedObj *a = provide_ref_ctnbl())
+    a->trivial();
+  for (CheckedObj *b = provide_ref_ctnbl(); b != nullptr;)
+    b->trivial();
+  CheckedObj *array[1];
+  for (CheckedObj *c : array)
+    c->trivial();
+  while (CheckedObj *d = provide_ref_ctnbl())
+    d->trivial();
+  do {
+    CheckedObj *e = provide_ref_ctnbl();
+    e->trivial();
+  } while (1);
+  someFunction();
+}
+
+void bar() {
+  if (CheckedObj *a = provide_ref_ctnbl()) {
+    // expected-warning@-1{{Local variable 'a' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    a->method();    
+  }
+  for (CheckedObj *b = provide_ref_ctnbl(); b != nullptr;) {
+    // expected-warning@-1{{Local variable 'b' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    b->method();
+  }
+  CheckedObj *array[1];
+  for (CheckedObj *c : array) {
+    // expected-warning@-1{{Local variable 'c' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    c->method();
+  }
+
+  while (CheckedObj *d = provide_ref_ctnbl()) {
+    // expected-warning@-1{{Local variable 'd' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    d->method();
+  }
+  do {
+    CheckedObj *e = provide_ref_ctnbl();
+    // expected-warning@-1{{Local variable 'e' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    e->method();
+  } while (1);
+  someFunction();
+}
+
+} // namespace ignore_for_if
+
+namespace ignore_system_headers {
+
+CheckedObj *provide_checkable();
+
+void system_header() {
+  localVar<CheckedObj>(provide_checkable);
+}
+
+} // ignore_system_headers
+
+namespace conditional_op {
+CheckedObj *provide_checkable();
+bool bar();
+
+void foo() {
+  CheckedObj *a = bar() ? nullptr : provide_checkable();
+  // expected-warning@-1{{Local variable 'a' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+  CheckedPtr<CheckedObj> b = provide_checkable();
+  {
+    CheckedObj* c = bar() ? nullptr : b.get();
+    c->method();
+    CheckedObj* d = bar() ? b.get() : nullptr;
+    d->method();
+  }
+}
+
+} // namespace conditional_op
+
+namespace local_assignment_basic {
+
+CheckedObj *provide_checkable();
+
+void foo(CheckedObj* a) {
+  CheckedObj* b = a;
+  // expected-warning@-1{{Local variable 'b' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+  if (b->trivial())
+    b = provide_checkable();
+}
+
+void bar(CheckedObj* a) {
+  CheckedObj* b;
+  // expected-warning@-1{{Local variable 'b' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+  b = provide_checkable();
+}
+
+void baz() {
+  CheckedPtr a = provide_checkable();
+  {
+    CheckedObj* b = a.get();
+    // expected-warning@-1{{Local variable 'b' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    b = provide_checkable();
+  }
+}
+
+} // namespace local_assignment_basic
+
+namespace local_assignment_to_parameter {
+
+CheckedObj *provide_checkable();
+void someFunction();
+
+void foo(CheckedObj* a) {
+  a = provide_checkable();
+  // expected-warning@-1{{Assignment to an unchecked parameter 'a' is unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+  someFunction();
+  a->method();
+}
+
+} // namespace local_assignment_to_parameter
+
+namespace local_assignment_to_static_local {
+
+CheckedObj *provide_checkable();
+void someFunction();
+
+void foo() {
+  static CheckedObj* a = nullptr;
+  // expected-warning@-1{{Static local variable 'a' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+  a = provide_checkable();
+  someFunction();
+  a->method();
+}
+
+} // namespace local_assignment_to_static_local
+
+namespace local_assignment_to_global {
+
+CheckedObj *provide_ref_cntbl();
+void someFunction();
+
+CheckedObj* g_a = nullptr;
+// expected-warning@-1{{Global variable 'local_assignment_to_global::g_a' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+
+void foo() {
+  g_a = provide_ref_cntbl();
+  someFunction();
+  g_a->method();
+}
+
+} // namespace local_assignment_to_global
+
+namespace local_refcountable_checkable_object {
+
+RefCountableAndCheckable* provide_obj();
+
+void local_raw_ptr() {
+  RefCountableAndCheckable* a = nullptr;
+  // expected-warning@-1{{Local variable 'a' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+  a = provide_obj();
+  a->method();
+}
+
+void local_checked_ptr() {
+  RefPtr<RefCountableAndCheckable> a = nullptr;
+  a = provide_obj();
+  a->method();
+}
+
+void local_var_with_guardian_checked_ptr() {
+  RefPtr<RefCountableAndCheckable> a = provide_obj();
+  {
+    auto* b = a.get();
+    b->method();
+  }
+}
+
+void local_var_with_guardian_checked_ptr_with_assignment() {
+  RefPtr<RefCountableAndCheckable> a = provide_obj();
+  {
+    RefCountableAndCheckable* b = a.get();
+    // expected-warning@-1{{Local variable 'b' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    b = provide_obj();
+    b->method();
+  }
+}
+
+void local_var_with_guardian_checked_ref() {
+  Ref<RefCountableAndCheckable> a = *provide_obj();
+  {
+    RefCountableAndCheckable& b = a;
+    b.method();
+  }
+}
+
+void static_var() {
+  static RefCountableAndCheckable* a = nullptr;
+  // expected-warning@-1{{Static local variable 'a' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+  a = provide_obj();
+}
+
+} // namespace local_refcountable_checkable_object
diff --git a/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/BUILD.gn b/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/BUILD.gn
index 7a6c360e88c14e..65600992e702d0 100644
--- a/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/BUILD.gn
+++ b/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Oct 25, 2024

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

Author: Ryosuke Niwa (rniwa)

Changes

This PR introduces alpha.webkit.UncheckedLocalVarsChecker which detects a raw reference or a raw pointer local, static, or global variable to a CheckedPtr capable object without a guardian variable in an outer scope.


Patch is 20.33 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/113708.diff

9 Files Affected:

  • (modified) clang/docs/analyzer/checkers.rst (+42-5)
  • (modified) clang/include/clang/StaticAnalyzer/Checkers/Checkers.td (+4)
  • (modified) clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt (+1-1)
  • (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp (+9)
  • (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h (+4)
  • (renamed) clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp (+44-10)
  • (modified) clang/test/Analysis/Checkers/WebKit/mock-types.h (+2)
  • (added) clang/test/Analysis/Checkers/WebKit/unchecked-local-vars.cpp (+342)
  • (modified) llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/BUILD.gn (+1-1)
diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst
index 58dbd686a6dc9f..f56f603a8f6eab 100644
--- a/clang/docs/analyzer/checkers.rst
+++ b/clang/docs/analyzer/checkers.rst
@@ -3615,7 +3615,7 @@ These are examples of cases that we consider safe:
       RefCountable* uncounted = this; // ok
     }
 
-Here are some examples of situations that we warn about as they *might* be potentially unsafe. The logic is that either we're able to guarantee that an argument is safe or it's considered if not a bug then bug-prone.
+Here are some examples of situations that we warn about as they *might* be potentially unsafe. The logic is that either we're able to guarantee that a local variable is safe or it's considered unsafe.
 
   .. code-block:: cpp
 
@@ -3634,11 +3634,48 @@ Here are some examples of situations that we warn about as they *might* be poten
       RefCountable* uncounted = counted.get(); // warn
     }
 
-We don't warn about these cases - we don't consider them necessarily safe but since they are very common and usually safe we'd introduce a lot of false positives otherwise:
-- variable defined in condition part of an ```if``` statement
-- variable defined in init statement condition of a ```for``` statement
+alpha.webkit.UncheckedLocalVarsChecker
+""""""""""""""""""""""""""""""""""""""
+The goal of this rule is to make sure that any unchecked local variable is backed by a CheckedPtr or CheckedRef with lifetime that is strictly larger than the scope of the unchecked local variable. To be on the safe side we require the scope of an unchecked variable to be embedded in the scope of CheckedPtr/CheckRef object that backs it.
+
+These are examples of cases that we consider safe:
+
+  .. code-block:: cpp
 
-For the time being we also don't warn about uninitialized uncounted local variables.
+    void foo1() {
+      CheckedPtr<RefCountable> counted;
+      // The scope of uncounted is EMBEDDED in the scope of counted.
+      {
+        RefCountable* uncounted = counted.get(); // ok
+      }
+    }
+
+    void foo2(CheckedPtr<RefCountable> counted_param) {
+      RefCountable* uncounted = counted_param.get(); // ok
+    }
+
+    void FooClass::foo_method() {
+      RefCountable* uncounted = this; // ok
+    }
+
+Here are some examples of situations that we warn about as they *might* be potentially unsafe. The logic is that either we're able to guarantee that a local variable is safe or it's considered unsafe.
+
+  .. code-block:: cpp
+
+    void foo1() {
+      RefCountable* uncounted = new RefCountable; // warn
+    }
+
+    RefCountable* global_uncounted;
+    void foo2() {
+      RefCountable* uncounted = global_uncounted; // warn
+    }
+
+    void foo3() {
+      RefPtr<RefCountable> counted;
+      // The scope of uncounted is not EMBEDDED in the scope of counted.
+      RefCountable* uncounted = counted.get(); // warn
+    }
 
 Debug Checkers
 ---------------
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 349040c15eeb83..2685d194482123 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -1782,4 +1782,8 @@ def UncountedLocalVarsChecker : Checker<"UncountedLocalVarsChecker">,
   HelpText<"Check uncounted local variables.">,
   Documentation<HasDocumentation>;
 
+def UncheckedLocalVarsChecker : Checker<"UncheckedLocalVarsChecker">,
+  HelpText<"Check unchecked local variables.">,
+  Documentation<HasDocumentation>;
+
 } // end alpha.webkit
diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 6da3665ab9a4df..4f2806593aaa30 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -138,7 +138,7 @@ add_clang_library(clangStaticAnalyzerCheckers
   WebKit/RefCntblBaseVirtualDtorChecker.cpp
   WebKit/UncountedCallArgsChecker.cpp
   WebKit/UncountedLambdaCapturesChecker.cpp
-  WebKit/UncountedLocalVarsChecker.cpp
+  WebKit/RawPtrRefLocalVarsChecker.cpp
 
   LINK_LIBS
   clangAST
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index 2293dcf1d4bd64..5d39d02a2f40f7 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -200,6 +200,15 @@ std::optional<bool> isUncountedPtr(const QualType T) {
   return false;
 }
 
+std::optional<bool> isUncheckedPtr(const QualType T)
+{
+  if (T->isPointerType() || T->isReferenceType()) {
+    if (auto *CXXRD = T->getPointeeCXXRecordDecl())
+      return isUnchecked(CXXRD);
+  }
+  return false;
+}
+
 std::optional<bool> isUnsafePtr(const QualType T) {
   if (T->isPointerType() || T->isReferenceType()) {
     if (auto *CXXRD = T->getPointeeCXXRecordDecl()) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
index 4b41ca96e1df1d..30bdaed706bb53 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
@@ -63,6 +63,10 @@ std::optional<bool> isUncounted(const clang::CXXRecordDecl* Class);
 /// class, false if not, std::nullopt if inconclusive.
 std::optional<bool> isUncountedPtr(const clang::QualType T);
 
+/// \returns true if \p T is either a raw pointer or reference to an unchecked
+/// class, false if not, std::nullopt if inconclusive.
+std::optional<bool> isUncheckedPtr(const clang::QualType T);
+
 /// \returns true if \p T is a RefPtr, Ref, CheckedPtr, CheckedRef, or its
 /// variant, false if not.
 bool isSafePtrType(const clang::QualType T);
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
similarity index 85%
rename from clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp
rename to clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
index 5cdf047738abcb..0842cdbc4037b7 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
@@ -103,15 +103,18 @@ bool isGuardedScopeEmbeddedInGuardianScope(const VarDecl *Guarded,
   return false;
 }
 
-class UncountedLocalVarsChecker
+class RawPtrRefLocalVarsChecker
     : public Checker<check::ASTDecl<TranslationUnitDecl>> {
-  BugType Bug{this,
-              "Uncounted raw pointer or reference not provably backed by "
-              "ref-counted variable",
-              "WebKit coding guidelines"};
+  BugType Bug;
   mutable BugReporter *BR;
 
 public:
+  RawPtrRefLocalVarsChecker(const char* description)
+      : Bug(this, description, "WebKit coding guidelines") {}
+
+  virtual std::optional<bool> isUnsafePtr(const QualType T) const = 0;
+  virtual const char *ptrKind() const = 0;
+
   void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR,
                     BugReporter &BRArg) const {
     BR = &BRArg;
@@ -120,14 +123,14 @@ class UncountedLocalVarsChecker
     // visit template instantiations or lambda classes. We
     // want to visit those, so we make our own RecursiveASTVisitor.
     struct LocalVisitor : public RecursiveASTVisitor<LocalVisitor> {
-      const UncountedLocalVarsChecker *Checker;
+      const RawPtrRefLocalVarsChecker *Checker;
       Decl *DeclWithIssue{nullptr};
 
       TrivialFunctionAnalysis TFA;
 
       using Base = RecursiveASTVisitor<LocalVisitor>;
 
-      explicit LocalVisitor(const UncountedLocalVarsChecker *Checker)
+      explicit LocalVisitor(const RawPtrRefLocalVarsChecker *Checker)
           : Checker(Checker) {
         assert(Checker);
       }
@@ -199,7 +202,7 @@ class UncountedLocalVarsChecker
     if (shouldSkipVarDecl(V))
       return;
 
-    std::optional<bool> IsUncountedPtr = isUncountedPtr(V->getType());
+    std::optional<bool> IsUncountedPtr = isUnsafePtr(V->getType());
     if (IsUncountedPtr && *IsUncountedPtr) {
       if (tryToFindPtrOrigin(
               Value, /*StopAtFirstRefCountedObj=*/false,
@@ -262,7 +265,7 @@ class UncountedLocalVarsChecker
     llvm::raw_svector_ostream Os(Buf);
 
     if (dyn_cast<ParmVarDecl>(V)) {
-      Os << "Assignment to an uncounted parameter ";
+      Os << "Assignment to an " << ptrKind() << " parameter ";
       printQuotedQualifiedName(Os, V);
       Os << " is unsafe.";
 
@@ -280,7 +283,7 @@ class UncountedLocalVarsChecker
       else
         Os << "Variable ";
       printQuotedQualifiedName(Os, V);
-      Os << " is uncounted and unsafe.";
+      Os << " is " << ptrKind() << " and unsafe.";
 
       PathDiagnosticLocation BSLoc(V->getLocation(), BR->getSourceManager());
       auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
@@ -290,6 +293,29 @@ class UncountedLocalVarsChecker
     }
   }
 };
+
+class UncountedLocalVarsChecker final : public RawPtrRefLocalVarsChecker {
+public:
+  UncountedLocalVarsChecker()
+      : RawPtrRefLocalVarsChecker("Uncounted raw pointer or reference not "
+                                  "provably backed by ref-counted variable") {}
+  std::optional<bool> isUnsafePtr(const QualType T) const final {
+    return isUncountedPtr(T);
+  }
+  const char *ptrKind() const final { return "uncounted"; }
+};
+
+class UncheckedLocalVarsChecker final : public RawPtrRefLocalVarsChecker {
+public:
+  UncheckedLocalVarsChecker()
+      : RawPtrRefLocalVarsChecker("Unchecked raw pointer or reference not "
+                                  "provably backed by checked variable") {}
+  std::optional<bool> isUnsafePtr(const QualType T) const final {
+    return isUncheckedPtr(T);
+  }
+  const char *ptrKind() const final { return "unchecked"; }
+};
+
 } // namespace
 
 void ento::registerUncountedLocalVarsChecker(CheckerManager &Mgr) {
@@ -299,3 +325,11 @@ void ento::registerUncountedLocalVarsChecker(CheckerManager &Mgr) {
 bool ento::shouldRegisterUncountedLocalVarsChecker(const CheckerManager &) {
   return true;
 }
+
+void ento::registerUncheckedLocalVarsChecker(CheckerManager &Mgr) {
+  Mgr.registerChecker<UncheckedLocalVarsChecker>();
+}
+
+bool ento::shouldRegisterUncheckedLocalVarsChecker(const CheckerManager &) {
+  return true;
+}
diff --git a/clang/test/Analysis/Checkers/WebKit/mock-types.h b/clang/test/Analysis/Checkers/WebKit/mock-types.h
index 8d8a90f0afae0e..5aed6a403fe8f4 100644
--- a/clang/test/Analysis/Checkers/WebKit/mock-types.h
+++ b/clang/test/Analysis/Checkers/WebKit/mock-types.h
@@ -154,6 +154,8 @@ class CheckedObj {
 public:
   void incrementPtrCount();
   void decrementPtrCount();
+  void method();
+  int trivial() { return 123; }
 };
 
 class RefCountableAndCheckable {
diff --git a/clang/test/Analysis/Checkers/WebKit/unchecked-local-vars.cpp b/clang/test/Analysis/Checkers/WebKit/unchecked-local-vars.cpp
new file mode 100644
index 00000000000000..3bc75230fcf821
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/unchecked-local-vars.cpp
@@ -0,0 +1,342 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncheckedLocalVarsChecker -verify %s
+
+#include "mock-types.h"
+#include "mock-system-header.h"
+
+void someFunction();
+
+namespace raw_ptr {
+void foo() {
+  CheckedObj *bar;
+  // FIXME: later on we might warn on uninitialized vars too
+}
+
+void bar(CheckedObj *) {}
+} // namespace raw_ptr
+
+namespace reference {
+void foo_ref() {
+  CheckedObj automatic;
+  CheckedObj &bar = automatic;
+  // expected-warning@-1{{Local variable 'bar' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+  someFunction();
+  bar.method();
+}
+
+void foo_ref_trivial() {
+  CheckedObj automatic;
+  CheckedObj &bar = automatic;
+}
+
+void bar_ref(CheckedObj &) {}
+} // namespace reference
+
+namespace guardian_scopes {
+void foo1() {
+  CheckedPtr<CheckedObj> foo;
+  { CheckedObj *bar = foo.get(); }
+}
+
+void foo2() {
+  CheckedPtr<CheckedObj> foo;
+  // missing embedded scope here
+  CheckedObj *bar = foo.get();
+  // expected-warning@-1{{Local variable 'bar' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+  someFunction();
+  bar->method();
+}
+
+void foo3() {
+  CheckedPtr<CheckedObj> foo;
+  {
+    { CheckedObj *bar = foo.get(); }
+  }
+}
+
+void foo4() {
+  {
+    CheckedPtr<CheckedObj> foo;
+    { CheckedObj *bar = foo.get(); }
+  }
+}
+
+void foo5() {
+  CheckedPtr<CheckedObj> foo;
+  auto* bar = foo.get();
+  bar->trivial();
+}
+
+void foo6() {
+  CheckedPtr<CheckedObj> foo;
+  auto* bar = foo.get();
+  // expected-warning@-1{{Local variable 'bar' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+  bar->method();
+}
+
+struct SelfReferencingStruct {
+  SelfReferencingStruct* ptr;
+  CheckedObj* obj { nullptr };
+};
+
+void foo7(CheckedObj* obj) {
+  SelfReferencingStruct bar = { &bar, obj };
+  bar.obj->method();
+}
+
+} // namespace guardian_scopes
+
+namespace auto_keyword {
+class Foo {
+  CheckedObj *provide_ref_ctnbl();
+
+  void evil_func() {
+    CheckedObj *bar = provide_ref_ctnbl();
+    // expected-warning@-1{{Local variable 'bar' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    auto *baz = provide_ref_ctnbl();
+    // expected-warning@-1{{Local variable 'baz' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    auto *baz2 = this->provide_ref_ctnbl();
+    // expected-warning@-1{{Local variable 'baz2' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    [[clang::suppress]] auto *baz_suppressed = provide_ref_ctnbl(); // no-warning
+  }
+
+  void func() {
+    CheckedObj *bar = provide_ref_ctnbl();
+    // expected-warning@-1{{Local variable 'bar' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    if (bar)
+      bar->method();
+  }
+};
+} // namespace auto_keyword
+
+namespace guardian_casts {
+void foo1() {
+  CheckedPtr<CheckedObj> foo;
+  {
+    CheckedObj *bar = downcast<CheckedObj>(foo.get());
+    bar->method();
+  }
+  foo->method();
+}
+
+void foo2() {
+  CheckedPtr<CheckedObj> foo;
+  {
+    CheckedObj *bar =
+        static_cast<CheckedObj *>(downcast<CheckedObj>(foo.get()));
+    someFunction();
+  }
+}
+} // namespace guardian_casts
+
+namespace guardian_ref_conversion_operator {
+void foo() {
+  CheckedRef<CheckedObj> rc;
+  {
+    CheckedObj &rr = rc;
+    rr.method();
+    someFunction();
+  }
+}
+} // namespace guardian_ref_conversion_operator
+
+namespace ignore_for_if {
+CheckedObj *provide_ref_ctnbl() { return nullptr; }
+
+void foo() {
+  // no warnings
+  if (CheckedObj *a = provide_ref_ctnbl())
+    a->trivial();
+  for (CheckedObj *b = provide_ref_ctnbl(); b != nullptr;)
+    b->trivial();
+  CheckedObj *array[1];
+  for (CheckedObj *c : array)
+    c->trivial();
+  while (CheckedObj *d = provide_ref_ctnbl())
+    d->trivial();
+  do {
+    CheckedObj *e = provide_ref_ctnbl();
+    e->trivial();
+  } while (1);
+  someFunction();
+}
+
+void bar() {
+  if (CheckedObj *a = provide_ref_ctnbl()) {
+    // expected-warning@-1{{Local variable 'a' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    a->method();    
+  }
+  for (CheckedObj *b = provide_ref_ctnbl(); b != nullptr;) {
+    // expected-warning@-1{{Local variable 'b' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    b->method();
+  }
+  CheckedObj *array[1];
+  for (CheckedObj *c : array) {
+    // expected-warning@-1{{Local variable 'c' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    c->method();
+  }
+
+  while (CheckedObj *d = provide_ref_ctnbl()) {
+    // expected-warning@-1{{Local variable 'd' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    d->method();
+  }
+  do {
+    CheckedObj *e = provide_ref_ctnbl();
+    // expected-warning@-1{{Local variable 'e' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    e->method();
+  } while (1);
+  someFunction();
+}
+
+} // namespace ignore_for_if
+
+namespace ignore_system_headers {
+
+CheckedObj *provide_checkable();
+
+void system_header() {
+  localVar<CheckedObj>(provide_checkable);
+}
+
+} // ignore_system_headers
+
+namespace conditional_op {
+CheckedObj *provide_checkable();
+bool bar();
+
+void foo() {
+  CheckedObj *a = bar() ? nullptr : provide_checkable();
+  // expected-warning@-1{{Local variable 'a' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+  CheckedPtr<CheckedObj> b = provide_checkable();
+  {
+    CheckedObj* c = bar() ? nullptr : b.get();
+    c->method();
+    CheckedObj* d = bar() ? b.get() : nullptr;
+    d->method();
+  }
+}
+
+} // namespace conditional_op
+
+namespace local_assignment_basic {
+
+CheckedObj *provide_checkable();
+
+void foo(CheckedObj* a) {
+  CheckedObj* b = a;
+  // expected-warning@-1{{Local variable 'b' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+  if (b->trivial())
+    b = provide_checkable();
+}
+
+void bar(CheckedObj* a) {
+  CheckedObj* b;
+  // expected-warning@-1{{Local variable 'b' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+  b = provide_checkable();
+}
+
+void baz() {
+  CheckedPtr a = provide_checkable();
+  {
+    CheckedObj* b = a.get();
+    // expected-warning@-1{{Local variable 'b' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    b = provide_checkable();
+  }
+}
+
+} // namespace local_assignment_basic
+
+namespace local_assignment_to_parameter {
+
+CheckedObj *provide_checkable();
+void someFunction();
+
+void foo(CheckedObj* a) {
+  a = provide_checkable();
+  // expected-warning@-1{{Assignment to an unchecked parameter 'a' is unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+  someFunction();
+  a->method();
+}
+
+} // namespace local_assignment_to_parameter
+
+namespace local_assignment_to_static_local {
+
+CheckedObj *provide_checkable();
+void someFunction();
+
+void foo() {
+  static CheckedObj* a = nullptr;
+  // expected-warning@-1{{Static local variable 'a' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+  a = provide_checkable();
+  someFunction();
+  a->method();
+}
+
+} // namespace local_assignment_to_static_local
+
+namespace local_assignment_to_global {
+
+CheckedObj *provide_ref_cntbl();
+void someFunction();
+
+CheckedObj* g_a = nullptr;
+// expected-warning@-1{{Global variable 'local_assignment_to_global::g_a' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+
+void foo() {
+  g_a = provide_ref_cntbl();
+  someFunction();
+  g_a->method();
+}
+
+} // namespace local_assignment_to_global
+
+namespace local_refcountable_checkable_object {
+
+RefCountableAndCheckable* provide_obj();
+
+void local_raw_ptr() {
+  RefCountableAndCheckable* a = nullptr;
+  // expected-warning@-1{{Local variable 'a' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+  a = provide_obj();
+  a->method();
+}
+
+void local_checked_ptr() {
+  RefPtr<RefCountableAndCheckable> a = nullptr;
+  a = provide_obj();
+  a->method();
+}
+
+void local_var_with_guardian_checked_ptr() {
+  RefPtr<RefCountableAndCheckable> a = provide_obj();
+  {
+    auto* b = a.get();
+    b->method();
+  }
+}
+
+void local_var_with_guardian_checked_ptr_with_assignment() {
+  RefPtr<RefCountableAndCheckable> a = provide_obj();
+  {
+    RefCountableAndCheckable* b = a.get();
+    // expected-warning@-1{{Local variable 'b' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    b = provide_obj();
+    b->method();
+  }
+}
+
+void local_var_with_guardian_checked_ref() {
+  Ref<RefCountableAndCheckable> a = *provide_obj();
+  {
+    RefCountableAndCheckable& b = a;
+    b.method();
+  }
+}
+
+void static_var() {
+  static RefCountableAndCheckable* a = nullptr;
+  // expected-warning@-1{{Static local variable 'a' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+  a = provide_obj();
+}
+
+} // namespace local_refcountable_checkable_object
diff --git a/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/BUILD.gn b/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/BUILD.gn
index 7a6c360e88c14e..65600992e702d0 100644
--- a/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/BUILD.gn
+++ b/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/...
[truncated]

@rniwa rniwa requested a review from t-rasmud October 25, 2024 16:29
Copy link

github-actions bot commented Oct 25, 2024

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

a = provide_obj();
}

} // namespace local_refcountable_checkable_object
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we expect a similar warning for assignments to struct members or class fields?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, struct members and class fields are checked by NoUncountedMemberChecker / NoUncheckedPtrMemberChecker.

Copy link
Contributor

@t-rasmud t-rasmud left a comment

Choose a reason for hiding this comment

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

LGTM!

@rniwa
Copy link
Contributor Author

rniwa commented Nov 1, 2024

LGTM!

Thanks for the review!

@rniwa rniwa merged commit 61a6439 into llvm:main Nov 1, 2024
9 checks passed
@rniwa rniwa deleted the unchecked-local-vars-checker branch November 1, 2024 06:53
@llvm-ci
Copy link
Collaborator

llvm-ci commented Nov 1, 2024

LLVM Buildbot has detected a new failure on builder clang-m68k-linux-cross running on suse-gary-m68k-cross while building clang,llvm at step 5 "ninja check 1".

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

Here is the relevant piece of the build log for the reference
Step 5 (ninja check 1) failure: stage 1 checked (failure)
...
[290/1135] Building CXX object tools/clang/unittests/AST/CMakeFiles/ASTTests.dir/ASTImporterODRStrategiesTest.cpp.o
[291/1135] Building CXX object tools/clang/unittests/ASTMatchers/CMakeFiles/ASTMatchersTests.dir/ASTMatchersNodeTest.cpp.o
[292/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/CastExprTest.cpp.o
[293/1135] Building CXX object tools/clang/unittests/AST/CMakeFiles/ASTTests.dir/StructuralEquivalenceTest.cpp.o
[294/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/ASTSelectionTest.cpp.o
[295/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/CommentHandlerTest.cpp.o
[296/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/DependencyScanning/DependencyScanningFilesystemTest.cpp.o
[297/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/ExecutionTest.cpp.o
[298/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/LexicallyOrderedRecursiveASTVisitorTest.cpp.o
[299/1135] Building CXX object tools/clang/unittests/AST/CMakeFiles/ASTTests.dir/ASTImporterTest.cpp.o
FAILED: tools/clang/unittests/AST/CMakeFiles/ASTTests.dir/ASTImporterTest.cpp.o 
/usr/bin/c++ -DGTEST_HAS_RTTI=0 -DLLVM_BUILD_STATIC -D_DEBUG -D_GLIBCXX_ASSERTIONS -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/tools/clang/unittests/AST -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/unittests/AST -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/tools/clang/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/llvm/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/third-party/unittest/googletest/include -I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/third-party/unittest/googlemock/include -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -fno-lifetime-dse -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wno-missing-field-initializers -pedantic -Wno-long-long -Wimplicit-fallthrough -Wno-maybe-uninitialized -Wno-nonnull -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wdelete-non-virtual-dtor -Wsuggest-override -Wno-comment -Wno-misleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -fno-common -Woverloaded-virtual -fno-strict-aliasing -O3 -DNDEBUG -std=c++17  -Wno-variadic-macros -fno-exceptions -funwind-tables -fno-rtti -UNDEBUG -Wno-suggest-override -MD -MT tools/clang/unittests/AST/CMakeFiles/ASTTests.dir/ASTImporterTest.cpp.o -MF tools/clang/unittests/AST/CMakeFiles/ASTTests.dir/ASTImporterTest.cpp.o.d -o tools/clang/unittests/AST/CMakeFiles/ASTTests.dir/ASTImporterTest.cpp.o -c /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/unittests/AST/ASTImporterTest.cpp
c++: fatal error: Killed signal terminated program cc1plus
compilation terminated.
[300/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/DependencyScanning/DependencyScannerTest.cpp.o
In file included from /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/include/clang/Serialization/ASTReader.h:30,
                 from /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h:19,
                 from /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h:17,
                 from /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h:13,
                 from /var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/unittests/Tooling/DependencyScanning/DependencyScannerTest.cpp:17:
/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/include/clang/Sema/Sema.h:463:7: warning: ‘clang::Sema’ declared with greater visibility than the type of its field ‘clang::Sema::UnusedFileScopedDecls’ [-Wattributes]
  463 | class Sema final : public SemaBase {
      |       ^~~~
/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/include/clang/Sema/Sema.h:463:7: warning: ‘clang::Sema’ declared with greater visibility than the type of its field ‘clang::Sema::TentativeDefinitions’ [-Wattributes]
/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/include/clang/Sema/Sema.h:463:7: warning: ‘clang::Sema’ declared with greater visibility than the type of its field ‘clang::Sema::ExtVectorDecls’ [-Wattributes]
/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/include/clang/Sema/Sema.h:463:7: warning: ‘clang::Sema’ declared with greater visibility than the type of its field ‘clang::Sema::DelegatingCtorDecls’ [-Wattributes]
[301/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/RecursiveASTVisitorTests/Class.cpp.o
[302/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/RecursiveASTVisitorTests/ImplicitCtorInitializer.cpp.o
[303/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/RecursiveASTVisitorTests/LambdaDefaultCapture.cpp.o
[304/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/RecursiveASTVisitorTests/CXXOperatorCallExprTraverser.cpp.o
[305/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/LookupTest.cpp.o
[306/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/RecursiveASTVisitorTests/InitListExprPostOrder.cpp.o
[307/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/RecursiveASTVisitorTests/LambdaTemplateParams.cpp.o
[308/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/RecursiveASTVisitorTests/IntegerLiteral.cpp.o
[309/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/RecursiveASTVisitorTests/DeductionGuide.cpp.o
[310/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/RecursiveASTVisitorTests/InitListExprPreOrderNoQueue.cpp.o
[311/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/RangeSelectorTest.cpp.o
[312/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/QualTypeNamesTest.cpp.o
[313/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/RecursiveASTVisitorTests/CXXBoolLiteralExpr.cpp.o
[314/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/RecursiveASTVisitorTests/LambdaExpr.cpp.o
[315/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/RecursiveASTVisitorTests/Attr.cpp.o
[316/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/RecursiveASTVisitorTests/CXXMethodDecl.cpp.o
[317/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/RecursiveASTVisitorTests/DeclRefExpr.cpp.o
[318/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/RecursiveASTVisitorTests/BitfieldInitializer.cpp.o
[319/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/RecursiveASTVisitorTests/CallbacksCallExpr.cpp.o
[320/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/RecursiveASTVisitorTests/ConstructExpr.cpp.o
[321/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/RecursiveASTVisitorTests/ImplicitCtor.cpp.o
[322/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/RecursiveASTVisitorTests/CXXMemberCall.cpp.o
[323/1135] Building CXX object tools/clang/unittests/Tooling/CMakeFiles/ToolingTests.dir/RecursiveASTVisitorTests/InitListExprPostOrderNoQueue.cpp.o

@llvm-ci
Copy link
Collaborator

llvm-ci commented Nov 1, 2024

LLVM Buildbot has detected a new failure on builder sanitizer-x86_64-linux running on sanitizer-buildbot1 while building clang,llvm at step 2 "annotate".

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

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-x86_64-linux/build/llvm-project/compiler-rt/test/lit.common.cfg.py:246: warning: COMPILER_RT_TEST_STANDALONE_BUILD_LIBS=ON, but this test suite does not support testing the just-built runtime libraries when the test compiler is configured to use different runtime libraries. Either modify this test suite to support this test configuration, or set COMPILER_RT_TEST_STANDALONE_BUILD_LIBS=OFF to test the runtime libraries included in the compiler instead.
llvm-lit: /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/lit.common.cfg.py:257: note: Testing using libraries in "/home/b/sanitizer-x86_64-linux/build/build_default/./lib/../lib/clang/20/lib/i386-unknown-linux-gnu"
llvm-lit: /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/lit.common.cfg.py:235: warning: Compiler lib dir != compiler-rt lib dir
Compiler libdir:     "/home/b/sanitizer-x86_64-linux/build/build_default/lib/clang/20/lib/i386-unknown-linux-gnu"
compiler-rt libdir:  "/home/b/sanitizer-x86_64-linux/build/build_default/lib/clang/20/lib/x86_64-unknown-linux-gnu"
llvm-lit: /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/lit.common.cfg.py:246: warning: COMPILER_RT_TEST_STANDALONE_BUILD_LIBS=ON, but this test suite does not support testing the just-built runtime libraries when the test compiler is configured to use different runtime libraries. Either modify this test suite to support this test configuration, or set COMPILER_RT_TEST_STANDALONE_BUILD_LIBS=OFF to test the runtime libraries included in the compiler instead.
llvm-lit: /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/lit.common.cfg.py:257: note: Testing using libraries in "/home/b/sanitizer-x86_64-linux/build/build_default/./lib/../lib/clang/20/lib/x86_64-unknown-linux-gnu"
llvm-lit: /home/b/sanitizer-x86_64-linux/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 900 seconds was requested on the command line. Forcing timeout to be 900 seconds.
-- Testing: 4720 of 10477 tests, 88 workers --
Testing:  0.. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90
FAIL: libFuzzer-x86_64-default-Linux :: reduce_inputs.test (4374 of 4720)
******************** TEST 'libFuzzer-x86_64-default-Linux :: reduce_inputs.test' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
RUN: at line 3: rm -rf /home/b/sanitizer-x86_64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp/C
+ rm -rf /home/b/sanitizer-x86_64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp/C
RUN: at line 4: mkdir -p /home/b/sanitizer-x86_64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp/C
+ mkdir -p /home/b/sanitizer-x86_64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp/C
RUN: at line 5: /home/b/sanitizer-x86_64-linux/build/build_default/./bin/clang    -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta   --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/lib/fuzzer -m64 /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/fuzzer/ShrinkControlFlowSimpleTest.cpp -o /home/b/sanitizer-x86_64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest
+ /home/b/sanitizer-x86_64-linux/build/build_default/./bin/clang -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/lib/fuzzer -m64 /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/fuzzer/ShrinkControlFlowSimpleTest.cpp -o /home/b/sanitizer-x86_64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest
RUN: at line 6: /home/b/sanitizer-x86_64-linux/build/build_default/./bin/clang    -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta   --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/lib/fuzzer -m64 /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/fuzzer/ShrinkControlFlowTest.cpp -o /home/b/sanitizer-x86_64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowTest
+ /home/b/sanitizer-x86_64-linux/build/build_default/./bin/clang -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/lib/fuzzer -m64 /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/fuzzer/ShrinkControlFlowTest.cpp -o /home/b/sanitizer-x86_64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowTest
RUN: at line 7: /home/b/sanitizer-x86_64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest  -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60   -runs=1000000 /home/b/sanitizer-x86_64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp/C 2>&1 | FileCheck /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test
+ FileCheck /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test
+ /home/b/sanitizer-x86_64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60 -runs=1000000 /home/b/sanitizer-x86_64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp/C
/home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test:8:8: error: CHECK: expected string not found in input
CHECK: INFO: found item with checksum '0eb8e4ed029b774d80f2b66408203801cb982a60'
       ^
<stdin>:1:1: note: scanning from here
INFO: Running with entropic power schedule (0xFF, 100).
^

Input file: <stdin>
Check file: /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test

-dump-input=help explains the following input dump.

Input was:
<<<<<<
         1: INFO: Running with entropic power schedule (0xFF, 100). 
check:8     X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: no match found
         2: INFO: Seed: 3546511603 
check:8     ~~~~~~~~~~~~~~~~~~~~~~~
         3: INFO: Loaded 1 modules (6 inline 8-bit counters): 6 [0x5b2169520048, 0x5b216952004e),  
check:8     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         4: INFO: Loaded 1 PC tables (6 PCs): 6 [0x5b2169520050,0x5b21695200b0),  
check:8     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Step 11 (test compiler-rt debug) failure: test compiler-rt debug (failure)
...
llvm-lit: /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/lit.common.cfg.py:246: warning: COMPILER_RT_TEST_STANDALONE_BUILD_LIBS=ON, but this test suite does not support testing the just-built runtime libraries when the test compiler is configured to use different runtime libraries. Either modify this test suite to support this test configuration, or set COMPILER_RT_TEST_STANDALONE_BUILD_LIBS=OFF to test the runtime libraries included in the compiler instead.
llvm-lit: /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/lit.common.cfg.py:257: note: Testing using libraries in "/home/b/sanitizer-x86_64-linux/build/build_default/./lib/../lib/clang/20/lib/i386-unknown-linux-gnu"
llvm-lit: /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/lit.common.cfg.py:235: warning: Compiler lib dir != compiler-rt lib dir
Compiler libdir:     "/home/b/sanitizer-x86_64-linux/build/build_default/lib/clang/20/lib/i386-unknown-linux-gnu"
compiler-rt libdir:  "/home/b/sanitizer-x86_64-linux/build/build_default/lib/clang/20/lib/x86_64-unknown-linux-gnu"
llvm-lit: /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/lit.common.cfg.py:246: warning: COMPILER_RT_TEST_STANDALONE_BUILD_LIBS=ON, but this test suite does not support testing the just-built runtime libraries when the test compiler is configured to use different runtime libraries. Either modify this test suite to support this test configuration, or set COMPILER_RT_TEST_STANDALONE_BUILD_LIBS=OFF to test the runtime libraries included in the compiler instead.
llvm-lit: /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/lit.common.cfg.py:257: note: Testing using libraries in "/home/b/sanitizer-x86_64-linux/build/build_default/./lib/../lib/clang/20/lib/x86_64-unknown-linux-gnu"
llvm-lit: /home/b/sanitizer-x86_64-linux/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 900 seconds was requested on the command line. Forcing timeout to be 900 seconds.
-- Testing: 4720 of 10477 tests, 88 workers --
Testing:  0.. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90
FAIL: libFuzzer-x86_64-default-Linux :: reduce_inputs.test (4374 of 4720)
******************** TEST 'libFuzzer-x86_64-default-Linux :: reduce_inputs.test' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
RUN: at line 3: rm -rf /home/b/sanitizer-x86_64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp/C
+ rm -rf /home/b/sanitizer-x86_64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp/C
RUN: at line 4: mkdir -p /home/b/sanitizer-x86_64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp/C
+ mkdir -p /home/b/sanitizer-x86_64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp/C
RUN: at line 5: /home/b/sanitizer-x86_64-linux/build/build_default/./bin/clang    -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta   --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/lib/fuzzer -m64 /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/fuzzer/ShrinkControlFlowSimpleTest.cpp -o /home/b/sanitizer-x86_64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest
+ /home/b/sanitizer-x86_64-linux/build/build_default/./bin/clang -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/lib/fuzzer -m64 /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/fuzzer/ShrinkControlFlowSimpleTest.cpp -o /home/b/sanitizer-x86_64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest
RUN: at line 6: /home/b/sanitizer-x86_64-linux/build/build_default/./bin/clang    -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta   --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/lib/fuzzer -m64 /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/fuzzer/ShrinkControlFlowTest.cpp -o /home/b/sanitizer-x86_64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowTest
+ /home/b/sanitizer-x86_64-linux/build/build_default/./bin/clang -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/lib/fuzzer -m64 /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/fuzzer/ShrinkControlFlowTest.cpp -o /home/b/sanitizer-x86_64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowTest
RUN: at line 7: /home/b/sanitizer-x86_64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest  -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60   -runs=1000000 /home/b/sanitizer-x86_64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp/C 2>&1 | FileCheck /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test
+ FileCheck /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test
+ /home/b/sanitizer-x86_64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60 -runs=1000000 /home/b/sanitizer-x86_64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp/C
/home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test:8:8: error: CHECK: expected string not found in input
CHECK: INFO: found item with checksum '0eb8e4ed029b774d80f2b66408203801cb982a60'
       ^
<stdin>:1:1: note: scanning from here
INFO: Running with entropic power schedule (0xFF, 100).
^

Input file: <stdin>
Check file: /home/b/sanitizer-x86_64-linux/build/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test

-dump-input=help explains the following input dump.

Input was:
<<<<<<
         1: INFO: Running with entropic power schedule (0xFF, 100). 
check:8     X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: no match found
         2: INFO: Seed: 3546511603 
check:8     ~~~~~~~~~~~~~~~~~~~~~~~
         3: INFO: Loaded 1 modules (6 inline 8-bit counters): 6 [0x5b2169520048, 0x5b216952004e),  
check:8     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         4: INFO: Loaded 1 PC tables (6 PCs): 6 [0x5b2169520050,0x5b21695200b0),  
check:8     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

rniwa added a commit to rniwa/llvm-project that referenced this pull request Nov 1, 2024
…13708)

This PR introduces alpha.webkit.UncheckedCallArgsChecker which detects a function argument
which is a raw reference or a raw pointer to a CheckedPtr capable object.
smallp-o-p pushed a commit to smallp-o-p/llvm-project that referenced this pull request Nov 3, 2024
…13708)

This PR introduces alpha.webkit.UncheckedLocalVarsChecker which detects
a raw reference or a raw pointer local, static, or global variable to a
CheckedPtr capable object without a guardian variable in an outer scope.
NoumanAmir657 pushed a commit to NoumanAmir657/llvm-project that referenced this pull request Nov 4, 2024
…13708)

This PR introduces alpha.webkit.UncheckedLocalVarsChecker which detects
a raw reference or a raw pointer local, static, or global variable to a
CheckedPtr capable object without a guardian variable in an outer scope.
rniwa added a commit that referenced this pull request Nov 7, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
… (#114522)

This PR introduces alpha.webkit.UncheckedCallArgsChecker which detects a
function argument which is a raw reference or a raw pointer to a
CheckedPtr capable object.
Groverkss pushed a commit to iree-org/llvm-project that referenced this pull request Nov 15, 2024

Verified

This commit was signed with the committer’s verified signature.
Groverkss Kunwar Grover
…13708) (llvm#114522)

This PR introduces alpha.webkit.UncheckedCallArgsChecker which detects a
function argument which is a raw reference or a raw pointer to a
CheckedPtr capable object.
rniwa added a commit to rniwa/llvm-project that referenced this pull request Feb 3, 2025
…13708)

This PR introduces alpha.webkit.UncheckedLocalVarsChecker which detects
a raw reference or a raw pointer local, static, or global variable to a
CheckedPtr capable object without a guardian variable in an outer scope.
rniwa added a commit to rniwa/llvm-project that referenced this pull request Feb 3, 2025
…13708) (llvm#114522)

This PR introduces alpha.webkit.UncheckedCallArgsChecker which detects a
function argument which is a raw reference or a raw pointer to a
CheckedPtr capable object.
devincoughlin pushed a commit to swiftlang/llvm-project that referenced this pull request Feb 25, 2025
…13708)

This PR introduces alpha.webkit.UncheckedLocalVarsChecker which detects
a raw reference or a raw pointer local, static, or global variable to a
CheckedPtr capable object without a guardian variable in an outer scope.
devincoughlin pushed a commit to swiftlang/llvm-project that referenced this pull request Feb 25, 2025
…13708) (llvm#114522)

This PR introduces alpha.webkit.UncheckedCallArgsChecker which detects a
function argument which is a raw reference or a raw pointer to a
CheckedPtr capable object.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:static analyzer clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants