-
Notifications
You must be signed in to change notification settings - Fork 13.4k
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
+448
−17
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
342 changes: 342 additions & 0 deletions
342
clang/test/Analysis/Checkers/WebKit/unchecked-local-vars.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
.