From b79d862af66d8dd9d059863813b9a27d744bd990 Mon Sep 17 00:00:00 2001 From: Anna Zaks Date: Thu, 3 May 2012 23:50:33 +0000 Subject: [PATCH] [analyzer] Assume pointer escapes when a callback is passed inside a struct. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@156135 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/StaticAnalyzer/Core/ObjCMessage.cpp | 24 +++++++++++++++++++++--- test/Analysis/malloc.c | 10 ++++++++++ test/Analysis/system-header-simulator.h | 9 +++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/lib/StaticAnalyzer/Core/ObjCMessage.cpp b/lib/StaticAnalyzer/Core/ObjCMessage.cpp index dc24e818ff..0c6d8a8b63 100644 --- a/lib/StaticAnalyzer/Core/ObjCMessage.cpp +++ b/lib/StaticAnalyzer/Core/ObjCMessage.cpp @@ -89,10 +89,28 @@ const Decl *CallOrObjCMessage::getDecl() const { } bool CallOrObjCMessage::isCallbackArg(unsigned Idx, const Type *T) const { - // Should we dig into struct fields, arrays ect? + // If the parameter is 0, it's harmless. + if (getArgSVal(Idx).isZeroConstant()) + return false; + + // If a parameter is a block or a callback, assume it can modify pointer. if (T->isBlockPointerType() || T->isFunctionPointerType()) - if (!getArgSVal(Idx).isZeroConstant()) - return true; + return true; + + // Check if a callback is passed inside a struct (for both, struct passed by + // reference and by value). Dig just one level into the struct for now. + if (const PointerType *PT = dyn_cast(T)) + T = PT->getPointeeType().getTypePtr(); + + if (const RecordType *RT = T->getAsStructureType()) { + const RecordDecl *RD = RT->getDecl(); + for (RecordDecl::field_iterator I = RD->field_begin(), + E = RD->field_end(); I != E; ++I ) { + const Type *FieldT = I->getType().getTypePtr(); + if (FieldT->isBlockPointerType() || FieldT->isFunctionPointerType()) + return true; + } + } return false; } diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c index f5bff4fa43..a7d5b0b0e9 100644 --- a/test/Analysis/malloc.c +++ b/test/Analysis/malloc.c @@ -819,6 +819,16 @@ void r11160612_4() { sqlite3_bind_text_my(0, x, 12, free); // no - warning } +// Passing callbacks in a struct. +void r11160612_5(StWithCallback St) { + void *x = malloc(12); + dealocateMemWhenDoneByVal(x, St); +} +void r11160612_6(StWithCallback St) { + void *x = malloc(12); + dealocateMemWhenDoneByRef(&St, x); +} + // ---------------------------------------------------------------------------- // Below are the known false positives. diff --git a/test/Analysis/system-header-simulator.h b/test/Analysis/system-header-simulator.h index c910ad9694..a8cba9ce5b 100644 --- a/test/Analysis/system-header-simulator.h +++ b/test/Analysis/system-header-simulator.h @@ -37,3 +37,12 @@ FILE *funopen(const void *, int (*)(void *)); int sqlite3_bind_text_my(int, const char*, int n, void(*)(void*)); + +typedef void (*freeCallback) (void*); +typedef struct { + int i; + freeCallback fc; +} StWithCallback; + +int dealocateMemWhenDoneByVal(void*, StWithCallback); +int dealocateMemWhenDoneByRef(StWithCallback*, const void*); -- 2.40.0