[clang] [llvm] Introduce a new WebKit checker for a unchecked local variable (PR #113708)

Ryosuke Niwa via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 31 15:37:30 PDT 2024


================
@@ -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 at -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 at -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 at -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 at -1{{Local variable 'bar' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    auto *baz = provide_ref_ctnbl();
+    // expected-warning at -1{{Local variable 'baz' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    auto *baz2 = this->provide_ref_ctnbl();
+    // expected-warning at -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 at -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 at -1{{Local variable 'a' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    a->method();    
+  }
+  for (CheckedObj *b = provide_ref_ctnbl(); b != nullptr;) {
+    // expected-warning at -1{{Local variable 'b' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    b->method();
+  }
+  CheckedObj *array[1];
+  for (CheckedObj *c : array) {
+    // expected-warning at -1{{Local variable 'c' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    c->method();
+  }
+
+  while (CheckedObj *d = provide_ref_ctnbl()) {
+    // expected-warning at -1{{Local variable 'd' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+    d->method();
+  }
+  do {
+    CheckedObj *e = provide_ref_ctnbl();
+    // expected-warning at -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 at -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 at -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 at -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 at -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 at -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 at -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 at -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 at -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 at -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 at -1{{Static local variable 'a' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
+  a = provide_obj();
+}
+
+} // namespace local_refcountable_checkable_object
----------------
rniwa wrote:

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

https://github.com/llvm/llvm-project/pull/113708


More information about the llvm-commits mailing list