[analyzer] Perform escaping in RetainCountChecker on type mismatch even for inlined functions

The fix done in D55465 did not previously apply when the function was inlined.

rdar://46889541

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

llvm-svn: 349876
This commit is contained in:
George Karpenkov 2018-12-21 02:16:36 +00:00
parent f508532627
commit aecb371a0a
2 changed files with 38 additions and 23 deletions

View File

@ -502,6 +502,25 @@ static Optional<RefVal> refValFromRetEffect(RetEffect RE,
return None;
}
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());
}
// We don't always get the exact modeling of the function with regards to the
// retain count checker even when the function is inlined. For example, we need
// to stop tracking the symbols which were marked with StopTrackingHard.
@ -512,11 +531,16 @@ void RetainCountChecker::processSummaryOfInlined(const RetainSummary &Summ,
// Evaluate the effect of the arguments.
for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) {
if (Summ.getArg(idx) == StopTrackingHard) {
SVal V = CallOrMsg.getArgSVal(idx);
if (SymbolRef Sym = V.getAsLocSymbol()) {
SVal V = CallOrMsg.getArgSVal(idx);
if (SymbolRef Sym = V.getAsLocSymbol()) {
bool ShouldRemoveBinding = Summ.getArg(idx) == StopTrackingHard;
if (const RefVal *T = getRefBinding(state, Sym))
if (shouldEscapeArgumentOnCall(CallOrMsg, idx, T))
ShouldRemoveBinding = true;
if (ShouldRemoveBinding)
state = removeRefBinding(state, Sym);
}
}
}
@ -574,25 +598,6 @@ 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 {

View File

@ -90,7 +90,10 @@ struct OSMetaClassBase {
static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta);
};
typedef unsigned long MYTYPE;
void escape(void *);
void escape_with_source(MYTYPE p) {}
bool coin();
bool os_consume_violation_two_args(OS_CONSUME OSObject *obj, bool extra) {
@ -139,6 +142,13 @@ void test_escaping_into_voidstar() {
escape(obj);
}
void test_escape_has_source() {
OSObject *obj = new OSObject;
if (obj)
escape_with_source((MYTYPE)obj);
return;
}
void test_no_infinite_check_recursion(MyArray *arr) {
OSObject *input = new OSObject;
OSObject *o = arr->generateObject(input);