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.
343 lines
8.4 KiB
C++
343 lines
8.4 KiB
C++
// 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
|