summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Sema/SemaInit.cpp26
-rw-r--r--test/Analysis/inner-pointer.cpp3
-rw-r--r--test/Sema/warn-lifetime-analysis-nocfg.cpp65
3 files changed, 74 insertions, 20 deletions
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 693d759db2..44504971d8 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -6564,6 +6564,25 @@ template <typename T> static bool isRecordWithAttr(QualType Type) {
return false;
}
+static bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) {
+ if (auto *Conv = dyn_cast_or_null<CXXConversionDecl>(Callee))
+ if (isRecordWithAttr<PointerAttr>(Conv->getConversionType()))
+ return true;
+ if (!Callee->getParent()->isInStdNamespace() || !Callee->getIdentifier())
+ return false;
+ if (!isRecordWithAttr<PointerAttr>(Callee->getThisObjectType()) &&
+ !isRecordWithAttr<OwnerAttr>(Callee->getThisObjectType()))
+ return false;
+ if (!isRecordWithAttr<PointerAttr>(Callee->getReturnType()) &&
+ !Callee->getReturnType()->isPointerType())
+ return false;
+ return llvm::StringSwitch<bool>(Callee->getName())
+ .Cases("begin", "rbegin", "cbegin", "crbegin", true)
+ .Cases("end", "rend", "cend", "crend", true)
+ .Cases("c_str", "data", "get", true)
+ .Default(false);
+}
+
static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call,
LocalVisitor Visit) {
auto VisitPointerArg = [&](const Decl *D, Expr *Arg) {
@@ -6577,10 +6596,9 @@ static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call,
};
if (auto *MCE = dyn_cast<CXXMemberCallExpr>(Call)) {
- const FunctionDecl *Callee = MCE->getDirectCallee();
- if (auto *Conv = dyn_cast_or_null<CXXConversionDecl>(Callee))
- if (isRecordWithAttr<PointerAttr>(Conv->getConversionType()))
- VisitPointerArg(Callee, MCE->getImplicitObjectArgument());
+ const auto *MD = cast_or_null<CXXMethodDecl>(MCE->getDirectCallee());
+ if (MD && shouldTrackImplicitObjectArg(MD))
+ VisitPointerArg(MD, MCE->getImplicitObjectArgument());
return;
}
diff --git a/test/Analysis/inner-pointer.cpp b/test/Analysis/inner-pointer.cpp
index f4646c20fc..5cee0bfbcc 100644
--- a/test/Analysis/inner-pointer.cpp
+++ b/test/Analysis/inner-pointer.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.InnerPointer \
+// RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.InnerPointer \
+// RUN: -Wno-dangling -Wno-dangling-field -Wno-return-stack-address \
// RUN: %s -analyzer-output=text -verify
#include "Inputs/system-header-simulator-cxx.h"
diff --git a/test/Sema/warn-lifetime-analysis-nocfg.cpp b/test/Sema/warn-lifetime-analysis-nocfg.cpp
index bf5f94830f..89cf39a9ca 100644
--- a/test/Sema/warn-lifetime-analysis-nocfg.cpp
+++ b/test/Sema/warn-lifetime-analysis-nocfg.cpp
@@ -2,7 +2,6 @@
struct [[gsl::Owner(int)]] MyIntOwner {
MyIntOwner();
int &operator*();
- int *c_str() const;
};
struct [[gsl::Pointer(int)]] MyIntPointer {
@@ -52,16 +51,6 @@ long *ownershipTransferToRawPointer() {
return t.releaseAsRawPointer(); // ok
}
-int *danglingRawPtrFromLocal() {
- MyIntOwner t;
- return t.c_str(); // TODO
-}
-
-int *danglingRawPtrFromTemp() {
- MyIntPointer p;
- return p.toOwner().c_str(); // TODO
-}
-
struct Y {
int a[4];
};
@@ -103,6 +92,12 @@ MyIntPointer danglingGslPtrFromTemporary() {
return MyIntOwner{}; // expected-warning {{returning address of local temporary object}}
}
+MyIntOwner makeTempOwner();
+
+MyIntPointer danglingGslPtrFromTemporary2() {
+ return makeTempOwner(); // expected-warning {{returning address of local temporary object}}
+}
+
MyLongPointerFromConversion danglingGslPtrFromTemporaryConv() {
return MyLongOwnerWithConversion{}; // expected-warning {{returning address of local temporary object}}
}
@@ -124,12 +119,52 @@ void initLocalGslPtrWithTempOwner() {
global2 = MyLongOwnerWithConversion{}; // TODO ?
}
-struct IntVector {
- int *begin();
- int *end();
+namespace std {
+template <typename T>
+struct basic_iterator {};
+
+template <typename T>
+struct vector {
+ typedef basic_iterator<T> iterator;
+ iterator begin();
+ T *data();
+};
+
+template<typename T>
+struct basic_string {
+ const T *c_str() const;
+};
+
+template<typename T>
+struct unique_ptr {
+ T *get() const;
};
+}
void modelIterators() {
- int *it = IntVector{}.begin(); // TODO ?
+ std::vector<int>::iterator it = std::vector<int>().begin(); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
(void)it;
}
+
+std::vector<int>::iterator modelIteratorReturn() {
+ return std::vector<int>().begin(); // expected-warning {{returning address of local temporary object}}
+}
+
+const char *danglingRawPtrFromLocal() {
+ std::basic_string<char> s;
+ return s.c_str(); // expected-warning {{address of stack memory associated with local variable 's' returned}}
+}
+
+const char *danglingRawPtrFromTemp() {
+ return std::basic_string<char>().c_str(); // expected-warning {{returning address of local temporary object}}
+}
+
+std::unique_ptr<int> getUniquePtr();
+
+int *danglingUniquePtrFromTemp() {
+ return getUniquePtr().get(); // expected-warning {{returning address of local temporary object}}
+}
+
+int *danglingUniquePtrFromTemp2() {
+ return std::unique_ptr<int>().get(); // expected-warning {{returning address of local temporary object}}
+}