}
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<PointerType>(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;
}
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.
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*);