aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp')
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp354
1 files changed, 0 insertions, 354 deletions
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp
deleted file mode 100644
index 1053424ae6fa..000000000000
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp
+++ /dev/null
@@ -1,354 +0,0 @@
-//===- NumberObjectConversionChecker.cpp -------------------------*- C++ -*-==//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines NumberObjectConversionChecker, which checks for a
-// particular common mistake when dealing with numbers represented as objects
-// passed around by pointers. Namely, the language allows to reinterpret the
-// pointer as a number directly, often without throwing any warnings,
-// but in most cases the result of such conversion is clearly unexpected,
-// as pointer value, rather than number value represented by the pointee object,
-// becomes the result of such operation.
-//
-// Currently the checker supports the Objective-C NSNumber class,
-// and the OSBoolean class found in macOS low-level code; the latter
-// can only hold boolean values.
-//
-// This checker has an option "Pedantic" (boolean), which enables detection of
-// more conversion patterns (which are most likely more harmless, and therefore
-// are more likely to produce false positives) - disabled by default,
-// enabled with `-analyzer-config osx.NumberObjectConversion:Pedantic=true'.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
-#include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
-#include "clang/Lex/Lexer.h"
-#include "llvm/ADT/APSInt.h"
-
-using namespace clang;
-using namespace ento;
-using namespace ast_matchers;
-
-namespace {
-
-class NumberObjectConversionChecker : public Checker<check::ASTCodeBody> {
-public:
- bool Pedantic;
-
- void checkASTCodeBody(const Decl *D, AnalysisManager &AM,
- BugReporter &BR) const;
-};
-
-class Callback : public MatchFinder::MatchCallback {
- const NumberObjectConversionChecker *C;
- BugReporter &BR;
- AnalysisDeclContext *ADC;
-
-public:
- Callback(const NumberObjectConversionChecker *C,
- BugReporter &BR, AnalysisDeclContext *ADC)
- : C(C), BR(BR), ADC(ADC) {}
- virtual void run(const MatchFinder::MatchResult &Result);
-};
-} // end of anonymous namespace
-
-void Callback::run(const MatchFinder::MatchResult &Result) {
- bool IsPedanticMatch =
- (Result.Nodes.getNodeAs<Stmt>("pedantic") != nullptr);
- if (IsPedanticMatch && !C->Pedantic)
- return;
-
- ASTContext &ACtx = ADC->getASTContext();
-
- if (const Expr *CheckIfNull =
- Result.Nodes.getNodeAs<Expr>("check_if_null")) {
- // Unless the macro indicates that the intended type is clearly not
- // a pointer type, we should avoid warning on comparing pointers
- // to zero literals in non-pedantic mode.
- // FIXME: Introduce an AST matcher to implement the macro-related logic?
- bool MacroIndicatesWeShouldSkipTheCheck = false;
- SourceLocation Loc = CheckIfNull->getBeginLoc();
- if (Loc.isMacroID()) {
- StringRef MacroName = Lexer::getImmediateMacroName(
- Loc, ACtx.getSourceManager(), ACtx.getLangOpts());
- if (MacroName == "NULL" || MacroName == "nil")
- return;
- if (MacroName == "YES" || MacroName == "NO")
- MacroIndicatesWeShouldSkipTheCheck = true;
- }
- if (!MacroIndicatesWeShouldSkipTheCheck) {
- Expr::EvalResult EVResult;
- if (CheckIfNull->IgnoreParenCasts()->EvaluateAsInt(
- EVResult, ACtx, Expr::SE_AllowSideEffects)) {
- llvm::APSInt Result = EVResult.Val.getInt();
- if (Result == 0) {
- if (!C->Pedantic)
- return;
- IsPedanticMatch = true;
- }
- }
- }
- }
-
- const Stmt *Conv = Result.Nodes.getNodeAs<Stmt>("conv");
- assert(Conv);
-
- const Expr *ConvertedCObject = Result.Nodes.getNodeAs<Expr>("c_object");
- const Expr *ConvertedCppObject = Result.Nodes.getNodeAs<Expr>("cpp_object");
- const Expr *ConvertedObjCObject = Result.Nodes.getNodeAs<Expr>("objc_object");
- bool IsCpp = (ConvertedCppObject != nullptr);
- bool IsObjC = (ConvertedObjCObject != nullptr);
- const Expr *Obj = IsObjC ? ConvertedObjCObject
- : IsCpp ? ConvertedCppObject
- : ConvertedCObject;
- assert(Obj);
-
- bool IsComparison =
- (Result.Nodes.getNodeAs<Stmt>("comparison") != nullptr);
-
- bool IsOSNumber =
- (Result.Nodes.getNodeAs<Decl>("osnumber") != nullptr);
-
- bool IsInteger =
- (Result.Nodes.getNodeAs<QualType>("int_type") != nullptr);
- bool IsObjCBool =
- (Result.Nodes.getNodeAs<QualType>("objc_bool_type") != nullptr);
- bool IsCppBool =
- (Result.Nodes.getNodeAs<QualType>("cpp_bool_type") != nullptr);
-
- llvm::SmallString<64> Msg;
- llvm::raw_svector_ostream OS(Msg);
-
- // Remove ObjC ARC qualifiers.
- QualType ObjT = Obj->getType().getUnqualifiedType();
-
- // Remove consts from pointers.
- if (IsCpp) {
- assert(ObjT.getCanonicalType()->isPointerType());
- ObjT = ACtx.getPointerType(
- ObjT->getPointeeType().getCanonicalType().getUnqualifiedType());
- }
-
- if (IsComparison)
- OS << "Comparing ";
- else
- OS << "Converting ";
-
- OS << "a pointer value of type '" << ObjT.getAsString() << "' to a ";
-
- std::string EuphemismForPlain = "primitive";
- std::string SuggestedApi = IsObjC ? (IsInteger ? "" : "-boolValue")
- : IsCpp ? (IsOSNumber ? "" : "getValue()")
- : "CFNumberGetValue()";
- if (SuggestedApi.empty()) {
- // A generic message if we're not sure what API should be called.
- // FIXME: Pattern-match the integer type to make a better guess?
- SuggestedApi =
- "a method on '" + ObjT.getAsString() + "' to get the scalar value";
- // "scalar" is not quite correct or common, but some documentation uses it
- // when describing object methods we suggest. For consistency, we use
- // "scalar" in the whole sentence when we need to use this word in at least
- // one place, otherwise we use "primitive".
- EuphemismForPlain = "scalar";
- }
-
- if (IsInteger)
- OS << EuphemismForPlain << " integer value";
- else if (IsObjCBool)
- OS << EuphemismForPlain << " BOOL value";
- else if (IsCppBool)
- OS << EuphemismForPlain << " bool value";
- else // Branch condition?
- OS << EuphemismForPlain << " boolean value";
-
-
- if (IsPedanticMatch)
- OS << "; instead, either compare the pointer to "
- << (IsObjC ? "nil" : IsCpp ? "nullptr" : "NULL") << " or ";
- else
- OS << "; did you mean to ";
-
- if (IsComparison)
- OS << "compare the result of calling " << SuggestedApi;
- else
- OS << "call " << SuggestedApi;
-
- if (!IsPedanticMatch)
- OS << "?";
-
- BR.EmitBasicReport(
- ADC->getDecl(), C, "Suspicious number object conversion", "Logic error",
- OS.str(),
- PathDiagnosticLocation::createBegin(Obj, BR.getSourceManager(), ADC),
- Conv->getSourceRange());
-}
-
-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());
-}
-
-void ento::registerNumberObjectConversionChecker(CheckerManager &Mgr) {
- NumberObjectConversionChecker *Chk =
- Mgr.registerChecker<NumberObjectConversionChecker>();
- Chk->Pedantic =
- Mgr.getAnalyzerOptions().getCheckerBooleanOption(Chk, "Pedantic");
-}
-
-bool ento::shouldRegisterNumberObjectConversionChecker(const LangOptions &LO) {
- return true;
-}