-
Notifications
You must be signed in to change notification settings - Fork 15k
[clang][analyzer] CallAndMessage warnings at pointer to uninitialized struct #164600
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
base: main
Are you sure you want to change the base?
Conversation
… struct CallAndMessageChecker did have a warning for the case when pointer to uninitialized data is passed to a function when the argument type is pointer to const. This did not work for struct types. The check is improved to handle cases when struct with uninitialized data is passed to a function.
|
@llvm/pr-subscribers-clang-static-analyzer-1 Author: Balázs Kéri (balazske) Changes
Full diff: https://github.com/llvm/llvm-project/pull/164600.diff 3 Files Affected:
diff --git a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 7cc146ed29d0d..cd24b1e816e01 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -183,8 +183,6 @@ bool CallAndMessageChecker::uninitRefOrPointer(
CheckerContext &C, SVal V, SourceRange ArgRange, const Expr *ArgEx,
const BugType &BT, const ParmVarDecl *ParamDecl, int ArgumentNumber) const {
- // The pointee being uninitialized is a sign of code smell, not a bug, no need
- // to sink here.
if (!ChecksEnabled[CK_ArgPointeeInitializedness])
return false;
@@ -212,8 +210,14 @@ bool CallAndMessageChecker::uninitRefOrPointer(
if (const MemRegion *SValMemRegion = V.getAsRegion()) {
const ProgramStateRef State = C.getState();
- const SVal PSV = State->getSVal(SValMemRegion, C.getASTContext().CharTy);
- if (PSV.isUndef()) {
+ QualType T = ParamDecl->getType()->getPointeeType();
+ if (T->isVoidType())
+ T = C.getASTContext().CharTy;
+ const SVal PSV = State->getSVal(SValMemRegion, T);
+ bool IsUndef = PSV.isUndef();
+ if (auto LCV = PSV.getAs<nonloc::LazyCompoundVal>())
+ IsUndef = LCV->getStore() == nullptr;
+ if (IsUndef) {
if (ExplodedNode *N = C.generateErrorNode()) {
auto R = std::make_unique<PathSensitiveBugReport>(BT, Os.str(), N);
R->addRange(ArgRange);
diff --git a/clang/test/Analysis/PR40625.cpp b/clang/test/Analysis/PR40625.cpp
index 5ebe2122945e6..ab3faa328298a 100644
--- a/clang/test/Analysis/PR40625.cpp
+++ b/clang/test/Analysis/PR40625.cpp
@@ -5,11 +5,11 @@
void f(const int *end);
void g(const int (&arrr)[10]) {
- f(arrr); // expected-warning{{1st function call argument is a pointer to uninitialized value}}
+ f(arrr);
}
void h() {
int arr[10];
- g(arr);
+ g(arr); // expected-warning{{1st function call argument is an uninitialized value}}
}
diff --git a/clang/test/Analysis/call-and-message.c b/clang/test/Analysis/call-and-message.c
index ade51145e2a93..fdac77176569b 100644
--- a/clang/test/Analysis/call-and-message.c
+++ b/clang/test/Analysis/call-and-message.c
@@ -24,6 +24,18 @@ void pointee_uninit(void) {
doStuff_pointerToConstInt(p); // expected-warning{{1st function call argument is a pointer to uninitialized value [core.CallAndMessage]}}
}
+typedef struct S {
+ int a;
+ short b;
+} S;
+
+void doStuff_pointerToConstStruct(const S *s){};
+void pointee_uninit_struct(void) {
+ S s;
+ S *p = &s;
+ doStuff_pointerToConstStruct(p); // expected-warning{{1st function call argument is a pointer to uninitialized value [core.CallAndMessage]}}
+}
+
// TODO: If this hash ever changes, turn
// core.CallAndMessage:ArgPointeeInitializedness from a checker option into a
// checker, as described in the CallAndMessage comments!
|
|
@llvm/pr-subscribers-clang Author: Balázs Kéri (balazske) Changes
Full diff: https://github.com/llvm/llvm-project/pull/164600.diff 3 Files Affected:
diff --git a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 7cc146ed29d0d..cd24b1e816e01 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -183,8 +183,6 @@ bool CallAndMessageChecker::uninitRefOrPointer(
CheckerContext &C, SVal V, SourceRange ArgRange, const Expr *ArgEx,
const BugType &BT, const ParmVarDecl *ParamDecl, int ArgumentNumber) const {
- // The pointee being uninitialized is a sign of code smell, not a bug, no need
- // to sink here.
if (!ChecksEnabled[CK_ArgPointeeInitializedness])
return false;
@@ -212,8 +210,14 @@ bool CallAndMessageChecker::uninitRefOrPointer(
if (const MemRegion *SValMemRegion = V.getAsRegion()) {
const ProgramStateRef State = C.getState();
- const SVal PSV = State->getSVal(SValMemRegion, C.getASTContext().CharTy);
- if (PSV.isUndef()) {
+ QualType T = ParamDecl->getType()->getPointeeType();
+ if (T->isVoidType())
+ T = C.getASTContext().CharTy;
+ const SVal PSV = State->getSVal(SValMemRegion, T);
+ bool IsUndef = PSV.isUndef();
+ if (auto LCV = PSV.getAs<nonloc::LazyCompoundVal>())
+ IsUndef = LCV->getStore() == nullptr;
+ if (IsUndef) {
if (ExplodedNode *N = C.generateErrorNode()) {
auto R = std::make_unique<PathSensitiveBugReport>(BT, Os.str(), N);
R->addRange(ArgRange);
diff --git a/clang/test/Analysis/PR40625.cpp b/clang/test/Analysis/PR40625.cpp
index 5ebe2122945e6..ab3faa328298a 100644
--- a/clang/test/Analysis/PR40625.cpp
+++ b/clang/test/Analysis/PR40625.cpp
@@ -5,11 +5,11 @@
void f(const int *end);
void g(const int (&arrr)[10]) {
- f(arrr); // expected-warning{{1st function call argument is a pointer to uninitialized value}}
+ f(arrr);
}
void h() {
int arr[10];
- g(arr);
+ g(arr); // expected-warning{{1st function call argument is an uninitialized value}}
}
diff --git a/clang/test/Analysis/call-and-message.c b/clang/test/Analysis/call-and-message.c
index ade51145e2a93..fdac77176569b 100644
--- a/clang/test/Analysis/call-and-message.c
+++ b/clang/test/Analysis/call-and-message.c
@@ -24,6 +24,18 @@ void pointee_uninit(void) {
doStuff_pointerToConstInt(p); // expected-warning{{1st function call argument is a pointer to uninitialized value [core.CallAndMessage]}}
}
+typedef struct S {
+ int a;
+ short b;
+} S;
+
+void doStuff_pointerToConstStruct(const S *s){};
+void pointee_uninit_struct(void) {
+ S s;
+ S *p = &s;
+ doStuff_pointerToConstStruct(p); // expected-warning{{1st function call argument is a pointer to uninitialized value [core.CallAndMessage]}}
+}
+
// TODO: If this hash ever changes, turn
// core.CallAndMessage:ArgPointeeInitializedness from a checker option into a
// checker, as described in the CallAndMessage comments!
|
|
Do we need more tests for this checker option (and in cpp mode)? |
| const SVal PSV = State->getSVal(SValMemRegion, T); | ||
| bool IsUndef = PSV.isUndef(); | ||
| if (auto LCV = PSV.getAs<nonloc::LazyCompoundVal>()) | ||
| IsUndef = LCV->getStore() == nullptr; |
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.
I did not find information about if this is the correct way of detecting that the value is not initialized.
| void pointee_uninit_struct(void) { | ||
| S s; | ||
| S *p = &s; | ||
| doStuff_pointerToConstStruct(p); // expected-warning{{1st function call argument is a pointer to uninitialized value [core.CallAndMessage]}} |
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 I understand it correctly that this testcase wouldn't pass without your change in the checker?
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.
I admit that my first impression is that "I don't know" -- I'm not familiar enough with the possible representations of undefined values in the analyzer to form an opinion about this PR. I could research this if it is really needed -- but perhaps @steakhal @haoNoQ or @Xazax-hun could say something wise more directly?
My first guess is that the old code should have been sufficient to detect whether the memory area is undefined -- and it is a bit sad that you need to write this more elaborate code. In general, I tend to notice a pattern that LazyCompoundVal is too opaque and its performance benefits come with lots of added code complexity as we always need to explicitly check for it. (However I don't know enough, perhaps this is still the least wrong approach.)
CallAndMessageCheckerdid have a warning for the case when pointer to uninitialized data is passed to a function when the argument type is pointer to const. This did not work for struct types. The check is improved to handle cases when struct with uninitialized data is passed to a function.