]> granicus.if.org Git - clang/commitdiff
Stop tracking retain count of OSObject after escape to void * / other primitive types
authorGeorge Karpenkov <ekarpenkov@apple.com>
Sat, 8 Dec 2018 01:18:40 +0000 (01:18 +0000)
committerGeorge Karpenkov <ekarpenkov@apple.com>
Sat, 8 Dec 2018 01:18:40 +0000 (01:18 +0000)
Escaping to void * / uint64_t / others non-OSObject * should stop tracking,
as such functions can have heterogeneous semantics depending on context,
and can not always be annotated.

rdar://46439133

Differential Revision: https://reviews.llvm.org/D55465

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@348675 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
test/Analysis/osobject-retain-release.cpp

index 02c482e6196f14a8e1d9c2901696432f23947fe9..8d0d407eab83d66dac73d959e5112dfa2aebe235 100644 (file)
@@ -574,6 +574,25 @@ static ProgramStateRef updateOutParameter(ProgramStateRef State,
   return State;
 }
 
+static bool isPointerToObject(QualType QT) {
+  QualType PT = QT->getPointeeType();
+  if (!PT.isNull())
+    if (PT->getAsCXXRecordDecl())
+      return true;
+  return false;
+}
+
+/// Whether the tracked value should be escaped on a given call.
+/// OSObjects are escaped when passed to void * / etc.
+static bool shouldEscapeArgumentOnCall(const CallEvent &CE, unsigned ArgIdx,
+                                       const RefVal *TrackedValue) {
+  if (TrackedValue->getObjKind() != RetEffect::OS)
+    return false;
+  if (ArgIdx >= CE.parameters().size())
+    return false;
+  return !isPointerToObject(CE.parameters()[ArgIdx]->getType());
+}
+
 void RetainCountChecker::checkSummary(const RetainSummary &Summ,
                                       const CallEvent &CallOrMsg,
                                       CheckerContext &C) const {
@@ -592,6 +611,10 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
       state = updateOutParameter(state, V, Effect);
     } else if (SymbolRef Sym = V.getAsLocSymbol()) {
       if (const RefVal *T = getRefBinding(state, Sym)) {
+
+        if (shouldEscapeArgumentOnCall(CallOrMsg, idx, T))
+          Effect = StopTrackingHard;
+
         state = updateSymbol(state, Sym, *T, Effect, hasErr, C);
         if (hasErr) {
           ErrorRange = CallOrMsg.getArgSourceRange(idx);
index 9c8bd78726a4280d912bc9a83dfe1a3b14355564..68529e9e972c09b1541fb3996dc6352e87cdf714 100644 (file)
@@ -89,6 +89,13 @@ struct OSMetaClassBase {
   static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta);
 };
 
+void escape(void *);
+
+void test_escaping_into_voidstar() {
+  OSObject *obj = new OSObject;
+  escape(obj);
+}
+
 void test_no_infinite_check_recursion(MyArray *arr) {
   OSObject *input = new OSObject;
   OSObject *o = arr->generateObject(input);