29#include "llvm/ADT/APInt.h"
30#include "llvm/ADT/APSInt.h"
31#include "llvm/ADT/STLFunctionalExtras.h"
32#include "llvm/ADT/SmallSet.h"
33#include "llvm/ADT/SmallVector.h"
34#include "llvm/ADT/StringRef.h"
50 std::string VisitBinaryOperator(
const BinaryOperator *BO) {
51 return "BinaryOperator(" + BO->
getOpcodeStr().str() +
")";
54 std::string VisitUnaryOperator(
const UnaryOperator *UO) {
58 std::string VisitImplicitCastExpr(
const ImplicitCastExpr *ICE) {
65static std::string getDREAncestorString(
const DeclRefExpr *DRE,
69 StmtDebugPrinter StmtPriner;
72 SS << StmtPriner.Visit(St);
76 if (StParents.
size() > 1)
77 return "unavailable due to multiple parents";
78 if (StParents.
empty())
97 virtual bool matches(
const DynTypedNode &DynNode, ASTContext &Ctx,
98 const UnsafeBufferUsageHandler &Handler) = 0;
99 virtual ~FastMatcher() =
default;
105 template <
typename T>
const T *getNodeAs(StringRef ID)
const {
106 auto It =
Nodes.find(ID);
107 if (It ==
Nodes.end()) {
110 return It->second.get<
T>();
113 void addNode(StringRef ID,
const DynTypedNode &Node) {
Nodes[
ID] = Node; }
116 llvm::StringMap<DynTypedNode>
Nodes;
120#define SIZED_CONTAINER_OR_VIEW_LIST \
121 "span", "array", "vector", "basic_string_view", "basic_string", \
132 bool FindAll,
bool ignoreUnevaluatedContext,
134 : Matcher(&Matcher), FindAll(FindAll), Matches(
false),
135 ignoreUnevaluatedContext(ignoreUnevaluatedContext),
136 ActiveASTContext(&Context), Handler(&NewHandler) {
173 if (ignoreUnevaluatedContext)
175 return DynamicRecursiveASTVisitor::TraverseGenericSelectionExpr(Node);
181 if (ignoreUnevaluatedContext)
183 return DynamicRecursiveASTVisitor::TraverseUnaryExprOrTypeTraitExpr(Node);
187 bool TraverseQualifier)
override {
189 if (ignoreUnevaluatedContext)
191 return DynamicRecursiveASTVisitor::TraverseTypeOfExprTypeLoc(
192 Node, TraverseQualifier);
196 bool TraverseQualifier)
override {
198 if (ignoreUnevaluatedContext)
200 return DynamicRecursiveASTVisitor::TraverseDecltypeTypeLoc(
201 Node, TraverseQualifier);
206 if (ignoreUnevaluatedContext)
208 return DynamicRecursiveASTVisitor::TraverseCXXNoexceptExpr(Node);
213 if (ignoreUnevaluatedContext)
215 return DynamicRecursiveASTVisitor::TraverseCXXTypeidExpr(Node);
221 return DynamicRecursiveASTVisitor::TraverseCXXDefaultInitExpr(Node);
237 template <
typename T>
bool match(
const T &Node) {
247 FastMatcher *
const Matcher;
251 bool ignoreUnevaluatedContext;
252 ASTContext *ActiveASTContext;
253 const UnsafeBufferUsageHandler *Handler;
268 FastMatcher &Matcher) {
276 FastMatcher &Matcher) {
304 const Stmt *S,
const llvm::function_ref<
void(
const Expr *)> OnResult) {
305 if (
const auto *CE = dyn_cast<ImplicitCastExpr>(S);
306 CE && CE->getCastKind() == CastKind::CK_LValueToRValue)
307 OnResult(CE->getSubExpr());
308 if (
const auto *BO = dyn_cast<BinaryOperator>(S);
316 const Stmt *S, llvm::function_ref<
void(
const Stmt *)> InnerMatcher) {
325 if (
auto *CE = dyn_cast<CallExpr>(S)) {
326 if (
const auto *FnDecl = CE->getDirectCallee();
327 FnDecl && FnDecl->hasAttr<UnsafeBufferUsageAttr>())
336 if (
auto *CE = dyn_cast<CastExpr>(S)) {
337 if (CE->getCastKind() != CastKind::CK_PointerToIntegral &&
338 CE->getCastKind() != CastKind::CK_PointerToBoolean)
342 InnerMatcher(CE->getSubExpr());
346 if (
const auto *BO = dyn_cast<BinaryOperator>(S);
360 if (
const auto *BO = dyn_cast<BinaryOperator>(S);
366 InnerMatcher(BO->
getLHS());
367 InnerMatcher(BO->
getRHS());
385 const Stmt *S, llvm::function_ref<
void(
const Stmt *)> InnerMatcher) {
390 if (
auto *CS = dyn_cast<CompoundStmt>(S)) {
391 for (
auto *Child : CS->body())
394 if (
auto *IfS = dyn_cast<IfStmt>(S)) {
396 InnerMatcher(IfS->getThen());
398 InnerMatcher(IfS->getElse());
449 case Stmt::DeclRefExprClass:
451 case Stmt::BinaryOperatorClass: {
454 BO2->getLHS(), BO2->getOpcode(),
480 dyn_cast<CXXMemberCallExpr>(Size->IgnoreParenImpCasts())) {
481 auto *DREOfPtr = dyn_cast<DeclRefExpr>(
482 MCEPtr->getImplicitObjectArgument()->IgnoreParenImpCasts());
483 auto *DREOfSize = dyn_cast<DeclRefExpr>(
484 MCESize->getImplicitObjectArgument()->IgnoreParenImpCasts());
486 if (!DREOfPtr || !DREOfSize)
490 if (DREOfPtr->getDecl() != DREOfSize->getDecl())
492 if (MCEPtr->getMethodDecl()->getName() !=
"data")
495 if (!MCEPtr->getRecordDecl()->isInStdNamespace())
498 auto *ObjII = MCEPtr->getRecordDecl()->getIdentifier();
505 if (!((AcceptSizeBytes &&
506 MCESize->getMethodDecl()->getName() ==
"size_bytes") ||
511 MCESize->getMethodDecl()->getName() ==
"size"))
521 if (Size->EvaluateAsInt(ER, Ctx)) {
527 return llvm::APSInt::compareValues(
528 SizeInt, llvm::APSInt(CAT->getSize(),
true)) == 0;
536 return UO && UO->
getOpcode() == UnaryOperator::Opcode::UO_AddrOf;
538 auto *FnDecl = CE->getDirectCallee();
540 return FnDecl && FnDecl->getNameAsString() ==
"addressof" &&
541 FnDecl->isInStdNamespace();
569 "expecting a two-parameter std::span constructor");
572 auto HaveEqualConstantValues = [&Ctx](
const Expr *E0,
const Expr *E1) {
574 if (
auto E1CV = E1->getIntegerConstantExpr(Ctx)) {
575 return llvm::APSInt::compareValues(*E0CV, *E1CV) == 0;
579 auto AreSameDRE = [](
const Expr *E0,
const Expr *E1) {
580 if (
auto *DRE0 = dyn_cast<DeclRefExpr>(E0))
581 if (
auto *DRE1 = dyn_cast<DeclRefExpr>(E1)) {
582 return DRE0->getDecl() == DRE1->getDecl();
588 if (Arg1CV && Arg1CV->isZero())
594 case Stmt::CXXNewExprClass:
597 return AreSameDRE((*Size)->IgnoreImplicit(), Arg1) ||
598 HaveEqualConstantValues(*Size, Arg1);
603 return Arg1CV && Arg1CV->isOne();
611 if (
auto CCast = dyn_cast<CStyleCastExpr>(Arg0)) {
612 if (!CCast->getType()->isPointerType())
620 if (
const auto *
Call = dyn_cast<CallExpr>(CCast->getSubExpr())) {
622 if (
auto *AllocAttr = FD->getAttr<AllocSizeAttr>()) {
623 const Expr *EleSizeExpr =
624 Call->getArg(AllocAttr->getElemSizeParam().getASTIndex());
626 ParamIdx NumElemIdx = AllocAttr->getNumElemsParam();
633 if (
auto BO = dyn_cast<BinaryOperator>(Arg1))
640 auto IsMethodCallToSizedObject = [](
const Stmt *Node, StringRef MethodName) {
641 if (
const auto *MC = dyn_cast<CXXMemberCallExpr>(Node)) {
642 const auto *MD = MC->getMethodDecl();
643 const auto *RD = MC->getRecordDecl();
646 if (
auto *II = RD->getDeclName().getAsIdentifierInfo();
647 II && RD->isInStdNamespace())
650 MD->getName() == MethodName;
655 if (IsMethodCallToSizedObject(Arg0,
"begin") &&
656 IsMethodCallToSizedObject(Arg1,
"end"))
660 ->getImplicitObjectArgument()
661 ->IgnoreParenImpCasts(),
663 ->getImplicitObjectArgument()
664 ->IgnoreParenImpCasts());
680 if (
const auto *CATy =
681 dyn_cast<ConstantArrayType>(Node.
getBase()
685 limit = CATy->getLimitedSize();
686 }
else if (
const auto *SLiteral = dyn_cast<clang::StringLiteral>(
688 limit = SLiteral->getLength() + 1;
697 llvm::APSInt ArrIdx = EVResult.
Val.
getInt();
700 if (ArrIdx.isNonNegative() && ArrIdx.getLimitedValue() < limit)
702 }
else if (
const auto *BE = dyn_cast<BinaryOperator>(IndexExpr)) {
705 if (BE->getOpcode() != BO_And && BE->getOpcode() != BO_Rem)
708 const Expr *LHS = BE->getLHS();
709 const Expr *RHS = BE->getRHS();
711 if (BE->getOpcode() == BO_Rem) {
718 llvm::APSInt result = EVResult.
Val.
getInt();
719 if (result.isNonNegative() && result.getLimitedValue() <= limit)
730 llvm::APSInt result = EVResult.
Val.
getInt();
731 if (result.isNonNegative() && result.getLimitedValue() < limit)
755 StringRef
matchName(StringRef FunName,
bool isBuiltin) {
757 if (isBuiltin && FunName.starts_with(
"__builtin_"))
761 FunName.drop_front(10 ));
763 if (FunName.starts_with(
"__asan_"))
771 if (Name.starts_with(
"__") && Name.ends_with(
"_chk"))
773 Name.drop_front(2).drop_back(4) );
778 if (Name.ends_with(
"_s"))
779 return Name.drop_back(2 );
790 if (
const auto *CE = dyn_cast<ConditionalOperator>(E)) {
793 if (CE->getCond()->EvaluateAsBooleanCondition(CondEval, Ctx))
794 return CondEval ? CE->getLHS() : CE->getRHS();
828 bool isKprintf =
false) {
829 class StringFormatStringHandler
833 const Expr *&UnsafeArg;
847 unsigned PArgIdx = -1;
851 if (0 < PArgIdx && PArgIdx < Call->getNumArgs()) {
852 const Expr *PArg =
Call->getArg(PArgIdx);
855 if (
auto *CE = dyn_cast<CastExpr>(PArg);
856 CE && CE->getType()->isSignedIntegerType())
857 PArg = CE->getSubExpr();
861 analyze_printf::OptionalAmount::HowSpecified::Constant) {
863 llvm::APSInt PArgVal = llvm::APSInt(
873 StringFormatStringHandler(
const CallExpr *
Call,
unsigned FmtArgIdx,
875 :
Call(
Call), FmtArgIdx(FmtArgIdx), UnsafeArg(UnsafeArg), Ctx(Ctx) {}
878 const char *startSpecifier,
879 unsigned specifierLen,
887 if (!(0 < ArgIdx && ArgIdx < Call->getNumArgs()))
891 const Expr *Arg =
Call->getArg(ArgIdx);
901 bool IsArgTypeValid =
904 ?
ArgType->getPointeeType()->isWideCharType()
905 :
ArgType->getPointeeType()->isCharType());
908 Precision && IsArgTypeValid)
912 UnsafeArg =
Call->getArg(ArgIdx);
917 const Expr *Fmt =
Call->getArg(FmtArgIdx);
920 if (SL->getCharByteWidth() == 1) {
921 StringRef FmtStr = SL->getString();
922 StringFormatStringHandler Handler(
Call, FmtArgIdx, UnsafeArg, Ctx);
925 Handler, FmtStr.begin(), FmtStr.end(), Ctx.
getLangOpts(),
929 if (
auto FmtStr = SL->tryEvaluateString(Ctx)) {
930 StringFormatStringHandler Handler(
Call, FmtArgIdx, UnsafeArg, Ctx);
932 Handler, FmtStr->data(), FmtStr->data() + FmtStr->size(),
940 llvm::make_range(
Call->arg_begin() + FmtArgIdx,
Call->arg_end()),
941 [&UnsafeArg, &Ctx](
const Expr *Arg) ->
bool {
942 if (Arg->getType()->isPointerType() && !isNullTermPointer(Arg, Ctx)) {
960 static std::unique_ptr<std::set<StringRef>> PredefinedNames =
nullptr;
961 if (!PredefinedNames)
963 std::make_unique<std::set<StringRef>, std::set<StringRef>>({
1044 if (PredefinedNames->find(Name) != PredefinedNames->end())
1047 std::string NameWCS = Name.str();
1048 size_t WcsPos = NameWCS.find(
"wcs");
1050 while (WcsPos != std::string::npos) {
1051 NameWCS[WcsPos++] =
's';
1052 NameWCS[WcsPos++] =
't';
1053 NameWCS[WcsPos++] =
'r';
1054 WcsPos = NameWCS.find(
"wcs", WcsPos);
1056 if (PredefinedNames->find(NameWCS) != PredefinedNames->end())
1060 return Name.ends_with(
"scanf");
1075 if (!Name.ends_with(
"printf"))
1077 return Name.starts_with(
"v");
1091 if (!Name.ends_with(
"printf") ||
1093 Name.starts_with(
"v"))
1096 StringRef Prefix = Name.drop_back(6);
1098 if (Prefix.ends_with(
"w"))
1099 Prefix = Prefix.drop_back(1);
1100 return Prefix ==
"s";
1115 if (!Name.ends_with(
"printf") || Name.starts_with(
"v"))
1118 StringRef Prefix = Name.drop_back(6);
1120 if (Prefix.ends_with(
"w"))
1121 Prefix = Prefix.drop_back(1);
1123 return Prefix.empty() || Prefix ==
"k" || Prefix ==
"f" || Prefix ==
"sn";
1131 MatchResult &Result, llvm::StringRef Tag) {
1135 assert(FD &&
"It should have been checked that FD is non-null.");
1153 const Expr *UnsafeArg;
1164 bool isKprintf =
false;
1165 const Expr *UnsafeArg;
1168 isKprintf = II->getName() ==
"kprintf";
1182 const Expr *UnsafeArg;
1193 for (
const auto *Arg : Node.
arguments())
1208 assert(FD &&
"It should have been checked that FD is non-null.");
1223 !Size->getType()->isUnsignedIntegerType())
1252#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1255 Gadget(Kind K) : K(K) {}
1257 Kind
getKind()
const {
return K; }
1260 StringRef getDebugName()
const {
1265#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1267 llvm_unreachable(
"Unhandled Gadget::Kind enum");
1271 virtual bool isWarningGadget()
const = 0;
1274 virtual SourceLocation getSourceLoc()
const = 0;
1279 virtual DeclUseList getClaimedVarUseSites()
const = 0;
1281 virtual ~Gadget() =
default;
1289class WarningGadget :
public Gadget {
1291 WarningGadget(Kind K) : Gadget(K) {}
1293 static bool classof(
const Gadget *G) {
return G->isWarningGadget(); }
1294 bool isWarningGadget() const final {
return true; }
1296 virtual void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1297 bool IsRelatedToDecl,
1298 ASTContext &Ctx)
const = 0;
1300 virtual SmallVector<const Expr *, 1> getUnsafePtrs()
const = 0;
1307class FixableGadget :
public Gadget {
1309 FixableGadget(Kind K) : Gadget(K) {}
1311 static bool classof(
const Gadget *G) {
return !G->isWarningGadget(); }
1312 bool isWarningGadget() const final {
return false; }
1317 virtual std::optional<FixItList> getFixits(
const FixitStrategy &)
const {
1318 return std::nullopt;
1327 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1328 getStrategyImplications()
const {
1329 return std::nullopt;
1333static bool isSupportedVariable(
const DeclRefExpr &Node) {
1345 dyn_cast<ClassTemplateSpecializationDecl>(
RecordDecl);
1346 if (!class_template_specialization_decl)
1351 if (template_args.
size() == 0)
1362class UniquePtrArrayAccessGadget :
public WarningGadget {
1364 static constexpr const char *
const AccessorTag =
"unique_ptr_array_access";
1365 const CXXOperatorCallExpr *AccessorExpr;
1369 : WarningGadget(
Kind::UniquePtrArrayAccess),
1370 AccessorExpr(
Result.getNodeAs<CXXOperatorCallExpr>(AccessorTag)) {
1371 assert(AccessorExpr &&
1372 "UniquePtrArrayAccessGadget requires a matched CXXOperatorCallExpr");
1375 static bool classof(
const Gadget *G) {
1376 return G->getKind() == Kind::UniquePtrArrayAccess;
1379 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1382 const CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(S);
1383 if (!OpCall || OpCall->
getOperator() != OO_Subscript)
1390 const CXXMethodDecl *
Method =
1395 if (
Method->getOverloadedOperator() != OO_Subscript)
1399 if (!isUniquePtrArray(RecordDecl))
1402 const Expr *IndexExpr = OpCall->
getArg(1);
1403 clang::Expr::EvalResult Eval;
1409 Result.addNode(AccessorTag, DynTypedNode::create(*OpCall));
1412 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1413 bool IsRelatedToDecl,
1414 ASTContext &Ctx)
const override {
1416 DynTypedNode::create(*AccessorExpr), IsRelatedToDecl, Ctx);
1419 SourceLocation getSourceLoc()
const override {
1421 return AccessorExpr->getOperatorLoc();
1422 return SourceLocation();
1425 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1426 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1429using FixableGadgetList = std::vector<std::unique_ptr<FixableGadget>>;
1430using WarningGadgetList = std::vector<std::unique_ptr<WarningGadget>>;
1434class IncrementGadget :
public WarningGadget {
1435 static constexpr const char *
const OpTag =
"op";
1436 const UnaryOperator *Op;
1440 : WarningGadget(
Kind::Increment),
1441 Op(
Result.getNodeAs<UnaryOperator>(OpTag)) {}
1443 static bool classof(
const Gadget *G) {
1444 return G->getKind() == Kind::Increment;
1447 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1449 const auto *UO = dyn_cast<UnaryOperator>(S);
1454 Result.addNode(OpTag, DynTypedNode::create(*UO));
1458 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1459 bool IsRelatedToDecl,
1460 ASTContext &Ctx)
const override {
1463 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1465 DeclUseList getClaimedVarUseSites()
const override {
1466 SmallVector<const DeclRefExpr *, 2> Uses;
1467 if (
const auto *DRE =
1468 dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
1469 Uses.push_back(DRE);
1472 return std::move(Uses);
1475 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1476 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1482class DecrementGadget :
public WarningGadget {
1483 static constexpr const char *
const OpTag =
"op";
1484 const UnaryOperator *Op;
1488 : WarningGadget(
Kind::Decrement),
1489 Op(
Result.getNodeAs<UnaryOperator>(OpTag)) {}
1491 static bool classof(
const Gadget *G) {
1492 return G->getKind() == Kind::Decrement;
1495 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1497 const auto *UO = dyn_cast<UnaryOperator>(S);
1502 Result.addNode(OpTag, DynTypedNode::create(*UO));
1506 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1507 bool IsRelatedToDecl,
1508 ASTContext &Ctx)
const override {
1511 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1513 DeclUseList getClaimedVarUseSites()
const override {
1514 if (
const auto *DRE =
1515 dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
1522 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1523 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1529class ArraySubscriptGadget :
public WarningGadget {
1530 static constexpr const char *
const ArraySubscrTag =
"ArraySubscript";
1531 const ArraySubscriptExpr *ASE;
1536 ASE(
Result.getNodeAs<ArraySubscriptExpr>(ArraySubscrTag)) {}
1538 static bool classof(
const Gadget *G) {
1539 return G->getKind() == Kind::ArraySubscript;
1542 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1544 const auto *ASE = dyn_cast<ArraySubscriptExpr>(S);
1547 const auto *
const Base = ASE->getBase()->IgnoreParenImpCasts();
1550 const auto *Idx = dyn_cast<IntegerLiteral>(ASE->getIdx());
1551 bool IsSafeIndex = (Idx && Idx->getValue().isZero()) ||
1555 Result.addNode(ArraySubscrTag, DynTypedNode::create(*ASE));
1559 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1560 bool IsRelatedToDecl,
1561 ASTContext &Ctx)
const override {
1564 SourceLocation getSourceLoc()
const override {
return ASE->getBeginLoc(); }
1566 DeclUseList getClaimedVarUseSites()
const override {
1567 if (
const auto *DRE =
1568 dyn_cast<DeclRefExpr>(ASE->getBase()->IgnoreParenImpCasts())) {
1575 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1576 return {ASE->getBase()->IgnoreParenImpCasts()};
1584class PointerArithmeticGadget :
public WarningGadget {
1585 static constexpr const char *
const PointerArithmeticTag =
"ptrAdd";
1586 static constexpr const char *
const PointerArithmeticPointerTag =
"ptrAddPtr";
1587 const BinaryOperator *PA;
1592 : WarningGadget(
Kind::PointerArithmetic),
1593 PA(
Result.getNodeAs<BinaryOperator>(PointerArithmeticTag)),
1594 Ptr(
Result.getNodeAs<Expr>(PointerArithmeticPointerTag)) {}
1596 static bool classof(
const Gadget *G) {
1597 return G->getKind() == Kind::PointerArithmetic;
1600 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1602 const auto *BO = dyn_cast<BinaryOperator>(S);
1605 const auto *LHS = BO->
getLHS();
1606 const auto *RHS = BO->
getRHS();
1611 RHS->getType()->isEnumeralType())) {
1612 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*LHS));
1613 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1619 (LHS->getType()->isIntegerType() || LHS->getType()->isEnumeralType())) {
1620 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*RHS));
1621 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1627 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1628 bool IsRelatedToDecl,
1629 ASTContext &Ctx)
const override {
1632 SourceLocation getSourceLoc()
const override {
return PA->getBeginLoc(); }
1634 DeclUseList getClaimedVarUseSites()
const override {
1635 if (
const auto *DRE = dyn_cast<DeclRefExpr>(Ptr->IgnoreParenImpCasts())) {
1642 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1643 return {Ptr->IgnoreParenImpCasts()};
1650class SpanTwoParamConstructorGadget :
public WarningGadget {
1651 static constexpr const char *
const SpanTwoParamConstructorTag =
1652 "spanTwoParamConstructor";
1653 const CXXConstructExpr *Ctor;
1657 : WarningGadget(
Kind::SpanTwoParamConstructor),
1658 Ctor(
Result.getNodeAs<CXXConstructExpr>(SpanTwoParamConstructorTag)) {}
1660 static bool classof(
const Gadget *G) {
1661 return G->getKind() == Kind::SpanTwoParamConstructor;
1665 const auto *CE = dyn_cast<CXXConstructExpr>(S);
1668 const auto *CDecl = CE->getConstructor();
1669 const auto *CRecordDecl = CDecl->getParent();
1670 auto HasTwoParamSpanCtorDecl =
1671 CRecordDecl->isInStdNamespace() &&
1672 CDecl->getDeclName().getAsString() ==
"span" && CE->getNumArgs() == 2;
1675 Result.addNode(SpanTwoParamConstructorTag, DynTypedNode::create(*CE));
1679 static bool matches(
const Stmt *S, ASTContext &Ctx,
1680 const UnsafeBufferUsageHandler *Handler,
1687 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1688 bool IsRelatedToDecl,
1689 ASTContext &Ctx)
const override {
1692 SourceLocation getSourceLoc()
const override {
return Ctor->getBeginLoc(); }
1694 DeclUseList getClaimedVarUseSites()
const override {
1697 if (
auto *DRE = dyn_cast<DeclRefExpr>(Ctor->getArg(0))) {
1704 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1711class PointerInitGadget :
public FixableGadget {
1713 static constexpr const char *
const PointerInitLHSTag =
"ptrInitLHS";
1714 static constexpr const char *
const PointerInitRHSTag =
"ptrInitRHS";
1715 const VarDecl *PtrInitLHS;
1716 const DeclRefExpr *PtrInitRHS;
1720 : FixableGadget(
Kind::PointerInit),
1721 PtrInitLHS(
Result.getNodeAs<VarDecl>(PointerInitLHSTag)),
1722 PtrInitRHS(
Result.getNodeAs<DeclRefExpr>(PointerInitRHSTag)) {}
1724 static bool classof(
const Gadget *G) {
1725 return G->getKind() == Kind::PointerInit;
1728 static bool matches(
const Stmt *S,
1729 llvm::SmallVectorImpl<MatchResult> &Results) {
1730 const DeclStmt *DS = dyn_cast<DeclStmt>(S);
1739 const auto *DRE = dyn_cast<DeclRefExpr>(
Init->IgnoreImpCasts());
1740 if (!DRE || !
hasPointerType(*DRE) || !isSupportedVariable(*DRE)) {
1744 R.addNode(PointerInitLHSTag, DynTypedNode::create(*VD));
1745 R.addNode(PointerInitRHSTag, DynTypedNode::create(*DRE));
1746 Results.emplace_back(std::move(R));
1750 virtual std::optional<FixItList>
1751 getFixits(
const FixitStrategy &S)
const override;
1752 SourceLocation getSourceLoc()
const override {
1753 return PtrInitRHS->getBeginLoc();
1756 virtual DeclUseList getClaimedVarUseSites()
const override {
1757 return DeclUseList{PtrInitRHS};
1760 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1761 getStrategyImplications()
const override {
1762 return std::make_pair(PtrInitLHS,
cast<VarDecl>(PtrInitRHS->getDecl()));
1771class PtrToPtrAssignmentGadget :
public FixableGadget {
1773 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1774 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1775 const DeclRefExpr *PtrLHS;
1776 const DeclRefExpr *PtrRHS;
1780 : FixableGadget(
Kind::PtrToPtrAssignment),
1781 PtrLHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
1782 PtrRHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
1784 static bool classof(
const Gadget *G) {
1785 return G->getKind() == Kind::PtrToPtrAssignment;
1788 static bool matches(
const Stmt *S,
1789 llvm::SmallVectorImpl<MatchResult> &Results) {
1790 size_t SizeBefore = Results.size();
1792 const auto *BO = dyn_cast<BinaryOperator>(S);
1793 if (!BO || BO->
getOpcode() != BO_Assign)
1796 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1798 !isSupportedVariable(*RHSRef)) {
1801 const auto *LHS = BO->
getLHS();
1802 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1804 !isSupportedVariable(*LHSRef)) {
1808 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
1809 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
1810 Results.emplace_back(std::move(R));
1812 return SizeBefore != Results.size();
1815 virtual std::optional<FixItList>
1816 getFixits(
const FixitStrategy &S)
const override;
1817 SourceLocation getSourceLoc()
const override {
return PtrLHS->getBeginLoc(); }
1819 virtual DeclUseList getClaimedVarUseSites()
const override {
1820 return DeclUseList{PtrLHS, PtrRHS};
1823 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1824 getStrategyImplications()
const override {
1835class CArrayToPtrAssignmentGadget :
public FixableGadget {
1837 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1838 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1839 const DeclRefExpr *PtrLHS;
1840 const DeclRefExpr *PtrRHS;
1844 : FixableGadget(
Kind::CArrayToPtrAssignment),
1845 PtrLHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
1846 PtrRHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
1848 static bool classof(
const Gadget *G) {
1849 return G->getKind() == Kind::CArrayToPtrAssignment;
1852 static bool matches(
const Stmt *S,
1853 llvm::SmallVectorImpl<MatchResult> &Results) {
1854 size_t SizeBefore = Results.size();
1856 const auto *BO = dyn_cast<BinaryOperator>(S);
1857 if (!BO || BO->
getOpcode() != BO_Assign)
1860 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1863 !isSupportedVariable(*RHSRef)) {
1866 const auto *LHS = BO->
getLHS();
1867 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1869 !isSupportedVariable(*LHSRef)) {
1873 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
1874 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
1875 Results.emplace_back(std::move(R));
1877 return SizeBefore != Results.size();
1880 virtual std::optional<FixItList>
1881 getFixits(
const FixitStrategy &S)
const override;
1882 SourceLocation getSourceLoc()
const override {
return PtrLHS->getBeginLoc(); }
1884 virtual DeclUseList getClaimedVarUseSites()
const override {
1885 return DeclUseList{PtrLHS, PtrRHS};
1888 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1889 getStrategyImplications()
const override {
1896class UnsafeBufferUsageAttrGadget :
public WarningGadget {
1897 constexpr static const char *
const OpTag =
"attr_expr";
1902 : WarningGadget(
Kind::UnsafeBufferUsageAttr),
1903 Op(
Result.getNodeAs<Expr>(OpTag)) {}
1905 static bool classof(
const Gadget *G) {
1906 return G->getKind() == Kind::UnsafeBufferUsageAttr;
1909 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1911 if (
auto *CE = dyn_cast<CallExpr>(S)) {
1912 if (CE->getDirectCallee() &&
1913 CE->getDirectCallee()->hasAttr<UnsafeBufferUsageAttr>()) {
1914 Result.addNode(OpTag, DynTypedNode::create(*CE));
1918 if (
auto *ME = dyn_cast<MemberExpr>(S)) {
1921 if (ME->getMemberDecl()->hasAttr<UnsafeBufferUsageAttr>()) {
1922 Result.addNode(OpTag, DynTypedNode::create(*ME));
1929 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1930 bool IsRelatedToDecl,
1931 ASTContext &Ctx)
const override {
1934 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1936 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1938 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1944class UnsafeBufferUsageCtorAttrGadget :
public WarningGadget {
1945 constexpr static const char *
const OpTag =
"cxx_construct_expr";
1946 const CXXConstructExpr *Op;
1950 : WarningGadget(
Kind::UnsafeBufferUsageCtorAttr),
1951 Op(
Result.getNodeAs<CXXConstructExpr>(OpTag)) {}
1953 static bool classof(
const Gadget *G) {
1954 return G->getKind() == Kind::UnsafeBufferUsageCtorAttr;
1958 const auto *CE = dyn_cast<CXXConstructExpr>(S);
1959 if (!CE || !CE->getConstructor()->hasAttr<UnsafeBufferUsageAttr>())
1963 if (SpanTwoParamConstructorGadget::matches(CE, Ctx, Tmp))
1965 Result.addNode(OpTag, DynTypedNode::create(*CE));
1969 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1970 bool IsRelatedToDecl,
1971 ASTContext &Ctx)
const override {
1974 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1976 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1978 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1985class DataInvocationGadget :
public WarningGadget {
1986 constexpr static const char *
const OpTag =
"data_invocation_expr";
1987 const ExplicitCastExpr *Op;
1991 : WarningGadget(
Kind::DataInvocation),
1992 Op(
Result.getNodeAs<ExplicitCastExpr>(OpTag)) {}
1994 static bool classof(
const Gadget *G) {
1995 return G->getKind() == Kind::DataInvocation;
1998 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
2000 auto *CE = dyn_cast<ExplicitCastExpr>(S);
2003 for (
auto *Child : CE->children()) {
2004 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(Child);
2005 MCE && isDataFunction(MCE)) {
2006 Result.addNode(OpTag, DynTypedNode::create(*CE));
2009 if (
auto *
Paren = dyn_cast<ParenExpr>(Child)) {
2010 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(
Paren->getSubExpr());
2011 MCE && isDataFunction(MCE)) {
2012 Result.addNode(OpTag, DynTypedNode::create(*CE));
2020 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2021 bool IsRelatedToDecl,
2022 ASTContext &Ctx)
const override {
2025 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2027 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2030 static bool isDataFunction(
const CXXMemberCallExpr *call) {
2037 if (method->getNameAsString() ==
"data" &&
2038 method->getParent()->isInStdNamespace() &&
2039 llvm::is_contained({SIZED_CONTAINER_OR_VIEW_LIST},
2040 method->getParent()->getName()))
2045 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2048class UnsafeLibcFunctionCallGadget :
public WarningGadget {
2049 const CallExpr *
const Call;
2050 const Expr *UnsafeArg =
nullptr;
2051 constexpr static const char *
const Tag =
"UnsafeLibcFunctionCall";
2053 constexpr static const char *
const UnsafeSprintfTag =
2054 "UnsafeLibcFunctionCall_sprintf";
2055 constexpr static const char *
const UnsafeSizedByTag =
2056 "UnsafeLibcFunctionCall_sized_by";
2057 constexpr static const char *
const UnsafeStringTag =
2058 "UnsafeLibcFunctionCall_string";
2059 constexpr static const char *
const UnsafeVaListTag =
2060 "UnsafeLibcFunctionCall_va_list";
2072 } WarnedFunKind = OTHERS;
2076 : WarningGadget(
Kind::UnsafeLibcFunctionCall),
2077 Call(
Result.getNodeAs<CallExpr>(Tag)) {
2078 if (
Result.getNodeAs<Decl>(UnsafeSprintfTag))
2079 WarnedFunKind = SPRINTF;
2080 else if (
auto *E =
Result.getNodeAs<Expr>(UnsafeStringTag)) {
2081 WarnedFunKind = STRING;
2083 }
else if (
Result.getNodeAs<CallExpr>(UnsafeSizedByTag)) {
2084 WarnedFunKind = SIZED_BY;
2085 UnsafeArg = Call->getArg(0);
2086 }
else if (
Result.getNodeAs<Decl>(UnsafeVaListTag))
2087 WarnedFunKind = VA_LIST;
2090 static bool matches(
const Stmt *S, ASTContext &Ctx,
2091 const UnsafeBufferUsageHandler *Handler,
2095 auto *CE = dyn_cast<CallExpr>(S);
2096 if (!CE || !CE->getDirectCallee())
2098 const auto *FD = dyn_cast<FunctionDecl>(CE->getDirectCallee());
2102 bool IsGlobalAndNotInAnyNamespace =
2103 FD->isGlobal() && !FD->getEnclosingNamespaceContext()->isNamespace();
2107 if (!FD->isInStdNamespace() && !IsGlobalAndNotInAnyNamespace)
2109 auto isSingleStringLiteralArg =
false;
2110 if (CE->getNumArgs() == 1) {
2111 isSingleStringLiteralArg =
2114 if (!isSingleStringLiteralArg) {
2117 Result.addNode(Tag, DynTypedNode::create(*CE));
2121 Result.addNode(Tag, DynTypedNode::create(*CE));
2122 Result.addNode(UnsafeVaListTag, DynTypedNode::create(*FD));
2126 Result.addNode(Tag, DynTypedNode::create(*CE));
2127 Result.addNode(UnsafeSprintfTag, DynTypedNode::create(*FD));
2133 Result.addNode(Tag, DynTypedNode::create(*CE));
2134 Result.addNode(UnsafeSizedByTag, DynTypedNode::create(*CE));
2139 Result.addNode(Tag, DynTypedNode::create(*CE));
2146 const Stmt *getBaseStmt()
const {
return Call; }
2148 SourceLocation getSourceLoc()
const override {
return Call->getBeginLoc(); }
2150 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2151 bool IsRelatedToDecl,
2152 ASTContext &Ctx)
const override {
2156 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2158 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2164class ULCArraySubscriptGadget :
public FixableGadget {
2166 static constexpr const char *
const ULCArraySubscriptTag =
2167 "ArraySubscriptUnderULC";
2168 const ArraySubscriptExpr *Node;
2172 : FixableGadget(
Kind::ULCArraySubscript),
2173 Node(
Result.getNodeAs<ArraySubscriptExpr>(ULCArraySubscriptTag)) {
2174 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2177 static bool classof(
const Gadget *G) {
2178 return G->getKind() == Kind::ULCArraySubscript;
2181 static bool matches(
const Stmt *S,
2182 llvm::SmallVectorImpl<MatchResult> &Results) {
2183 size_t SizeBefore = Results.size();
2185 const auto *ASE = dyn_cast<ArraySubscriptExpr>(E);
2191 !isSupportedVariable(*DRE))
2194 R.addNode(ULCArraySubscriptTag, DynTypedNode::create(*ASE));
2195 Results.emplace_back(std::move(R));
2197 return SizeBefore != Results.size();
2200 virtual std::optional<FixItList>
2201 getFixits(
const FixitStrategy &S)
const override;
2202 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2204 virtual DeclUseList getClaimedVarUseSites()
const override {
2205 if (
const auto *DRE =
2206 dyn_cast<DeclRefExpr>(Node->getBase()->IgnoreImpCasts())) {
2216class UPCStandalonePointerGadget :
public FixableGadget {
2218 static constexpr const char *
const DeclRefExprTag =
"StandalonePointer";
2219 const DeclRefExpr *Node;
2223 : FixableGadget(
Kind::UPCStandalonePointer),
2224 Node(
Result.getNodeAs<DeclRefExpr>(DeclRefExprTag)) {
2225 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2228 static bool classof(
const Gadget *G) {
2229 return G->getKind() == Kind::UPCStandalonePointer;
2232 static bool matches(
const Stmt *S,
2233 llvm::SmallVectorImpl<MatchResult> &Results) {
2234 size_t SizeBefore = Results.size();
2236 auto *E = dyn_cast<Expr>(S);
2241 !isSupportedVariable(*DRE))
2244 R.addNode(DeclRefExprTag, DynTypedNode::create(*DRE));
2245 Results.emplace_back(std::move(R));
2247 return SizeBefore != Results.size();
2250 virtual std::optional<FixItList>
2251 getFixits(
const FixitStrategy &S)
const override;
2252 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2254 virtual DeclUseList getClaimedVarUseSites()
const override {
return {Node}; }
2257class PointerDereferenceGadget :
public FixableGadget {
2258 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2259 static constexpr const char *
const OperatorTag =
"op";
2261 const DeclRefExpr *BaseDeclRefExpr =
nullptr;
2262 const UnaryOperator *Op =
nullptr;
2266 : FixableGadget(
Kind::PointerDereference),
2267 BaseDeclRefExpr(
Result.getNodeAs<DeclRefExpr>(BaseDeclRefExprTag)),
2268 Op(
Result.getNodeAs<UnaryOperator>(OperatorTag)) {}
2270 static bool classof(
const Gadget *G) {
2271 return G->getKind() == Kind::PointerDereference;
2274 static bool matches(
const Stmt *S,
2275 llvm::SmallVectorImpl<MatchResult> &Results) {
2276 size_t SizeBefore = Results.size();
2278 const auto *UO = dyn_cast<UnaryOperator>(S);
2281 const auto *CE = dyn_cast<Expr>(UO->
getSubExpr());
2284 CE = CE->IgnoreParenImpCasts();
2285 const auto *DRE = dyn_cast<DeclRefExpr>(CE);
2286 if (!DRE || !isSupportedVariable(*DRE))
2289 R.addNode(BaseDeclRefExprTag, DynTypedNode::create(*DRE));
2290 R.addNode(OperatorTag, DynTypedNode::create(*UO));
2291 Results.emplace_back(std::move(R));
2293 return SizeBefore != Results.size();
2296 DeclUseList getClaimedVarUseSites()
const override {
2297 return {BaseDeclRefExpr};
2300 virtual std::optional<FixItList>
2301 getFixits(
const FixitStrategy &S)
const override;
2302 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2308class UPCAddressofArraySubscriptGadget :
public FixableGadget {
2310 static constexpr const char *
const UPCAddressofArraySubscriptTag =
2311 "AddressofArraySubscriptUnderUPC";
2312 const UnaryOperator *Node;
2316 : FixableGadget(
Kind::ULCArraySubscript),
2317 Node(
Result.getNodeAs<UnaryOperator>(UPCAddressofArraySubscriptTag)) {
2318 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2321 static bool classof(
const Gadget *G) {
2322 return G->getKind() == Kind::UPCAddressofArraySubscript;
2325 static bool matches(
const Stmt *S,
2326 llvm::SmallVectorImpl<MatchResult> &Results) {
2327 size_t SizeBefore = Results.size();
2329 auto *E = dyn_cast<Expr>(S);
2333 if (!UO || UO->
getOpcode() != UO_AddrOf)
2335 const auto *ASE = dyn_cast<ArraySubscriptExpr>(UO->
getSubExpr());
2340 if (!DRE || !isSupportedVariable(*DRE))
2343 R.addNode(UPCAddressofArraySubscriptTag, DynTypedNode::create(*UO));
2344 Results.emplace_back(std::move(R));
2346 return SizeBefore != Results.size();
2349 virtual std::optional<FixItList>
2350 getFixits(
const FixitStrategy &)
const override;
2351 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2353 virtual DeclUseList getClaimedVarUseSites()
const override {
2366class DeclUseTracker {
2367 using UseSetTy = llvm::SmallPtrSet<const DeclRefExpr *, 16>;
2368 using DefMapTy = llvm::DenseMap<const VarDecl *, const DeclStmt *>;
2371 std::unique_ptr<UseSetTy> Uses{std::make_unique<UseSetTy>()};
2375 DeclUseTracker() =
default;
2376 DeclUseTracker(
const DeclUseTracker &) =
delete;
2377 DeclUseTracker &operator=(
const DeclUseTracker &) =
delete;
2378 DeclUseTracker(DeclUseTracker &&) =
default;
2379 DeclUseTracker &operator=(DeclUseTracker &&) =
default;
2382 void discoverUse(
const DeclRefExpr *DRE) { Uses->insert(DRE); }
2385 void claimUse(
const DeclRefExpr *DRE) {
2386 assert(Uses->count(DRE) &&
2387 "DRE not found or claimed by multiple matchers!");
2392 bool hasUnclaimedUses(
const VarDecl *VD)
const {
2394 return any_of(*Uses, [VD](
const DeclRefExpr *DRE) {
2399 UseSetTy getUnclaimedUses(
const VarDecl *VD)
const {
2401 for (
auto use : *Uses) {
2403 ReturnSet.insert(use);
2409 void discoverDecl(
const DeclStmt *DS) {
2410 for (
const Decl *D : DS->
decls()) {
2411 if (
const auto *VD = dyn_cast<VarDecl>(D)) {
2422 const DeclStmt *lookupDecl(
const VarDecl *VD)
const {
2423 return Defs.lookup(VD);
2432 static constexpr const char *
const UPCPreIncrementTag =
2433 "PointerPreIncrementUnderUPC";
2438 : FixableGadget(Kind::UPCPreIncrement),
2440 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2444 return G->getKind() == Kind::UPCPreIncrement;
2453 size_t SizeBefore = Results.size();
2455 auto *E = dyn_cast<Expr>(S);
2459 if (!UO || UO->
getOpcode() != UO_PreInc)
2461 const auto *DRE = dyn_cast<DeclRefExpr>(UO->
getSubExpr());
2462 if (!DRE || !isSupportedVariable(*DRE))
2466 Results.emplace_back(std::move(R));
2468 return SizeBefore != Results.size();
2471 virtual std::optional<FixItList>
2476 return {dyn_cast<DeclRefExpr>(Node->getSubExpr())};
2484 static constexpr const char *
const UUCAddAssignTag =
2485 "PointerAddAssignUnderUUC";
2486 static constexpr const char *
const OffsetTag =
"Offset";
2489 const Expr *Offset =
nullptr;
2493 : FixableGadget(Kind::UUCAddAssign),
2496 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2500 return G->getKind() == Kind::UUCAddAssign;
2505 size_t SizeBefore = Results.size();
2507 const auto *E = dyn_cast<Expr>(S);
2511 if (!BO || BO->
getOpcode() != BO_AddAssign)
2513 const auto *DRE = dyn_cast<DeclRefExpr>(BO->
getLHS());
2519 Results.emplace_back(std::move(R));
2521 return SizeBefore != Results.size();
2524 virtual std::optional<FixItList>
2529 return {dyn_cast<DeclRefExpr>(Node->getLHS())};
2536 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2537 static constexpr const char *
const DerefOpTag =
"DerefOp";
2538 static constexpr const char *
const AddOpTag =
"AddOp";
2539 static constexpr const char *
const OffsetTag =
"Offset";
2548 : FixableGadget(Kind::DerefSimplePtrArithFixable),
2556 auto IsPtr = [](
const Expr *E, MatchResult &R) {
2560 if (!DRE || !isSupportedVariable(*DRE))
2565 const auto IsPlusOverPtrAndInteger = [&IsPtr](
const Expr *E,
2567 const auto *BO = dyn_cast<BinaryOperator>(E);
2571 const auto *LHS = BO->
getLHS();
2572 const auto *RHS = BO->
getRHS();
2585 size_t SizeBefore = Results.size();
2586 const auto InnerMatcher = [&IsPlusOverPtrAndInteger,
2587 &Results](
const Expr *E) {
2588 const auto *UO = dyn_cast<UnaryOperator>(E);
2594 if (IsPlusOverPtrAndInteger(Operand, R)) {
2596 Results.emplace_back(std::move(R));
2600 return SizeBefore != Results.size();
2603 virtual std::optional<FixItList>
2606 return DerefOp->getBeginLoc();
2610 return {BaseDeclRefExpr};
2618 : WarningGadgets(WarningGadgets) {}
2627#define WARNING_GADGET(name) \
2628 if (name##Gadget::matches(S, Ctx, Result) && \
2629 notInSafeBufferOptOut(*S, &Handler)) { \
2630 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2633#define WARNING_OPTIONAL_GADGET(name) \
2634 if (name##Gadget::matches(S, Ctx, &Handler, Result) && \
2635 notInSafeBufferOptOut(*S, &Handler)) { \
2636 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2639#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2644 WarningGadgetList &WarningGadgets;
2651 DeclUseTracker &Tracker)
2652 : FixableGadgets(FixableGadgets), Tracker(Tracker) {}
2656 bool matchFound =
false;
2663#define FIXABLE_GADGET(name) \
2664 if (name##Gadget::matches(S, Results)) { \
2665 for (const auto &R : Results) { \
2666 FixableGadgets.push_back(std::make_unique<name##Gadget>(R)); \
2667 matchFound = true; \
2671#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2674 if (
auto *DRE = findDeclRefExpr(S); DRE) {
2675 Tracker.discoverUse(DRE);
2681 if (
auto *DS = findDeclStmt(S); DS) {
2682 Tracker.discoverDecl(DS);
2690 const auto *DRE = dyn_cast<DeclRefExpr>(S);
2698 const DeclStmt *findDeclStmt(
const Stmt *S) {
2699 const auto *DS = dyn_cast<DeclStmt>(S);
2704 FixableGadgetList &FixableGadgets;
2705 DeclUseTracker &Tracker;
2711 bool EmitSuggestions, FixableGadgetList &FixableGadgets,
2712 WarningGadgetList &WarningGadgets,
2713 DeclUseTracker &Tracker) {
2716 if (EmitSuggestions) {
2725 return N1->getBeginLoc().getRawEncoding() <
2726 N2->getBeginLoc().getRawEncoding();
2736 const Expr *UnsafeArg =
nullptr)
override {}
2744 bool IsRelatedToDecl,
2761 FixableGadgetList FixableGadgets;
2762 WarningGadgetList WarningGadgets;
2763 DeclUseTracker Tracker;
2764 MockReporter IgnoreHandler;
2767 FixableGadgets, WarningGadgets, Tracker);
2769 std::set<const Expr *>
Result;
2770 for (
auto &G : WarningGadgets) {
2771 for (
const Expr *E : G->getUnsafePtrs()) {
2780 std::map<const VarDecl *, std::set<const WarningGadget *>,
2794 for (
auto &G : AllUnsafeOperations) {
2795 DeclUseList ClaimedVarUseSites = G->getClaimedVarUseSites();
2797 bool AssociatedWithVarDecl =
false;
2798 for (
const DeclRefExpr *DRE : ClaimedVarUseSites) {
2799 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2800 result.
byVar[VD].insert(G.get());
2801 AssociatedWithVarDecl =
true;
2805 if (!AssociatedWithVarDecl) {
2806 result.
noVar.push_back(G.get());
2814 std::map<const VarDecl *, std::set<const FixableGadget *>,
2824 for (
auto &F : AllFixableOperations) {
2825 DeclUseList DREs = F->getClaimedVarUseSites();
2828 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2829 FixablesForUnsafeVars.
byVar[VD].insert(F.get());
2833 return FixablesForUnsafeVars;
2840 std::vector<const FixItHint *>
All;
2844 std::sort(
All.begin(),
All.end(),
2846 return SM.isBeforeInTranslationUnit(H1->RemoveRange.getBegin(),
2847 H2->RemoveRange.getBegin());
2855 Hint->RemoveRange.getBegin())) {
2867std::optional<FixItList>
2868PtrToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
2871 switch (S.
lookup(LeftVD)) {
2875 return std::nullopt;
2877 return std::nullopt;
2880 return std::nullopt;
2882 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2884 return std::nullopt;
2888static inline std::optional<FixItList>
createDataFixit(
const ASTContext &Ctx,
2889 const DeclRefExpr *DRE);
2891std::optional<FixItList>
2892CArrayToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
2911 if (S.
lookup(LeftVD) == FixitStrategy::Kind::Span) {
2912 if (S.
lookup(RightVD) == FixitStrategy::Kind::Wontfix) {
2915 }
else if (S.
lookup(LeftVD) == FixitStrategy::Kind::Wontfix) {
2916 if (S.
lookup(RightVD) == FixitStrategy::Kind::Array) {
2920 return std::nullopt;
2923std::optional<FixItList>
2924PointerInitGadget::getFixits(
const FixitStrategy &S)
const {
2925 const auto *LeftVD = PtrInitLHS;
2927 switch (S.
lookup(LeftVD)) {
2928 case FixitStrategy::Kind::Span:
2929 if (S.
lookup(RightVD) == FixitStrategy::Kind::Span)
2931 return std::nullopt;
2932 case FixitStrategy::Kind::Wontfix:
2933 return std::nullopt;
2934 case FixitStrategy::Kind::Iterator:
2935 case FixitStrategy::Kind::Array:
2936 return std::nullopt;
2937 case FixitStrategy::Kind::Vector:
2938 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2940 return std::nullopt;
2946 if (ConstVal->isNegative())
2953std::optional<FixItList>
2954ULCArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
2955 if (
const auto *DRE =
2957 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2959 case FixitStrategy::Kind::Span: {
2963 const ASTContext &Ctx =
2966 return std::nullopt;
2970 case FixitStrategy::Kind::Array:
2972 case FixitStrategy::Kind::Wontfix:
2973 case FixitStrategy::Kind::Iterator:
2974 case FixitStrategy::Kind::Vector:
2975 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2978 return std::nullopt;
2981static std::optional<FixItList>
2984std::optional<FixItList>
2985UPCAddressofArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
2986 auto DREs = getClaimedVarUseSites();
2990 case FixitStrategy::Kind::Span:
2992 case FixitStrategy::Kind::Wontfix:
2993 case FixitStrategy::Kind::Iterator:
2994 case FixitStrategy::Kind::Array:
2995 return std::nullopt;
2996 case FixitStrategy::Kind::Vector:
2997 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2999 return std::nullopt;
3004 static const char *
const EOL =
"\n";
3011 std::string
s = std::string(
"<# ");
3012 s += HintTextToUser;
3018template <
typename NodeTy>
3019static std::optional<SourceLocation>
3022 if (
unsigned TkLen =
3029 return std::nullopt;
3042 bool AttrRangeOverlapping = llvm::any_of(VD->
attrs(), [&](
Attr *At) ->
bool {
3043 return !(SM.isBeforeInTranslationUnit(At->getRange().getEnd(),
3044 VD->getBeginLoc())) &&
3045 !(SM.isBeforeInTranslationUnit(VD->getEndLoc(),
3046 At->getRange().getBegin()));
3050 AttrRangeOverlapping;
3092 std::optional<Qualifiers> Quals = std::nullopt) {
3093 const char *
const SpanOpen =
"std::span<";
3096 return SpanOpen + EltTyText.str() +
' ' + Quals->getAsString() +
'>';
3097 return SpanOpen + EltTyText.str() +
'>';
3100std::optional<FixItList>
3102 const VarDecl *VD = dyn_cast<VarDecl>(BaseDeclRefExpr->getDecl());
3107 if (
auto ConstVal = Offset->getIntegerConstantExpr(Ctx))
3108 if (ConstVal->isNegative())
3109 return std::nullopt;
3130 const Expr *LHS = AddOp->getLHS(), *RHS = AddOp->getRHS();
3137 std::optional<SourceLocation> LHSLocation =
getPastLoc(LHS,
SM, LangOpts);
3139 return std::nullopt;
3144 std::optional<SourceLocation> AddOpLocation =
3146 std::optional<SourceLocation> DerefOpLocation =
3149 if (!AddOpLocation || !DerefOpLocation)
3150 return std::nullopt;
3160 return std::nullopt;
3163std::optional<FixItList>
3164PointerDereferenceGadget::getFixits(
const FixitStrategy &S)
const {
3175 if (
auto LocPastOperand =
3182 case FixitStrategy::Kind::Iterator:
3183 case FixitStrategy::Kind::Array:
3184 return std::nullopt;
3185 case FixitStrategy::Kind::Vector:
3186 llvm_unreachable(
"FixitStrategy not implemented yet!");
3187 case FixitStrategy::Kind::Wontfix:
3188 llvm_unreachable(
"Invalid strategy!");
3191 return std::nullopt;
3198 std::optional<SourceLocation> EndOfOperand =
3204 return std::nullopt;
3209std::optional<FixItList>
3210UPCStandalonePointerGadget::getFixits(
const FixitStrategy &S)
const {
3213 case FixitStrategy::Kind::Array:
3214 case FixitStrategy::Kind::Span: {
3219 case FixitStrategy::Kind::Wontfix:
3220 case FixitStrategy::Kind::Iterator:
3221 return std::nullopt;
3222 case FixitStrategy::Kind::Vector:
3223 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3226 return std::nullopt;
3231static std::optional<FixItList>
3238 const Expr *Idx = ArraySub->getIdx();
3241 std::stringstream SS;
3242 bool IdxIsLitZero =
false;
3245 if ((*ICE).isZero())
3246 IdxIsLitZero =
true;
3247 std::optional<StringRef> DreString =
getExprText(DRE,
SM, LangOpts);
3249 return std::nullopt;
3253 SS << (*DreString).str() <<
".data()";
3255 std::optional<StringRef> IndexString =
getExprText(Idx,
SM, LangOpts);
3257 return std::nullopt;
3259 SS <<
"&" << (*DreString).str() <<
".data()"
3260 <<
"[" << (*IndexString).str() <<
"]";
3266std::optional<FixItList>
3270 if (DREs.size() != 1)
3271 return std::nullopt;
3273 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3277 const Stmt *AddAssignNode = Node;
3278 StringRef varName = VD->
getName();
3282 return std::nullopt;
3286 (Offset->IgnoreParens()->getBeginLoc() == Offset->getBeginLoc());
3287 std::string SS = varName.str() +
" = " + varName.str() +
".subspan";
3291 std::optional<SourceLocation> AddAssignLocation =
getEndCharLoc(
3293 if (!AddAssignLocation)
3294 return std::nullopt;
3301 Offset->getEndLoc().getLocWithOffset(1),
")"));
3305 return std::nullopt;
3308std::optional<FixItList>
3312 if (DREs.size() != 1)
3313 return std::nullopt;
3315 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3318 std::stringstream SS;
3319 StringRef varName = VD->
getName();
3323 SS <<
"(" << varName.data() <<
" = " << varName.data()
3324 <<
".subspan(1)).data()";
3325 std::optional<SourceLocation> PreIncLocation =
3327 if (!PreIncLocation)
3328 return std::nullopt;
3331 SourceRange(Node->getBeginLoc(), *PreIncLocation), SS.str()));
3335 return std::nullopt;
3353static std::optional<FixItList>
3355 const StringRef UserFillPlaceHolder) {
3363 if (
Init->isNullPointerConstant(
3368 NPC_ValueDependentIsNotNull)) {
3369 std::optional<SourceLocation> InitLocation =
3372 return std::nullopt;
3380 std::string ExtentText = UserFillPlaceHolder.data();
3381 StringRef One =
"1";
3386 if (
auto CxxNew = dyn_cast<CXXNewExpr>(
Init->IgnoreImpCasts())) {
3391 if (
const Expr *Ext = CxxNew->getArraySize().value_or(
nullptr)) {
3392 if (!Ext->HasSideEffects(Ctx)) {
3393 std::optional<StringRef> ExtentString =
getExprText(Ext,
SM, LangOpts);
3395 return std::nullopt;
3396 ExtentText = *ExtentString;
3398 }
else if (!CxxNew->isArray())
3410 if (
auto AddrOfExpr = dyn_cast<UnaryOperator>(
Init->IgnoreImpCasts()))
3411 if (AddrOfExpr->getOpcode() == UnaryOperatorKind::UO_AddrOf &&
3412 isa_and_present<DeclRefExpr>(AddrOfExpr->getSubExpr()))
3419 std::optional<SourceLocation> LocPassInit =
getPastLoc(
Init,
SM, LangOpts);
3422 return std::nullopt;
3424 StrBuffer.append(
", ");
3425 StrBuffer.append(ExtentText);
3426 StrBuffer.append(
"}");
3432#define DEBUG_NOTE_DECL_FAIL(D, Msg) \
3433 Handler.addDebugNoteForVar((D), (D)->getBeginLoc(), \
3434 "failed to produce fixit for declaration '" + \
3435 (D)->getNameAsString() + "'" + (Msg))
3437#define DEBUG_NOTE_DECL_FAIL(D, Msg)
3443static std::optional<std::string>
3447 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3452 return std::nullopt;
3454 std::string SpanTyText =
"std::span<";
3456 SpanTyText.append(*PteTyText);
3458 if (PteTyQualifiers) {
3459 SpanTyText.append(
" ");
3460 SpanTyText.append(PteTyQualifiers->getAsString());
3462 SpanTyText.append(
">");
3481 const StringRef UserFillPlaceHolder,
3495 std::stringstream SS;
3500 std::optional<FixItList> InitFixIts =
3504 FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts->begin()),
3505 std::make_move_iterator(InitFixIts->end()));
3512 if (!EndLocForReplacement.
isValid()) {
3562static std::optional<FixItList>
3568 return std::nullopt;
3573 std::vector<std::string> NewTysTexts(NumParms);
3574 std::vector<bool> ParmsMask(NumParms,
false);
3575 bool AtLeastOneParmToFix =
false;
3577 for (
unsigned i = 0; i < NumParms; i++) {
3584 return std::nullopt;
3586 std::optional<Qualifiers> PteTyQuals = std::nullopt;
3587 std::optional<std::string> PteTyText =
3592 return std::nullopt;
3596 ParmsMask[i] =
true;
3597 AtLeastOneParmToFix =
true;
3599 if (!AtLeastOneParmToFix)
3606 const auto NewOverloadSignatureCreator =
3607 [&
SM, &LangOpts, &NewTysTexts,
3608 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3609 std::stringstream SS;
3617 SS << Prefix->str();
3619 return std::nullopt;
3623 for (
unsigned i = 0; i < NumParms; i++) {
3631 SS << NewTysTexts[i];
3634 SS <<
' ' << II->getName().str();
3635 }
else if (
auto ParmTypeText =
3639 SS << ParmTypeText->str();
3641 return std::nullopt;
3642 if (i != NumParms - 1)
3651 const auto OldOverloadDefCreator =
3652 [&Handler, &
SM, &LangOpts, &NewTysTexts,
3653 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3654 std::stringstream SS;
3662 << FDPrefix->str() <<
"{";
3664 return std::nullopt;
3667 SS <<
"return " << FunQualName->str() <<
"(";
3669 return std::nullopt;
3673 for (
unsigned i = 0; i < NumParms; i++) {
3682 return std::nullopt;
3689 if (i != NumParms - 1)
3700 std::optional<SourceLocation> Loc =
getPastLoc(FReDecl,
SM, LangOpts);
3704 if (FReDecl->isThisDeclarationADefinition()) {
3705 assert(FReDecl == FD &&
"inconsistent function definition");
3708 if (
auto OldOverloadDef = OldOverloadDefCreator(FReDecl))
3714 if (!FReDecl->hasAttr<UnsafeBufferUsageAttr>()) {
3717 FReDecl->getBeginLoc(),
" ")));
3720 if (
auto NewOverloadDecl = NewOverloadSignatureCreator(FReDecl))
3742 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3758 std::stringstream SS;
3761 if (PteTyQualifiers)
3770 SS <<
' ' << PVDNameText->str();
3776 const DeclUseTracker &Tracker,
3779 const DeclStmt *DS = Tracker.lookupDecl(VD);
3782 " : variables declared this way not implemented yet");
3806 const QualType &ArrayEltT = CAT->getElementType();
3807 assert(!ArrayEltT.
isNull() &&
"Trying to fix a non-array type variable!");
3816 auto MaybeElemTypeTxt =
3819 if (!MaybeElemTypeTxt)
3821 const llvm::StringRef ElemTypeTxt = MaybeElemTypeTxt->trim();
3826 while (NextTok && !NextTok->is(tok::l_square) &&
3839 if (!MaybeArraySizeTxt)
3841 const llvm::StringRef ArraySizeTxt = MaybeArraySizeTxt->trim();
3842 if (ArraySizeTxt.empty()) {
3853 std::optional<StringRef> IdentText =
3862 llvm::raw_svector_ostream OS(Replacement);
3863 OS <<
"std::array<" << ElemTypeTxt <<
", " << ArraySizeTxt <<
"> "
3864 << IdentText->str();
3874 const DeclUseTracker &Tracker,
3877 const DeclStmt *DS = Tracker.lookupDecl(VD);
3878 assert(DS &&
"Fixing non-local variables not implemented yet!");
3897 const DeclUseTracker &Tracker,
ASTContext &Ctx,
3899 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD)) {
3900 auto *FD = dyn_cast<clang::FunctionDecl>(PVD->getDeclContext());
3901 if (!FD || FD != D) {
3912 if (FD->isMain() || FD->isConstexpr() ||
3919 FD->isOverloadedOperator()) {
3928 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD))
3946 llvm_unreachable(
"FixitStrategy not implemented yet!");
3948 llvm_unreachable(
"Invalid strategy!");
3950 llvm_unreachable(
"Unknown strategy!");
3958 return llvm::any_of(FixIts, [](
const FixItHint &Hint) {
3960 if (Range.getBegin().isMacroID() || Range.getEnd().isMacroID())
3977 std::map<const VarDecl *, FixItList> &FixItsForVariable,
3982 for (
const auto &[VD, Ignore] : FixItsForVariable) {
3984 if (llvm::any_of(Grp,
3985 [&FixItsForVariable](
const VarDecl *GrpMember) ->
bool {
3986 return !FixItsForVariable.count(GrpMember);
3991 ToErase.push_back(
Member);
3994 for (
auto *VarToErase : ToErase)
3995 FixItsForVariable.erase(VarToErase);
4006 std::map<const VarDecl *, FixItList> &FixItsForVariable ,
4010 FixItList FixItsSharedByParms{};
4012 std::optional<FixItList> OverloadFixes =
4015 if (OverloadFixes) {
4016 FixItsSharedByParms.append(*OverloadFixes);
4022 FixItsForVariable.erase(
Member);
4024 return FixItsSharedByParms;
4028static std::map<const VarDecl *, FixItList>
4037 std::map<const VarDecl *, FixItList> FixItsForVariable;
4042 for (
const auto &[VD, Fixables] : FixablesForAllVars.
byVar) {
4043 FixItsForVariable[VD] =
4047 if (FixItsForVariable[VD].empty()) {
4048 FixItsForVariable.erase(VD);
4051 for (
const auto &F : Fixables) {
4052 std::optional<FixItList> Fixits = F->getFixits(S);
4055 FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
4056 Fixits->begin(), Fixits->end());
4061 VD, F->getSourceLoc(),
4062 (
"gadget '" + F->getDebugName() +
"' refused to produce a fix")
4065 FixItsForVariable.erase(VD);
4084 FixItList FixItsSharedByParms{};
4086 if (
auto *FD = dyn_cast<FunctionDecl>(D))
4088 FixItsForVariable, VarGrpMgr, FD, S, Ctx, Handler);
4092 std::map<const VarDecl *, FixItList> FinalFixItsForVariable{
4095 for (
auto &[Var, Ignore] : FixItsForVariable) {
4096 bool AnyParm =
false;
4097 const auto VarGroupForVD = VarGrpMgr.
getGroupOfVar(Var, &AnyParm);
4099 for (
const VarDecl *GrpMate : VarGroupForVD) {
4102 if (FixItsForVariable.count(GrpMate))
4103 FinalFixItsForVariable[Var].append(FixItsForVariable[GrpMate]);
4107 assert(!FixItsSharedByParms.empty() &&
4108 "Should not try to fix a parameter that does not belong to a "
4110 FinalFixItsForVariable[Var].append(FixItsSharedByParms);
4117 for (
auto Iter = FinalFixItsForVariable.begin();
4118 Iter != FinalFixItsForVariable.end();)
4121 Iter = FinalFixItsForVariable.erase(Iter);
4124 return FinalFixItsForVariable;
4127template <
typename VarDeclIterTy>
4131 for (
const VarDecl *VD : UnsafeVars) {
4142 const std::vector<VarGrpTy> Groups;
4143 const std::map<const VarDecl *, unsigned> &VarGrpMap;
4144 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms;
4148 const std::vector<VarGrpTy> &Groups,
4149 const std::map<const VarDecl *, unsigned> &VarGrpMap,
4150 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms)
4151 : Groups(Groups), VarGrpMap(VarGrpMap),
4152 GrpsUnionForParms(GrpsUnionForParms) {}
4155 if (GrpsUnionForParms.contains(Var)) {
4158 return GrpsUnionForParms.getArrayRef();
4163 auto It = VarGrpMap.find(Var);
4165 if (It == VarGrpMap.end())
4167 return Groups[It->second];
4171 return GrpsUnionForParms.getArrayRef();
4176 WarningGadgetList WarningGadgets,
4177 DeclUseTracker Tracker,
4179 bool EmitSuggestions) {
4180 if (!EmitSuggestions) {
4184 for (
const auto &G : WarningGadgets) {
4185 G->handleUnsafeOperation(Handler,
false,
4191 assert(FixableGadgets.empty() &&
4192 "Fixable gadgets found but suggestions not requested!");
4198 if (!WarningGadgets.empty()) {
4202 for (
const auto &G : FixableGadgets) {
4203 for (
const auto *DRE : G->getClaimedVarUseSites()) {
4204 Tracker.claimUse(DRE);
4220 if (WarningGadgets.empty())
4228 std::map<const VarDecl *, FixItList> FixItsForVariableGroup;
4231 for (
auto it = FixablesForAllVars.
byVar.cbegin();
4232 it != FixablesForAllVars.
byVar.cend();) {
4237 (
"failed to produce fixit for '" +
4238 it->first->getNameAsString() +
4239 "' : neither local nor a parameter"));
4241 it = FixablesForAllVars.
byVar.erase(it);
4242 }
else if (it->first->getType().getCanonicalType()->isReferenceType()) {
4245 (
"failed to produce fixit for '" +
4246 it->first->getNameAsString() +
4247 "' : has a reference type"));
4249 it = FixablesForAllVars.
byVar.erase(it);
4250 }
else if (Tracker.hasUnclaimedUses(it->first)) {
4251 it = FixablesForAllVars.
byVar.erase(it);
4252 }
else if (it->first->isInitCapture()) {
4255 (
"failed to produce fixit for '" +
4256 it->first->getNameAsString() +
4257 "' : init capture"));
4259 it = FixablesForAllVars.
byVar.erase(it);
4266 for (
const auto &it : UnsafeOps.
byVar) {
4267 const VarDecl *
const UnsafeVD = it.first;
4268 auto UnclaimedDREs = Tracker.getUnclaimedUses(UnsafeVD);
4269 if (UnclaimedDREs.empty())
4273 std::string UnclaimedUseTrace =
4278 (
"failed to produce fixit for '" + UnfixedVDName +
4279 "' : has an unclaimed use\nThe unclaimed DRE trace: " +
4280 UnclaimedUseTrace));
4287 llvm::DenseMap<const VarDecl *, llvm::SetVector<const VarDecl *>>;
4288 DepMapTy DependenciesMap{};
4289 DepMapTy PtrAssignmentGraph{};
4291 for (
const auto &it : FixablesForAllVars.
byVar) {
4292 for (
const FixableGadget *fixable : it.second) {
4293 std::optional<std::pair<const VarDecl *, const VarDecl *>> ImplPair =
4294 fixable->getStrategyImplications();
4296 std::pair<const VarDecl *, const VarDecl *> Impl = std::move(*ImplPair);
4297 PtrAssignmentGraph[Impl.first].insert(Impl.second);
4319 std::set<const VarDecl *> VisitedVarsDirected{};
4320 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4321 if (VisitedVarsDirected.find(Var) == VisitedVarsDirected.end()) {
4323 std::queue<const VarDecl *> QueueDirected{};
4324 QueueDirected.push(Var);
4325 while (!QueueDirected.empty()) {
4326 const VarDecl *CurrentVar = QueueDirected.front();
4327 QueueDirected.pop();
4328 VisitedVarsDirected.insert(CurrentVar);
4329 auto AdjacentNodes = PtrAssignmentGraph[CurrentVar];
4330 for (
const VarDecl *Adj : AdjacentNodes) {
4331 if (VisitedVarsDirected.find(Adj) == VisitedVarsDirected.end()) {
4332 QueueDirected.push(Adj);
4334 DependenciesMap[Var].insert(Adj);
4335 DependenciesMap[Adj].insert(Var);
4342 std::vector<VarGrpTy> Groups;
4346 std::map<const VarDecl *, unsigned> VarGrpMap;
4348 llvm::SetVector<const VarDecl *>
4353 std::set<const VarDecl *> VisitedVars{};
4354 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4355 if (VisitedVars.find(Var) == VisitedVars.end()) {
4356 VarGrpTy &VarGroup = Groups.emplace_back();
4357 std::queue<const VarDecl *> Queue{};
4360 while (!Queue.empty()) {
4361 const VarDecl *CurrentVar = Queue.front();
4363 VisitedVars.insert(CurrentVar);
4364 VarGroup.push_back(CurrentVar);
4365 auto AdjacentNodes = DependenciesMap[CurrentVar];
4366 for (
const VarDecl *Adj : AdjacentNodes) {
4367 if (VisitedVars.find(Adj) == VisitedVars.end()) {
4373 bool HasParm =
false;
4374 unsigned GrpIdx = Groups.size() - 1;
4376 for (
const VarDecl *
V : VarGroup) {
4377 VarGrpMap[
V] = GrpIdx;
4382 GrpsUnionForParms.insert_range(VarGroup);
4404 for (
auto I = FixablesForAllVars.
byVar.begin();
4405 I != FixablesForAllVars.
byVar.end();) {
4407 if (!VisitedVars.count((*I).first)) {
4409 I = FixablesForAllVars.
byVar.erase(I);
4417 VisitedVars, [&FixablesForAllVars](
const VarDecl *
V) {
4419 return FixablesForAllVars.
byVar.count(
V);
4426 FixItsForVariableGroup =
4428 Tracker, Handler, VarGrpMgr);
4430 for (
const auto &G : UnsafeOps.
noVar) {
4431 G->handleUnsafeOperation(Handler,
false,
4435 for (
const auto &[VD, WarningGadgets] : UnsafeOps.
byVar) {
4436 auto FixItsIt = FixItsForVariableGroup.find(VD);
4438 FixItsIt != FixItsForVariableGroup.end()
4439 ? std::move(FixItsIt->second)
4442 for (
const auto &G : WarningGadgets) {
4443 G->handleUnsafeOperation(Handler,
true,
4451 bool EmitSuggestions) {
4460 if (
const auto *FD = dyn_cast<FunctionDecl>(D)) {
4464 if (
const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
4465 if (MD->getParent()->isLambda() && MD->getParent()->isLocalClass())
4470 if (FReDecl->isExternC()) {
4473 EmitSuggestions =
false;
4478 Stmts.push_back(FD->getBody());
4480 if (
const auto *ID = dyn_cast<CXXConstructorDecl>(D)) {
4482 Stmts.push_back(CI->getInit());
4486 Stmts.push_back(D->
getBody());
4489 assert(!Stmts.empty());
4491 FixableGadgetList FixableGadgets;
4492 WarningGadgetList WarningGadgets;
4493 DeclUseTracker Tracker;
4494 for (
Stmt *S : Stmts) {
4496 WarningGadgets, Tracker);
4498 applyGadgets(D, std::move(FixableGadgets), std::move(WarningGadgets),
4499 std::move(Tracker), Handler, EmitSuggestions);
Defines the clang::ASTContext interface.
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.
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 bool isSafeArraySubscript(const ArraySubscriptExpr &Node, const ASTContext &Ctx)
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 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 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)
#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 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 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 std::optional< StringRef > getFunNameText(const FunctionDecl *FD, const SourceManager &SM, const LangOptions &LangOpts)
__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
MatchDescendantVisitor(ASTContext &Context, FastMatcher &Matcher, bool FindAll, bool ignoreUnevaluatedContext, const UnsafeBufferUsageHandler &NewHandler)
bool TraverseDecltypeTypeLoc(DecltypeTypeLoc Node, bool TraverseQualifier) override
bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc Node, bool TraverseQualifier) override
bool TraverseGenericSelectionExpr(GenericSelectionExpr *Node) override
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.
Represents a C++ base or member 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 character-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...
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.
param_iterator param_begin()
redecl_range redecls() const
Returns an iterator range for all the redeclarations of the same decl.
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
DeclarationNameInfo getNameInfo() const
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 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,...
bool hasDataArgument() const
HowSpecified getHowSpecified() const
unsigned getConstantAmount() const
unsigned getPositionalArgIndex() 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)
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)
std::vector< const VarDecl * > VarGrpTy
std::optional< StringRef > getExprText(const Expr *E, const SourceManager &SM, const LangOptions &LangOpts)
static bool classof(const Stmt *T)
@ Result
The result type of a method or function.
const FunctionProtoType * T
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)
std::set< const Expr * > findUnsafePointers(const FunctionDecl *FD)
ArrayRef< const VarDecl * > VarGrpRef
static bool hasUnsafePrintfStringArg(const CallExpr &Node, ASTContext &Ctx, MatchResult &Result, llvm::StringRef Tag)
static bool hasUnsafeFormatOrSArg(const CallExpr *Call, const Expr *&UnsafeArg, const unsigned FmtArgIdx, ASTContext &Ctx, bool isKprintf=false)
static bool isPredefinedUnsafeLibcFunc(const FunctionDecl &Node)
static bool hasUnsafeSnprintfBuffer(const CallExpr &Node, ASTContext &Ctx)
static const Expr * tryConstantFoldConditionalExpr(const Expr *E, const ASTContext &Ctx)
static bool isUnsafeVaListPrintfFunc(const FunctionDecl &Node)
static bool isUnsafeSprintfFunc(const FunctionDecl &Node)
static bool isNullTermPointer(const Expr *Ptr, ASTContext &Ctx)
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.
StringRef matchLibcName(StringRef Name)
StringRef matchName(StringRef FunName, bool isBuiltin)
StringRef matchLibcNameOrBuiltinChk(StringRef Name)