diff options
Diffstat (limited to 'clang/lib/Analysis/UnsafeBufferUsage.cpp')
-rw-r--r-- | clang/lib/Analysis/UnsafeBufferUsage.cpp | 99 |
1 files changed, 97 insertions, 2 deletions
diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index ad3d234..f5a3686 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -13,6 +13,7 @@ #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/DynamicRecursiveASTVisitor.h" #include "clang/AST/Expr.h" #include "clang/AST/FormatString.h" @@ -1318,6 +1319,97 @@ static bool isSupportedVariable(const DeclRefExpr &Node) { return D != nullptr && isa<VarDecl>(D); } +// Returns true for RecordDecl of type std::unique_ptr<T[]> +static bool isUniquePtrArray(const CXXRecordDecl *RecordDecl) { + if (!RecordDecl || !RecordDecl->isInStdNamespace() || + RecordDecl->getNameAsString() != "unique_ptr") + return false; + + const ClassTemplateSpecializationDecl *class_template_specialization_decl = + dyn_cast<ClassTemplateSpecializationDecl>(RecordDecl); + if (!class_template_specialization_decl) + return false; + + const TemplateArgumentList &template_args = + class_template_specialization_decl->getTemplateArgs(); + if (template_args.size() == 0) + return false; + + const TemplateArgument &first_arg = template_args[0]; + if (first_arg.getKind() != TemplateArgument::Type) + return false; + + QualType referred_type = first_arg.getAsType(); + return referred_type->isArrayType(); +} + +class UniquePtrArrayAccessGadget : public WarningGadget { +private: + static constexpr const char *const AccessorTag = "unique_ptr_array_access"; + const CXXOperatorCallExpr *AccessorExpr; + +public: + UniquePtrArrayAccessGadget(const MatchResult &Result) + : WarningGadget(Kind::UniquePtrArrayAccess), + AccessorExpr(Result.getNodeAs<CXXOperatorCallExpr>(AccessorTag)) { + assert(AccessorExpr && + "UniquePtrArrayAccessGadget requires a matched CXXOperatorCallExpr"); + } + + static bool classof(const Gadget *G) { + return G->getKind() == Kind::UniquePtrArrayAccess; + } + + static bool matches(const Stmt *S, const ASTContext &Ctx, + MatchResult &Result) { + + const CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(S); + if (!OpCall || OpCall->getOperator() != OO_Subscript) + return false; + + const Expr *Callee = OpCall->getCallee()->IgnoreParenImpCasts(); + if (!Callee) + return false; + + const CXXMethodDecl *Method = + dyn_cast_or_null<CXXMethodDecl>(OpCall->getDirectCallee()); + if (!Method) + return false; + + if (Method->getOverloadedOperator() != OO_Subscript) + return false; + + const CXXRecordDecl *RecordDecl = Method->getParent(); + if (!isUniquePtrArray(RecordDecl)) + return false; + + const Expr *IndexExpr = OpCall->getArg(1); + clang::Expr::EvalResult Eval; + + // Allow [0] + if (IndexExpr->EvaluateAsInt(Eval, Ctx) && Eval.Val.getInt().isZero()) + return false; + + Result.addNode(AccessorTag, DynTypedNode::create(*OpCall)); + return true; + } + void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler, + bool IsRelatedToDecl, + ASTContext &Ctx) const override { + Handler.handleUnsafeUniquePtrArrayAccess( + DynTypedNode::create(*AccessorExpr), IsRelatedToDecl, Ctx); + } + + SourceLocation getSourceLoc() const override { + if (AccessorExpr) + return AccessorExpr->getOperatorLoc(); + return SourceLocation(); + } + + DeclUseList getClaimedVarUseSites() const override { return {}; } + SmallVector<const Expr *, 1> getUnsafePtrs() const override { return {}; } +}; + using FixableGadgetList = std::vector<std::unique_ptr<FixableGadget>>; using WarningGadgetList = std::vector<std::unique_ptr<WarningGadget>>; @@ -2632,10 +2724,13 @@ std::set<const Expr *> clang::findUnsafePointers(const FunctionDecl *FD) { const VariableGroupsManager &, FixItList &&, const Decl *, const FixitStrategy &) override {} - bool isSafeBufferOptOut(const SourceLocation &) const override { + void handleUnsafeUniquePtrArrayAccess(const DynTypedNode &Node, + bool IsRelatedToDecl, + ASTContext &Ctx) override {} + bool ignoreUnsafeBufferInContainer(const SourceLocation &) const override { return false; } - bool ignoreUnsafeBufferInContainer(const SourceLocation &) const override { + bool isSafeBufferOptOut(const SourceLocation &) const override { return false; } bool ignoreUnsafeBufferInLibcCall(const SourceLocation &) const override { |