void NumberObjectConversionChecker::checkASTCodeBody(const Decl *D, AnalysisManager &AM, BugReporter &BR) const { // Currently this matches CoreFoundation opaque pointer typedefs. auto CSuspiciousNumberObjectExprM = expr(ignoringParenImpCasts( expr(hasType( typedefType(hasDeclaration(anyOf( typedefDecl(hasName("CFNumberRef")), typedefDecl(hasName("CFBooleanRef"))))))) .bind("c_object"))); // Currently this matches XNU kernel number-object pointers. auto CppSuspiciousNumberObjectExprM = expr(ignoringParenImpCasts( expr(hasType(hasCanonicalType( pointerType(pointee(hasCanonicalType( recordType(hasDeclaration( anyOf( cxxRecordDecl(hasName("OSBoolean")), cxxRecordDecl(hasName("OSNumber")) .bind("osnumber")))))))))) .bind("cpp_object"))); // Currently this matches NeXTSTEP number objects. auto ObjCSuspiciousNumberObjectExprM = expr(ignoringParenImpCasts( expr(hasType(hasCanonicalType( objcObjectPointerType(pointee( qualType(hasCanonicalType( qualType(hasDeclaration( objcInterfaceDecl(hasName("NSNumber"))))))))))) .bind("objc_object"))); auto SuspiciousNumberObjectExprM = anyOf( CSuspiciousNumberObjectExprM, CppSuspiciousNumberObjectExprM, ObjCSuspiciousNumberObjectExprM); // Useful for predicates like "Unless we've seen the same object elsewhere". auto AnotherSuspiciousNumberObjectExprM = expr(anyOf( equalsBoundNode("c_object"), equalsBoundNode("objc_object"), equalsBoundNode("cpp_object"))); // The .bind here is in order to compose the error message more accurately. auto ObjCSuspiciousScalarBooleanTypeM = qualType(typedefType(hasDeclaration( typedefDecl(hasName("BOOL"))))).bind("objc_bool_type"); // The .bind here is in order to compose the error message more accurately. auto SuspiciousScalarBooleanTypeM = qualType(anyOf(qualType(booleanType()).bind("cpp_bool_type"), ObjCSuspiciousScalarBooleanTypeM)); // The .bind here is in order to compose the error message more accurately. // Also avoid intptr_t and uintptr_t because they were specifically created // for storing pointers. auto SuspiciousScalarNumberTypeM = qualType(hasCanonicalType(isInteger()), unless(typedefType(hasDeclaration( typedefDecl(matchesName("^::u?intptr_t$")))))) .bind("int_type"); auto SuspiciousScalarTypeM = qualType(anyOf(SuspiciousScalarBooleanTypeM, SuspiciousScalarNumberTypeM)); auto SuspiciousScalarExprM = expr(ignoringParenImpCasts(expr(hasType(SuspiciousScalarTypeM)))); auto ConversionThroughAssignmentM = binaryOperator(allOf(hasOperatorName("="), hasLHS(SuspiciousScalarExprM), hasRHS(SuspiciousNumberObjectExprM))); auto ConversionThroughBranchingM = ifStmt(allOf( hasCondition(SuspiciousNumberObjectExprM), unless(hasConditionVariableStatement(declStmt()) ))).bind("pedantic"); auto ConversionThroughCallM = callExpr(hasAnyArgument(allOf(hasType(SuspiciousScalarTypeM), ignoringParenImpCasts( SuspiciousNumberObjectExprM)))); // We bind "check_if_null" to modify the warning message // in case it was intended to compare a pointer to 0 with a relatively-ok // construct "x == 0" or "x != 0". auto ConversionThroughEquivalenceM = binaryOperator(allOf(anyOf(hasOperatorName("=="), hasOperatorName("!=")), hasEitherOperand(SuspiciousNumberObjectExprM), hasEitherOperand(SuspiciousScalarExprM .bind("check_if_null")))) .bind("comparison"); auto ConversionThroughComparisonM = binaryOperator(allOf(anyOf(hasOperatorName(">="), hasOperatorName(">"), hasOperatorName("<="), hasOperatorName("<")), hasEitherOperand(SuspiciousNumberObjectExprM), hasEitherOperand(SuspiciousScalarExprM))) .bind("comparison"); auto ConversionThroughConditionalOperatorM = conditionalOperator(allOf( hasCondition(SuspiciousNumberObjectExprM), unless(hasTrueExpression( hasDescendant(AnotherSuspiciousNumberObjectExprM))), unless(hasFalseExpression( hasDescendant(AnotherSuspiciousNumberObjectExprM))))) .bind("pedantic"); auto ConversionThroughExclamationMarkM = unaryOperator(allOf(hasOperatorName("!"), has(expr(SuspiciousNumberObjectExprM)))) .bind("pedantic"); auto ConversionThroughExplicitBooleanCastM = explicitCastExpr(allOf(hasType(SuspiciousScalarBooleanTypeM), has(expr(SuspiciousNumberObjectExprM)))); auto ConversionThroughExplicitNumberCastM = explicitCastExpr(allOf(hasType(SuspiciousScalarNumberTypeM), has(expr(SuspiciousNumberObjectExprM)))); auto ConversionThroughInitializerM = declStmt(hasSingleDecl( varDecl(hasType(SuspiciousScalarTypeM), hasInitializer(SuspiciousNumberObjectExprM)))); auto FinalM = stmt(anyOf(ConversionThroughAssignmentM, ConversionThroughBranchingM, ConversionThroughCallM, ConversionThroughComparisonM, ConversionThroughConditionalOperatorM, ConversionThroughEquivalenceM, ConversionThroughExclamationMarkM, ConversionThroughExplicitBooleanCastM, ConversionThroughExplicitNumberCastM, ConversionThroughInitializerM)).bind("conv"); MatchFinder F; Callback CB(this, BR, AM.getAnalysisDeclContext(D)); F.addMatcher(stmt(forEachDescendant(FinalM)), &CB); F.match(*D->getBody(), AM.getASTContext()); }