180412c4e28c8247ad9c8d30d04c94938f01b21fbAnna Zaks//===--- NonNullParamChecker.cpp - Undefined arguments checker -*- C++ -*--===// 294943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu// 394943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu// The LLVM Compiler Infrastructure 494943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu// 594943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu// This file is distributed under the University of Illinois Open Source 694943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu// License. See LICENSE.TXT for details. 794943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu// 894943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu//===----------------------------------------------------------------------===// 994943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu// 1080412c4e28c8247ad9c8d30d04c94938f01b21fbAnna Zaks// This defines NonNullParamChecker, which checks for arguments expected not to 1180412c4e28c8247ad9c8d30d04c94938f01b21fbAnna Zaks// be null due to: 1280412c4e28c8247ad9c8d30d04c94938f01b21fbAnna Zaks// - the corresponding parameters being declared to have nonnull attribute 1380412c4e28c8247ad9c8d30d04c94938f01b21fbAnna Zaks// - the corresponding parameters being references; since the call would form 1480412c4e28c8247ad9c8d30d04c94938f01b21fbAnna Zaks// a reference to a null pointer 1594943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu// 1694943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu//===----------------------------------------------------------------------===// 1794943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu 18bd90076671c8012244bb7e3fd84b6789e47cb199Argyrios Kyrtzidis#include "ClangSACheckers.h" 192fa67efeaf66a9332c30a026dc1c21bef6c33a6cBenjamin Kramer#include "clang/AST/Attr.h" 2055fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 21ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/Checker.h" 22bd90076671c8012244bb7e3fd84b6789e47cb199Argyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/CheckerManager.h" 23f540c54701e3eeb34cb619a3a4eb18f1ac70ef2dJordan Rose#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 24bd90076671c8012244bb7e3fd84b6789e47cb199Argyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 2594943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu 2694943b6d913718216a95a91864040ffc11a1d779Zhongxing Xuusing namespace clang; 279ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekusing namespace ento; 2894943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu 29f493f49fae3ab242ae055ae00b24fa5512655e15Ted Kremeneknamespace { 3080412c4e28c8247ad9c8d30d04c94938f01b21fbAnna Zaksclass NonNullParamChecker 31fe6a011a113b3ddcb32f42af152d7476054e7f79Jordan Rose : public Checker< check::PreCall > { 32651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines mutable std::unique_ptr<BugType> BTAttrNonNull; 33651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines mutable std::unique_ptr<BugType> BTNullRefArg; 34651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 35f493f49fae3ab242ae055ae00b24fa5512655e15Ted Kremenekpublic: 36bd90076671c8012244bb7e3fd84b6789e47cb199Argyrios Kyrtzidis 37fe6a011a113b3ddcb32f42af152d7476054e7f79Jordan Rose void checkPreCall(const CallEvent &Call, CheckerContext &C) const; 38018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks 39018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks BugReport *genReportNullAttrNonNull(const ExplodedNode *ErrorN, 40018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks const Expr *ArgE) const; 41018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks BugReport *genReportReferenceToNullPointer(const ExplodedNode *ErrorN, 42018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks const Expr *ArgE) const; 43f493f49fae3ab242ae055ae00b24fa5512655e15Ted Kremenek}; 44f493f49fae3ab242ae055ae00b24fa5512655e15Ted Kremenek} // end anonymous namespace 45f493f49fae3ab242ae055ae00b24fa5512655e15Ted Kremenek 4680412c4e28c8247ad9c8d30d04c94938f01b21fbAnna Zaksvoid NonNullParamChecker::checkPreCall(const CallEvent &Call, 47651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines CheckerContext &C) const { 48fe6a011a113b3ddcb32f42af152d7476054e7f79Jordan Rose const Decl *FD = Call.getDecl(); 4994943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu if (!FD) 5094943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu return; 5194943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu 52fe6a011a113b3ddcb32f42af152d7476054e7f79Jordan Rose const NonNullAttr *Att = FD->getAttr<NonNullAttr>(); 5394943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu 54fe6a011a113b3ddcb32f42af152d7476054e7f79Jordan Rose ProgramStateRef state = C.getState(); 5594943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu 56018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks CallEvent::param_type_iterator TyI = Call.param_type_begin(), 57018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks TyE = Call.param_type_end(); 58018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks 59018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks for (unsigned idx = 0, count = Call.getNumArgs(); idx != count; ++idx){ 60018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks 61018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks // Check if the parameter is a reference. We want to report when reference 62018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks // to a null pointer is passed as a paramter. 63018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks bool haveRefTypeParam = false; 64018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks if (TyI != TyE) { 65018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks haveRefTypeParam = (*TyI)->isReferenceType(); 66018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks TyI++; 67018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks } 68018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks 69018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks bool haveAttrNonNull = Att && Att->isNonNull(idx); 70651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (!haveAttrNonNull) { 71651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines // Check if the parameter is also marked 'nonnull'. 72651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines ArrayRef<ParmVarDecl*> parms = Call.parameters(); 73651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (idx < parms.size()) 74651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines haveAttrNonNull = parms[idx]->hasAttr<NonNullAttr>(); 75651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines } 76018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks 77018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks if (!haveRefTypeParam && !haveAttrNonNull) 7894943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu continue; 7994943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu 80018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks // If the value is unknown or undefined, we can't perform this check. 81018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks const Expr *ArgE = Call.getArgExpr(idx); 82fe6a011a113b3ddcb32f42af152d7476054e7f79Jordan Rose SVal V = Call.getArgSVal(idx); 83dc84cd5efdd3430efb22546b4ac656aa0540b210David Blaikie Optional<DefinedSVal> DV = V.getAs<DefinedSVal>(); 849a126850968b0aa25f7c6f214e7309e33f2d800aJordy Rose if (!DV) 859a126850968b0aa25f7c6f214e7309e33f2d800aJordy Rose continue; 8694943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu 87018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks // Process the case when the argument is not a location. 88018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks assert(!haveRefTypeParam || DV->getAs<Loc>()); 89018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks 90018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks if (haveAttrNonNull && !DV->getAs<Loc>()) { 91bb0ba0bca7896e76f8ce9b709ee881cc505e4d5eTed Kremenek // If the argument is a union type, we want to handle a potential 92fe6a011a113b3ddcb32f42af152d7476054e7f79Jordan Rose // transparent_union GCC extension. 93fe6a011a113b3ddcb32f42af152d7476054e7f79Jordan Rose if (!ArgE) 94fe6a011a113b3ddcb32f42af152d7476054e7f79Jordan Rose continue; 95fe6a011a113b3ddcb32f42af152d7476054e7f79Jordan Rose 96fe6a011a113b3ddcb32f42af152d7476054e7f79Jordan Rose QualType T = ArgE->getType(); 97bb0ba0bca7896e76f8ce9b709ee881cc505e4d5eTed Kremenek const RecordType *UT = T->getAsUnionType(); 98bb0ba0bca7896e76f8ce9b709ee881cc505e4d5eTed Kremenek if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>()) 99bb0ba0bca7896e76f8ce9b709ee881cc505e4d5eTed Kremenek continue; 100fe6a011a113b3ddcb32f42af152d7476054e7f79Jordan Rose 101dc84cd5efdd3430efb22546b4ac656aa0540b210David Blaikie if (Optional<nonloc::CompoundVal> CSV = 1025251abea41b446c26e3239c8dd6c7edea6fc335dDavid Blaikie DV->getAs<nonloc::CompoundVal>()) { 103bb0ba0bca7896e76f8ce9b709ee881cc505e4d5eTed Kremenek nonloc::CompoundVal::iterator CSV_I = CSV->begin(); 104bb0ba0bca7896e76f8ce9b709ee881cc505e4d5eTed Kremenek assert(CSV_I != CSV->end()); 105bb0ba0bca7896e76f8ce9b709ee881cc505e4d5eTed Kremenek V = *CSV_I; 1065251abea41b446c26e3239c8dd6c7edea6fc335dDavid Blaikie DV = V.getAs<DefinedSVal>(); 107bb0ba0bca7896e76f8ce9b709ee881cc505e4d5eTed Kremenek assert(++CSV_I == CSV->end()); 108651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines // FIXME: Handle (some_union){ some_other_union_val }, which turns into 109651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines // a LazyCompoundVal inside a CompoundVal. 110651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (!V.getAs<Loc>()) 11142773d64f98db0dd5cc80181c3b2d561851668f7Anna Zaks continue; 11242773d64f98db0dd5cc80181c3b2d561851668f7Anna Zaks // Retrieve the corresponding expression. 11342773d64f98db0dd5cc80181c3b2d561851668f7Anna Zaks if (const CompoundLiteralExpr *CE = dyn_cast<CompoundLiteralExpr>(ArgE)) 11442773d64f98db0dd5cc80181c3b2d561851668f7Anna Zaks if (const InitListExpr *IE = 11542773d64f98db0dd5cc80181c3b2d561851668f7Anna Zaks dyn_cast<InitListExpr>(CE->getInitializer())) 11642773d64f98db0dd5cc80181c3b2d561851668f7Anna Zaks ArgE = dyn_cast<Expr>(*(IE->begin())); 11742773d64f98db0dd5cc80181c3b2d561851668f7Anna Zaks 118fe6a011a113b3ddcb32f42af152d7476054e7f79Jordan Rose } else { 119bb0ba0bca7896e76f8ce9b709ee881cc505e4d5eTed Kremenek // FIXME: Handle LazyCompoundVals? 120bb0ba0bca7896e76f8ce9b709ee881cc505e4d5eTed Kremenek continue; 121bb0ba0bca7896e76f8ce9b709ee881cc505e4d5eTed Kremenek } 122bb0ba0bca7896e76f8ce9b709ee881cc505e4d5eTed Kremenek } 123bb0ba0bca7896e76f8ce9b709ee881cc505e4d5eTed Kremenek 12494943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu ConstraintManager &CM = C.getConstraintManager(); 1258bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek ProgramStateRef stateNotNull, stateNull; 126651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV); 12794943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu 12894943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu if (stateNull && !stateNotNull) { 12994943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu // Generate an error node. Check for a null node in case 13094943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu // we cache out. 131d048c6ef5b6cfaa0cecb8cc1d4bdace32ed21d07Ted Kremenek if (ExplodedNode *errorNode = C.generateSink(stateNull)) { 13294943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu 1336bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines BugReport *R = nullptr; 134018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks if (haveAttrNonNull) 135018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks R = genReportNullAttrNonNull(errorNode, ArgE); 136018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks else if (haveRefTypeParam) 137018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks R = genReportReferenceToNullPointer(errorNode, ArgE); 13894943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu 13994943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu // Highlight the range of the argument that was null. 140fe6a011a113b3ddcb32f42af152d7476054e7f79Jordan Rose R->addRange(Call.getArgSourceRange(idx)); 141018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks 14294943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu // Emit the bug report. 143785950e59424dca7ce0081bebf13c0acd2c4fff6Jordan Rose C.emitReport(R); 14494943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu } 14594943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu 14694943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu // Always return. Either we cached out or we just emitted an error. 14794943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu return; 14894943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu } 14994943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu 15094943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu // If a pointer value passed the check we should assume that it is 15194943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu // indeed not null from this point forward. 15294943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu assert(stateNotNull); 15394943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu state = stateNotNull; 15494943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu } 15594943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu 15694943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu // If we reach here all of the arguments passed the nonnull check. 15794943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu // If 'state' has been updated generated a new node. 1580bd6b110e908892d4b5c8671a9f435a1d72ad16aAnna Zaks C.addTransition(state); 15994943b6d913718216a95a91864040ffc11a1d779Zhongxing Xu} 160bd90076671c8012244bb7e3fd84b6789e47cb199Argyrios Kyrtzidis 16180412c4e28c8247ad9c8d30d04c94938f01b21fbAnna ZaksBugReport *NonNullParamChecker::genReportNullAttrNonNull( 162018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks const ExplodedNode *ErrorNode, const Expr *ArgE) const { 163018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks // Lazily allocate the BugType object if it hasn't already been 164018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks // created. Ownership is transferred to the BugReporter object once 165018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks // the BugReport is passed to 'EmitWarning'. 166018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks if (!BTAttrNonNull) 167018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks BTAttrNonNull.reset(new BugType( 168651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines this, "Argument with 'nonnull' attribute passed null", "API")); 169018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks 170018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks BugReport *R = new BugReport(*BTAttrNonNull, 171018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks "Null pointer passed as an argument to a 'nonnull' parameter", 172018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks ErrorNode); 173018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks if (ArgE) 174018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks bugreporter::trackNullOrUndefValue(ErrorNode, ArgE, *R); 175018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks 176018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks return R; 177018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks} 178018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks 17980412c4e28c8247ad9c8d30d04c94938f01b21fbAnna ZaksBugReport *NonNullParamChecker::genReportReferenceToNullPointer( 180018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks const ExplodedNode *ErrorNode, const Expr *ArgE) const { 181018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks if (!BTNullRefArg) 182651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines BTNullRefArg.reset(new BuiltinBug(this, "Dereference of null pointer")); 183018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks 184018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks BugReport *R = new BugReport(*BTNullRefArg, 185018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks "Forming reference to null pointer", 186018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks ErrorNode); 187018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks if (ArgE) { 188018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks const Expr *ArgEDeref = bugreporter::getDerefExpr(ArgE); 1896bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines if (!ArgEDeref) 190018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks ArgEDeref = ArgE; 191018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks bugreporter::trackNullOrUndefValue(ErrorNode, 192018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks ArgEDeref, 193018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks *R); 194018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks } 195018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks return R; 196018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks 197018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks} 198018e9aa033ff7363797c62fc3b14669d0558284bAnna Zaks 19980412c4e28c8247ad9c8d30d04c94938f01b21fbAnna Zaksvoid ento::registerNonNullParamChecker(CheckerManager &mgr) { 20080412c4e28c8247ad9c8d30d04c94938f01b21fbAnna Zaks mgr.registerChecker<NonNullParamChecker>(); 201bd90076671c8012244bb7e3fd84b6789e47cb199Argyrios Kyrtzidis} 202