[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