From 4818d5cde66e6b064a599d9eac5174c2f9467174 Mon Sep 17 00:00:00 2001 From: Artem Dergachev Date: Wed, 13 Jan 2016 15:52:25 +0000 Subject: [PATCH] Revert "[analyzer] Provide .def-files and visitors for SVal/SymExpr/MemRegion." This reverts commit r257605. The test fails on architectures that use unsigned int as size_t. SymbolManager.h fails with compile errors on some platforms. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@257608 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/analyzer/DebugChecks.rst | 35 --- .../StaticAnalyzer/Checkers/SValExplainer.h | 233 ------------------ .../Core/PathSensitive/MemRegion.h | 50 +++- .../Core/PathSensitive/Regions.def | 89 ------- .../Core/PathSensitive/SValVisitor.h | 151 ------------ .../Core/PathSensitive/SVals.def | 74 ------ .../StaticAnalyzer/Core/PathSensitive/SVals.h | 19 +- .../Core/PathSensitive/SymbolManager.h | 17 +- .../Core/PathSensitive/Symbols.def | 55 ----- .../Checkers/ExprInspectionChecker.cpp | 85 +++---- test/Analysis/explain-svals.cpp | 98 -------- 11 files changed, 100 insertions(+), 806 deletions(-) delete mode 100644 include/clang/StaticAnalyzer/Checkers/SValExplainer.h delete mode 100644 include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def delete mode 100644 include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h delete mode 100644 include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def delete mode 100644 include/clang/StaticAnalyzer/Core/PathSensitive/Symbols.def delete mode 100644 test/Analysis/explain-svals.cpp diff --git a/docs/analyzer/DebugChecks.rst b/docs/analyzer/DebugChecks.rst index bfa3142efb..771e39fc43 100644 --- a/docs/analyzer/DebugChecks.rst +++ b/docs/analyzer/DebugChecks.rst @@ -162,41 +162,6 @@ ExprInspection checks } while(0); // expected-warning{{SYMBOL DEAD}} -- void clang_analyzer_explain(a single argument of any type); - - This function explains the value of its argument in a human-readable manner - in the warning message. You can make as many overrides of its prototype - in the test code as necessary to explain various integral, pointer, - or even record-type values. - - Example usage:: - - void clang_analyzer_explain(int); - void clang_analyzer_explain(void *); - - void foo(int param, void *ptr) { - clang_analyzer_explain(param); // expected-warning{{argument 'param'}} - if (!ptr) - clang_analyzer_explain(ptr); // expected-warning{{memory address '0'}} - } - -- size_t clang_analyzer_getExtent(void *); - - This function returns the value that represents the extent of a memory region - pointed to by the argument. This value is often difficult to obtain otherwise, - because no valid code that produces this value. However, it may be useful - for testing purposes, to see how well does the analyzer model region extents. - - Example usage:: - - void foo() { - int x, *y; - size_t xs = clang_analyzer_getExtent(&x); - clang_analyzer_explain(xs); // expected-warning{{'4'}} - size_t ys = clang_analyzer_getExtent(&y); - clang_analyzer_explain(ys); // expected-warning{{'8'}} - } - Statistics ========== diff --git a/include/clang/StaticAnalyzer/Checkers/SValExplainer.h b/include/clang/StaticAnalyzer/Checkers/SValExplainer.h deleted file mode 100644 index 28cfbef910..0000000000 --- a/include/clang/StaticAnalyzer/Checkers/SValExplainer.h +++ /dev/null @@ -1,233 +0,0 @@ -//== SValExplainer.h - Symbolic value explainer -----------------*- C++ -*--==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines SValExplainer, a class for pretty-printing a -// human-readable description of a symbolic value. For example, -// "reg_$0" is turned into "initial value of variable 'x'". -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_SVALEXPLAINER_H -#define LLVM_CLANG_STATICANALYZER_CHECKERS_SVALEXPLAINER_H - -#include "clang/AST/DeclCXX.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h" - -namespace clang { - -namespace ento { - -class SValExplainer : public FullSValVisitor { -private: - ASTContext &ACtx; - - std::string printStmt(const Stmt *S) { - std::string Str; - llvm::raw_string_ostream OS(Str); - S->printPretty(OS, nullptr, PrintingPolicy(ACtx.getLangOpts())); - return OS.str(); - } - - bool isThisObject(const SymbolicRegion *R) { - if (auto S = dyn_cast(R->getSymbol())) - if (isa(S->getRegion())) - return true; - return false; - } - -public: - SValExplainer(ASTContext &Ctx) : ACtx(Ctx) {} - - std::string VisitUnknownVal(UnknownVal V) { - return "unknown value"; - } - - std::string VisitUndefinedVal(UndefinedVal V) { - return "undefined value"; - } - - std::string VisitLocMemRegionVal(loc::MemRegionVal V) { - const MemRegion *R = V.getRegion(); - // Avoid the weird "pointer to pointee of ...". - if (auto SR = dyn_cast(R)) { - // However, "pointer to 'this' object" is fine. - if (!isThisObject(SR)) - return Visit(SR->getSymbol()); - } - return "pointer to " + Visit(R); - } - - std::string VisitLocConcreteInt(loc::ConcreteInt V) { - llvm::APSInt I = V.getValue(); - std::string Str; - llvm::raw_string_ostream OS(Str); - OS << "concrete memory address '" << I << "'"; - return OS.str(); - } - - std::string VisitNonLocSymbolVal(nonloc::SymbolVal V) { - return Visit(V.getSymbol()); - } - - std::string VisitNonLocConcreteInt(nonloc::ConcreteInt V) { - llvm::APSInt I = V.getValue(); - std::string Str; - llvm::raw_string_ostream OS(Str); - OS << (I.isSigned() ? "signed " : "unsigned ") << I.getBitWidth() - << "-bit integer '" << I << "'"; - return OS.str(); - } - - std::string VisitNonLocLazyCompoundVal(nonloc::LazyCompoundVal V) { - return "lazily frozen compound value of " + Visit(V.getRegion()); - } - - std::string VisitSymbolRegionValue(const SymbolRegionValue *S) { - const MemRegion *R = S->getRegion(); - // Special handling for argument values. - if (auto V = dyn_cast(R)) - if (auto D = dyn_cast(V->getDecl())) - return "argument '" + D->getQualifiedNameAsString() + "'"; - return "initial value of " + Visit(R); - } - - std::string VisitSymbolConjured(const SymbolConjured *S) { - return "symbol of type '" + S->getType().getAsString() + - "' conjured at statement '" + printStmt(S->getStmt()) + "'"; - } - - std::string VisitSymbolDerived(const SymbolDerived *S) { - return "value derived from (" + Visit(S->getParentSymbol()) + - ") for " + Visit(S->getRegion()); - } - - std::string VisitSymbolExtent(const SymbolExtent *S) { - return "extent of " + Visit(S->getRegion()); - } - - std::string VisitSymbolMetadata(const SymbolMetadata *S) { - return "metadata of type '" + S->getType().getAsString() + "' tied to " + - Visit(S->getRegion()); - } - - std::string VisitSymIntExpr(const SymIntExpr *S) { - std::string Str; - llvm::raw_string_ostream OS(Str); - OS << "(" << Visit(S->getLHS()) << ") " - << std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) << " " - << S->getRHS(); - return OS.str(); - } - - // TODO: IntSymExpr doesn't appear in practice. - // Add the relevant code once it does. - - std::string VisitSymSymExpr(const SymSymExpr *S) { - return "(" + Visit(S->getLHS()) + ") " + - std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) + - " (" + Visit(S->getRHS()) + ")"; - } - - // TODO: SymbolCast doesn't appear in practice. - // Add the relevant code once it does. - - std::string VisitSymbolicRegion(const SymbolicRegion *R) { - // Explain 'this' object here. - // TODO: Explain CXXThisRegion itself, find a way to test it. - if (isThisObject(R)) - return "'this' object"; - return "pointee of " + Visit(R->getSymbol()); - } - - std::string VisitAllocaRegion(const AllocaRegion *R) { - return "region allocated by '" + printStmt(R->getExpr()) + "'"; - } - - std::string VisitCompoundLiteralRegion(const CompoundLiteralRegion *R) { - return "compound literal " + printStmt(R->getLiteralExpr()); - } - - std::string VisitStringRegion(const StringRegion *R) { - return "string literal " + R->getString(); - } - - std::string VisitElementRegion(const ElementRegion *R) { - std::string Str; - llvm::raw_string_ostream OS(Str); - OS << "element of type '" << R->getElementType().getAsString() - << "' with index "; - // For concrete index: omit type of the index integer. - if (auto I = R->getIndex().getAs()) - OS << I->getValue(); - else - OS << "'" << Visit(R->getIndex()) << "'"; - OS << " of " + Visit(R->getSuperRegion()); - return OS.str(); - } - - std::string VisitVarRegion(const VarRegion *R) { - const VarDecl *VD = R->getDecl(); - std::string Name = VD->getQualifiedNameAsString(); - if (isa(VD)) - return "parameter '" + Name + "'"; - else if (VD->hasLocalStorage()) - return "local variable '" + Name + "'"; - else if (VD->isStaticLocal()) - return "static local variable '" + Name + "'"; - else if (VD->hasGlobalStorage()) - return "global variable '" + Name + "'"; - else - llvm_unreachable("A variable is either local or global"); - } - - std::string VisitFieldRegion(const FieldRegion *R) { - return "field '" + R->getDecl()->getNameAsString() + "' of " + - Visit(R->getSuperRegion()); - } - - std::string VisitCXXTempObjectRegion(const CXXTempObjectRegion *R) { - return "temporary object constructed at statement '" + - printStmt(R->getExpr()) + "'"; - } - - std::string VisitCXXBaseObjectRegion(const CXXBaseObjectRegion *R) { - return "base object '" + R->getDecl()->getQualifiedNameAsString() + - "' inside " + Visit(R->getSuperRegion()); - } - - std::string VisitSVal(SVal V) { - std::string Str; - llvm::raw_string_ostream OS(Str); - OS << V; - return "a value unsupported by the explainer: (" + - std::string(OS.str()) + ")"; - } - - std::string VisitSymExpr(SymbolRef S) { - std::string Str; - llvm::raw_string_ostream OS(Str); - S->dumpToStream(OS); - return "a symbolic expression unsupported by the explainer: (" + - std::string(OS.str()) + ")"; - } - - std::string VisitMemRegion(const MemRegion *R) { - std::string Str; - llvm::raw_string_ostream OS(Str); - OS << R; - return "a memory region unsupported by the explainer (" + - std::string(OS.str()) + ")"; - } -}; - -} // end namespace ento - -} // end namespace clang - -#endif diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h index 6ab22669d0..43f6e5cda0 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -79,11 +79,48 @@ class MemRegion : public llvm::FoldingSetNode { friend class MemRegionManager; public: enum Kind { -#define REGION(Id, Parent) Id ## Kind, -#define REGION_RANGE(Id, First, Last) BEGIN_##Id = First, END_##Id = Last, -#include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def" + // Memory spaces. + CodeSpaceRegionKind, + StackLocalsSpaceRegionKind, + StackArgumentsSpaceRegionKind, + HeapSpaceRegionKind, + UnknownSpaceRegionKind, + StaticGlobalSpaceRegionKind, + GlobalInternalSpaceRegionKind, + GlobalSystemSpaceRegionKind, + GlobalImmutableSpaceRegionKind, + BEGIN_NON_STATIC_GLOBAL_MEMSPACES = GlobalInternalSpaceRegionKind, + END_NON_STATIC_GLOBAL_MEMSPACES = GlobalImmutableSpaceRegionKind, + BEGIN_GLOBAL_MEMSPACES = StaticGlobalSpaceRegionKind, + END_GLOBAL_MEMSPACES = GlobalImmutableSpaceRegionKind, + BEGIN_MEMSPACES = CodeSpaceRegionKind, + END_MEMSPACES = GlobalImmutableSpaceRegionKind, + // Untyped regions. + SymbolicRegionKind, + AllocaRegionKind, + // Typed regions. + BEGIN_TYPED_REGIONS, + FunctionCodeRegionKind = BEGIN_TYPED_REGIONS, + BlockCodeRegionKind, + BlockDataRegionKind, + BEGIN_TYPED_VALUE_REGIONS, + CompoundLiteralRegionKind = BEGIN_TYPED_VALUE_REGIONS, + CXXThisRegionKind, + StringRegionKind, + ObjCStringRegionKind, + ElementRegionKind, + // Decl Regions. + BEGIN_DECL_REGIONS, + VarRegionKind = BEGIN_DECL_REGIONS, + FieldRegionKind, + ObjCIvarRegionKind, + END_DECL_REGIONS = ObjCIvarRegionKind, + CXXTempObjectRegionKind, + CXXBaseObjectRegionKind, + END_TYPED_VALUE_REGIONS = CXXBaseObjectRegionKind, + END_TYPED_REGIONS = CXXBaseObjectRegionKind }; - + private: const Kind kind; @@ -349,7 +386,8 @@ public: static bool classof(const MemRegion *R) { Kind k = R->getKind(); - return k >= BEGIN_STACK_MEMSPACES && k <= END_STACK_MEMSPACES; + return k >= StackLocalsSpaceRegionKind && + k <= StackArgumentsSpaceRegionKind; } }; @@ -511,7 +549,7 @@ public: static bool classof(const MemRegion* R) { Kind k = R->getKind(); - return k >= BEGIN_CODE_TEXT_REGIONS && k <= END_CODE_TEXT_REGIONS; + return k >= FunctionCodeRegionKind && k <= BlockCodeRegionKind; } }; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def b/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def deleted file mode 100644 index c84a1ff13f..0000000000 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def +++ /dev/null @@ -1,89 +0,0 @@ -//===-- Regions.def - Metadata about MemRegion kinds ------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// The list of regions (MemRegion sub-classes) used in the Static Analyzer. -// In order to use this information, users of this file must define one or more -// of the three macros: -// -// REGION(Id, Parent) - for specific MemRegion sub-classes, reserving -// enum value IdKind for their kind. -// -// ABSTRACT_REGION(Id, Parent) - for abstract region classes, -// -// REGION_RANGE(Id, First, Last) - for ranges of kind-enums, -// allowing to determine abstract class of a region -// based on the kind-enum value. -// -//===----------------------------------------------------------------------===// - -#ifndef REGION -#define REGION(Id, Parent) -#endif - -#ifndef ABSTRACT_REGION -#define ABSTRACT_REGION(Id, Parent) -#endif - -#ifndef REGION_RANGE -#define REGION_RANGE(Id, First, Last) -#endif - -ABSTRACT_REGION(MemSpaceRegion, MemRegion) - REGION(CodeSpaceRegion, MemSpaceRegion) - ABSTRACT_REGION(GlobalsSpaceRegion, MemSpaceRegion) - ABSTRACT_REGION(NonStaticGlobalSpaceRegion, GlobalsSpaceRegion) - REGION(GlobalImmutableSpaceRegion, NonStaticGlobalSpaceRegion) - REGION(GlobalInternalSpaceRegion, NonStaticGlobalSpaceRegion) - REGION(GlobalSystemSpaceRegion, NonStaticGlobalSpaceRegion) - REGION_RANGE(NON_STATIC_GLOBAL_MEMSPACES, GlobalImmutableSpaceRegionKind, - GlobalSystemSpaceRegionKind) - REGION(StaticGlobalSpaceRegion, MemSpaceRegion) - REGION_RANGE(GLOBAL_MEMSPACES, GlobalImmutableSpaceRegionKind, - StaticGlobalSpaceRegionKind) - REGION(HeapSpaceRegion, MemSpaceRegion) - ABSTRACT_REGION(StackSpaceRegion, MemSpaceRegion) - REGION(StackArgumentsSpaceRegion, StackSpaceRegion) - REGION(StackLocalsSpaceRegion, StackSpaceRegion) - REGION_RANGE(STACK_MEMSPACES, StackArgumentsSpaceRegionKind, - StackLocalsSpaceRegionKind) - REGION(UnknownSpaceRegion, MemSpaceRegion) - REGION_RANGE(MEMSPACES, CodeSpaceRegionKind, - UnknownSpaceRegionKind) -ABSTRACT_REGION(SubRegion, MemRegion) - REGION(AllocaRegion, SubRegion) - REGION(SymbolicRegion, SubRegion) - ABSTRACT_REGION(TypedRegion, SubRegion) - REGION(BlockDataRegion, TypedRegion) - ABSTRACT_REGION(CodeTextRegion, TypedRegion) - REGION(BlockCodeRegion, CodeTextRegion) - REGION(FunctionCodeRegion, CodeTextRegion) - REGION_RANGE(CODE_TEXT_REGIONS, BlockCodeRegionKind, - FunctionCodeRegionKind) - ABSTRACT_REGION(TypedValueRegion, TypedRegion) - REGION(CompoundLiteralRegion, TypedValueRegion) - REGION(CXXBaseObjectRegion, TypedValueRegion) - REGION(CXXTempObjectRegion, TypedValueRegion) - REGION(CXXThisRegion, TypedValueRegion) - ABSTRACT_REGION(DeclRegion, TypedValueRegion) - REGION(FieldRegion, DeclRegion) - REGION(ObjCIvarRegion, DeclRegion) - REGION(VarRegion, DeclRegion) - REGION_RANGE(DECL_REGIONS, FieldRegionKind, - VarRegionKind) - REGION(ElementRegion, TypedValueRegion) - REGION(ObjCStringRegion, TypedValueRegion) - REGION(StringRegion, TypedValueRegion) - REGION_RANGE(TYPED_VALUE_REGIONS, CompoundLiteralRegionKind, - StringRegionKind) - REGION_RANGE(TYPED_REGIONS, BlockDataRegionKind, - StringRegionKind) - -#undef REGION_RANGE -#undef ABSTRACT_REGION -#undef REGION diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h deleted file mode 100644 index f87fdce156..0000000000 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h +++ /dev/null @@ -1,151 +0,0 @@ -//===--- SValVisitor.h - Visitor for SVal subclasses ------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the SValVisitor, SymExprVisitor, and MemRegionVisitor -// interfaces, and also FullSValVisitor, which visits all three hierarchies. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALVISITOR_H -#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALVISITOR_H - -#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" - -namespace clang { - -namespace ento { - -/// SValVisitor - this class implements a simple visitor for SVal -/// subclasses. -template class SValVisitor { -public: - -#define DISPATCH(NAME, CLASS) \ - return static_cast(this)->Visit ## NAME(V.castAs()) - - RetTy Visit(SVal V) { - // Dispatch to VisitFooVal for each FooVal. - // Take namespaces (loc:: and nonloc::) into account. - switch (V.getBaseKind()) { -#define BASIC_SVAL(Id, Parent) case SVal::Id ## Kind: DISPATCH(Id, Id); -#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def" - case SVal::LocKind: - switch (V.getSubKind()) { -#define LOC_SVAL(Id, Parent) \ - case loc::Id ## Kind: DISPATCH(Loc ## Id, loc :: Id); -#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def" - } - llvm_unreachable("Unknown Loc sub-kind!"); - case SVal::NonLocKind: - switch (V.getSubKind()) { -#define NONLOC_SVAL(Id, Parent) \ - case nonloc::Id ## Kind: DISPATCH(NonLoc ## Id, nonloc :: Id); -#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def" - } - llvm_unreachable("Unknown NonLoc sub-kind!"); - } - llvm_unreachable("Unknown SVal kind!"); - } - -#define BASIC_SVAL(Id, Parent) \ - RetTy Visit ## Id(Id V) { DISPATCH(Parent, Id); } -#define ABSTRACT_SVAL(Id, Parent) \ - BASIC_SVAL(Id, Parent) -#define LOC_SVAL(Id, Parent) \ - RetTy VisitLoc ## Id(loc::Id V) { DISPATCH(Parent, Parent); } -#define NONLOC_SVAL(Id, Parent) \ - RetTy VisitNonLoc ## Id(nonloc::Id V) { DISPATCH(Parent, Parent); } -#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def" - - // Base case, ignore it. :) - RetTy VisitSVal(SVal V) { return RetTy(); } - -#undef DISPATCH -}; - -/// SymExprVisitor - this class implements a simple visitor for SymExpr -/// subclasses. -template class SymExprVisitor { -public: - -#define DISPATCH(CLASS) \ - return static_cast(this)->Visit ## CLASS(cast(S)) - - RetTy Visit(SymbolRef S) { - // Dispatch to VisitSymbolFoo for each SymbolFoo. - switch (S->getKind()) { -#define SYMBOL(Id, Parent) \ - case SymExpr::Id ## Kind: DISPATCH(Id); -#include "clang/StaticAnalyzer/Core/PathSensitive/Symbols.def" - } - llvm_unreachable("Unknown SymExpr kind!"); - } - - // If the implementation chooses not to implement a certain visit method, fall - // back on visiting the superclass. -#define SYMBOL(Id, Parent) RetTy Visit ## Id(const Id *S) { DISPATCH(Parent); } -#define ABSTRACT_SYMBOL(Id, Parent) SYMBOL(Id, Parent) -#include "clang/StaticAnalyzer/Core/PathSensitive/Symbols.def" - - // Base case, ignore it. :) - RetTy VisitSymExpr(SymbolRef S) { return RetTy(); } - -#undef DISPATCH -}; - -/// MemRegionVisitor - this class implements a simple visitor for MemRegion -/// subclasses. -template class MemRegionVisitor { -public: - -#define DISPATCH(CLASS) \ - return static_cast(this)->Visit ## CLASS(cast(R)) - - RetTy Visit(const MemRegion *R) { - // Dispatch to VisitFooRegion for each FooRegion. - switch (R->getKind()) { -#define REGION(Id, Parent) case MemRegion::Id ## Kind: DISPATCH(Id); -#include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def" - } - llvm_unreachable("Unknown MemRegion kind!"); - } - - // If the implementation chooses not to implement a certain visit method, fall - // back on visiting the superclass. -#define REGION(Id, Parent) \ - RetTy Visit ## Id(const Id *R) { DISPATCH(Parent); } -#define ABSTRACT_REGION(Id, Parent) \ - REGION(Id, Parent) -#include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def" - - // Base case, ignore it. :) - RetTy VisitMemRegion(const MemRegion *R) { return RetTy(); } - -#undef DISPATCH -}; - -/// FullSValVisitor - a convenient mixed visitor for all three: -/// SVal, SymExpr and MemRegion subclasses. -template -class FullSValVisitor : public SValVisitor, - public SymExprVisitor, - public MemRegionVisitor { -public: - using SValVisitor::Visit; - using SymExprVisitor::Visit; - using MemRegionVisitor::Visit; -}; - -} // end namespace ento - -} // end namespace clang - -#endif diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def deleted file mode 100644 index 2faec670b3..0000000000 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def +++ /dev/null @@ -1,74 +0,0 @@ -//===-- SVals.def - Metadata about SVal kinds -------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// The list of symbolic values (SVal kinds and sub-kinds) used in the Static -// Analyzer. The distinction between loc:: and nonloc:: SVal namespaces is -// currently hardcoded, because it is too peculiar and explicit to be handled -// uniformly. In order to use this information, users of this file must define -// one or more of the following macros: -// -// BASIC_SVAL(Id, Parent) - for specific SVal sub-kinds, which are -// neither in loc:: nor in nonloc:: namespace; these classes occupy -// their own base kind IdKind. -// -// ABSTRACT_SVAL(Id, Parent) - for abstract SVal classes which are -// neither in loc:: nor in nonloc:: namespace, -// -// ABSTRACT_SVAL_WITH_KIND(Id, Parent) - for SVal classes which are also -// neither in loc:: nor in nonloc:: namespace, but occupy a whole base kind -// identifier IdKind, much like BASIC_SVALs. -// -// LOC_SVAL(Id, Parent) - for values in loc:: namespace, which occupy a sub-kind -// loc::IdKind. -// -// NONLOC_SVAL(Id, Parent) - for values in nonloc:: namespace, which occupy a -// sub-kind nonloc::IdKind. -// -//===----------------------------------------------------------------------===// - -#ifndef BASIC_SVAL -#define BASIC_SVAL(Id, Parent) -#endif - -#ifndef ABSTRACT_SVAL -#define ABSTRACT_SVAL(Id, Parent) -#endif - -#ifndef ABSTRACT_SVAL_WITH_KIND -#define ABSTRACT_SVAL_WITH_KIND(Id, Parent) ABSTRACT_SVAL(Id, Parent) -#endif - -#ifndef LOC_SVAL -#define LOC_SVAL(Id, Parent) -#endif - -#ifndef NONLOC_SVAL -#define NONLOC_SVAL(Id, Parent) -#endif - -BASIC_SVAL(UndefinedVal, SVal) -ABSTRACT_SVAL(DefinedOrUnknownSVal, SVal) - BASIC_SVAL(UnknownVal, DefinedOrUnknownSVal) - ABSTRACT_SVAL(DefinedSVal, DefinedOrUnknownSVal) - ABSTRACT_SVAL_WITH_KIND(Loc, DefinedSVal) - LOC_SVAL(ConcreteInt, Loc) - LOC_SVAL(GotoLabel, Loc) - LOC_SVAL(MemRegionVal, Loc) - ABSTRACT_SVAL_WITH_KIND(NonLoc, DefinedSVal) - NONLOC_SVAL(CompoundVal, NonLoc) - NONLOC_SVAL(ConcreteInt, NonLoc) - NONLOC_SVAL(LazyCompoundVal, NonLoc) - NONLOC_SVAL(LocAsInteger, NonLoc) - NONLOC_SVAL(SymbolVal, NonLoc) - -#undef NONLOC_SVAL -#undef LOC_SVAL -#undef ABSTRACT_SVAL_WITH_KIND -#undef ABSTRACT_SVAL -#undef BASIC_SVAL diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h index 8b353bcbdf..d64425412c 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h @@ -45,9 +45,11 @@ class SVal { public: enum BaseKind { // The enumerators must be representable using 2 bits. -#define BASIC_SVAL(Id, Parent) Id ## Kind, -#define ABSTRACT_SVAL_WITH_KIND(Id, Parent) Id ## Kind, -#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def" + UndefinedValKind = 0, // for subclass UndefinedVal (an uninitialized value) + UnknownValKind = 1, // for subclass UnknownVal (a void value) + LocKind = 2, // for subclass Loc (an L-value) + NonLocKind = 3 // for subclass NonLoc (an R-value that's not + // an L-value) }; enum { BaseBits = 2, BaseMask = 0x3 }; @@ -304,10 +306,8 @@ private: namespace nonloc { -enum Kind { -#define NONLOC_SVAL(Id, Parent) Id ## Kind, -#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def" -}; +enum Kind { ConcreteIntKind, SymbolValKind, + LocAsIntegerKind, CompoundValKind, LazyCompoundValKind }; /// \brief Represents symbolic expression. class SymbolVal : public NonLoc { @@ -465,10 +465,7 @@ private: namespace loc { -enum Kind { -#define LOC_SVAL(Id, Parent) Id ## Kind, -#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def" -}; +enum Kind { GotoLabelKind, MemRegionValKind, ConcreteIntKind }; class GotoLabel : public Loc { public: diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h index 535203a7f2..77d12e5ba6 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h @@ -43,10 +43,21 @@ class SymExpr : public llvm::FoldingSetNode { virtual void anchor(); public: enum Kind { -#define SYMBOL(Id, Parent) Id ## Kind, -#define SYMBOL_RANGE(Id, First, Last) BEGIN_##Id = First, END_##Id = Last, -#include "clang/StaticAnalyzer/Core/PathSensitive/Symbols.def" + SymbolRegionValueKind, + SymbolConjuredKind, + SymbolDerivedKind, + SymbolExtentKind, + SymbolMetadataKind, + BEGIN_SYMBOLS = SymbolRegionValueKind, + END_SYMBOLS = SymbolMetadataKind, + SymIntExprKind, + IntSymExprKind, + SymSymExprKind, + BEGIN_BINARYSYMEXPRS = SymIntExprKind, + END_BINARYSYMEXPRS = SymSymExprKind, + SymbolCastKind }; + private: Kind K; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Symbols.def b/include/clang/StaticAnalyzer/Core/PathSensitive/Symbols.def deleted file mode 100644 index 7d4d8fe0a5..0000000000 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/Symbols.def +++ /dev/null @@ -1,55 +0,0 @@ -//===-- Symbols.def - Metadata about SymExpr kinds --------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// The list of symbols (SymExpr sub-classes) used in the Static Analyzer. -// In order to use this information, users of this file must define -// one or more of the three macros: -// -// SYMBOL(Id, Parent) - for specific SymExpr sub-classes, reserving the -// IdKind identifier for its kind enumeration value. -// -// ABSTRACT_SYMBOL(Id, Parent) - for abstract symbol classes, -// -// SYMBOL_RANGE(Id, First, Last) - for ranges of kind-enums, -// allowing to determine abstract class of a symbol -// based on the kind enumeration value. -// -//===----------------------------------------------------------------------===// - -#ifndef SYMBOL -#define SYMBOL(Id, Parent) -#endif - -#ifndef ABSTRACT_SYMBOL -#define ABSTRACT_SYMBOL(Id, Parent) -#endif - -#ifndef SYMBOL_RANGE -#define SYMBOL_RANGE(Id, First, Last) -#endif - -ABSTRACT_SYMBOL(BinarySymExpr, SymExpr) - SYMBOL(IntSymExpr, BinarySymExpr) - SYMBOL(SymIntExpr, BinarySymExpr) - SYMBOL(SymSymExpr, BinarySymExpr) -SYMBOL_RANGE(BINARYSYMEXPRS, IntSymExprKind, SymSymExprKind) - -SYMBOL(SymbolCast, SymExpr) - -ABSTRACT_SYMBOL(SymbolData, SymExpr) - SYMBOL(SymbolConjured, SymbolData) - SYMBOL(SymbolDerived, SymbolData) - SYMBOL(SymbolExtent, SymbolData) - SYMBOL(SymbolMetadata, SymbolData) - SYMBOL(SymbolRegionValue, SymbolData) -SYMBOL_RANGE(SYMBOLS, SymbolConjuredKind, SymbolRegionValueKind) - -#undef SYMBOL -#undef ABSTRACT_SYMBOL -#undef SYMBOL_RANGE diff --git a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp index 31e9150cc1..8f6c20ab19 100644 --- a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp @@ -11,7 +11,6 @@ #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" -#include "clang/StaticAnalyzer/Checkers/SValExplainer.h" #include "llvm/ADT/StringSwitch.h" using namespace clang; @@ -26,21 +25,17 @@ class ExprInspectionChecker : public Checker { void analyzerWarnIfReached(const CallExpr *CE, CheckerContext &C) const; void analyzerCrash(const CallExpr *CE, CheckerContext &C) const; void analyzerWarnOnDeadSymbol(const CallExpr *CE, CheckerContext &C) const; - void analyzerExplain(const CallExpr *CE, CheckerContext &C) const; - void analyzerGetExtent(const CallExpr *CE, CheckerContext &C) const; typedef void (ExprInspectionChecker::*FnCheck)(const CallExpr *, CheckerContext &C) const; - void reportBug(llvm::StringRef Msg, CheckerContext &C) const; - public: bool evalCall(const CallExpr *CE, CheckerContext &C) const; void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; }; } -REGISTER_SET_WITH_PROGRAMSTATE(MarkedSymbols, SymbolRef) +REGISTER_SET_WITH_PROGRAMSTATE(MarkedSymbols, const void *) bool ExprInspectionChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { @@ -55,8 +50,6 @@ bool ExprInspectionChecker::evalCall(const CallExpr *CE, &ExprInspectionChecker::analyzerWarnIfReached) .Case("clang_analyzer_warnOnDeadSymbol", &ExprInspectionChecker::analyzerWarnOnDeadSymbol) - .Case("clang_analyzer_explain", &ExprInspectionChecker::analyzerExplain) - .Case("clang_analyzer_getExtent", &ExprInspectionChecker::analyzerGetExtent) .Default(nullptr); if (!Handler) @@ -98,18 +91,6 @@ static const char *getArgumentValueString(const CallExpr *CE, } } -void ExprInspectionChecker::reportBug(llvm::StringRef Msg, - CheckerContext &C) const { - if (!BT) - BT.reset(new BugType(this, "Checking analyzer assumptions", "debug")); - - ExplodedNode *N = C.generateNonFatalErrorNode(); - if (!N) - return; - - C.emitReport(llvm::make_unique(*BT, Msg, N)); -} - void ExprInspectionChecker::analyzerEval(const CallExpr *CE, CheckerContext &C) const { const LocationContext *LC = C.getPredecessor()->getLocationContext(); @@ -119,12 +100,26 @@ void ExprInspectionChecker::analyzerEval(const CallExpr *CE, if (LC->getCurrentStackFrame()->getParent() != nullptr) return; - reportBug(getArgumentValueString(CE, C), C); + if (!BT) + BT.reset(new BugType(this, "Checking analyzer assumptions", "debug")); + + ExplodedNode *N = C.generateNonFatalErrorNode(); + if (!N) + return; + C.emitReport( + llvm::make_unique(*BT, getArgumentValueString(CE, C), N)); } void ExprInspectionChecker::analyzerWarnIfReached(const CallExpr *CE, CheckerContext &C) const { - reportBug("REACHABLE", C); + + if (!BT) + BT.reset(new BugType(this, "Checking analyzer assumptions", "debug")); + + ExplodedNode *N = C.generateNonFatalErrorNode(); + if (!N) + return; + C.emitReport(llvm::make_unique(*BT, "REACHABLE", N)); } void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE, @@ -139,32 +134,14 @@ void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE, if (LC->getCurrentStackFrame()->getParent() == nullptr) return; - reportBug(getArgumentValueString(CE, C), C); -} - -void ExprInspectionChecker::analyzerExplain(const CallExpr *CE, - CheckerContext &C) const { - if (CE->getNumArgs() == 0) - reportBug("Missing argument for explaining", C); - - SVal V = C.getSVal(CE->getArg(0)); - SValExplainer Ex(C.getASTContext()); - reportBug(Ex.Visit(V), C); -} - -void ExprInspectionChecker::analyzerGetExtent(const CallExpr *CE, - CheckerContext &C) const { - if (CE->getNumArgs() == 0) - reportBug("Missing region for obtaining extent", C); - - auto MR = dyn_cast_or_null(C.getSVal(CE->getArg(0)).getAsRegion()); - if (!MR) - reportBug("Obtaining extent of a non-region", C); + if (!BT) + BT.reset(new BugType(this, "Checking analyzer assumptions", "debug")); - ProgramStateRef State = C.getState(); - State = State->BindExpr(CE, C.getLocationContext(), - MR->getExtent(C.getSValBuilder())); - C.addTransition(State); + ExplodedNode *N = C.generateNonFatalErrorNode(); + if (!N) + return; + C.emitReport( + llvm::make_unique(*BT, getArgumentValueString(CE, C), N)); } void ExprInspectionChecker::analyzerWarnOnDeadSymbol(const CallExpr *CE, @@ -186,14 +163,20 @@ void ExprInspectionChecker::checkDeadSymbols(SymbolReaper &SymReaper, ProgramStateRef State = C.getState(); const MarkedSymbolsTy &Syms = State->get(); for (auto I = Syms.begin(), E = Syms.end(); I != E; ++I) { - SymbolRef Sym = *I; + SymbolRef Sym = static_cast(*I); if (!SymReaper.isDead(Sym)) continue; - reportBug("SYMBOL DEAD", C); - State = State->remove(Sym); + if (!BT) + BT.reset(new BugType(this, "Checking analyzer assumptions", "debug")); + + ExplodedNode *N = C.generateNonFatalErrorNode(); + if (!N) + return; + + C.emitReport(llvm::make_unique(*BT, "SYMBOL DEAD", N)); + C.addTransition(State->remove(Sym), N); } - C.addTransition(State); } void ExprInspectionChecker::analyzerCrash(const CallExpr *CE, diff --git a/test/Analysis/explain-svals.cpp b/test/Analysis/explain-svals.cpp deleted file mode 100644 index 675935c58f..0000000000 --- a/test/Analysis/explain-svals.cpp +++ /dev/null @@ -1,98 +0,0 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=core.builtin,debug.ExprInspection,unix.cstring -verify %s - -typedef unsigned long size_t; - -struct S { - struct S3 { - int y[10]; - }; - struct S2 : S3 { - int *x; - } s2[10]; - int z; -}; - - -void clang_analyzer_explain(int); -void clang_analyzer_explain(void *); -void clang_analyzer_explain(S); - -size_t clang_analyzer_getExtent(void *); - -size_t strlen(const char *); - -int conjure(); -S conjure_S(); - -int glob; -static int stat_glob; -void *glob_ptr; - -// Test strings are regex'ed because we need to match exact string -// rather than a substring. - -void test_1(int param, void *ptr) { - clang_analyzer_explain(&glob); // expected-warning-re{{{{^pointer to global variable 'glob'$}}}} - clang_analyzer_explain(param); // expected-warning-re{{{{^argument 'param'$}}}} - clang_analyzer_explain(ptr); // expected-warning-re{{{{^argument 'ptr'$}}}} - if (param == 42) - clang_analyzer_explain(param); // expected-warning-re{{{{^signed 32-bit integer '42'$}}}} -} - -void test_2(char *ptr, int ext) { - clang_analyzer_explain((void *) "asdf"); // expected-warning-re{{{{^pointer to element of type 'char' with index 0 of string literal "asdf"$}}}} - clang_analyzer_explain(strlen(ptr)); // expected-warning-re{{{{^metadata of type 'unsigned long' tied to pointee of argument 'ptr'$}}}} - clang_analyzer_explain(conjure()); // expected-warning-re{{{{^symbol of type 'int' conjured at statement 'conjure\(\)'$}}}} - clang_analyzer_explain(glob); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at statement 'conjure\(\)'\) for global variable 'glob'$}}}} - clang_analyzer_explain(glob_ptr); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at statement 'conjure\(\)'\) for global variable 'glob_ptr'$}}}} - clang_analyzer_explain(clang_analyzer_getExtent(ptr)); // expected-warning-re{{{{^extent of pointee of argument 'ptr'$}}}} - int *x = new int[ext]; - clang_analyzer_explain(x); // expected-warning-re{{{{^pointer to element of type 'int' with index 0 of pointee of symbol of type 'int \*' conjured at statement 'new int \[ext\]'$}}}} - // Sic! What gets computed is the extent of the element-region. - clang_analyzer_explain(clang_analyzer_getExtent(x)); // expected-warning-re{{{{^signed 32-bit integer '4'$}}}} - delete[] x; -} - -void test_3(S s) { - clang_analyzer_explain(&s); // expected-warning-re{{{{^pointer to parameter 's'$}}}} - clang_analyzer_explain(s.z); // expected-warning-re{{{{^initial value of field 'z' of parameter 's'$}}}} - clang_analyzer_explain(&s.s2[5].y[3]); // expected-warning-re{{{{^pointer to element of type 'int' with index 3 of field 'y' of base object 'S::S3' inside element of type 'struct S::S2' with index 5 of field 's2' of parameter 's'$}}}} - if (!s.s2[7].x) { - clang_analyzer_explain(s.s2[7].x); // expected-warning-re{{{{^concrete memory address '0'$}}}} - // FIXME: we need to be explaining '1' rather than '0' here; not explainer bug. - clang_analyzer_explain(s.s2[7].x + 1); // expected-warning-re{{{{^concrete memory address '0'$}}}} - } -} - -void test_4(int x, int y) { - int z; - static int stat; - clang_analyzer_explain(x + 1); // expected-warning-re{{{{^\(argument 'x'\) \+ 1$}}}} - clang_analyzer_explain(1 + y); // expected-warning-re{{{{^\(argument 'y'\) \+ 1$}}}} - clang_analyzer_explain(x + y); // expected-warning-re{{{{^unknown value$}}}} - clang_analyzer_explain(z); // expected-warning-re{{{{^undefined value$}}}} - clang_analyzer_explain(&z); // expected-warning-re{{{{^pointer to local variable 'z'$}}}} - clang_analyzer_explain(stat); // expected-warning-re{{{{^signed 32-bit integer '0'$}}}} - clang_analyzer_explain(&stat); // expected-warning-re{{{{^pointer to static local variable 'stat'$}}}} - clang_analyzer_explain(stat_glob); // expected-warning-re{{{{^initial value of global variable 'stat_glob'$}}}} - clang_analyzer_explain(&stat_glob); // expected-warning-re{{{{^pointer to global variable 'stat_glob'$}}}} - clang_analyzer_explain((int[]){1, 2, 3}); // expected-warning-re{{{{^pointer to element of type 'int' with index 0 of compound literal \(int \[3\]\)\{1, 2, 3\}$}}}} -} - -namespace { -class C { - int x[10]; - -public: - void test_5(int i) { - clang_analyzer_explain(this); // expected-warning-re{{{{^pointer to 'this' object$}}}} - clang_analyzer_explain(&x[i]); // expected-warning-re{{{{^pointer to element of type 'int' with index 'argument 'i'' of field 'x' of 'this' object$}}}} - clang_analyzer_explain(__builtin_alloca(i)); // expected-warning-re{{{{^pointer to region allocated by '__builtin_alloca\(i\)'$}}}} - } -}; -} // end of anonymous namespace - -void test_6() { - clang_analyzer_explain(conjure_S()); // expected-warning-re{{{{^lazily frozen compound value of temporary object constructed at statement 'conjure_S\(\)'$}}}} - clang_analyzer_explain(conjure_S().z); // expected-warning-re{{{{^value derived from \(symbol of type 'struct S' conjured at statement 'conjure_S\(\)'\) for field 'z' of temporary object constructed at statement 'conjure_S\(\)'$}}}} -} -- 2.40.0