29#include "llvm/ADT/APInt.h"
30#include "llvm/ADT/APSInt.h"
31#include "llvm/ADT/STLExtras.h"
32#include "llvm/ADT/STLFunctionalExtras.h"
33#include "llvm/ADT/SmallVector.h"
34#include "llvm/ADT/StringRef.h"
51 std::string VisitBinaryOperator(
const BinaryOperator *BO) {
52 return "BinaryOperator(" + BO->
getOpcodeStr().str() +
")";
55 std::string VisitUnaryOperator(
const UnaryOperator *UO) {
59 std::string VisitImplicitCastExpr(
const ImplicitCastExpr *ICE) {
66static std::string getDREAncestorString(
const DeclRefExpr *DRE,
70 StmtDebugPrinter StmtPriner;
73 SS << StmtPriner.Visit(St);
77 if (StParents.
size() > 1)
78 return "unavailable due to multiple parents";
79 if (StParents.
empty())
98 virtual bool matches(
const DynTypedNode &DynNode, ASTContext &Ctx,
99 const UnsafeBufferUsageHandler &Handler) = 0;
100 virtual ~FastMatcher() =
default;
106 template <
typename T>
const T *getNodeAs(StringRef ID)
const {
107 auto It =
Nodes.find(ID);
108 if (It ==
Nodes.end()) {
111 return It->second.get<T>();
114 void addNode(StringRef ID,
const DynTypedNode &Node) {
Nodes[
ID] = Node; }
117 llvm::StringMap<DynTypedNode>
Nodes;
121#define SIZED_CONTAINER_OR_VIEW_LIST \
122 "span", "array", "vector", "basic_string_view", "basic_string", \
133 bool FindAll,
bool IgnoreUnevaluatedContext,
135 : Matcher(&Matcher), FindAll(FindAll), Matches(
false),
136 IgnoreUnevaluatedContext(IgnoreUnevaluatedContext),
137 ActiveASTContext(&Context), Handler(&NewHandler) {
174 if (IgnoreUnevaluatedContext)
176 return DynamicRecursiveASTVisitor::TraverseGenericSelectionExpr(Node);
182 if (IgnoreUnevaluatedContext)
184 return DynamicRecursiveASTVisitor::TraverseUnaryExprOrTypeTraitExpr(Node);
188 bool TraverseQualifier)
override {
190 if (IgnoreUnevaluatedContext)
192 return DynamicRecursiveASTVisitor::TraverseTypeOfExprTypeLoc(
193 Node, TraverseQualifier);
197 bool TraverseQualifier)
override {
199 if (IgnoreUnevaluatedContext)
201 return DynamicRecursiveASTVisitor::TraverseDecltypeTypeLoc(
202 Node, TraverseQualifier);
207 if (IgnoreUnevaluatedContext)
209 return DynamicRecursiveASTVisitor::TraverseCXXNoexceptExpr(Node);
214 if (IgnoreUnevaluatedContext)
216 return DynamicRecursiveASTVisitor::TraverseCXXTypeidExpr(Node);
222 return DynamicRecursiveASTVisitor::TraverseCXXDefaultInitExpr(Node);
238 template <
typename T>
bool match(
const T &Node) {
248 FastMatcher *
const Matcher;
252 bool IgnoreUnevaluatedContext;
253 ASTContext *ActiveASTContext;
254 const UnsafeBufferUsageHandler *Handler;
269 FastMatcher &Matcher) {
277 FastMatcher &Matcher) {
305 const Stmt *S,
const llvm::function_ref<
void(
const Expr *)> OnResult) {
306 if (
const auto *CE = dyn_cast<ImplicitCastExpr>(S);
307 CE && CE->getCastKind() == CastKind::CK_LValueToRValue)
308 OnResult(CE->getSubExpr());
309 if (
const auto *BO = dyn_cast<BinaryOperator>(S);
317 const Stmt *S, llvm::function_ref<
void(
const Stmt *)> InnerMatcher) {
326 if (
auto *CE = dyn_cast<CallExpr>(S)) {
327 if (
const auto *FnDecl = CE->getDirectCallee();
328 FnDecl && FnDecl->hasAttr<UnsafeBufferUsageAttr>())
337 if (
auto *CE = dyn_cast<CastExpr>(S)) {
338 if (CE->getCastKind() != CastKind::CK_PointerToIntegral &&
339 CE->getCastKind() != CastKind::CK_PointerToBoolean)
343 InnerMatcher(CE->getSubExpr());
347 if (
const auto *BO = dyn_cast<BinaryOperator>(S);
361 if (
const auto *BO = dyn_cast<BinaryOperator>(S);
367 InnerMatcher(BO->
getLHS());
368 InnerMatcher(BO->
getRHS());
386 const Stmt *S, llvm::function_ref<
void(
const Stmt *)> InnerMatcher) {
391 if (
auto *CS = dyn_cast<CompoundStmt>(S)) {
392 for (
auto *Child : CS->body())
395 if (
auto *IfS = dyn_cast<IfStmt>(S)) {
397 InnerMatcher(IfS->getThen());
399 InnerMatcher(IfS->getElse());
450 case Stmt::DeclRefExprClass:
452 case Stmt::BinaryOperatorClass: {
455 BO2->getLHS(), BO2->getOpcode(),
472 if (
const auto *UO = dyn_cast<UnaryOperator>(Ptr)) {
473 if (UO->
getOpcode() != UnaryOperator::Opcode::UO_AddrOf)
479 if (
const auto *CE = dyn_cast<CallExpr>(Ptr)) {
484 return CE->getArg(0)->IgnoreParenImpCasts();
494 const auto *SizeOfExpr =
496 if (!SizeOfExpr || SizeOfExpr->getKind() != UETT_SizeOf)
498 if (SizeOfExpr->isArgumentType())
500 return SizeOfExpr->getArgumentExpr()->IgnoreParenImpCasts();
521 dyn_cast<CXXMemberCallExpr>(Size->IgnoreParenImpCasts())) {
522 auto *DREOfPtr = dyn_cast<DeclRefExpr>(
523 MCEPtr->getImplicitObjectArgument()->IgnoreParenImpCasts());
524 auto *DREOfSize = dyn_cast<DeclRefExpr>(
525 MCESize->getImplicitObjectArgument()->IgnoreParenImpCasts());
527 if (!DREOfPtr || !DREOfSize)
531 if (DREOfPtr->getDecl() != DREOfSize->getDecl())
533 if (MCEPtr->getMethodDecl()->getName() !=
"data")
536 if (!MCEPtr->getRecordDecl()->isInStdNamespace())
539 auto *ObjII = MCEPtr->getRecordDecl()->getIdentifier();
546 if (!((AcceptSizeBytes &&
547 MCESize->getMethodDecl()->getName() ==
"size_bytes") ||
552 MCESize->getMethodDecl()->getName() ==
"size"))
562 if (Size->EvaluateAsInt(ER, Ctx)) {
568 return llvm::APSInt::compareValues(
569 SizeInt, llvm::APSInt(CAT->getSize(),
true)) == 0;
603 "expecting a two-parameter std::span constructor");
606 auto HaveEqualConstantValues = [&Ctx](
const Expr *E0,
const Expr *E1) {
608 if (
auto E1CV = E1->getIntegerConstantExpr(Ctx)) {
609 return llvm::APSInt::compareValues(*E0CV, *E1CV) == 0;
613 auto AreSameDRE = [](
const Expr *E0,
const Expr *E1) {
614 if (
auto *DRE0 = dyn_cast<DeclRefExpr>(E0))
615 if (
auto *DRE1 = dyn_cast<DeclRefExpr>(E1)) {
616 return DRE0->getDecl() == DRE1->getDecl();
622 if (Arg1CV && Arg1CV->isZero())
628 case Stmt::CXXNewExprClass:
631 return AreSameDRE((*Size)->IgnoreImplicit(), Arg1) ||
632 HaveEqualConstantValues(*Size, Arg1);
637 return Arg1CV && Arg1CV->isOne();
645 if (
auto CCast = dyn_cast<CStyleCastExpr>(Arg0)) {
646 if (!CCast->getType()->isPointerType())
654 if (
const auto *
Call = dyn_cast<CallExpr>(CCast->getSubExpr())) {
656 if (
auto *AllocAttr = FD->getAttr<AllocSizeAttr>()) {
657 const Expr *EleSizeExpr =
658 Call->getArg(AllocAttr->getElemSizeParam().getASTIndex());
660 ParamIdx NumElemIdx = AllocAttr->getNumElemsParam();
667 if (
auto BO = dyn_cast<BinaryOperator>(Arg1))
674 auto IsMethodCallToSizedObject = [](
const Stmt *Node, StringRef MethodName) {
675 if (
const auto *MC = dyn_cast<CXXMemberCallExpr>(Node)) {
676 const auto *MD = MC->getMethodDecl();
677 const auto *RD = MC->getRecordDecl();
680 if (
auto *II = RD->getDeclName().getAsIdentifierInfo();
681 II && RD->isInStdNamespace())
684 MD->getName() == MethodName;
689 if (IsMethodCallToSizedObject(Arg0,
"begin") &&
690 IsMethodCallToSizedObject(Arg1,
"end"))
694 ->getImplicitObjectArgument()
695 ->IgnoreParenImpCasts(),
697 ->getImplicitObjectArgument()
698 ->IgnoreParenImpCasts());
706 const bool IgnoreStaticSizedArrays) {
715 if (
const auto *CATy =
716 dyn_cast<ConstantArrayType>(Node.
getBase()
720 limit = CATy->getLimitedSize();
721 }
else if (
const auto *SLiteral = dyn_cast<clang::StringLiteral>(
723 limit = SLiteral->getLength() + 1;
728 if (IgnoreStaticSizedArrays) {
738 llvm::APSInt ArrIdx = EVResult.
Val.
getInt();
741 if (ArrIdx.isNonNegative() && ArrIdx.getLimitedValue() < limit)
743 }
else if (
const auto *BE = dyn_cast<BinaryOperator>(IndexExpr)) {
746 if (BE->getOpcode() != BO_And && BE->getOpcode() != BO_Rem)
749 const Expr *LHS = BE->getLHS();
750 const Expr *RHS = BE->getRHS();
752 if (BE->getOpcode() == BO_Rem) {
759 llvm::APSInt result = EVResult.
Val.
getInt();
760 if (result.isNonNegative() && result.getLimitedValue() <= limit)
771 llvm::APSInt result = EVResult.
Val.
getInt();
772 if (result.isNonNegative() && result.getLimitedValue() < limit)
786 if (
const auto *CE = dyn_cast<ConditionalOperator>(E)) {
788 const auto *
Cond = CE->getCond();
790 if (!
Cond->isValueDependent() &&
791 Cond->EvaluateAsBooleanCondition(CondEval, Ctx))
792 return CondEval ? CE->getLHS() : CE->getRHS();
802 if (
const auto *DefaultArgE = dyn_cast<CXXDefaultArgExpr>(Ptr))
810 if (
const auto *CondE = dyn_cast<ConditionalOperator>(Ptr)) {
819 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(Ptr)) {
829 static const llvm::StringSet<> NullTermFunctions = {
"strerror"};
830 if (
auto *CE = dyn_cast<CallExpr>(Ptr)) {
853 if (Name.ends_with(
"_s"))
854 return Name.drop_back(2 );
861 if (Name.starts_with(
"__") && Name.ends_with(
"_chk"))
863 Name.drop_front(2).drop_back(4) );
867static StringRef
matchName(StringRef FunName,
bool isBuiltin) {
869 if (isBuiltin && FunName.starts_with(
"__builtin_"))
873 FunName.drop_front(10 ));
875 if (FunName.starts_with(
"__asan_"))
892 const Expr *&UnsafeArg,
const unsigned FmtIdx,
893 std::optional<const unsigned> FmtArgIdx = std::nullopt,
894 bool isKprintf =
false) {
895 class StringFormatStringHandler
899 const Expr *&UnsafeArg;
915 unsigned PArgIdx = Precision.
getArgIndex() + FmtArgIdx;
917 if (PArgIdx < Call->getNumArgs()) {
918 const Expr *PArg =
Call->getArg(PArgIdx);
921 if (
auto *CE = dyn_cast<CastExpr>(PArg);
922 CE && CE->getType()->isSignedIntegerType())
923 PArg = CE->getSubExpr();
928 analyze_printf::OptionalAmount::HowSpecified::Constant) {
930 llvm::APSInt PArgVal = llvm::APSInt(
940 StringFormatStringHandler(
const CallExpr *
Call,
unsigned FmtArgIdx,
942 :
Call(
Call), FmtArgIdx(FmtArgIdx), UnsafeArg(UnsafeArg), Ctx(Ctx),
943 UnsafeArgSet(
false) {}
946 const char *startSpecifier,
947 unsigned specifierLen,
955 if (ArgIdx >=
Call->getNumArgs())
959 const Expr *Arg =
Call->getArg(ArgIdx);
969 bool IsArgTypeValid =
972 ?
ArgType->getPointeeType()->isWideCharType()
973 :
ArgType->getPointeeType()->isCharType());
976 Precision && IsArgTypeValid)
980 UnsafeArg =
Call->getArg(ArgIdx);
985 bool isUnsafeArgSet() {
return UnsafeArgSet; }
988 const Expr *Fmt =
Call->getArg(FmtIdx);
989 unsigned FmtArgStartingIdx =
990 FmtArgIdx.has_value() ?
static_cast<unsigned>(*FmtArgIdx) : FmtIdx + 1;
993 if (SL->getCharByteWidth() == 1) {
994 StringRef FmtStr = SL->getString();
995 StringFormatStringHandler Handler(
Call, FmtArgStartingIdx, UnsafeArg,
999 Handler, FmtStr.begin(), FmtStr.end(), Ctx.
getLangOpts(),
1001 Handler.isUnsafeArgSet();
1004 if (
auto FmtStr = SL->tryEvaluateString(Ctx)) {
1005 StringFormatStringHandler Handler(
Call, FmtArgStartingIdx, UnsafeArg,
1008 Handler, FmtStr->data(), FmtStr->data() + FmtStr->size(),
1010 Handler.isUnsafeArgSet();
1016 return llvm::any_of(
1017 llvm::make_range(
Call->arg_begin() + FmtIdx,
Call->arg_end()),
1018 [&UnsafeArg, &Ctx](
const Expr *Arg) ->
bool {
1019 if (Arg->getType()->isPointerType() && !isNullTermPointer(Arg, Ctx)) {
1037 static const std::set<StringRef> PredefinedNames = {
1116 if (PredefinedNames.count(Name))
1119 std::string NameWCS = Name.str();
1120 size_t WcsPos = NameWCS.find(
"wcs");
1122 while (WcsPos != std::string::npos) {
1123 NameWCS[WcsPos++] =
's';
1124 NameWCS[WcsPos++] =
't';
1125 NameWCS[WcsPos++] =
'r';
1126 WcsPos = NameWCS.find(
"wcs", WcsPos);
1128 if (PredefinedNames.count(NameWCS))
1132 return Name.ends_with(
"scanf");
1140 assert(FD &&
"It should have been checked that FD is non-null.");
1147 if (Name !=
"memset")
1159 const auto *AddressOfVar = dyn_cast_if_present<DeclRefExpr>(
1164 const auto *SizeOfVar =
1169 return AddressOfVar->getDecl() != SizeOfVar->getDecl();
1183 return Name.starts_with(
"v") && Name.ends_with(
"printf");
1196 return Name ==
"sprintf" || Name ==
"swprintf";
1210 if (!Name.ends_with(
"printf"))
1213 StringRef Prefix = Name.drop_back(6);
1215 if (Prefix.ends_with(
"w"))
1216 Prefix = Prefix.drop_back(1);
1218 return Prefix.empty() || Prefix ==
"k" || Prefix ==
"f" || Prefix ==
"sn";
1226 MatchResult &Result, llvm::StringRef Tag) {
1230 assert(FD &&
"It should have been checked that FD is non-null.");
1248 const Expr *UnsafeArg;
1259 bool isKprintf =
false;
1260 const Expr *UnsafeArg;
1263 isKprintf = II->getName() ==
"kprintf";
1265 std::nullopt, isKprintf)) {
1278 const Expr *UnsafeArg;
1289 for (
const auto *Arg : Node.
arguments())
1304 assert(FD &&
"It should have been checked that FD is non-null.");
1319 !Size->getType()->isUnsignedIntegerType())
1348#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1351 Gadget(Kind K) : K(K) {}
1353 Kind
getKind()
const {
return K; }
1356 StringRef getDebugName()
const {
1361#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1363 llvm_unreachable(
"Unhandled Gadget::Kind enum");
1367 virtual bool isWarningGadget()
const = 0;
1370 virtual SourceLocation getSourceLoc()
const = 0;
1375 virtual DeclUseList getClaimedVarUseSites()
const = 0;
1377 virtual ~Gadget() =
default;
1385class WarningGadget :
public Gadget {
1387 WarningGadget(Kind K) : Gadget(K) {}
1389 static bool classof(
const Gadget *G) {
return G->isWarningGadget(); }
1390 bool isWarningGadget() const final {
return true; }
1392 virtual void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1393 bool IsRelatedToDecl,
1394 ASTContext &Ctx)
const = 0;
1396 virtual SmallVector<const Expr *, 1> getUnsafePtrs()
const = 0;
1403class FixableGadget :
public Gadget {
1405 FixableGadget(Kind K) : Gadget(K) {}
1407 static bool classof(
const Gadget *G) {
return !G->isWarningGadget(); }
1408 bool isWarningGadget() const final {
return false; }
1413 virtual std::optional<FixItList> getFixits(
const FixitStrategy &)
const {
1414 return std::nullopt;
1423 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1424 getStrategyImplications()
const {
1425 return std::nullopt;
1429static bool isSupportedVariable(
const DeclRefExpr &Node) {
1441 dyn_cast<ClassTemplateSpecializationDecl>(
RecordDecl);
1442 if (!class_template_specialization_decl)
1447 if (template_args.
size() == 0)
1458class UniquePtrArrayAccessGadget :
public WarningGadget {
1460 static constexpr const char *
const AccessorTag =
"unique_ptr_array_access";
1461 const CXXOperatorCallExpr *AccessorExpr;
1465 : WarningGadget(
Kind::UniquePtrArrayAccess),
1466 AccessorExpr(
Result.getNodeAs<CXXOperatorCallExpr>(AccessorTag)) {
1467 assert(AccessorExpr &&
1468 "UniquePtrArrayAccessGadget requires a matched CXXOperatorCallExpr");
1471 static bool classof(
const Gadget *G) {
1472 return G->getKind() == Kind::UniquePtrArrayAccess;
1475 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1478 const CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(S);
1479 if (!OpCall || OpCall->
getOperator() != OO_Subscript)
1486 const CXXMethodDecl *
Method =
1491 if (
Method->getOverloadedOperator() != OO_Subscript)
1495 if (!isUniquePtrArray(RecordDecl))
1498 const Expr *IndexExpr = OpCall->
getArg(1);
1499 clang::Expr::EvalResult Eval;
1505 Result.addNode(AccessorTag, DynTypedNode::create(*OpCall));
1508 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1509 bool IsRelatedToDecl,
1510 ASTContext &Ctx)
const override {
1512 DynTypedNode::create(*AccessorExpr), IsRelatedToDecl, Ctx);
1515 SourceLocation getSourceLoc()
const override {
1517 return AccessorExpr->getOperatorLoc();
1518 return SourceLocation();
1521 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1522 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1525using FixableGadgetList = std::vector<std::unique_ptr<FixableGadget>>;
1526using WarningGadgetList = std::vector<std::unique_ptr<WarningGadget>>;
1530class IncrementGadget :
public WarningGadget {
1531 static constexpr const char *
const OpTag =
"op";
1532 const UnaryOperator *Op;
1536 : WarningGadget(
Kind::Increment),
1537 Op(
Result.getNodeAs<UnaryOperator>(OpTag)) {}
1539 static bool classof(
const Gadget *G) {
1540 return G->getKind() == Kind::Increment;
1543 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1545 const auto *UO = dyn_cast<UnaryOperator>(S);
1550 Result.addNode(OpTag, DynTypedNode::create(*UO));
1554 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1555 bool IsRelatedToDecl,
1556 ASTContext &Ctx)
const override {
1559 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1561 DeclUseList getClaimedVarUseSites()
const override {
1562 SmallVector<const DeclRefExpr *, 2> Uses;
1563 if (
const auto *DRE =
1564 dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
1565 Uses.push_back(DRE);
1568 return std::move(Uses);
1571 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1572 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1578class DecrementGadget :
public WarningGadget {
1579 static constexpr const char *
const OpTag =
"op";
1580 const UnaryOperator *Op;
1584 : WarningGadget(
Kind::Decrement),
1585 Op(
Result.getNodeAs<UnaryOperator>(OpTag)) {}
1587 static bool classof(
const Gadget *G) {
1588 return G->getKind() == Kind::Decrement;
1591 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1593 const auto *UO = dyn_cast<UnaryOperator>(S);
1598 Result.addNode(OpTag, DynTypedNode::create(*UO));
1602 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1603 bool IsRelatedToDecl,
1604 ASTContext &Ctx)
const override {
1607 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1609 DeclUseList getClaimedVarUseSites()
const override {
1610 if (
const auto *DRE =
1611 dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
1618 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1619 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1625class ArraySubscriptGadget :
public WarningGadget {
1626 static constexpr const char *
const ArraySubscrTag =
"ArraySubscript";
1627 const ArraySubscriptExpr *ASE;
1632 ASE(
Result.getNodeAs<ArraySubscriptExpr>(ArraySubscrTag)) {}
1634 static bool classof(
const Gadget *G) {
1635 return G->getKind() == Kind::ArraySubscript;
1638 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1639 const UnsafeBufferUsageHandler *Handler,
1641 const auto *ASE = dyn_cast<ArraySubscriptExpr>(S);
1644 const auto *
const Base = ASE->getBase()->IgnoreParenImpCasts();
1647 const auto *Idx = dyn_cast<IntegerLiteral>(ASE->getIdx());
1648 bool IsSafeIndex = (Idx && Idx->getValue().isZero()) ||
1655 Result.addNode(ArraySubscrTag, DynTypedNode::create(*ASE));
1659 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1660 bool IsRelatedToDecl,
1661 ASTContext &Ctx)
const override {
1664 SourceLocation getSourceLoc()
const override {
return ASE->getBeginLoc(); }
1666 DeclUseList getClaimedVarUseSites()
const override {
1667 if (
const auto *DRE =
1668 dyn_cast<DeclRefExpr>(ASE->getBase()->IgnoreParenImpCasts())) {
1675 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1676 return {ASE->getBase()->IgnoreParenImpCasts()};
1684class PointerArithmeticGadget :
public WarningGadget {
1685 static constexpr const char *
const PointerArithmeticTag =
"ptrAdd";
1686 static constexpr const char *
const PointerArithmeticPointerTag =
"ptrAddPtr";
1687 const BinaryOperator *PA;
1692 : WarningGadget(
Kind::PointerArithmetic),
1693 PA(
Result.getNodeAs<BinaryOperator>(PointerArithmeticTag)),
1694 Ptr(
Result.getNodeAs<Expr>(PointerArithmeticPointerTag)) {}
1696 static bool classof(
const Gadget *G) {
1697 return G->getKind() == Kind::PointerArithmetic;
1700 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1702 const auto *BO = dyn_cast<BinaryOperator>(S);
1705 const auto *LHS = BO->
getLHS();
1706 const auto *RHS = BO->
getRHS();
1711 RHS->getType()->isEnumeralType())) {
1712 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*LHS));
1713 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1719 (LHS->getType()->isIntegerType() || LHS->getType()->isEnumeralType())) {
1720 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*RHS));
1721 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1727 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1728 bool IsRelatedToDecl,
1729 ASTContext &Ctx)
const override {
1732 SourceLocation getSourceLoc()
const override {
return PA->getBeginLoc(); }
1734 DeclUseList getClaimedVarUseSites()
const override {
1735 if (
const auto *DRE = dyn_cast<DeclRefExpr>(Ptr->IgnoreParenImpCasts())) {
1742 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1743 return {Ptr->IgnoreParenImpCasts()};
1750class SpanTwoParamConstructorGadget :
public WarningGadget {
1751 static constexpr const char *
const SpanTwoParamConstructorTag =
1752 "spanTwoParamConstructor";
1753 const CXXConstructExpr *Ctor;
1757 : WarningGadget(
Kind::SpanTwoParamConstructor),
1758 Ctor(
Result.getNodeAs<CXXConstructExpr>(SpanTwoParamConstructorTag)) {}
1760 static bool classof(
const Gadget *G) {
1761 return G->getKind() == Kind::SpanTwoParamConstructor;
1765 const auto *CE = dyn_cast<CXXConstructExpr>(S);
1768 const auto *CDecl = CE->getConstructor();
1769 const auto *CRecordDecl = CDecl->getParent();
1770 auto HasTwoParamSpanCtorDecl =
1771 CRecordDecl->isInStdNamespace() &&
1772 CDecl->getDeclName().getAsString() ==
"span" && CE->getNumArgs() == 2;
1775 Result.addNode(SpanTwoParamConstructorTag, DynTypedNode::create(*CE));
1779 static bool matches(
const Stmt *S, ASTContext &Ctx,
1780 const UnsafeBufferUsageHandler *Handler,
1787 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1788 bool IsRelatedToDecl,
1789 ASTContext &Ctx)
const override {
1792 SourceLocation getSourceLoc()
const override {
return Ctor->getBeginLoc(); }
1794 DeclUseList getClaimedVarUseSites()
const override {
1797 if (
auto *DRE = dyn_cast<DeclRefExpr>(Ctor->getArg(0))) {
1804 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1811class PointerInitGadget :
public FixableGadget {
1813 static constexpr const char *
const PointerInitLHSTag =
"ptrInitLHS";
1814 static constexpr const char *
const PointerInitRHSTag =
"ptrInitRHS";
1815 const VarDecl *PtrInitLHS;
1816 const DeclRefExpr *PtrInitRHS;
1820 : FixableGadget(
Kind::PointerInit),
1821 PtrInitLHS(
Result.getNodeAs<VarDecl>(PointerInitLHSTag)),
1822 PtrInitRHS(
Result.getNodeAs<DeclRefExpr>(PointerInitRHSTag)) {}
1824 static bool classof(
const Gadget *G) {
1825 return G->getKind() == Kind::PointerInit;
1828 static bool matches(
const Stmt *S,
1829 llvm::SmallVectorImpl<MatchResult> &Results) {
1830 const DeclStmt *DS = dyn_cast<DeclStmt>(S);
1839 const auto *DRE = dyn_cast<DeclRefExpr>(
Init->IgnoreImpCasts());
1840 if (!DRE || !
hasPointerType(*DRE) || !isSupportedVariable(*DRE)) {
1844 R.addNode(PointerInitLHSTag, DynTypedNode::create(*VD));
1845 R.addNode(PointerInitRHSTag, DynTypedNode::create(*DRE));
1846 Results.emplace_back(std::move(R));
1850 virtual std::optional<FixItList>
1851 getFixits(
const FixitStrategy &S)
const override;
1852 SourceLocation getSourceLoc()
const override {
1853 return PtrInitRHS->getBeginLoc();
1856 virtual DeclUseList getClaimedVarUseSites()
const override {
1857 return DeclUseList{PtrInitRHS};
1860 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1861 getStrategyImplications()
const override {
1862 return std::make_pair(PtrInitLHS,
cast<VarDecl>(PtrInitRHS->getDecl()));
1871class PtrToPtrAssignmentGadget :
public FixableGadget {
1873 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1874 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1875 const DeclRefExpr *PtrLHS;
1876 const DeclRefExpr *PtrRHS;
1880 : FixableGadget(
Kind::PtrToPtrAssignment),
1881 PtrLHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
1882 PtrRHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
1884 static bool classof(
const Gadget *G) {
1885 return G->getKind() == Kind::PtrToPtrAssignment;
1888 static bool matches(
const Stmt *S,
1889 llvm::SmallVectorImpl<MatchResult> &Results) {
1890 size_t SizeBefore = Results.size();
1892 const auto *BO = dyn_cast<BinaryOperator>(S);
1893 if (!BO || BO->
getOpcode() != BO_Assign)
1896 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1898 !isSupportedVariable(*RHSRef)) {
1901 const auto *LHS = BO->
getLHS();
1902 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1904 !isSupportedVariable(*LHSRef)) {
1908 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
1909 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
1910 Results.emplace_back(std::move(R));
1912 return SizeBefore != Results.size();
1915 virtual std::optional<FixItList>
1916 getFixits(
const FixitStrategy &S)
const override;
1917 SourceLocation getSourceLoc()
const override {
return PtrLHS->getBeginLoc(); }
1919 virtual DeclUseList getClaimedVarUseSites()
const override {
1920 return DeclUseList{PtrLHS, PtrRHS};
1923 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1924 getStrategyImplications()
const override {
1935class CArrayToPtrAssignmentGadget :
public FixableGadget {
1937 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1938 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1939 const DeclRefExpr *PtrLHS;
1940 const DeclRefExpr *PtrRHS;
1944 : FixableGadget(
Kind::CArrayToPtrAssignment),
1945 PtrLHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
1946 PtrRHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
1948 static bool classof(
const Gadget *G) {
1949 return G->getKind() == Kind::CArrayToPtrAssignment;
1952 static bool matches(
const Stmt *S,
1953 llvm::SmallVectorImpl<MatchResult> &Results) {
1954 size_t SizeBefore = Results.size();
1956 const auto *BO = dyn_cast<BinaryOperator>(S);
1957 if (!BO || BO->
getOpcode() != BO_Assign)
1960 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1963 !isSupportedVariable(*RHSRef)) {
1966 const auto *LHS = BO->
getLHS();
1967 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1969 !isSupportedVariable(*LHSRef)) {
1973 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
1974 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
1975 Results.emplace_back(std::move(R));
1977 return SizeBefore != Results.size();
1980 virtual std::optional<FixItList>
1981 getFixits(
const FixitStrategy &S)
const override;
1982 SourceLocation getSourceLoc()
const override {
return PtrLHS->getBeginLoc(); }
1984 virtual DeclUseList getClaimedVarUseSites()
const override {
1985 return DeclUseList{PtrLHS, PtrRHS};
1988 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1989 getStrategyImplications()
const override {
1996class UnsafeBufferUsageAttrGadget :
public WarningGadget {
1997 constexpr static const char *
const OpTag =
"attr_expr";
2002 : WarningGadget(
Kind::UnsafeBufferUsageAttr),
2003 Op(
Result.getNodeAs<Expr>(OpTag)) {}
2005 static bool classof(
const Gadget *G) {
2006 return G->getKind() == Kind::UnsafeBufferUsageAttr;
2009 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
2011 if (
auto *CE = dyn_cast<CallExpr>(S)) {
2012 if (CE->getDirectCallee() &&
2013 CE->getDirectCallee()->hasAttr<UnsafeBufferUsageAttr>()) {
2014 Result.addNode(OpTag, DynTypedNode::create(*CE));
2018 if (
auto *ME = dyn_cast<MemberExpr>(S)) {
2021 if (ME->getMemberDecl()->hasAttr<UnsafeBufferUsageAttr>()) {
2022 Result.addNode(OpTag, DynTypedNode::create(*ME));
2029 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2030 bool IsRelatedToDecl,
2031 ASTContext &Ctx)
const override {
2034 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2036 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2038 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2044class UnsafeBufferUsageCtorAttrGadget :
public WarningGadget {
2045 constexpr static const char *
const OpTag =
"cxx_construct_expr";
2046 const CXXConstructExpr *Op;
2050 : WarningGadget(
Kind::UnsafeBufferUsageCtorAttr),
2051 Op(
Result.getNodeAs<CXXConstructExpr>(OpTag)) {}
2053 static bool classof(
const Gadget *G) {
2054 return G->getKind() == Kind::UnsafeBufferUsageCtorAttr;
2058 const auto *CE = dyn_cast<CXXConstructExpr>(S);
2059 if (!CE || !CE->getConstructor()->hasAttr<UnsafeBufferUsageAttr>())
2063 if (SpanTwoParamConstructorGadget::matches(CE, Ctx, Tmp))
2065 Result.addNode(OpTag, DynTypedNode::create(*CE));
2069 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2070 bool IsRelatedToDecl,
2071 ASTContext &Ctx)
const override {
2074 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2076 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2078 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2085class DataInvocationGadget :
public WarningGadget {
2086 constexpr static const char *
const OpTag =
"data_invocation_expr";
2087 const ExplicitCastExpr *Op;
2091 : WarningGadget(
Kind::DataInvocation),
2092 Op(
Result.getNodeAs<ExplicitCastExpr>(OpTag)) {}
2094 static bool classof(
const Gadget *G) {
2095 return G->getKind() == Kind::DataInvocation;
2098 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
2100 auto *CE = dyn_cast<ExplicitCastExpr>(S);
2103 for (
auto *Child : CE->children()) {
2104 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(Child);
2105 MCE && isDataFunction(MCE)) {
2106 Result.addNode(OpTag, DynTypedNode::create(*CE));
2109 if (
auto *
Paren = dyn_cast<ParenExpr>(Child)) {
2110 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(
Paren->getSubExpr());
2111 MCE && isDataFunction(MCE)) {
2112 Result.addNode(OpTag, DynTypedNode::create(*CE));
2120 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2121 bool IsRelatedToDecl,
2122 ASTContext &Ctx)
const override {
2125 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2127 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2130 static bool isDataFunction(
const CXXMemberCallExpr *call) {
2137 if (method->getNameAsString() ==
"data" &&
2138 method->getParent()->isInStdNamespace() &&
2139 llvm::is_contained({SIZED_CONTAINER_OR_VIEW_LIST},
2140 method->getParent()->getName()))
2145 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2148class UnsafeLibcFunctionCallGadget :
public WarningGadget {
2149 const CallExpr *
const Call;
2150 const Expr *UnsafeArg =
nullptr;
2151 constexpr static const char *
const Tag =
"UnsafeLibcFunctionCall";
2153 constexpr static const char *
const UnsafeSprintfTag =
2154 "UnsafeLibcFunctionCall_sprintf";
2155 constexpr static const char *
const UnsafeSizedByTag =
2156 "UnsafeLibcFunctionCall_sized_by";
2157 constexpr static const char *
const UnsafeStringTag =
2158 "UnsafeLibcFunctionCall_string";
2159 constexpr static const char *
const UnsafeVaListTag =
2160 "UnsafeLibcFunctionCall_va_list";
2174 } WarnedFunKind = OTHERS;
2177 : WarningGadget(
Kind::UnsafeLibcFunctionCall),
2178 Call(
Result.getNodeAs<CallExpr>(Tag)) {
2179 if (
Result.getNodeAs<Decl>(UnsafeSprintfTag))
2180 WarnedFunKind = SPRINTF;
2181 else if (
auto *E =
Result.getNodeAs<Expr>(UnsafeStringTag)) {
2182 WarnedFunKind = STRING;
2184 }
else if (
Result.getNodeAs<CallExpr>(UnsafeSizedByTag)) {
2185 WarnedFunKind = SIZED_BY;
2186 UnsafeArg = Call->getArg(0);
2187 }
else if (
Result.getNodeAs<Decl>(UnsafeVaListTag))
2188 WarnedFunKind = VA_LIST;
2191 static bool matches(
const Stmt *S, ASTContext &Ctx,
2192 const UnsafeBufferUsageHandler *Handler,
2196 const auto *CE = dyn_cast<CallExpr>(S);
2199 const auto *FD = CE->getDirectCallee();
2203 const bool IsGlobalAndNotInAnyNamespace =
2204 FD->isGlobal() && !FD->getEnclosingNamespaceContext()->isNamespace();
2208 if (!FD->isInStdNamespace() && !IsGlobalAndNotInAnyNamespace)
2215 const bool isSingleStringLiteralArg =
2216 CE->getNumArgs() == 1 &&
2218 if (!isSingleStringLiteralArg) {
2221 Result.addNode(Tag, DynTypedNode::create(*CE));
2225 Result.addNode(Tag, DynTypedNode::create(*CE));
2229 Result.addNode(Tag, DynTypedNode::create(*CE));
2230 Result.addNode(UnsafeVaListTag, DynTypedNode::create(*FD));
2234 Result.addNode(Tag, DynTypedNode::create(*CE));
2235 Result.addNode(UnsafeSprintfTag, DynTypedNode::create(*FD));
2241 Result.addNode(Tag, DynTypedNode::create(*CE));
2242 Result.addNode(UnsafeSizedByTag, DynTypedNode::create(*CE));
2247 Result.addNode(Tag, DynTypedNode::create(*CE));
2254 const Stmt *getBaseStmt()
const {
return Call; }
2256 SourceLocation getSourceLoc()
const override {
return Call->getBeginLoc(); }
2258 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2259 bool IsRelatedToDecl,
2260 ASTContext &Ctx)
const override {
2264 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2266 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2269class UnsafeFormatAttributedFunctionCallGadget :
public WarningGadget {
2270 const CallExpr *
const Call;
2271 const Expr *UnsafeArg =
nullptr;
2272 constexpr static const char *
const Tag =
"UnsafeFormatAttributedFunctionCall";
2273 constexpr static const char *
const UnsafeStringTag =
2274 "UnsafeFormatAttributedFunctionCall_string";
2278 : WarningGadget(
Kind::UnsafeLibcFunctionCall),
2279 Call(
Result.getNodeAs<CallExpr>(Tag)),
2280 UnsafeArg(
Result.getNodeAs<Expr>(UnsafeStringTag)) {}
2282 static bool matches(
const Stmt *S, ASTContext &Ctx,
2283 const UnsafeBufferUsageHandler *Handler,
2287 auto *CE = dyn_cast<CallExpr>(S);
2288 if (!CE || !CE->getDirectCallee())
2290 const FunctionDecl *FD = CE->getDirectCallee();
2294 const FormatAttr *Attr =
nullptr;
2295 bool IsPrintf =
false;
2296 bool AnyAttr = llvm::any_of(
2298 [&Attr, &IsPrintf](
const FormatAttr *FA) ->
bool {
2299 if (const auto *II = FA->getType()) {
2300 if (II->getName() ==
"printf" || II->getName() ==
"scanf") {
2302 IsPrintf = II->getName() ==
"printf";
2308 const Expr *UnsafeArg;
2314 unsigned FmtIdx = Attr->getFormatIdx() - 1;
2315 std::optional<unsigned> FmtArgIdx = Attr->getFirstArg() - 1;
2325 }
else if (CE->getStmtClass() != Stmt::CallExprClass &&
2328 if (*FmtArgIdx >= CE->getNumArgs())
2335 FmtArgIdx = std::nullopt;
2337 if (AnyAttr && !IsPrintf && FmtArgIdx) {
2339 Result.addNode(Tag, DynTypedNode::create(*CE));
2344 Ctx, CE, UnsafeArg, FmtIdx, FmtArgIdx)) {
2345 Result.addNode(Tag, DynTypedNode::create(*CE));
2346 Result.addNode(UnsafeStringTag, DynTypedNode::create(*UnsafeArg));
2352 const Stmt *getBaseStmt()
const {
return Call; }
2357 bool IsRelatedToDecl,
2362 UnsafeLibcFunctionCallGadget::UnsafeKind::STRING |
2363 UnsafeLibcFunctionCallGadget::UnsafeKind::FORMAT_ATTR,
2368 UnsafeLibcFunctionCallGadget::UnsafeKind::OTHERS |
2369 UnsafeLibcFunctionCallGadget::UnsafeKind::FORMAT_ATTR,
2373 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2381class ULCArraySubscriptGadget :
public FixableGadget {
2383 static constexpr const char *
const ULCArraySubscriptTag =
2384 "ArraySubscriptUnderULC";
2385 const ArraySubscriptExpr *Node;
2389 : FixableGadget(
Kind::ULCArraySubscript),
2390 Node(
Result.getNodeAs<ArraySubscriptExpr>(ULCArraySubscriptTag)) {
2391 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2394 static bool classof(
const Gadget *G) {
2395 return G->getKind() == Kind::ULCArraySubscript;
2398 static bool matches(
const Stmt *S,
2399 llvm::SmallVectorImpl<MatchResult> &Results) {
2400 size_t SizeBefore = Results.size();
2402 const auto *ASE = dyn_cast<ArraySubscriptExpr>(E);
2408 !isSupportedVariable(*DRE))
2411 R.addNode(ULCArraySubscriptTag, DynTypedNode::create(*ASE));
2412 Results.emplace_back(std::move(R));
2414 return SizeBefore != Results.size();
2417 virtual std::optional<FixItList>
2418 getFixits(
const FixitStrategy &S)
const override;
2419 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2421 virtual DeclUseList getClaimedVarUseSites()
const override {
2422 if (
const auto *DRE =
2423 dyn_cast<DeclRefExpr>(Node->getBase()->IgnoreImpCasts())) {
2433class UPCStandalonePointerGadget :
public FixableGadget {
2435 static constexpr const char *
const DeclRefExprTag =
"StandalonePointer";
2436 const DeclRefExpr *Node;
2440 : FixableGadget(
Kind::UPCStandalonePointer),
2441 Node(
Result.getNodeAs<DeclRefExpr>(DeclRefExprTag)) {
2442 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2445 static bool classof(
const Gadget *G) {
2446 return G->getKind() == Kind::UPCStandalonePointer;
2449 static bool matches(
const Stmt *S,
2450 llvm::SmallVectorImpl<MatchResult> &Results) {
2451 size_t SizeBefore = Results.size();
2453 auto *E = dyn_cast<Expr>(S);
2458 !isSupportedVariable(*DRE))
2461 R.addNode(DeclRefExprTag, DynTypedNode::create(*DRE));
2462 Results.emplace_back(std::move(R));
2464 return SizeBefore != Results.size();
2467 virtual std::optional<FixItList>
2468 getFixits(
const FixitStrategy &S)
const override;
2469 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2471 virtual DeclUseList getClaimedVarUseSites()
const override {
return {Node}; }
2474class PointerDereferenceGadget :
public FixableGadget {
2475 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2476 static constexpr const char *
const OperatorTag =
"op";
2478 const DeclRefExpr *BaseDeclRefExpr =
nullptr;
2479 const UnaryOperator *Op =
nullptr;
2483 : FixableGadget(
Kind::PointerDereference),
2484 BaseDeclRefExpr(
Result.getNodeAs<DeclRefExpr>(BaseDeclRefExprTag)),
2485 Op(
Result.getNodeAs<UnaryOperator>(OperatorTag)) {}
2487 static bool classof(
const Gadget *G) {
2488 return G->getKind() == Kind::PointerDereference;
2491 static bool matches(
const Stmt *S,
2492 llvm::SmallVectorImpl<MatchResult> &Results) {
2493 size_t SizeBefore = Results.size();
2495 const auto *UO = dyn_cast<UnaryOperator>(S);
2502 const auto *DRE = dyn_cast<DeclRefExpr>(CE);
2503 if (!DRE || !isSupportedVariable(*DRE))
2506 R.addNode(BaseDeclRefExprTag, DynTypedNode::create(*DRE));
2507 R.addNode(OperatorTag, DynTypedNode::create(*UO));
2508 Results.emplace_back(std::move(R));
2510 return SizeBefore != Results.size();
2513 DeclUseList getClaimedVarUseSites()
const override {
2514 return {BaseDeclRefExpr};
2517 virtual std::optional<FixItList>
2518 getFixits(
const FixitStrategy &S)
const override;
2519 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2525class UPCAddressofArraySubscriptGadget :
public FixableGadget {
2527 static constexpr const char *
const UPCAddressofArraySubscriptTag =
2528 "AddressofArraySubscriptUnderUPC";
2529 const UnaryOperator *Node;
2533 : FixableGadget(
Kind::ULCArraySubscript),
2534 Node(
Result.getNodeAs<UnaryOperator>(UPCAddressofArraySubscriptTag)) {
2535 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2538 static bool classof(
const Gadget *G) {
2539 return G->getKind() == Kind::UPCAddressofArraySubscript;
2542 static bool matches(
const Stmt *S,
2543 llvm::SmallVectorImpl<MatchResult> &Results) {
2544 size_t SizeBefore = Results.size();
2546 auto *E = dyn_cast<Expr>(S);
2550 if (!UO || UO->
getOpcode() != UO_AddrOf)
2552 const auto *ASE = dyn_cast<ArraySubscriptExpr>(UO->
getSubExpr());
2557 if (!DRE || !isSupportedVariable(*DRE))
2560 R.addNode(UPCAddressofArraySubscriptTag, DynTypedNode::create(*UO));
2561 Results.emplace_back(std::move(R));
2563 return SizeBefore != Results.size();
2566 virtual std::optional<FixItList>
2567 getFixits(
const FixitStrategy &)
const override;
2568 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2570 virtual DeclUseList getClaimedVarUseSites()
const override {
2583class DeclUseTracker {
2584 using UseSetTy = llvm::SmallPtrSet<const DeclRefExpr *, 16>;
2585 using DefMapTy = llvm::DenseMap<const VarDecl *, const DeclStmt *>;
2588 std::unique_ptr<UseSetTy> Uses{std::make_unique<UseSetTy>()};
2592 DeclUseTracker() =
default;
2593 DeclUseTracker(
const DeclUseTracker &) =
delete;
2594 DeclUseTracker &operator=(
const DeclUseTracker &) =
delete;
2595 DeclUseTracker(DeclUseTracker &&) =
default;
2596 DeclUseTracker &operator=(DeclUseTracker &&) =
default;
2599 void discoverUse(
const DeclRefExpr *DRE) { Uses->insert(DRE); }
2602 void claimUse(
const DeclRefExpr *DRE) {
2603 assert(Uses->count(DRE) &&
2604 "DRE not found or claimed by multiple matchers!");
2609 bool hasUnclaimedUses(
const VarDecl *VD)
const {
2611 return any_of(*Uses, [VD](
const DeclRefExpr *DRE) {
2616 UseSetTy getUnclaimedUses(
const VarDecl *VD)
const {
2618 for (
auto use : *Uses) {
2620 ReturnSet.insert(use);
2626 void discoverDecl(
const DeclStmt *DS) {
2627 for (
const Decl *D : DS->
decls()) {
2628 if (
const auto *VD = dyn_cast<VarDecl>(D)) {
2639 const DeclStmt *lookupDecl(
const VarDecl *VD)
const {
2640 return Defs.lookup(VD);
2649 static constexpr const char *
const UPCPreIncrementTag =
2650 "PointerPreIncrementUnderUPC";
2655 : FixableGadget(Kind::UPCPreIncrement),
2657 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2661 return G->getKind() == Kind::UPCPreIncrement;
2670 size_t SizeBefore = Results.size();
2672 auto *E = dyn_cast<Expr>(S);
2676 if (!UO || UO->
getOpcode() != UO_PreInc)
2678 const auto *DRE = dyn_cast<DeclRefExpr>(UO->
getSubExpr());
2679 if (!DRE || !isSupportedVariable(*DRE))
2683 Results.emplace_back(std::move(R));
2685 return SizeBefore != Results.size();
2688 virtual std::optional<FixItList>
2693 return {dyn_cast<DeclRefExpr>(Node->getSubExpr())};
2701 static constexpr const char *
const UUCAddAssignTag =
2702 "PointerAddAssignUnderUUC";
2703 static constexpr const char *
const OffsetTag =
"Offset";
2706 const Expr *Offset =
nullptr;
2710 : FixableGadget(Kind::UUCAddAssign),
2713 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2717 return G->getKind() == Kind::UUCAddAssign;
2722 size_t SizeBefore = Results.size();
2724 const auto *E = dyn_cast<Expr>(S);
2728 if (!BO || BO->
getOpcode() != BO_AddAssign)
2730 const auto *DRE = dyn_cast<DeclRefExpr>(BO->
getLHS());
2736 Results.emplace_back(std::move(R));
2738 return SizeBefore != Results.size();
2741 virtual std::optional<FixItList>
2746 return {dyn_cast<DeclRefExpr>(Node->getLHS())};
2753 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2754 static constexpr const char *
const DerefOpTag =
"DerefOp";
2755 static constexpr const char *
const AddOpTag =
"AddOp";
2756 static constexpr const char *
const OffsetTag =
"Offset";
2765 : FixableGadget(Kind::DerefSimplePtrArithFixable),
2773 auto IsPtr = [](
const Expr *E, MatchResult &R) {
2777 if (!DRE || !isSupportedVariable(*DRE))
2782 const auto IsPlusOverPtrAndInteger = [&IsPtr](
const Expr *E,
2784 const auto *BO = dyn_cast<BinaryOperator>(E);
2788 const auto *LHS = BO->
getLHS();
2789 const auto *RHS = BO->
getRHS();
2802 size_t SizeBefore = Results.size();
2803 const auto InnerMatcher = [&IsPlusOverPtrAndInteger,
2804 &Results](
const Expr *E) {
2805 const auto *UO = dyn_cast<UnaryOperator>(E);
2811 if (IsPlusOverPtrAndInteger(Operand, R)) {
2813 Results.emplace_back(std::move(R));
2817 return SizeBefore != Results.size();
2820 virtual std::optional<FixItList>
2823 return DerefOp->getBeginLoc();
2827 return {BaseDeclRefExpr};
2835 : WarningGadgets(WarningGadgets) {}
2844#define WARNING_GADGET(name) \
2845 if (name##Gadget::matches(S, Ctx, Result) && \
2846 notInSafeBufferOptOut(*S, &Handler)) { \
2847 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2850#define WARNING_OPTIONAL_GADGET(name) \
2851 if (name##Gadget::matches(S, Ctx, &Handler, Result) && \
2852 notInSafeBufferOptOut(*S, &Handler)) { \
2853 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2856#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2861 WarningGadgetList &WarningGadgets;
2868 DeclUseTracker &Tracker)
2869 : FixableGadgets(FixableGadgets), Tracker(Tracker) {}
2873 bool matchFound =
false;
2880#define FIXABLE_GADGET(name) \
2881 if (name##Gadget::matches(S, Results)) { \
2882 for (const auto &R : Results) { \
2883 FixableGadgets.push_back(std::make_unique<name##Gadget>(R)); \
2884 matchFound = true; \
2888#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2891 if (
auto *DRE = findDeclRefExpr(S); DRE) {
2892 Tracker.discoverUse(DRE);
2898 if (
auto *DS = findDeclStmt(S); DS) {
2899 Tracker.discoverDecl(DS);
2907 const auto *DRE = dyn_cast<DeclRefExpr>(S);
2915 const DeclStmt *findDeclStmt(
const Stmt *S) {
2916 const auto *DS = dyn_cast<DeclStmt>(S);
2921 FixableGadgetList &FixableGadgets;
2922 DeclUseTracker &Tracker;
2928 bool EmitSuggestions, FixableGadgetList &FixableGadgets,
2929 WarningGadgetList &WarningGadgets,
2930 DeclUseTracker &Tracker) {
2933 if (EmitSuggestions) {
2942 return N1->getBeginLoc().getRawEncoding() <
2943 N2->getBeginLoc().getRawEncoding();
2956 auto AddStmt = [&Stmts](
const Stmt *S) {
2960 if (
const auto *FD = dyn_cast<FunctionDecl>(D)) {
2963 if (PD->hasDefaultArg() && !PD->hasUninstantiatedDefaultArg())
2964 AddStmt(PD->getDefaultArg());
2965 if (
const auto *CtorD = dyn_cast<CXXConstructorDecl>(FD))
2967 Stmts, llvm::map_range(CtorD->inits(),
2971 }
else if (
const auto *VD = dyn_cast<VarDecl>(D)) {
2973 }
else if (
const auto *FD = dyn_cast<FieldDecl>(D)) {
2974 AddStmt(FD->getInClassInitializer());
2979 std::map<const VarDecl *, std::set<const WarningGadget *>,
2993 for (
auto &G : AllUnsafeOperations) {
2994 DeclUseList ClaimedVarUseSites = G->getClaimedVarUseSites();
2996 bool AssociatedWithVarDecl =
false;
2997 for (
const DeclRefExpr *DRE : ClaimedVarUseSites) {
2998 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2999 result.
byVar[VD].insert(G.get());
3000 AssociatedWithVarDecl =
true;
3004 if (!AssociatedWithVarDecl) {
3005 result.
noVar.push_back(G.get());
3013 std::map<const VarDecl *, std::set<const FixableGadget *>,
3023 for (
auto &F : AllFixableOperations) {
3024 DeclUseList DREs = F->getClaimedVarUseSites();
3027 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
3028 FixablesForUnsafeVars.
byVar[VD].insert(F.get());
3032 return FixablesForUnsafeVars;
3039 std::vector<const FixItHint *>
All;
3043 std::sort(
All.begin(),
All.end(),
3045 return SM.isBeforeInTranslationUnit(H1->RemoveRange.getBegin(),
3046 H2->RemoveRange.getBegin());
3054 Hint->RemoveRange.getBegin())) {
3066std::optional<FixItList>
3067PtrToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
3070 switch (S.
lookup(LeftVD)) {
3074 return std::nullopt;
3076 return std::nullopt;
3079 return std::nullopt;
3081 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3083 return std::nullopt;
3087static inline std::optional<FixItList>
createDataFixit(
const ASTContext &Ctx,
3088 const DeclRefExpr *DRE);
3090std::optional<FixItList>
3091CArrayToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
3110 if (S.
lookup(LeftVD) == FixitStrategy::Kind::Span) {
3111 if (S.
lookup(RightVD) == FixitStrategy::Kind::Wontfix) {
3114 }
else if (S.
lookup(LeftVD) == FixitStrategy::Kind::Wontfix) {
3115 if (S.
lookup(RightVD) == FixitStrategy::Kind::Array) {
3119 return std::nullopt;
3122std::optional<FixItList>
3123PointerInitGadget::getFixits(
const FixitStrategy &S)
const {
3124 const auto *LeftVD = PtrInitLHS;
3126 switch (S.
lookup(LeftVD)) {
3127 case FixitStrategy::Kind::Span:
3128 if (S.
lookup(RightVD) == FixitStrategy::Kind::Span)
3130 return std::nullopt;
3131 case FixitStrategy::Kind::Wontfix:
3132 return std::nullopt;
3133 case FixitStrategy::Kind::Iterator:
3134 case FixitStrategy::Kind::Array:
3135 return std::nullopt;
3136 case FixitStrategy::Kind::Vector:
3137 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3139 return std::nullopt;
3145 if (ConstVal->isNegative())
3152std::optional<FixItList>
3153ULCArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
3154 if (
const auto *DRE =
3156 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
3158 case FixitStrategy::Kind::Span: {
3162 const ASTContext &Ctx =
3165 return std::nullopt;
3169 case FixitStrategy::Kind::Array:
3171 case FixitStrategy::Kind::Wontfix:
3172 case FixitStrategy::Kind::Iterator:
3173 case FixitStrategy::Kind::Vector:
3174 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3177 return std::nullopt;
3180static std::optional<FixItList>
3183std::optional<FixItList>
3184UPCAddressofArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
3185 auto DREs = getClaimedVarUseSites();
3189 case FixitStrategy::Kind::Span:
3191 case FixitStrategy::Kind::Wontfix:
3192 case FixitStrategy::Kind::Iterator:
3193 case FixitStrategy::Kind::Array:
3194 return std::nullopt;
3195 case FixitStrategy::Kind::Vector:
3196 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3198 return std::nullopt;
3203 static const char *
const EOL =
"\n";
3210 std::string
s = std::string(
"<# ");
3211 s += HintTextToUser;
3217template <
typename NodeTy>
3218static std::optional<SourceLocation>
3221 if (
unsigned TkLen =
3228 return std::nullopt;
3241 bool AttrRangeOverlapping = llvm::any_of(VD->
attrs(), [&](
Attr *At) ->
bool {
3242 return !(SM.isBeforeInTranslationUnit(At->getRange().getEnd(),
3243 VD->getBeginLoc())) &&
3244 !(SM.isBeforeInTranslationUnit(VD->getEndLoc(),
3245 At->getRange().getBegin()));
3249 AttrRangeOverlapping;
3291 std::optional<Qualifiers> Quals = std::nullopt) {
3292 const char *
const SpanOpen =
"std::span<";
3295 return SpanOpen + EltTyText.str() +
' ' + Quals->getAsString() +
'>';
3296 return SpanOpen + EltTyText.str() +
'>';
3299std::optional<FixItList>
3301 const VarDecl *VD = dyn_cast<VarDecl>(BaseDeclRefExpr->getDecl());
3306 if (
auto ConstVal = Offset->getIntegerConstantExpr(Ctx))
3307 if (ConstVal->isNegative())
3308 return std::nullopt;
3329 const Expr *LHS = AddOp->getLHS(), *RHS = AddOp->getRHS();
3336 std::optional<SourceLocation> LHSLocation =
getPastLoc(LHS,
SM, LangOpts);
3338 return std::nullopt;
3343 std::optional<SourceLocation> AddOpLocation =
3345 std::optional<SourceLocation> DerefOpLocation =
3348 if (!AddOpLocation || !DerefOpLocation)
3349 return std::nullopt;
3359 return std::nullopt;
3362std::optional<FixItList>
3363PointerDereferenceGadget::getFixits(
const FixitStrategy &S)
const {
3374 if (
auto LocPastOperand =
3381 case FixitStrategy::Kind::Iterator:
3382 case FixitStrategy::Kind::Array:
3383 return std::nullopt;
3384 case FixitStrategy::Kind::Vector:
3385 llvm_unreachable(
"FixitStrategy not implemented yet!");
3386 case FixitStrategy::Kind::Wontfix:
3387 llvm_unreachable(
"Invalid strategy!");
3390 return std::nullopt;
3397 std::optional<SourceLocation> EndOfOperand =
3403 return std::nullopt;
3408std::optional<FixItList>
3409UPCStandalonePointerGadget::getFixits(
const FixitStrategy &S)
const {
3412 case FixitStrategy::Kind::Array:
3413 case FixitStrategy::Kind::Span: {
3418 case FixitStrategy::Kind::Wontfix:
3419 case FixitStrategy::Kind::Iterator:
3420 return std::nullopt;
3421 case FixitStrategy::Kind::Vector:
3422 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3425 return std::nullopt;
3430static std::optional<FixItList>
3437 const Expr *Idx = ArraySub->getIdx();
3440 std::stringstream SS;
3441 bool IdxIsLitZero =
false;
3444 if ((*ICE).isZero())
3445 IdxIsLitZero =
true;
3446 std::optional<StringRef> DreString =
getExprText(DRE,
SM, LangOpts);
3448 return std::nullopt;
3452 SS << (*DreString).str() <<
".data()";
3454 std::optional<StringRef> IndexString =
getExprText(Idx,
SM, LangOpts);
3456 return std::nullopt;
3458 SS <<
"&" << (*DreString).str() <<
".data()"
3459 <<
"[" << (*IndexString).str() <<
"]";
3465std::optional<FixItList>
3469 if (DREs.size() != 1)
3470 return std::nullopt;
3472 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3476 const Stmt *AddAssignNode = Node;
3477 StringRef varName = VD->
getName();
3481 return std::nullopt;
3485 (Offset->IgnoreParens()->getBeginLoc() == Offset->getBeginLoc());
3486 std::string SS = varName.str() +
" = " + varName.str() +
".subspan";
3490 std::optional<SourceLocation> AddAssignLocation =
getEndCharLoc(
3492 if (!AddAssignLocation)
3493 return std::nullopt;
3500 Offset->getEndLoc().getLocWithOffset(1),
")"));
3504 return std::nullopt;
3507std::optional<FixItList>
3511 if (DREs.size() != 1)
3512 return std::nullopt;
3514 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3517 std::stringstream SS;
3518 StringRef varName = VD->
getName();
3522 SS <<
"(" << varName.data() <<
" = " << varName.data()
3523 <<
".subspan(1)).data()";
3524 std::optional<SourceLocation> PreIncLocation =
3526 if (!PreIncLocation)
3527 return std::nullopt;
3530 SourceRange(Node->getBeginLoc(), *PreIncLocation), SS.str()));
3534 return std::nullopt;
3552static std::optional<FixItList>
3554 const StringRef UserFillPlaceHolder) {
3562 if (
Init->isNullPointerConstant(
3567 NPC_ValueDependentIsNotNull)) {
3568 std::optional<SourceLocation> InitLocation =
3571 return std::nullopt;
3579 std::string ExtentText = UserFillPlaceHolder.data();
3580 StringRef One =
"1";
3585 if (
auto CxxNew = dyn_cast<CXXNewExpr>(
Init->IgnoreImpCasts())) {
3590 if (
const Expr *Ext = CxxNew->getArraySize().value_or(
nullptr)) {
3591 if (!Ext->HasSideEffects(Ctx)) {
3592 std::optional<StringRef> ExtentString =
getExprText(Ext,
SM, LangOpts);
3594 return std::nullopt;
3595 ExtentText = *ExtentString;
3597 }
else if (!CxxNew->isArray())
3609 if (
auto AddrOfExpr = dyn_cast<UnaryOperator>(
Init->IgnoreImpCasts()))
3610 if (AddrOfExpr->getOpcode() == UnaryOperatorKind::UO_AddrOf &&
3611 isa_and_present<DeclRefExpr>(AddrOfExpr->getSubExpr()))
3618 std::optional<SourceLocation> LocPassInit =
getPastLoc(
Init,
SM, LangOpts);
3621 return std::nullopt;
3623 StrBuffer.append(
", ");
3624 StrBuffer.append(ExtentText);
3625 StrBuffer.append(
"}");
3631#define DEBUG_NOTE_DECL_FAIL(D, Msg) \
3632 Handler.addDebugNoteForVar((D), (D)->getBeginLoc(), \
3633 "failed to produce fixit for declaration '" + \
3634 (D)->getNameAsString() + "'" + (Msg))
3636#define DEBUG_NOTE_DECL_FAIL(D, Msg)
3642static std::optional<std::string>
3646 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3651 return std::nullopt;
3653 std::string SpanTyText =
"std::span<";
3655 SpanTyText.append(*PteTyText);
3657 if (PteTyQualifiers) {
3658 SpanTyText.append(
" ");
3659 SpanTyText.append(PteTyQualifiers->getAsString());
3661 SpanTyText.append(
">");
3680 const StringRef UserFillPlaceHolder,
3694 std::stringstream SS;
3699 std::optional<FixItList> InitFixIts =
3703 FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts->begin()),
3704 std::make_move_iterator(InitFixIts->end()));
3711 if (!EndLocForReplacement.
isValid()) {
3761static std::optional<FixItList>
3767 return std::nullopt;
3772 std::vector<std::string> NewTysTexts(NumParms);
3773 std::vector<bool> ParmsMask(NumParms,
false);
3774 bool AtLeastOneParmToFix =
false;
3776 for (
unsigned i = 0; i < NumParms; i++) {
3783 return std::nullopt;
3785 std::optional<Qualifiers> PteTyQuals = std::nullopt;
3786 std::optional<std::string> PteTyText =
3791 return std::nullopt;
3795 ParmsMask[i] =
true;
3796 AtLeastOneParmToFix =
true;
3798 if (!AtLeastOneParmToFix)
3805 const auto NewOverloadSignatureCreator =
3806 [&
SM, &LangOpts, &NewTysTexts,
3807 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3808 std::stringstream SS;
3816 SS << Prefix->str();
3818 return std::nullopt;
3822 for (
unsigned i = 0; i < NumParms; i++) {
3830 SS << NewTysTexts[i];
3833 SS <<
' ' << II->getName().str();
3834 }
else if (
auto ParmTypeText =
3838 SS << ParmTypeText->str();
3840 return std::nullopt;
3841 if (i != NumParms - 1)
3850 const auto OldOverloadDefCreator =
3851 [&Handler, &
SM, &LangOpts, &NewTysTexts,
3852 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3853 std::stringstream SS;
3861 << FDPrefix->str() <<
"{";
3863 return std::nullopt;
3866 SS <<
"return " << FunQualName->str() <<
"(";
3868 return std::nullopt;
3872 for (
unsigned i = 0; i < NumParms; i++) {
3881 return std::nullopt;
3888 if (i != NumParms - 1)
3899 std::optional<SourceLocation> Loc =
getPastLoc(FReDecl,
SM, LangOpts);
3903 if (FReDecl->isThisDeclarationADefinition()) {
3904 assert(FReDecl == FD &&
"inconsistent function definition");
3907 if (
auto OldOverloadDef = OldOverloadDefCreator(FReDecl))
3913 if (!FReDecl->hasAttr<UnsafeBufferUsageAttr>()) {
3916 FReDecl->getBeginLoc(),
" ")));
3919 if (
auto NewOverloadDecl = NewOverloadSignatureCreator(FReDecl))
3941 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3957 std::stringstream SS;
3960 if (PteTyQualifiers)
3969 SS <<
' ' << PVDNameText->str();
3975 const DeclUseTracker &Tracker,
3978 const DeclStmt *DS = Tracker.lookupDecl(VD);
3981 " : variables declared this way not implemented yet");
4005 const QualType &ArrayEltT = CAT->getElementType();
4006 assert(!ArrayEltT.
isNull() &&
"Trying to fix a non-array type variable!");
4015 auto MaybeElemTypeTxt =
4018 if (!MaybeElemTypeTxt)
4020 const llvm::StringRef ElemTypeTxt = MaybeElemTypeTxt->trim();
4025 while (NextTok && !NextTok->is(tok::l_square) &&
4038 if (!MaybeArraySizeTxt)
4040 const llvm::StringRef ArraySizeTxt = MaybeArraySizeTxt->trim();
4041 if (ArraySizeTxt.empty()) {
4052 std::optional<StringRef> IdentText =
4061 llvm::raw_svector_ostream OS(Replacement);
4062 OS <<
"std::array<" << ElemTypeTxt <<
", " << ArraySizeTxt <<
"> "
4063 << IdentText->str();
4073 const DeclUseTracker &Tracker,
4076 const DeclStmt *DS = Tracker.lookupDecl(VD);
4077 assert(DS &&
"Fixing non-local variables not implemented yet!");
4096 const DeclUseTracker &Tracker,
ASTContext &Ctx,
4098 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD)) {
4099 auto *FD = dyn_cast<clang::FunctionDecl>(PVD->getDeclContext());
4100 if (!FD || FD != D) {
4127 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD))
4145 llvm_unreachable(
"FixitStrategy not implemented yet!");
4147 llvm_unreachable(
"Invalid strategy!");
4149 llvm_unreachable(
"Unknown strategy!");
4157 return llvm::any_of(FixIts, [](
const FixItHint &Hint) {
4159 if (Range.getBegin().isMacroID() || Range.getEnd().isMacroID())
4176 std::map<const VarDecl *, FixItList> &FixItsForVariable,
4181 for (
const auto &[VD, Ignore] : FixItsForVariable) {
4183 if (llvm::any_of(Grp,
4184 [&FixItsForVariable](
const VarDecl *GrpMember) ->
bool {
4185 return !FixItsForVariable.count(GrpMember);
4190 ToErase.push_back(
Member);
4193 for (
auto *VarToErase : ToErase)
4194 FixItsForVariable.erase(VarToErase);
4205 std::map<const VarDecl *, FixItList> &FixItsForVariable ,
4209 FixItList FixItsSharedByParms{};
4211 std::optional<FixItList> OverloadFixes =
4214 if (OverloadFixes) {
4215 FixItsSharedByParms.append(*OverloadFixes);
4221 FixItsForVariable.erase(
Member);
4223 return FixItsSharedByParms;
4227static std::map<const VarDecl *, FixItList>
4236 std::map<const VarDecl *, FixItList> FixItsForVariable;
4241 for (
const auto &[VD, Fixables] : FixablesForAllVars.
byVar) {
4242 FixItsForVariable[VD] =
4246 if (FixItsForVariable[VD].empty()) {
4247 FixItsForVariable.erase(VD);
4250 for (
const auto &F : Fixables) {
4251 std::optional<FixItList> Fixits = F->getFixits(S);
4254 FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
4255 Fixits->begin(), Fixits->end());
4260 VD, F->getSourceLoc(),
4261 (
"gadget '" + F->getDebugName() +
"' refused to produce a fix")
4264 FixItsForVariable.erase(VD);
4283 FixItList FixItsSharedByParms{};
4285 if (
auto *FD = dyn_cast<FunctionDecl>(D))
4287 FixItsForVariable, VarGrpMgr, FD, S, Ctx, Handler);
4291 std::map<const VarDecl *, FixItList> FinalFixItsForVariable{
4294 for (
auto &[Var, Ignore] : FixItsForVariable) {
4295 bool AnyParm =
false;
4296 const auto VarGroupForVD = VarGrpMgr.
getGroupOfVar(Var, &AnyParm);
4298 for (
const VarDecl *GrpMate : VarGroupForVD) {
4301 if (FixItsForVariable.count(GrpMate))
4302 FinalFixItsForVariable[Var].append(FixItsForVariable[GrpMate]);
4306 assert(!FixItsSharedByParms.empty() &&
4307 "Should not try to fix a parameter that does not belong to a "
4309 FinalFixItsForVariable[Var].append(FixItsSharedByParms);
4316 for (
auto Iter = FinalFixItsForVariable.begin();
4317 Iter != FinalFixItsForVariable.end();)
4320 Iter = FinalFixItsForVariable.erase(Iter);
4323 return FinalFixItsForVariable;
4326template <
typename VarDeclIterTy>
4330 for (
const VarDecl *VD : UnsafeVars) {
4341 const std::vector<VarGrpTy> &Groups;
4342 const std::map<const VarDecl *, unsigned> &VarGrpMap;
4343 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms;
4347 const std::vector<VarGrpTy> &Groups,
4348 const std::map<const VarDecl *, unsigned> &VarGrpMap,
4349 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms)
4350 : Groups(Groups), VarGrpMap(VarGrpMap),
4351 GrpsUnionForParms(GrpsUnionForParms) {}
4354 if (GrpsUnionForParms.contains(Var)) {
4357 return GrpsUnionForParms.getArrayRef();
4362 auto It = VarGrpMap.find(Var);
4364 if (It == VarGrpMap.end())
4366 return Groups[It->second];
4370 return GrpsUnionForParms.getArrayRef();
4375 WarningGadgetList WarningGadgets,
4376 DeclUseTracker Tracker,
4378 bool EmitSuggestions) {
4379 if (!EmitSuggestions) {
4383 for (
const auto &G : WarningGadgets) {
4384 G->handleUnsafeOperation(Handler,
false,
4390 assert(FixableGadgets.empty() &&
4391 "Fixable gadgets found but suggestions not requested!");
4397 if (!WarningGadgets.empty()) {
4401 for (
const auto &G : FixableGadgets) {
4402 for (
const auto *DRE : G->getClaimedVarUseSites()) {
4403 Tracker.claimUse(DRE);
4419 if (WarningGadgets.empty())
4427 std::map<const VarDecl *, FixItList> FixItsForVariableGroup;
4430 for (
auto it = FixablesForAllVars.
byVar.cbegin();
4431 it != FixablesForAllVars.
byVar.cend();) {
4436 (
"failed to produce fixit for '" +
4437 it->first->getNameAsString() +
4438 "' : neither local nor a parameter"));
4440 it = FixablesForAllVars.
byVar.erase(it);
4441 }
else if (it->first->getType().getCanonicalType()->isReferenceType()) {
4444 (
"failed to produce fixit for '" +
4445 it->first->getNameAsString() +
4446 "' : has a reference type"));
4448 it = FixablesForAllVars.
byVar.erase(it);
4449 }
else if (Tracker.hasUnclaimedUses(it->first)) {
4450 it = FixablesForAllVars.
byVar.erase(it);
4451 }
else if (it->first->isInitCapture()) {
4454 (
"failed to produce fixit for '" +
4455 it->first->getNameAsString() +
4456 "' : init capture"));
4458 it = FixablesForAllVars.
byVar.erase(it);
4465 for (
const auto &it : UnsafeOps.
byVar) {
4466 const VarDecl *
const UnsafeVD = it.first;
4467 auto UnclaimedDREs = Tracker.getUnclaimedUses(UnsafeVD);
4468 if (UnclaimedDREs.empty())
4472 std::string UnclaimedUseTrace =
4477 (
"failed to produce fixit for '" + UnfixedVDName +
4478 "' : has an unclaimed use\nThe unclaimed DRE trace: " +
4479 UnclaimedUseTrace));
4486 llvm::DenseMap<const VarDecl *, llvm::SetVector<const VarDecl *>>;
4487 DepMapTy DependenciesMap{};
4488 DepMapTy PtrAssignmentGraph{};
4490 for (
const auto &it : FixablesForAllVars.
byVar) {
4491 for (
const FixableGadget *fixable : it.second) {
4492 std::optional<std::pair<const VarDecl *, const VarDecl *>> ImplPair =
4493 fixable->getStrategyImplications();
4495 std::pair<const VarDecl *, const VarDecl *> Impl = std::move(*ImplPair);
4496 PtrAssignmentGraph[Impl.first].insert(Impl.second);
4518 std::set<const VarDecl *> VisitedVarsDirected{};
4519 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4520 if (VisitedVarsDirected.find(Var) == VisitedVarsDirected.end()) {
4522 std::queue<const VarDecl *> QueueDirected{};
4523 QueueDirected.push(Var);
4524 while (!QueueDirected.empty()) {
4525 const VarDecl *CurrentVar = QueueDirected.front();
4526 QueueDirected.pop();
4527 VisitedVarsDirected.insert(CurrentVar);
4528 auto AdjacentNodes = PtrAssignmentGraph[CurrentVar];
4529 for (
const VarDecl *Adj : AdjacentNodes) {
4530 if (VisitedVarsDirected.find(Adj) == VisitedVarsDirected.end()) {
4531 QueueDirected.push(Adj);
4533 DependenciesMap[Var].insert(Adj);
4534 DependenciesMap[Adj].insert(Var);
4541 std::vector<VarGrpTy> Groups;
4545 std::map<const VarDecl *, unsigned> VarGrpMap;
4547 llvm::SetVector<const VarDecl *>
4552 std::set<const VarDecl *> VisitedVars{};
4553 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4554 if (VisitedVars.find(Var) == VisitedVars.end()) {
4555 VarGrpTy &VarGroup = Groups.emplace_back();
4556 std::queue<const VarDecl *> Queue{};
4559 while (!Queue.empty()) {
4560 const VarDecl *CurrentVar = Queue.front();
4562 VisitedVars.insert(CurrentVar);
4563 VarGroup.push_back(CurrentVar);
4564 auto AdjacentNodes = DependenciesMap[CurrentVar];
4565 for (
const VarDecl *Adj : AdjacentNodes) {
4566 if (VisitedVars.find(Adj) == VisitedVars.end()) {
4572 bool HasParm =
false;
4573 unsigned GrpIdx = Groups.size() - 1;
4575 for (
const VarDecl *
V : VarGroup) {
4576 VarGrpMap[
V] = GrpIdx;
4581 GrpsUnionForParms.insert_range(VarGroup);
4603 for (
auto I = FixablesForAllVars.
byVar.begin();
4604 I != FixablesForAllVars.
byVar.end();) {
4606 if (!VisitedVars.count((*I).first)) {
4608 I = FixablesForAllVars.
byVar.erase(I);
4616 VisitedVars, [&FixablesForAllVars](
const VarDecl *
V) {
4618 return FixablesForAllVars.
byVar.count(
V);
4625 FixItsForVariableGroup =
4627 Tracker, Handler, VarGrpMgr);
4629 for (
const auto &G : UnsafeOps.
noVar) {
4630 G->handleUnsafeOperation(Handler,
false,
4634 for (
const auto &[VD, WarningGadgets] : UnsafeOps.
byVar) {
4635 auto FixItsIt = FixItsForVariableGroup.find(VD);
4637 FixItsIt != FixItsForVariableGroup.end()
4638 ? std::move(FixItsIt->second)
4641 for (
const auto &G : WarningGadgets) {
4642 G->handleUnsafeOperation(Handler,
true,
4650 bool EmitSuggestions) {
4656 if (
const auto *FD = dyn_cast<FunctionDecl>(D)) {
4664 if (
const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
4665 if (MD->getParent()->isLambda() && MD->getParent()->isLocalClass())
4670 if (FReDecl->isExternC()) {
4673 EmitSuggestions =
false;
4683 assert(!Stmts.empty());
4685 FixableGadgetList FixableGadgets;
4686 WarningGadgetList WarningGadgets;
4687 DeclUseTracker Tracker;
4688 for (
const Stmt *S : Stmts) {
4690 WarningGadgets, Tracker);
4692 applyGadgets(D, std::move(FixableGadgets), std::move(WarningGadgets),
4693 std::move(Tracker), Handler, EmitSuggestions);
4697 std::set<const Expr *> &UnsafePointers) {
4701 void handleUnsafeOperation(
const Stmt *,
bool,
ASTContext &)
override {}
4703 const Expr *UnsafeArg =
nullptr)
override {}
4704 void handleUnsafeOperationInContainer(
const Stmt *,
bool,
4706 void handleUnsafeVariableGroup(
const VarDecl *,
4710 void handleUnsafeUniquePtrArrayAccess(
const DynTypedNode &Node,
4711 bool IsRelatedToDecl,
4719 bool ignoreUnsafeBufferInLibcCall(
const SourceLocation &)
const override {
4722 bool ignoreUnsafeBufferInStaticSizedArray(
4726 std::string getUnsafeBufferUsageAttributeTextAt(
4737 WarningGadgetList WarningGadgets;
4738 bool Matched =
false;
4746#define WARNING_GADGET(name) \
4747 if (name##Gadget::matches(S, Ctx, Result)) \
4748 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result));
4749#define WARNING_OPTIONAL_GADGET(name) \
4750 if (name##Gadget::matches(S, Ctx, &Handler, Result)) \
4751 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result));
4752#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
4754 for (
auto &WG : WarningGadgets)
4755 for (
auto *E : WG->getUnsafePtrs()) {
4756 UnsafePointers.insert(E);
Defines the clang::ASTContext interface.
static bool ignoreUnsafeLibcCall(const ASTContext &Ctx, const Stmt &Node, const UnsafeBufferUsageHandler *Handler)
static void findStmtsInUnspecifiedLvalueContext(const Stmt *S, const llvm::function_ref< void(const Expr *)> OnResult)
static std::string getUserFillPlaceHolder(StringRef HintTextToUser="placeholder")
static FixItList fixVariableWithSpan(const VarDecl *VD, const DeclUseTracker &Tracker, ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static std::optional< FixItList > fixUPCAddressofArraySubscriptWithSpan(const UnaryOperator *Node)
static bool ignoreUnsafeBufferInContainer(const Stmt &Node, const UnsafeBufferUsageHandler *Handler)
static WarningGadgetSets groupWarningGadgetsByVar(const WarningGadgetList &AllUnsafeOperations)
static bool hasArrayType(const Expr &E)
static StringRef getEndOfLine()
static bool notInSafeBufferOptOut(const Stmt &Node, const UnsafeBufferUsageHandler *Handler)
static std::optional< FixItList > FixVarInitializerWithSpan(const Expr *Init, ASTContext &Ctx, const StringRef UserFillPlaceHolder)
static std::optional< SourceLocation > getEndCharLoc(const NodeTy *Node, const SourceManager &SM, const LangOptions &LangOpts)
static FixItList fixVariableWithArray(const VarDecl *VD, const DeclUseTracker &Tracker, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static bool areEqualIntegralBinaryOperators(const BinaryOperator *E1, const Expr *E2_LHS, BinaryOperatorKind BOP, const Expr *E2_RHS, ASTContext &Ctx)
static bool hasPointerType(const Expr &E)
static std::string getSpanTypeText(StringRef EltTyText, std::optional< Qualifiers > Quals=std::nullopt)
static SourceRange getSourceRangeToTokenEnd(const Decl *D, const SourceManager &SM, const LangOptions &LangOpts)
static FixItList fixLocalVarDeclWithSpan(const VarDecl *D, ASTContext &Ctx, const StringRef UserFillPlaceHolder, UnsafeBufferUsageHandler &Handler)
static bool isSafeArraySubscript(const ArraySubscriptExpr &Node, const ASTContext &Ctx, const bool IgnoreStaticSizedArrays)
static std::optional< FixItList > createDataFixit(const ASTContext &Ctx, const DeclRefExpr *DRE)
static FixItList createFunctionOverloadsForParms(std::map< const VarDecl *, FixItList > &FixItsForVariable, const VariableGroupsManager &VarGrpMgr, const FunctionDecl *FD, const FixitStrategy &S, ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static bool isNullTermPointer(const Expr *Ptr, ASTContext &Ctx)
static bool isSafeSpanTwoParamConstruct(const CXXConstructExpr &Node, ASTContext &Ctx)
static FixItList fixVarDeclWithArray(const VarDecl *D, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static FixItList fixVariable(const VarDecl *VD, FixitStrategy::Kind K, const Decl *D, const DeclUseTracker &Tracker, ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static FixItList fixParamWithSpan(const ParmVarDecl *PVD, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static FixitStrategy getNaiveStrategy(llvm::iterator_range< VarDeclIterTy > UnsafeVars)
static std::optional< std::string > createSpanTypeForVarDecl(const VarDecl *VD, const ASTContext &Ctx)
static bool hasConflictingOverload(const FunctionDecl *FD)
static void findStmtsInUnspecifiedPointerContext(const Stmt *S, llvm::function_ref< void(const Stmt *)> InnerMatcher)
static bool isNonNegativeIntegerExpr(const Expr *Expr, const VarDecl *VD, const ASTContext &Ctx)
static bool overlapWithMacro(const FixItList &FixIts)
static void forEachDescendantStmt(const Stmt *S, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler, FastMatcher &Matcher)
static bool hasUnsupportedSpecifiers(const VarDecl *VD, const SourceManager &SM)
static const Expr * tryConstantFoldConditionalExpr(const Expr *E, const ASTContext &Ctx)
#define DEBUG_NOTE_DECL_FAIL(D, Msg)
static void applyGadgets(const Decl *D, FixableGadgetList FixableGadgets, WarningGadgetList WarningGadgets, DeclUseTracker Tracker, UnsafeBufferUsageHandler &Handler, bool EmitSuggestions)
static bool areEqualIntegers(const Expr *E1, const Expr *E2, ASTContext &Ctx)
static void findGadgets(const Stmt *S, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler, bool EmitSuggestions, FixableGadgetList &FixableGadgets, WarningGadgetList &WarningGadgets, DeclUseTracker &Tracker)
static const Expr * getSubExprInSizeOfExpr(const Expr &E)
static std::map< const VarDecl *, FixItList > getFixIts(FixableGadgetSets &FixablesForAllVars, const FixitStrategy &S, ASTContext &Ctx, const Decl *D, const DeclUseTracker &Tracker, UnsafeBufferUsageHandler &Handler, const VariableGroupsManager &VarGrpMgr)
static bool isPtrBufferSafe(const Expr *Ptr, const Expr *Size, ASTContext &Ctx)
static const Expr * getSubExprInAddressOfExpr(const Expr &E)
static void forEachDescendantEvaluatedStmt(const Stmt *S, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler, FastMatcher &Matcher)
static void findStmtsInUnspecifiedUntypedContext(const Stmt *S, llvm::function_ref< void(const Stmt *)> InnerMatcher)
static std::optional< FixItList > createOverloadsForFixedParams(const FixitStrategy &S, const FunctionDecl *FD, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
static void eraseVarsForUnfixableGroupMates(std::map< const VarDecl *, FixItList > &FixItsForVariable, const VariableGroupsManager &VarGrpMgr)
static FixableGadgetSets groupFixablesByVar(FixableGadgetList &&AllFixableOperations)
static bool isParameterOf(const VarDecl *VD, const Decl *D)
#define SIZED_CONTAINER_OR_VIEW_LIST
static void populateStmtsForFindingGadgets(SmallVector< const Stmt * > &Stmts, const Decl *D)
static std::optional< StringRef > getFunNameText(const FunctionDecl *FD, const SourceManager &SM, const LangOptions &LangOpts)
static Decl::Kind getKind(const Decl *D)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the C++ template declaration subclasses.
Defines the clang::Preprocessor interface.
MatchFinder::MatchResult MatchResult
Defines the clang::SourceLocation class and associated facilities.
static QualType getPointeeType(const MemRegion *R)
C Language Family Type Representation.
__device__ __2f16 float __ockl_bool s
virtual std::optional< FixItList > getFixits(const FixitStrategy &s) const final
static bool matches(const Stmt *S, llvm::SmallVectorImpl< MatchResult > &Results)
DerefSimplePtrArithFixableGadget(const MatchResult &Result)
SourceLocation getSourceLoc() const override
virtual DeclUseList getClaimedVarUseSites() const final
FixableGadgetMatcher(FixableGadgetList &FixableGadgets, DeclUseTracker &Tracker)
bool matches(const DynTypedNode &DynNode, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler) override
Represents the length modifier in a format string in scanf/printf.
bool TraverseCXXTypeidExpr(CXXTypeidExpr *Node) override
bool TraverseDecltypeTypeLoc(DecltypeTypeLoc Node, bool TraverseQualifier) override
bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc Node, bool TraverseQualifier) override
bool TraverseGenericSelectionExpr(GenericSelectionExpr *Node) override
MatchDescendantVisitor(ASTContext &Context, FastMatcher &Matcher, bool FindAll, bool IgnoreUnevaluatedContext, const UnsafeBufferUsageHandler &NewHandler)
bool TraverseDecl(Decl *Node) override
bool TraverseUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node) override
bool findMatch(const DynTypedNode &DynNode)
bool TraverseCXXDefaultInitExpr(CXXDefaultInitExpr *Node) override
bool TraverseCXXNoexceptExpr(CXXNoexceptExpr *Node) override
bool TraverseStmt(Stmt *Node) override
virtual std::optional< FixItList > getFixits(const FixitStrategy &S) const override
static bool matches(const Stmt *S, llvm::SmallVectorImpl< MatchResult > &Results)
SourceLocation getSourceLoc() const override
virtual DeclUseList getClaimedVarUseSites() const override
UPCPreIncrementGadget(const MatchResult &Result)
static bool classof(const Gadget *G)
static bool classof(const Gadget *G)
UUCAddAssignGadget(const MatchResult &Result)
virtual std::optional< FixItList > getFixits(const FixitStrategy &S) const override
static bool matches(const Stmt *S, llvm::SmallVectorImpl< MatchResult > &Results)
virtual DeclUseList getClaimedVarUseSites() const override
SourceLocation getSourceLoc() const override
VariableGroupsManagerImpl(const std::vector< VarGrpTy > &Groups, const std::map< const VarDecl *, unsigned > &VarGrpMap, const llvm::SetVector< const VarDecl * > &GrpsUnionForParms)
VarGrpRef getGroupOfVar(const VarDecl *Var, bool *HasParm) const override
Returns the set of variables (including Var) that need to be fixed together in one step.
VarGrpRef getGroupOfParms() const override
Returns the non-empty group of variables that include parameters of the analyzing function,...
bool matches(const DynTypedNode &DynNode, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler) override
WarningGadgetMatcher(WarningGadgetList &WarningGadgets)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SourceManager & getSourceManager()
const ConstantArrayType * getAsConstantArrayType(QualType T) const
DynTypedNodeList getParents(const NodeT &Node)
Forwards to get node parents from the ParentMapContext.
QualType getFILEType() const
Retrieve the C FILE type.
const LangOptions & getLangOpts() const
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
QualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
const TargetInfo & getTargetInfo() const
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
Attr - This represents one attribute.
A builtin binary operation expression such as "x + y" or "x <= y".
static StringRef getOpcodeStr(Opcode Op)
getOpcodeStr - Turn an Opcode enum value into the punctuation char it corresponds to,...
Represents a call to a C++ constructor.
Expr * getArg(unsigned Arg)
Return the specified argument.
unsigned getNumArgs() const
Return the number of arguments to the constructor call.
Expr * getInit() const
Get the initializer.
A use of a default initializer in a constructor or in aggregate initialization.
Expr * getExpr()
Get the initialization expression that will be used.
Represents a static or instance method of a struct/union/class.
Represents a C++11 noexcept expression (C++ [expr.unary.noexcept]).
OverloadedOperatorKind getOperator() const
Returns the kind of overloaded operator that this expression refers to.
Represents a C++ struct/union/class.
CXXRecordDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
A C++ typeid expression (C++ [expr.typeid]), which gets the type_info that corresponds to the supplie...
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
static const char * getCastKindName(CastKind CK)
Represents a byte-granular source range.
static CharSourceRange getCharRange(SourceRange R)
SourceLocation getEnd() const
bool isOne() const
isOne - Test whether the quantity equals one.
Represents a class template specialization, which refers to a class template with a given set of temp...
const TemplateArgumentList & getTemplateArgs() const
Retrieve the template arguments of the class template specialization.
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
bool isSingleResult() const
DeclContext * getParent()
getParent - Returns the containing DeclContext.
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
A reference to a declared variable, function, enum, etc.
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
bool isSingleDecl() const
isSingleDecl - This method returns true if this DeclStmt refers to a single Decl.
const Decl * getSingleDecl() const
Decl - This represents one declaration (or definition), e.g.
bool isInStdNamespace() const
SourceLocation getEndLoc() const LLVM_READONLY
ASTContext & getASTContext() const LLVM_READONLY
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const
DeclContext * getDeclContext()
SourceLocation getBeginLoc() const LLVM_READONLY
virtual Decl * getCanonicalDecl()
Retrieves the "canonical" declaration of the given declaration.
SourceLocation getTypeSpecEndLoc() const
SourceLocation getBeginLoc() const LLVM_READONLY
NestedNameSpecifierLoc getQualifierLoc() const
Retrieve the nested-name-specifier (with source-location information) that qualifies the name of this...
NestedNameSpecifier getQualifier() const
Retrieve the nested-name-specifier that qualifies the name of this declaration, if it was present in ...
Container for either a single DynTypedNode or for an ArrayRef to DynTypedNode.
const DynTypedNode * begin() const
A dynamically typed AST node container.
const T * get() const
Retrieve the stored node as type T.
static DynTypedNode create(const T &Node)
Creates a DynTypedNode from Node.
virtual bool TraverseDecl(MaybeConst< Decl > *D)
bool ShouldVisitTemplateInstantiations
bool ShouldVisitImplicitCode
virtual bool TraverseStmt(MaybeConst< Stmt > *S)
This represents one expression.
bool EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects, bool InConstantContext=false) const
EvaluateAsInt - Return true if this is a constant which we can fold and convert to an integer,...
bool isValueDependent() const
Determines whether the value of this expression depends on.
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
std::optional< llvm::APSInt > getIntegerConstantExpr(const ASTContext &Ctx) const
isIntegerConstantExpr - Return the value if this expression is a valid integer constant expression.
NullPointerConstantValueDependence
Enumeration used to describe how isNullPointerConstant() should cope with value-dependent expressions...
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
Annotates a diagnostic with some code that should be inserted, removed, or replaced to fix the proble...
CharSourceRange RemoveRange
Code that should be replaced to correct the error.
static FixItHint CreateReplacement(CharSourceRange RemoveRange, StringRef Code)
Create a code modification hint that replaces the given source range with the given code string.
static FixItHint CreateRemoval(CharSourceRange RemoveRange)
Create a code modification hint that removes the given source range.
static FixItHint CreateInsertion(SourceLocation InsertionLoc, StringRef Code, bool BeforePreviousInsertions=false)
Create a code modification hint that inserts the given code string at a specific location.
Kind lookup(const VarDecl *VD) const
void set(const VarDecl *VD, Kind K)
Represents a function declaration or definition.
const ParmVarDecl * getParamDecl(unsigned i) const
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
unsigned getBuiltinID(bool ConsiderWrapperFunctions=false) const
Returns a value indicating whether this function corresponds to a builtin function.
ArrayRef< ParmVarDecl * > parameters() const
param_iterator param_begin()
bool isVariadic() const
Whether this function is variadic.
TemplatedKind getTemplatedKind() const
What kind of templated function this is.
bool isConstexpr() const
Whether this is a (C++11) constexpr function or constexpr constructor.
redecl_range redecls() const
Returns an iterator range for all the redeclarations of the same decl.
bool isMain() const
Determines whether this function is "main", which is the entry point into an executable program.
bool isOverloadedOperator() const
Whether this function declaration represents an C++ overloaded operator, e.g., "operator+".
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
DeclarationNameInfo getNameInfo() const
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
Represents a C11 generic selection.
Expr * getResultExpr()
Return the result expression of this controlling expression.
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
A simple pair of identifier info and location.
static IntegerLiteral * Create(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l)
Returns a new integer literal with value 'V' and type 'type'.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
static std::optional< Token > findNextToken(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts, bool IncludeComments=false)
Finds the token that comes right after the given location.
static unsigned MeasureTokenLength(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
MeasureTokenLength - Relex the token at the specified location and return its length in bytes in the ...
static SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset, const SourceManager &SM, const LangOptions &LangOpts)
Computes the source location just past the end of the token at this source location.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
SourceLocation getBeginLoc() const
Retrieve the location of the beginning of this nested-name-specifier.
A single parameter index whose accessors require each use to make explicit the parameter index encodi...
bool isValid() const
Is this parameter index valid?
unsigned getASTIndex() const
Get the parameter index as it would normally be encoded at the AST level of representation: zero-orig...
Represents a parameter to a function.
bool hasDefaultArg() const
Determines whether this parameter has a default argument, either parsed or not.
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
PointerType - C99 6.7.5.1 - Pointer Declarators.
A (possibly-)qualified type.
bool hasQualifiers() const
Determine whether this type has any qualifiers.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
QualType getCanonicalType() const
bool isConstQualified() const
Determine whether this type is const-qualified.
std::string getAsString() const
Represents a struct/union/class.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
This class handles loading and caching of source files into memory.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
Stmt - This represents one statement.
StmtClass getStmtClass() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
const char * getStmtClassName() const
SourceLocation getBeginLoc() const LLVM_READONLY
Exposes information about the current target.
A template argument list.
unsigned size() const
Retrieve the number of template arguments in this template argument list.
Represents a template argument.
QualType getAsType() const
Retrieve the type for a type template argument.
@ Type
The template argument is a type.
ArgKind getKind() const
Return the kind of stored template argument.
The base class of the type hierarchy.
bool isConstantSizeType() const
Return true if this is not a variable sized type, according to the rules of C99 6....
bool isPointerType() const
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
const T * castAs() const
Member-template castAs<specific type>.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
bool isAnyCharacterType() const
Determine whether this type is any of the built-in character types.
bool isUnsignedIntegerType() const
Return true if this is an integer type that is unsigned, according to C99 6.2.5p6 [which returns true...
bool isAnyPointerType() const
const Type * getUnqualifiedDesugaredType() const
Return the specified type with any "sugar" removed from the type, removing any typedefs,...
UnaryExprOrTypeTraitExpr - expression with either a type or (unevaluated) expression operand.
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Expr * getSubExpr() const
static bool isIncrementOp(Opcode Op)
SourceLocation getBeginLoc() const LLVM_READONLY
static bool isDecrementOp(Opcode Op)
static StringRef getOpcodeStr(Opcode Op)
getOpcodeStr - Turn an Opcode enum value into the punctuation char it corresponds to,...
The interface that lets the caller handle unsafe buffer usage analysis results by overriding this cla...
virtual void handleUnsafeUniquePtrArrayAccess(const DynTypedNode &Node, bool IsRelatedToDecl, ASTContext &Ctx)=0
void addDebugNoteForVar(const VarDecl *VD, SourceLocation Loc, std::string Text)
virtual std::string getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc, StringRef WSSuffix="") const =0
virtual bool isSafeBufferOptOut(const SourceLocation &Loc) const =0
virtual bool ignoreUnsafeBufferInContainer(const SourceLocation &Loc) const =0
virtual void handleUnsafeOperation(const Stmt *Operation, bool IsRelatedToDecl, ASTContext &Ctx)=0
Invoked when an unsafe operation over raw pointers is found.
virtual void handleUnsafeVariableGroup(const VarDecl *Variable, const VariableGroupsManager &VarGrpMgr, FixItList &&Fixes, const Decl *D, const FixitStrategy &VarTargetTypes)=0
Invoked when a fix is suggested against a variable.
virtual void handleUnsafeOperationInContainer(const Stmt *Operation, bool IsRelatedToDecl, ASTContext &Ctx)=0
Invoked when an unsafe operation with a std container is found.
virtual bool ignoreUnsafeBufferInStaticSizedArray(const SourceLocation &Loc) const =0
virtual bool ignoreUnsafeBufferInLibcCall(const SourceLocation &Loc) const =0
virtual void handleUnsafeLibcCall(const CallExpr *Call, unsigned PrintfInfo, ASTContext &Ctx, const Expr *UnsafeArg=nullptr)=0
Invoked when a call to an unsafe libc function is found.
Represents a variable declaration or definition.
bool isConstexpr() const
Whether this variable is (C++11) constexpr.
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
VarDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
bool isInlineSpecified() const
bool hasConstantInitialization() const
Determine whether this variable has constant initialization.
const Expr * getInit() const
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
bool isLocalVarDecl() const
Returns true for local variable declarations other than parameters.
const Expr * getAnyInitializer() const
Get the initializer for this variable, no matter which declaration it is attached to.
VariableGroupsManager()=default
virtual VarGrpRef getGroupOfVar(const VarDecl *Var, bool *HasParm=nullptr) const =0
Returns the set of variables (including Var) that need to be fixed together in one step.
virtual VarGrpRef getGroupOfParms() const =0
Returns the non-empty group of variables that include parameters of the analyzing function,...
unsigned getArgIndex() const
bool hasDataArgument() const
HowSpecified getHowSpecified() const
unsigned getConstantAmount() const
const OptionalAmount & getPrecision() const
const PrintfConversionSpecifier & getConversionSpecifier() const
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
void matchEachArgumentWithParamType(const CallExpr &Node, llvm::function_ref< void(QualType, const Expr *)> OnParamAndArg)
bool anyConflict(const llvm::SmallVectorImpl< FixItHint > &FixIts, const SourceManager &SM)
bool matches(const til::SExpr *E1, const til::SExpr *E2)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
bool matchUnsafePointers(const DynTypedNode &N, ASTContext &Ctx, std::set< const Expr * > &UnsafePointers)
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
void checkUnsafeBufferUsage(const Decl *D, UnsafeBufferUsageHandler &Handler, bool EmitSuggestions)
SourceLocation getVarDeclIdentifierLoc(const DeclaratorDecl *VD)
static bool classof(const OMPClause *T)
std::vector< const VarDecl * > VarGrpTy
std::optional< StringRef > getExprText(const Expr *E, const SourceManager &SM, const LangOptions &LangOpts)
@ Result
The result type of a method or function.
std::optional< std::string > getPointeeTypeText(const DeclaratorDecl *VD, const SourceManager &SM, const LangOptions &LangOpts, std::optional< Qualifiers > *QualifiersToAppend)
std::optional< StringRef > getRangeText(SourceRange SR, const SourceManager &SM, const LangOptions &LangOpts)
std::optional< StringRef > getVarDeclIdentifierText(const DeclaratorDecl *VD, const SourceManager &SM, const LangOptions &LangOpts)
std::optional< SourceLocation > getPastLoc(const NodeTy *Node, const SourceManager &SM, const LangOptions &LangOpts)
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
U cast(CodeGen::Address addr)
ArrayRef< const VarDecl * > VarGrpRef
static StringRef matchLibcNameOrBuiltinChk(StringRef Name)
static bool hasUnsafePrintfStringArg(const CallExpr &Node, ASTContext &Ctx, MatchResult &Result, llvm::StringRef Tag)
static bool isPredefinedUnsafeLibcFunc(const FunctionDecl &Node)
static bool hasUnsafeSnprintfBuffer(const CallExpr &Node, ASTContext &Ctx)
static bool isUnsafeVaListPrintfFunc(const FunctionDecl &Node)
static bool isUnsafeSprintfFunc(const FunctionDecl &Node)
static bool hasUnsafeFormatOrSArg(ASTContext &Ctx, const CallExpr *Call, const Expr *&UnsafeArg, const unsigned FmtIdx, std::optional< const unsigned > FmtArgIdx=std::nullopt, bool isKprintf=false)
static StringRef matchLibcName(StringRef Name)
static bool isUnsafeMemset(const CallExpr &Node, ASTContext &Ctx)
static StringRef matchName(StringRef FunName, bool isBuiltin)
static bool isNormalPrintfFunc(const FunctionDecl &Node)
bool operator()(const NodeTy *N1, const NodeTy *N2) const
std::map< const VarDecl *, std::set< const FixableGadget * >, CompareNode< VarDecl > > byVar
std::map< const VarDecl *, std::set< const WarningGadget * >, CompareNode< VarDecl > > byVar
llvm::SmallVector< const WarningGadget *, 16 > noVar
SourceLocation getBeginLoc() const
getBeginLoc - Retrieve the location of the first token.
SourceLocation getEndLoc() const LLVM_READONLY
EvalResult is a struct with detailed info about an evaluated expression.
APValue Val
Val - This is the value the expression can be folded to.
const BoundNodes Nodes
Contains the nodes bound on the current match.