29 using namespace clang;
45 class TrustNonnullChecker :
public Checker<check::PostCall,
46 check::PostObjCMessage,
50 static unsigned constexpr ComplexityThreshold = 10;
53 Selector SetObjectForKeyedSubscriptSel;
58 : ObjectForKeyedSubscriptSel(
61 SetObjectForKeyedSubscriptSel(
67 bool Assumption)
const {
68 const SymbolRef CondS = Cond.getAsSymbol();
69 if (!CondS || CondS->computeComplexity() > ComplexityThreshold)
72 for (
auto B=CondS->symbol_begin(), E=CondS->symbol_end(); B != E; ++B) {
74 State = addImplication(Antecedent,
State,
true);
75 State = addImplication(Antecedent,
State,
false);
81 void checkPostCall(
const CallEvent &Call, CheckerContext &C)
const {
83 if (!
Call.isInSystemHeader())
88 if (isNonNullPtr(Call, C))
89 if (
auto L =
Call.getReturnValue().getAs<Loc>())
95 void checkPostObjCMessage(
const ObjCMethodCall &Msg,
96 CheckerContext &C)
const {
105 if (interfaceHasSuperclass(
ID,
"NSMutableDictionary") &&
106 (Msg.getSelector() == SetObjectForKeyedSubscriptSel ||
107 Msg.getSelector() == SetObjectForKeySel)) {
108 if (
auto L = Msg.getArgSVal(1).getAs<Loc>())
113 if (interfaceHasSuperclass(
ID,
"NSDictionary") &&
114 (Msg.getSelector() == ObjectForKeyedSubscriptSel ||
115 Msg.getSelector() == ObjectForKeySel)) {
116 SymbolRef ArgS = Msg.getArgSVal(0).getAsSymbol();
117 SymbolRef RetS = Msg.getReturnValue().getAsSymbol();
122 State =
State->set<NonNullImplicationMap>(RetS, ArgS);
126 State =
State->set<NullImplicationMap>(ArgS, RetS);
133 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C)
const {
136 State = dropDeadFromGDM<NullImplicationMap>(SymReaper,
State);
137 State = dropDeadFromGDM<NonNullImplicationMap>(SymReaper,
State);
146 template <
typename MapName>
149 for (
const std::pair<SymbolRef, SymbolRef> &
P :
State->get<MapName>())
150 if (!SymReaper.isLive(
P.first) || !SymReaper.isLive(
P.second))
157 bool isNonNullPtr(
const CallEvent &Call, CheckerContext &C)
const {
167 if (!isa<ObjCMethodCall>(&Call))
170 const auto *MCall = cast<ObjCMethodCall>(&Call);
183 if (!MCall->isInstanceMessage())
187 SVal Receiver = MCall->getReceiverSVal();
188 ConditionTruthVal TV =
C.getState()->isNonNull(Receiver);
189 if (TV.isConstrainedTrue())
197 StringRef ClassName)
const {
198 if (
ID->getIdentifier()->getName() == ClassName)
202 return interfaceHasSuperclass(Super, ClassName);
215 bool Negated)
const {
218 SValBuilder &SVB = InputState->getStateManager().getSValBuilder();
220 Negated ? InputState->get<NonNullImplicationMap>(Antecedent)
221 : InputState->get<NullImplicationMap>(Antecedent);
225 SVal AntecedentV = SVB.makeSymbolVal(Antecedent);
228 if ((Negated && InputState->isNonNull(AntecedentV).isConstrainedTrue())
229 || (!Negated && InputState->isNull(AntecedentV).isConstrainedTrue())) {
230 SVal ConsequentS = SVB.makeSymbolVal(*Consequent);
231 State = InputState->assume(ConsequentS.castAs<DefinedSVal>(), Negated);
237 State =
State->remove<NonNullImplicationMap>(Antecedent);
238 State =
State->remove<NullImplicationMap>(*Consequent);
240 State =
State->remove<NullImplicationMap>(Antecedent);
241 State =
State->remove<NonNullImplicationMap>(*Consequent);
251 void ento::registerTrustNonnullChecker(CheckerManager &Mgr) {
252 Mgr.registerChecker<TrustNonnullChecker>(Mgr.getASTContext());
255 bool ento::shouldRegisterTrustNonnullChecker(
const CheckerManager &mgr) {