-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[analyzer] Make it a noop when initializing a field of empty record #138594
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
Conversation
…cord. Previously, Static Analyzer initializes empty type fields with zeroes. This can cause problems when those fields have no unique addresses. For example, llvm#137252. rdar://146753089
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-static-analyzer-1 Author: Ziqing Luo (ziqingluo-90) ChangesPreviously, Static Analyzer initializes empty type fields with zeroes. This can cause problems when those fields have no unique addresses. For example, #137252. rdar://146753089 Full diff: https://github.com/llvm/llvm-project/pull/138594.diff 2 Files Affected:
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 92ce3fa2225c8..219d7b4d2278c 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/ASTContext.h"
#include "clang/AST/AttrIterator.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ParentMap.h"
@@ -700,6 +701,7 @@ void ExprEngine::handleConstructor(const Expr *E,
if (CE) {
// FIXME: Is it possible and/or useful to do this before PreStmt?
StmtNodeBuilder Bldr(DstPreVisit, PreInitialized, *currBldrCtx);
+ ASTContext &Ctx = LCtx->getAnalysisDeclContext()->getASTContext();
for (ExplodedNode *N : DstPreVisit) {
ProgramStateRef State = N->getState();
if (CE->requiresZeroInitialization()) {
@@ -715,7 +717,11 @@ void ExprEngine::handleConstructor(const Expr *E,
// actually make things worse. Placement new makes this tricky as well,
// since it's then possible to be initializing one part of a multi-
// dimensional array.
- State = State->bindDefaultZero(Target, LCtx);
+ const CXXRecordDecl *TargetHeldRecord =
+ Target.getType(Ctx)->getPointeeCXXRecordDecl();
+
+ if (!TargetHeldRecord || !TargetHeldRecord->isEmpty())
+ State = State->bindDefaultZero(Target, LCtx);
}
Bldr.generateNode(CE, N, State, /*tag=*/nullptr,
diff --git a/clang/test/Analysis/issue-137252.cpp b/clang/test/Analysis/issue-137252.cpp
new file mode 100644
index 0000000000000..8064e3f54d9fd
--- /dev/null
+++ b/clang/test/Analysis/issue-137252.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus -verify %s -DEMPTY_CLASS
+
+// expected-no-diagnostics
+
+// This test reproduces the issue that previously the static analyzer
+// initialized an [[__no_unique_address__]] empty field to zero,
+// over-writing a non-empty field with the same offset.
+
+namespace std {
+#ifdef EMPTY_CLASS
+
+ template <typename T>
+ class default_delete {
+ T dump();
+ static T x;
+ };
+ template <class _Tp, class _Dp = default_delete<_Tp> >
+#else
+
+ struct default_delete {};
+ template <class _Tp, class _Dp = default_delete >
+#endif
+ class unique_ptr {
+ [[__no_unique_address__]] _Tp * __ptr_;
+ [[__no_unique_address__]] _Dp __deleter_;
+
+ public:
+ explicit unique_ptr(_Tp* __p) noexcept
+ : __ptr_(__p),
+ __deleter_() {}
+
+ ~unique_ptr() {
+ delete __ptr_;
+ }
+ };
+}
+
+struct X {};
+
+int main()
+{
+ std::unique_ptr<X> a(new X()); // previously leak falsely reported
+ return 0;
+}
|
CC: @dtarditi |
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.
LGTM
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.
Thank you for your contribution, and debugging the case.
Left a couple of comments inline.
LGTM. @ziqingluo-90 thank you for fixing this problem! |
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.
Indeed, it looks great now. Thank you!
Let's merge this.
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/144/builds/24534 Here is the relevant piece of the build log for the reference
|
Sorry for the post-merge comment, but can we please wait for the CI to finish before merging a patch, so that we can check if everything is fine? Apparently, we broke the trunk. |
const CXXRecordDecl *TargetHeldRecord = | ||
cast<CXXRecordDecl>(CE->getType()->getAsRecordDecl()); |
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.
This cast can actually fail. See the broken testcase:
llvm-project/llvm/include/llvm/Support/Casting.h:109: static bool llvm::isa_impl_cl<To, const From*>::doit(const From*) [with To = clang::CXXRecordDecl; From = clang::RecordDecl]: Assertion `Val && "isa<> used on a null pointer"' failed.
It happened in an Objective-C test though.
struct raw_pair {
int p1;
int p2;
};
void testArrayNew() {
raw_pair *p = new raw_pair[2]();
clang_analyzer_eval(p[0].p1 == 0); // expected-warning{{TRUE}}
clang_analyzer_eval(p[0].p2 == 0); // expected-warning{{TRUE}}
clang_analyzer_eval(p[1].p1 == 0); // expected-warning{{TRUE}}
clang_analyzer_eval(p[1].p2 == 0); // expected-warning{{TRUE}}
}
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.
Thanks for the heads up. I re-landed the commit: b756c82
…record" (#138951) Reverts #138594 Crashes, see: https://lab.llvm.org/buildbot/#/builders/144/builds/24534
…d of empty record" (#138951) Reverts llvm/llvm-project#138594 Crashes, see: https://lab.llvm.org/buildbot/#/builders/144/builds/24534
Re-landed: b756c82 |
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/60/builds/26748 Here is the relevant piece of the build log for the reference
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/56/builds/25255 Here is the relevant piece of the build log for the reference
|
…lvm#138594) Previously, Static Analyzer initializes empty type fields with zeroes. This can cause problems when those fields have no unique addresses. For example, llvm#137252. rdar://146753089
Previously, Static Analyzer initializes empty type fields with zeroes. This can cause problems when those fields have no unique addresses. For example, #137252.
rdar://146753089