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)
745 if (
const auto *CE = dyn_cast<ConditionalOperator>(E)) {
747 const auto *
Cond = CE->getCond();
749 if (!
Cond->isValueDependent() &&
750 Cond->EvaluateAsBooleanCondition(CondEval, Ctx))
751 return CondEval ? CE->getLHS() : CE->getRHS();
791 StringRef
matchName(StringRef FunName,
bool isBuiltin) {
793 if (isBuiltin && FunName.starts_with(
"__builtin_"))
797 FunName.drop_front(10 ));
799 if (FunName.starts_with(
"__asan_"))
807 if (Name.starts_with(
"__") && Name.ends_with(
"_chk"))
809 Name.drop_front(2).drop_back(4) );
814 if (Name.ends_with(
"_s"))
815 return Name.drop_back(2 );
830 bool isKprintf =
false) {
831 class StringFormatStringHandler
835 const Expr *&UnsafeArg;
850 unsigned PArgIdx = -1;
854 if (0 < PArgIdx && PArgIdx < Call->getNumArgs()) {
855 const Expr *PArg =
Call->getArg(PArgIdx);
858 if (
auto *CE = dyn_cast<CastExpr>(PArg);
859 CE && CE->getType()->isSignedIntegerType())
860 PArg = CE->getSubExpr();
864 analyze_printf::OptionalAmount::HowSpecified::Constant) {
866 llvm::APSInt PArgVal = llvm::APSInt(
876 StringFormatStringHandler(
const CallExpr *
Call,
unsigned FmtArgIdx,
878 :
Call(
Call), FmtArgIdx(FmtArgIdx), UnsafeArg(UnsafeArg), Ctx(Ctx),
879 UnsafeArgSet(
false) {}
882 const char *startSpecifier,
883 unsigned specifierLen,
891 if (!(0 < ArgIdx && ArgIdx < Call->getNumArgs()))
895 const Expr *Arg =
Call->getArg(ArgIdx);
905 bool IsArgTypeValid =
908 ?
ArgType->getPointeeType()->isWideCharType()
909 :
ArgType->getPointeeType()->isCharType());
912 Precision && IsArgTypeValid)
916 UnsafeArg =
Call->getArg(ArgIdx);
921 bool isUnsafeArgSet() {
return UnsafeArgSet; }
924 const Expr *Fmt =
Call->getArg(FmtArgIdx);
927 if (SL->getCharByteWidth() == 1) {
928 StringRef FmtStr = SL->getString();
929 StringFormatStringHandler Handler(
Call, FmtArgIdx, UnsafeArg, Ctx);
932 Handler, FmtStr.begin(), FmtStr.end(), Ctx.
getLangOpts(),
934 Handler.isUnsafeArgSet();
937 if (
auto FmtStr = SL->tryEvaluateString(Ctx)) {
938 StringFormatStringHandler Handler(
Call, FmtArgIdx, UnsafeArg, Ctx);
940 Handler, FmtStr->data(), FmtStr->data() + FmtStr->size(),
942 Handler.isUnsafeArgSet();
949 llvm::make_range(
Call->arg_begin() + FmtArgIdx,
Call->arg_end()),
950 [&UnsafeArg, &Ctx](
const Expr *Arg) ->
bool {
951 if (Arg->getType()->isPointerType() && !isNullTermPointer(Arg, Ctx)) {
969 static std::unique_ptr<std::set<StringRef>> PredefinedNames =
nullptr;
970 if (!PredefinedNames)
972 std::make_unique<std::set<StringRef>, std::set<StringRef>>({
1053 if (PredefinedNames->find(Name) != PredefinedNames->end())
1056 std::string NameWCS = Name.str();
1057 size_t WcsPos = NameWCS.find(
"wcs");
1059 while (WcsPos != std::string::npos) {
1060 NameWCS[WcsPos++] =
's';
1061 NameWCS[WcsPos++] =
't';
1062 NameWCS[WcsPos++] =
'r';
1063 WcsPos = NameWCS.find(
"wcs", WcsPos);
1065 if (PredefinedNames->find(NameWCS) != PredefinedNames->end())
1069 return Name.ends_with(
"scanf");
1084 if (!Name.ends_with(
"printf"))
1086 return Name.starts_with(
"v");
1100 if (!Name.ends_with(
"printf") ||
1102 Name.starts_with(
"v"))
1105 StringRef Prefix = Name.drop_back(6);
1107 if (Prefix.ends_with(
"w"))
1108 Prefix = Prefix.drop_back(1);
1109 return Prefix ==
"s";
1124 if (!Name.ends_with(
"printf") || Name.starts_with(
"v"))
1127 StringRef Prefix = Name.drop_back(6);
1129 if (Prefix.ends_with(
"w"))
1130 Prefix = Prefix.drop_back(1);
1132 return Prefix.empty() || Prefix ==
"k" || Prefix ==
"f" || Prefix ==
"sn";
1140 MatchResult &Result, llvm::StringRef Tag) {
1144 assert(FD &&
"It should have been checked that FD is non-null.");
1162 const Expr *UnsafeArg;
1173 bool isKprintf =
false;
1174 const Expr *UnsafeArg;
1177 isKprintf = II->getName() ==
"kprintf";
1191 const Expr *UnsafeArg;
1202 for (
const auto *Arg : Node.
arguments())
1217 assert(FD &&
"It should have been checked that FD is non-null.");
1232 !Size->getType()->isUnsignedIntegerType())
1261#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1264 Gadget(Kind K) : K(K) {}
1266 Kind
getKind()
const {
return K; }
1269 StringRef getDebugName()
const {
1274#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1276 llvm_unreachable(
"Unhandled Gadget::Kind enum");
1280 virtual bool isWarningGadget()
const = 0;
1283 virtual SourceLocation getSourceLoc()
const = 0;
1288 virtual DeclUseList getClaimedVarUseSites()
const = 0;
1290 virtual ~Gadget() =
default;
1298class WarningGadget :
public Gadget {
1300 WarningGadget(Kind K) : Gadget(K) {}
1302 static bool classof(
const Gadget *G) {
return G->isWarningGadget(); }
1303 bool isWarningGadget() const final {
return true; }
1305 virtual void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1306 bool IsRelatedToDecl,
1307 ASTContext &Ctx)
const = 0;
1309 virtual SmallVector<const Expr *, 1> getUnsafePtrs()
const = 0;
1316class FixableGadget :
public Gadget {
1318 FixableGadget(Kind K) : Gadget(K) {}
1320 static bool classof(
const Gadget *G) {
return !G->isWarningGadget(); }
1321 bool isWarningGadget() const final {
return false; }
1326 virtual std::optional<FixItList> getFixits(
const FixitStrategy &)
const {
1327 return std::nullopt;
1336 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1337 getStrategyImplications()
const {
1338 return std::nullopt;
1342static bool isSupportedVariable(
const DeclRefExpr &Node) {
1354 dyn_cast<ClassTemplateSpecializationDecl>(
RecordDecl);
1355 if (!class_template_specialization_decl)
1360 if (template_args.
size() == 0)
1371class UniquePtrArrayAccessGadget :
public WarningGadget {
1373 static constexpr const char *
const AccessorTag =
"unique_ptr_array_access";
1374 const CXXOperatorCallExpr *AccessorExpr;
1378 : WarningGadget(
Kind::UniquePtrArrayAccess),
1379 AccessorExpr(
Result.getNodeAs<CXXOperatorCallExpr>(AccessorTag)) {
1380 assert(AccessorExpr &&
1381 "UniquePtrArrayAccessGadget requires a matched CXXOperatorCallExpr");
1384 static bool classof(
const Gadget *G) {
1385 return G->getKind() == Kind::UniquePtrArrayAccess;
1388 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1391 const CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(S);
1392 if (!OpCall || OpCall->
getOperator() != OO_Subscript)
1399 const CXXMethodDecl *
Method =
1404 if (
Method->getOverloadedOperator() != OO_Subscript)
1408 if (!isUniquePtrArray(RecordDecl))
1411 const Expr *IndexExpr = OpCall->
getArg(1);
1412 clang::Expr::EvalResult Eval;
1418 Result.addNode(AccessorTag, DynTypedNode::create(*OpCall));
1421 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1422 bool IsRelatedToDecl,
1423 ASTContext &Ctx)
const override {
1425 DynTypedNode::create(*AccessorExpr), IsRelatedToDecl, Ctx);
1428 SourceLocation getSourceLoc()
const override {
1430 return AccessorExpr->getOperatorLoc();
1431 return SourceLocation();
1434 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1435 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1438using FixableGadgetList = std::vector<std::unique_ptr<FixableGadget>>;
1439using WarningGadgetList = std::vector<std::unique_ptr<WarningGadget>>;
1443class IncrementGadget :
public WarningGadget {
1444 static constexpr const char *
const OpTag =
"op";
1445 const UnaryOperator *Op;
1449 : WarningGadget(
Kind::Increment),
1450 Op(
Result.getNodeAs<UnaryOperator>(OpTag)) {}
1452 static bool classof(
const Gadget *G) {
1453 return G->getKind() == Kind::Increment;
1456 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1458 const auto *UO = dyn_cast<UnaryOperator>(S);
1463 Result.addNode(OpTag, DynTypedNode::create(*UO));
1467 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1468 bool IsRelatedToDecl,
1469 ASTContext &Ctx)
const override {
1472 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1474 DeclUseList getClaimedVarUseSites()
const override {
1475 SmallVector<const DeclRefExpr *, 2> Uses;
1476 if (
const auto *DRE =
1477 dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
1478 Uses.push_back(DRE);
1481 return std::move(Uses);
1484 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1485 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1491class DecrementGadget :
public WarningGadget {
1492 static constexpr const char *
const OpTag =
"op";
1493 const UnaryOperator *Op;
1497 : WarningGadget(
Kind::Decrement),
1498 Op(
Result.getNodeAs<UnaryOperator>(OpTag)) {}
1500 static bool classof(
const Gadget *G) {
1501 return G->getKind() == Kind::Decrement;
1504 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1506 const auto *UO = dyn_cast<UnaryOperator>(S);
1511 Result.addNode(OpTag, DynTypedNode::create(*UO));
1515 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1516 bool IsRelatedToDecl,
1517 ASTContext &Ctx)
const override {
1520 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1522 DeclUseList getClaimedVarUseSites()
const override {
1523 if (
const auto *DRE =
1524 dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
1531 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1532 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1538class ArraySubscriptGadget :
public WarningGadget {
1539 static constexpr const char *
const ArraySubscrTag =
"ArraySubscript";
1540 const ArraySubscriptExpr *ASE;
1545 ASE(
Result.getNodeAs<ArraySubscriptExpr>(ArraySubscrTag)) {}
1547 static bool classof(
const Gadget *G) {
1548 return G->getKind() == Kind::ArraySubscript;
1551 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1553 const auto *ASE = dyn_cast<ArraySubscriptExpr>(S);
1556 const auto *
const Base = ASE->getBase()->IgnoreParenImpCasts();
1559 const auto *Idx = dyn_cast<IntegerLiteral>(ASE->getIdx());
1560 bool IsSafeIndex = (Idx && Idx->getValue().isZero()) ||
1564 Result.addNode(ArraySubscrTag, DynTypedNode::create(*ASE));
1568 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1569 bool IsRelatedToDecl,
1570 ASTContext &Ctx)
const override {
1573 SourceLocation getSourceLoc()
const override {
return ASE->getBeginLoc(); }
1575 DeclUseList getClaimedVarUseSites()
const override {
1576 if (
const auto *DRE =
1577 dyn_cast<DeclRefExpr>(ASE->getBase()->IgnoreParenImpCasts())) {
1584 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1585 return {ASE->getBase()->IgnoreParenImpCasts()};
1593class PointerArithmeticGadget :
public WarningGadget {
1594 static constexpr const char *
const PointerArithmeticTag =
"ptrAdd";
1595 static constexpr const char *
const PointerArithmeticPointerTag =
"ptrAddPtr";
1596 const BinaryOperator *PA;
1601 : WarningGadget(
Kind::PointerArithmetic),
1602 PA(
Result.getNodeAs<BinaryOperator>(PointerArithmeticTag)),
1603 Ptr(
Result.getNodeAs<Expr>(PointerArithmeticPointerTag)) {}
1605 static bool classof(
const Gadget *G) {
1606 return G->getKind() == Kind::PointerArithmetic;
1609 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1611 const auto *BO = dyn_cast<BinaryOperator>(S);
1614 const auto *LHS = BO->
getLHS();
1615 const auto *RHS = BO->
getRHS();
1620 RHS->getType()->isEnumeralType())) {
1621 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*LHS));
1622 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1628 (LHS->getType()->isIntegerType() || LHS->getType()->isEnumeralType())) {
1629 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*RHS));
1630 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1636 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1637 bool IsRelatedToDecl,
1638 ASTContext &Ctx)
const override {
1641 SourceLocation getSourceLoc()
const override {
return PA->getBeginLoc(); }
1643 DeclUseList getClaimedVarUseSites()
const override {
1644 if (
const auto *DRE = dyn_cast<DeclRefExpr>(Ptr->IgnoreParenImpCasts())) {
1651 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1652 return {Ptr->IgnoreParenImpCasts()};
1659class SpanTwoParamConstructorGadget :
public WarningGadget {
1660 static constexpr const char *
const SpanTwoParamConstructorTag =
1661 "spanTwoParamConstructor";
1662 const CXXConstructExpr *Ctor;
1666 : WarningGadget(
Kind::SpanTwoParamConstructor),
1667 Ctor(
Result.getNodeAs<CXXConstructExpr>(SpanTwoParamConstructorTag)) {}
1669 static bool classof(
const Gadget *G) {
1670 return G->getKind() == Kind::SpanTwoParamConstructor;
1674 const auto *CE = dyn_cast<CXXConstructExpr>(S);
1677 const auto *CDecl = CE->getConstructor();
1678 const auto *CRecordDecl = CDecl->getParent();
1679 auto HasTwoParamSpanCtorDecl =
1680 CRecordDecl->isInStdNamespace() &&
1681 CDecl->getDeclName().getAsString() ==
"span" && CE->getNumArgs() == 2;
1684 Result.addNode(SpanTwoParamConstructorTag, DynTypedNode::create(*CE));
1688 static bool matches(
const Stmt *S, ASTContext &Ctx,
1689 const UnsafeBufferUsageHandler *Handler,
1696 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1697 bool IsRelatedToDecl,
1698 ASTContext &Ctx)
const override {
1701 SourceLocation getSourceLoc()
const override {
return Ctor->getBeginLoc(); }
1703 DeclUseList getClaimedVarUseSites()
const override {
1706 if (
auto *DRE = dyn_cast<DeclRefExpr>(Ctor->getArg(0))) {
1713 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1720class PointerInitGadget :
public FixableGadget {
1722 static constexpr const char *
const PointerInitLHSTag =
"ptrInitLHS";
1723 static constexpr const char *
const PointerInitRHSTag =
"ptrInitRHS";
1724 const VarDecl *PtrInitLHS;
1725 const DeclRefExpr *PtrInitRHS;
1729 : FixableGadget(
Kind::PointerInit),
1730 PtrInitLHS(
Result.getNodeAs<VarDecl>(PointerInitLHSTag)),
1731 PtrInitRHS(
Result.getNodeAs<DeclRefExpr>(PointerInitRHSTag)) {}
1733 static bool classof(
const Gadget *G) {
1734 return G->getKind() == Kind::PointerInit;
1737 static bool matches(
const Stmt *S,
1738 llvm::SmallVectorImpl<MatchResult> &Results) {
1739 const DeclStmt *DS = dyn_cast<DeclStmt>(S);
1748 const auto *DRE = dyn_cast<DeclRefExpr>(
Init->IgnoreImpCasts());
1749 if (!DRE || !
hasPointerType(*DRE) || !isSupportedVariable(*DRE)) {
1753 R.addNode(PointerInitLHSTag, DynTypedNode::create(*VD));
1754 R.addNode(PointerInitRHSTag, DynTypedNode::create(*DRE));
1755 Results.emplace_back(std::move(R));
1759 virtual std::optional<FixItList>
1760 getFixits(
const FixitStrategy &S)
const override;
1761 SourceLocation getSourceLoc()
const override {
1762 return PtrInitRHS->getBeginLoc();
1765 virtual DeclUseList getClaimedVarUseSites()
const override {
1766 return DeclUseList{PtrInitRHS};
1769 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1770 getStrategyImplications()
const override {
1771 return std::make_pair(PtrInitLHS,
cast<VarDecl>(PtrInitRHS->getDecl()));
1780class PtrToPtrAssignmentGadget :
public FixableGadget {
1782 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1783 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1784 const DeclRefExpr *PtrLHS;
1785 const DeclRefExpr *PtrRHS;
1789 : FixableGadget(
Kind::PtrToPtrAssignment),
1790 PtrLHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
1791 PtrRHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
1793 static bool classof(
const Gadget *G) {
1794 return G->getKind() == Kind::PtrToPtrAssignment;
1797 static bool matches(
const Stmt *S,
1798 llvm::SmallVectorImpl<MatchResult> &Results) {
1799 size_t SizeBefore = Results.size();
1801 const auto *BO = dyn_cast<BinaryOperator>(S);
1802 if (!BO || BO->
getOpcode() != BO_Assign)
1805 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1807 !isSupportedVariable(*RHSRef)) {
1810 const auto *LHS = BO->
getLHS();
1811 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1813 !isSupportedVariable(*LHSRef)) {
1817 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
1818 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
1819 Results.emplace_back(std::move(R));
1821 return SizeBefore != Results.size();
1824 virtual std::optional<FixItList>
1825 getFixits(
const FixitStrategy &S)
const override;
1826 SourceLocation getSourceLoc()
const override {
return PtrLHS->getBeginLoc(); }
1828 virtual DeclUseList getClaimedVarUseSites()
const override {
1829 return DeclUseList{PtrLHS, PtrRHS};
1832 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1833 getStrategyImplications()
const override {
1844class CArrayToPtrAssignmentGadget :
public FixableGadget {
1846 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1847 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1848 const DeclRefExpr *PtrLHS;
1849 const DeclRefExpr *PtrRHS;
1853 : FixableGadget(
Kind::CArrayToPtrAssignment),
1854 PtrLHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
1855 PtrRHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
1857 static bool classof(
const Gadget *G) {
1858 return G->getKind() == Kind::CArrayToPtrAssignment;
1861 static bool matches(
const Stmt *S,
1862 llvm::SmallVectorImpl<MatchResult> &Results) {
1863 size_t SizeBefore = Results.size();
1865 const auto *BO = dyn_cast<BinaryOperator>(S);
1866 if (!BO || BO->
getOpcode() != BO_Assign)
1869 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1872 !isSupportedVariable(*RHSRef)) {
1875 const auto *LHS = BO->
getLHS();
1876 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1878 !isSupportedVariable(*LHSRef)) {
1882 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
1883 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
1884 Results.emplace_back(std::move(R));
1886 return SizeBefore != Results.size();
1889 virtual std::optional<FixItList>
1890 getFixits(
const FixitStrategy &S)
const override;
1891 SourceLocation getSourceLoc()
const override {
return PtrLHS->getBeginLoc(); }
1893 virtual DeclUseList getClaimedVarUseSites()
const override {
1894 return DeclUseList{PtrLHS, PtrRHS};
1897 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1898 getStrategyImplications()
const override {
1905class UnsafeBufferUsageAttrGadget :
public WarningGadget {
1906 constexpr static const char *
const OpTag =
"attr_expr";
1911 : WarningGadget(
Kind::UnsafeBufferUsageAttr),
1912 Op(
Result.getNodeAs<Expr>(OpTag)) {}
1914 static bool classof(
const Gadget *G) {
1915 return G->getKind() == Kind::UnsafeBufferUsageAttr;
1918 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1920 if (
auto *CE = dyn_cast<CallExpr>(S)) {
1921 if (CE->getDirectCallee() &&
1922 CE->getDirectCallee()->hasAttr<UnsafeBufferUsageAttr>()) {
1923 Result.addNode(OpTag, DynTypedNode::create(*CE));
1927 if (
auto *ME = dyn_cast<MemberExpr>(S)) {
1930 if (ME->getMemberDecl()->hasAttr<UnsafeBufferUsageAttr>()) {
1931 Result.addNode(OpTag, DynTypedNode::create(*ME));
1938 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1939 bool IsRelatedToDecl,
1940 ASTContext &Ctx)
const override {
1943 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1945 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1947 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1953class UnsafeBufferUsageCtorAttrGadget :
public WarningGadget {
1954 constexpr static const char *
const OpTag =
"cxx_construct_expr";
1955 const CXXConstructExpr *Op;
1959 : WarningGadget(
Kind::UnsafeBufferUsageCtorAttr),
1960 Op(
Result.getNodeAs<CXXConstructExpr>(OpTag)) {}
1962 static bool classof(
const Gadget *G) {
1963 return G->getKind() == Kind::UnsafeBufferUsageCtorAttr;
1967 const auto *CE = dyn_cast<CXXConstructExpr>(S);
1968 if (!CE || !CE->getConstructor()->hasAttr<UnsafeBufferUsageAttr>())
1972 if (SpanTwoParamConstructorGadget::matches(CE, Ctx, Tmp))
1974 Result.addNode(OpTag, DynTypedNode::create(*CE));
1978 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1979 bool IsRelatedToDecl,
1980 ASTContext &Ctx)
const override {
1983 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1985 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1987 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1994class DataInvocationGadget :
public WarningGadget {
1995 constexpr static const char *
const OpTag =
"data_invocation_expr";
1996 const ExplicitCastExpr *Op;
2000 : WarningGadget(
Kind::DataInvocation),
2001 Op(
Result.getNodeAs<ExplicitCastExpr>(OpTag)) {}
2003 static bool classof(
const Gadget *G) {
2004 return G->getKind() == Kind::DataInvocation;
2007 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
2009 auto *CE = dyn_cast<ExplicitCastExpr>(S);
2012 for (
auto *Child : CE->children()) {
2013 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(Child);
2014 MCE && isDataFunction(MCE)) {
2015 Result.addNode(OpTag, DynTypedNode::create(*CE));
2018 if (
auto *
Paren = dyn_cast<ParenExpr>(Child)) {
2019 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(
Paren->getSubExpr());
2020 MCE && isDataFunction(MCE)) {
2021 Result.addNode(OpTag, DynTypedNode::create(*CE));
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 {}; }
2039 static bool isDataFunction(
const CXXMemberCallExpr *call) {
2046 if (method->getNameAsString() ==
"data" &&
2047 method->getParent()->isInStdNamespace() &&
2048 llvm::is_contained({SIZED_CONTAINER_OR_VIEW_LIST},
2049 method->getParent()->getName()))
2054 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2057class UnsafeLibcFunctionCallGadget :
public WarningGadget {
2058 const CallExpr *
const Call;
2059 const Expr *UnsafeArg =
nullptr;
2060 constexpr static const char *
const Tag =
"UnsafeLibcFunctionCall";
2062 constexpr static const char *
const UnsafeSprintfTag =
2063 "UnsafeLibcFunctionCall_sprintf";
2064 constexpr static const char *
const UnsafeSizedByTag =
2065 "UnsafeLibcFunctionCall_sized_by";
2066 constexpr static const char *
const UnsafeStringTag =
2067 "UnsafeLibcFunctionCall_string";
2068 constexpr static const char *
const UnsafeVaListTag =
2069 "UnsafeLibcFunctionCall_va_list";
2081 } WarnedFunKind = OTHERS;
2085 : WarningGadget(
Kind::UnsafeLibcFunctionCall),
2086 Call(
Result.getNodeAs<CallExpr>(Tag)) {
2087 if (
Result.getNodeAs<Decl>(UnsafeSprintfTag))
2088 WarnedFunKind = SPRINTF;
2089 else if (
auto *E =
Result.getNodeAs<Expr>(UnsafeStringTag)) {
2090 WarnedFunKind = STRING;
2092 }
else if (
Result.getNodeAs<CallExpr>(UnsafeSizedByTag)) {
2093 WarnedFunKind = SIZED_BY;
2094 UnsafeArg = Call->getArg(0);
2095 }
else if (
Result.getNodeAs<Decl>(UnsafeVaListTag))
2096 WarnedFunKind = VA_LIST;
2099 static bool matches(
const Stmt *S, ASTContext &Ctx,
2100 const UnsafeBufferUsageHandler *Handler,
2104 auto *CE = dyn_cast<CallExpr>(S);
2105 if (!CE || !CE->getDirectCallee())
2107 const auto *FD = dyn_cast<FunctionDecl>(CE->getDirectCallee());
2111 bool IsGlobalAndNotInAnyNamespace =
2112 FD->isGlobal() && !FD->getEnclosingNamespaceContext()->isNamespace();
2116 if (!FD->isInStdNamespace() && !IsGlobalAndNotInAnyNamespace)
2122 auto isSingleStringLiteralArg =
false;
2123 if (CE->getNumArgs() == 1) {
2124 isSingleStringLiteralArg =
2127 if (!isSingleStringLiteralArg) {
2130 Result.addNode(Tag, DynTypedNode::create(*CE));
2134 Result.addNode(Tag, DynTypedNode::create(*CE));
2135 Result.addNode(UnsafeVaListTag, DynTypedNode::create(*FD));
2139 Result.addNode(Tag, DynTypedNode::create(*CE));
2140 Result.addNode(UnsafeSprintfTag, DynTypedNode::create(*FD));
2146 Result.addNode(Tag, DynTypedNode::create(*CE));
2147 Result.addNode(UnsafeSizedByTag, DynTypedNode::create(*CE));
2152 Result.addNode(Tag, DynTypedNode::create(*CE));
2159 const Stmt *getBaseStmt()
const {
return Call; }
2161 SourceLocation getSourceLoc()
const override {
return Call->getBeginLoc(); }
2163 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2164 bool IsRelatedToDecl,
2165 ASTContext &Ctx)
const override {
2169 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2171 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2177class ULCArraySubscriptGadget :
public FixableGadget {
2179 static constexpr const char *
const ULCArraySubscriptTag =
2180 "ArraySubscriptUnderULC";
2181 const ArraySubscriptExpr *Node;
2185 : FixableGadget(
Kind::ULCArraySubscript),
2186 Node(
Result.getNodeAs<ArraySubscriptExpr>(ULCArraySubscriptTag)) {
2187 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2190 static bool classof(
const Gadget *G) {
2191 return G->getKind() == Kind::ULCArraySubscript;
2194 static bool matches(
const Stmt *S,
2195 llvm::SmallVectorImpl<MatchResult> &Results) {
2196 size_t SizeBefore = Results.size();
2198 const auto *ASE = dyn_cast<ArraySubscriptExpr>(E);
2204 !isSupportedVariable(*DRE))
2207 R.addNode(ULCArraySubscriptTag, DynTypedNode::create(*ASE));
2208 Results.emplace_back(std::move(R));
2210 return SizeBefore != Results.size();
2213 virtual std::optional<FixItList>
2214 getFixits(
const FixitStrategy &S)
const override;
2215 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2217 virtual DeclUseList getClaimedVarUseSites()
const override {
2218 if (
const auto *DRE =
2219 dyn_cast<DeclRefExpr>(Node->getBase()->IgnoreImpCasts())) {
2229class UPCStandalonePointerGadget :
public FixableGadget {
2231 static constexpr const char *
const DeclRefExprTag =
"StandalonePointer";
2232 const DeclRefExpr *Node;
2236 : FixableGadget(
Kind::UPCStandalonePointer),
2237 Node(
Result.getNodeAs<DeclRefExpr>(DeclRefExprTag)) {
2238 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2241 static bool classof(
const Gadget *G) {
2242 return G->getKind() == Kind::UPCStandalonePointer;
2245 static bool matches(
const Stmt *S,
2246 llvm::SmallVectorImpl<MatchResult> &Results) {
2247 size_t SizeBefore = Results.size();
2249 auto *E = dyn_cast<Expr>(S);
2254 !isSupportedVariable(*DRE))
2257 R.addNode(DeclRefExprTag, DynTypedNode::create(*DRE));
2258 Results.emplace_back(std::move(R));
2260 return SizeBefore != Results.size();
2263 virtual std::optional<FixItList>
2264 getFixits(
const FixitStrategy &S)
const override;
2265 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2267 virtual DeclUseList getClaimedVarUseSites()
const override {
return {Node}; }
2270class PointerDereferenceGadget :
public FixableGadget {
2271 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2272 static constexpr const char *
const OperatorTag =
"op";
2274 const DeclRefExpr *BaseDeclRefExpr =
nullptr;
2275 const UnaryOperator *Op =
nullptr;
2279 : FixableGadget(
Kind::PointerDereference),
2280 BaseDeclRefExpr(
Result.getNodeAs<DeclRefExpr>(BaseDeclRefExprTag)),
2281 Op(
Result.getNodeAs<UnaryOperator>(OperatorTag)) {}
2283 static bool classof(
const Gadget *G) {
2284 return G->getKind() == Kind::PointerDereference;
2287 static bool matches(
const Stmt *S,
2288 llvm::SmallVectorImpl<MatchResult> &Results) {
2289 size_t SizeBefore = Results.size();
2291 const auto *UO = dyn_cast<UnaryOperator>(S);
2294 const auto *CE = dyn_cast<Expr>(UO->
getSubExpr());
2297 CE = CE->IgnoreParenImpCasts();
2298 const auto *DRE = dyn_cast<DeclRefExpr>(CE);
2299 if (!DRE || !isSupportedVariable(*DRE))
2302 R.addNode(BaseDeclRefExprTag, DynTypedNode::create(*DRE));
2303 R.addNode(OperatorTag, DynTypedNode::create(*UO));
2304 Results.emplace_back(std::move(R));
2306 return SizeBefore != Results.size();
2309 DeclUseList getClaimedVarUseSites()
const override {
2310 return {BaseDeclRefExpr};
2313 virtual std::optional<FixItList>
2314 getFixits(
const FixitStrategy &S)
const override;
2315 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2321class UPCAddressofArraySubscriptGadget :
public FixableGadget {
2323 static constexpr const char *
const UPCAddressofArraySubscriptTag =
2324 "AddressofArraySubscriptUnderUPC";
2325 const UnaryOperator *Node;
2329 : FixableGadget(
Kind::ULCArraySubscript),
2330 Node(
Result.getNodeAs<UnaryOperator>(UPCAddressofArraySubscriptTag)) {
2331 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2334 static bool classof(
const Gadget *G) {
2335 return G->getKind() == Kind::UPCAddressofArraySubscript;
2338 static bool matches(
const Stmt *S,
2339 llvm::SmallVectorImpl<MatchResult> &Results) {
2340 size_t SizeBefore = Results.size();
2342 auto *E = dyn_cast<Expr>(S);
2346 if (!UO || UO->
getOpcode() != UO_AddrOf)
2348 const auto *ASE = dyn_cast<ArraySubscriptExpr>(UO->
getSubExpr());
2353 if (!DRE || !isSupportedVariable(*DRE))
2356 R.addNode(UPCAddressofArraySubscriptTag, DynTypedNode::create(*UO));
2357 Results.emplace_back(std::move(R));
2359 return SizeBefore != Results.size();
2362 virtual std::optional<FixItList>
2363 getFixits(
const FixitStrategy &)
const override;
2364 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2366 virtual DeclUseList getClaimedVarUseSites()
const override {
2379class DeclUseTracker {
2380 using UseSetTy = llvm::SmallPtrSet<const DeclRefExpr *, 16>;
2381 using DefMapTy = llvm::DenseMap<const VarDecl *, const DeclStmt *>;
2384 std::unique_ptr<UseSetTy> Uses{std::make_unique<UseSetTy>()};
2388 DeclUseTracker() =
default;
2389 DeclUseTracker(
const DeclUseTracker &) =
delete;
2390 DeclUseTracker &operator=(
const DeclUseTracker &) =
delete;
2391 DeclUseTracker(DeclUseTracker &&) =
default;
2392 DeclUseTracker &operator=(DeclUseTracker &&) =
default;
2395 void discoverUse(
const DeclRefExpr *DRE) { Uses->insert(DRE); }
2398 void claimUse(
const DeclRefExpr *DRE) {
2399 assert(Uses->count(DRE) &&
2400 "DRE not found or claimed by multiple matchers!");
2405 bool hasUnclaimedUses(
const VarDecl *VD)
const {
2407 return any_of(*Uses, [VD](
const DeclRefExpr *DRE) {
2412 UseSetTy getUnclaimedUses(
const VarDecl *VD)
const {
2414 for (
auto use : *Uses) {
2416 ReturnSet.insert(use);
2422 void discoverDecl(
const DeclStmt *DS) {
2423 for (
const Decl *D : DS->
decls()) {
2424 if (
const auto *VD = dyn_cast<VarDecl>(D)) {
2435 const DeclStmt *lookupDecl(
const VarDecl *VD)
const {
2436 return Defs.lookup(VD);
2445 static constexpr const char *
const UPCPreIncrementTag =
2446 "PointerPreIncrementUnderUPC";
2451 : FixableGadget(Kind::UPCPreIncrement),
2453 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2457 return G->getKind() == Kind::UPCPreIncrement;
2466 size_t SizeBefore = Results.size();
2468 auto *E = dyn_cast<Expr>(S);
2472 if (!UO || UO->
getOpcode() != UO_PreInc)
2474 const auto *DRE = dyn_cast<DeclRefExpr>(UO->
getSubExpr());
2475 if (!DRE || !isSupportedVariable(*DRE))
2479 Results.emplace_back(std::move(R));
2481 return SizeBefore != Results.size();
2484 virtual std::optional<FixItList>
2489 return {dyn_cast<DeclRefExpr>(Node->getSubExpr())};
2497 static constexpr const char *
const UUCAddAssignTag =
2498 "PointerAddAssignUnderUUC";
2499 static constexpr const char *
const OffsetTag =
"Offset";
2502 const Expr *Offset =
nullptr;
2506 : FixableGadget(Kind::UUCAddAssign),
2509 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2513 return G->getKind() == Kind::UUCAddAssign;
2518 size_t SizeBefore = Results.size();
2520 const auto *E = dyn_cast<Expr>(S);
2524 if (!BO || BO->
getOpcode() != BO_AddAssign)
2526 const auto *DRE = dyn_cast<DeclRefExpr>(BO->
getLHS());
2532 Results.emplace_back(std::move(R));
2534 return SizeBefore != Results.size();
2537 virtual std::optional<FixItList>
2542 return {dyn_cast<DeclRefExpr>(Node->getLHS())};
2549 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2550 static constexpr const char *
const DerefOpTag =
"DerefOp";
2551 static constexpr const char *
const AddOpTag =
"AddOp";
2552 static constexpr const char *
const OffsetTag =
"Offset";
2561 : FixableGadget(Kind::DerefSimplePtrArithFixable),
2569 auto IsPtr = [](
const Expr *E, MatchResult &R) {
2573 if (!DRE || !isSupportedVariable(*DRE))
2578 const auto IsPlusOverPtrAndInteger = [&IsPtr](
const Expr *E,
2580 const auto *BO = dyn_cast<BinaryOperator>(E);
2584 const auto *LHS = BO->
getLHS();
2585 const auto *RHS = BO->
getRHS();
2598 size_t SizeBefore = Results.size();
2599 const auto InnerMatcher = [&IsPlusOverPtrAndInteger,
2600 &Results](
const Expr *E) {
2601 const auto *UO = dyn_cast<UnaryOperator>(E);
2607 if (IsPlusOverPtrAndInteger(Operand, R)) {
2609 Results.emplace_back(std::move(R));
2613 return SizeBefore != Results.size();
2616 virtual std::optional<FixItList>
2619 return DerefOp->getBeginLoc();
2623 return {BaseDeclRefExpr};
2631 : WarningGadgets(WarningGadgets) {}
2640#define WARNING_GADGET(name) \
2641 if (name##Gadget::matches(S, Ctx, Result) && \
2642 notInSafeBufferOptOut(*S, &Handler)) { \
2643 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2646#define WARNING_OPTIONAL_GADGET(name) \
2647 if (name##Gadget::matches(S, Ctx, &Handler, Result) && \
2648 notInSafeBufferOptOut(*S, &Handler)) { \
2649 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2652#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2657 WarningGadgetList &WarningGadgets;
2664 DeclUseTracker &Tracker)
2665 : FixableGadgets(FixableGadgets), Tracker(Tracker) {}
2669 bool matchFound =
false;
2676#define FIXABLE_GADGET(name) \
2677 if (name##Gadget::matches(S, Results)) { \
2678 for (const auto &R : Results) { \
2679 FixableGadgets.push_back(std::make_unique<name##Gadget>(R)); \
2680 matchFound = true; \
2684#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2687 if (
auto *DRE = findDeclRefExpr(S); DRE) {
2688 Tracker.discoverUse(DRE);
2694 if (
auto *DS = findDeclStmt(S); DS) {
2695 Tracker.discoverDecl(DS);
2703 const auto *DRE = dyn_cast<DeclRefExpr>(S);
2711 const DeclStmt *findDeclStmt(
const Stmt *S) {
2712 const auto *DS = dyn_cast<DeclStmt>(S);
2717 FixableGadgetList &FixableGadgets;
2718 DeclUseTracker &Tracker;
2724 bool EmitSuggestions, FixableGadgetList &FixableGadgets,
2725 WarningGadgetList &WarningGadgets,
2726 DeclUseTracker &Tracker) {
2729 if (EmitSuggestions) {
2738 return N1->getBeginLoc().getRawEncoding() <
2739 N2->getBeginLoc().getRawEncoding();
2749 const Expr *UnsafeArg =
nullptr)
override {}
2757 bool IsRelatedToDecl,
2774 FixableGadgetList FixableGadgets;
2775 WarningGadgetList WarningGadgets;
2776 DeclUseTracker Tracker;
2777 MockReporter IgnoreHandler;
2780 FixableGadgets, WarningGadgets, Tracker);
2782 std::set<const Expr *>
Result;
2783 for (
auto &G : WarningGadgets) {
2784 for (
const Expr *E : G->getUnsafePtrs()) {
2793 std::map<const VarDecl *, std::set<const WarningGadget *>,
2807 for (
auto &G : AllUnsafeOperations) {
2808 DeclUseList ClaimedVarUseSites = G->getClaimedVarUseSites();
2810 bool AssociatedWithVarDecl =
false;
2811 for (
const DeclRefExpr *DRE : ClaimedVarUseSites) {
2812 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2813 result.
byVar[VD].insert(G.get());
2814 AssociatedWithVarDecl =
true;
2818 if (!AssociatedWithVarDecl) {
2819 result.
noVar.push_back(G.get());
2827 std::map<const VarDecl *, std::set<const FixableGadget *>,
2837 for (
auto &F : AllFixableOperations) {
2838 DeclUseList DREs = F->getClaimedVarUseSites();
2841 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2842 FixablesForUnsafeVars.
byVar[VD].insert(F.get());
2846 return FixablesForUnsafeVars;
2853 std::vector<const FixItHint *>
All;
2857 std::sort(
All.begin(),
All.end(),
2859 return SM.isBeforeInTranslationUnit(H1->RemoveRange.getBegin(),
2860 H2->RemoveRange.getBegin());
2868 Hint->RemoveRange.getBegin())) {
2880std::optional<FixItList>
2881PtrToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
2884 switch (S.
lookup(LeftVD)) {
2888 return std::nullopt;
2890 return std::nullopt;
2893 return std::nullopt;
2895 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2897 return std::nullopt;
2901static inline std::optional<FixItList>
createDataFixit(
const ASTContext &Ctx,
2902 const DeclRefExpr *DRE);
2904std::optional<FixItList>
2905CArrayToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
2924 if (S.
lookup(LeftVD) == FixitStrategy::Kind::Span) {
2925 if (S.
lookup(RightVD) == FixitStrategy::Kind::Wontfix) {
2928 }
else if (S.
lookup(LeftVD) == FixitStrategy::Kind::Wontfix) {
2929 if (S.
lookup(RightVD) == FixitStrategy::Kind::Array) {
2933 return std::nullopt;
2936std::optional<FixItList>
2937PointerInitGadget::getFixits(
const FixitStrategy &S)
const {
2938 const auto *LeftVD = PtrInitLHS;
2940 switch (S.
lookup(LeftVD)) {
2941 case FixitStrategy::Kind::Span:
2942 if (S.
lookup(RightVD) == FixitStrategy::Kind::Span)
2944 return std::nullopt;
2945 case FixitStrategy::Kind::Wontfix:
2946 return std::nullopt;
2947 case FixitStrategy::Kind::Iterator:
2948 case FixitStrategy::Kind::Array:
2949 return std::nullopt;
2950 case FixitStrategy::Kind::Vector:
2951 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2953 return std::nullopt;
2959 if (ConstVal->isNegative())
2966std::optional<FixItList>
2967ULCArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
2968 if (
const auto *DRE =
2970 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2972 case FixitStrategy::Kind::Span: {
2976 const ASTContext &Ctx =
2979 return std::nullopt;
2983 case FixitStrategy::Kind::Array:
2985 case FixitStrategy::Kind::Wontfix:
2986 case FixitStrategy::Kind::Iterator:
2987 case FixitStrategy::Kind::Vector:
2988 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2991 return std::nullopt;
2994static std::optional<FixItList>
2997std::optional<FixItList>
2998UPCAddressofArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
2999 auto DREs = getClaimedVarUseSites();
3003 case FixitStrategy::Kind::Span:
3005 case FixitStrategy::Kind::Wontfix:
3006 case FixitStrategy::Kind::Iterator:
3007 case FixitStrategy::Kind::Array:
3008 return std::nullopt;
3009 case FixitStrategy::Kind::Vector:
3010 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3012 return std::nullopt;
3017 static const char *
const EOL =
"\n";
3024 std::string
s = std::string(
"<# ");
3025 s += HintTextToUser;
3031template <
typename NodeTy>
3032static std::optional<SourceLocation>
3035 if (
unsigned TkLen =
3042 return std::nullopt;
3055 bool AttrRangeOverlapping = llvm::any_of(VD->
attrs(), [&](
Attr *At) ->
bool {
3056 return !(SM.isBeforeInTranslationUnit(At->getRange().getEnd(),
3057 VD->getBeginLoc())) &&
3058 !(SM.isBeforeInTranslationUnit(VD->getEndLoc(),
3059 At->getRange().getBegin()));
3063 AttrRangeOverlapping;
3105 std::optional<Qualifiers> Quals = std::nullopt) {
3106 const char *
const SpanOpen =
"std::span<";
3109 return SpanOpen + EltTyText.str() +
' ' + Quals->getAsString() +
'>';
3110 return SpanOpen + EltTyText.str() +
'>';
3113std::optional<FixItList>
3115 const VarDecl *VD = dyn_cast<VarDecl>(BaseDeclRefExpr->getDecl());
3120 if (
auto ConstVal = Offset->getIntegerConstantExpr(Ctx))
3121 if (ConstVal->isNegative())
3122 return std::nullopt;
3143 const Expr *LHS = AddOp->getLHS(), *RHS = AddOp->getRHS();
3150 std::optional<SourceLocation> LHSLocation =
getPastLoc(LHS,
SM, LangOpts);
3152 return std::nullopt;
3157 std::optional<SourceLocation> AddOpLocation =
3159 std::optional<SourceLocation> DerefOpLocation =
3162 if (!AddOpLocation || !DerefOpLocation)
3163 return std::nullopt;
3173 return std::nullopt;
3176std::optional<FixItList>
3177PointerDereferenceGadget::getFixits(
const FixitStrategy &S)
const {
3188 if (
auto LocPastOperand =
3195 case FixitStrategy::Kind::Iterator:
3196 case FixitStrategy::Kind::Array:
3197 return std::nullopt;
3198 case FixitStrategy::Kind::Vector:
3199 llvm_unreachable(
"FixitStrategy not implemented yet!");
3200 case FixitStrategy::Kind::Wontfix:
3201 llvm_unreachable(
"Invalid strategy!");
3204 return std::nullopt;
3211 std::optional<SourceLocation> EndOfOperand =
3217 return std::nullopt;
3222std::optional<FixItList>
3223UPCStandalonePointerGadget::getFixits(
const FixitStrategy &S)
const {
3226 case FixitStrategy::Kind::Array:
3227 case FixitStrategy::Kind::Span: {
3232 case FixitStrategy::Kind::Wontfix:
3233 case FixitStrategy::Kind::Iterator:
3234 return std::nullopt;
3235 case FixitStrategy::Kind::Vector:
3236 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3239 return std::nullopt;
3244static std::optional<FixItList>
3251 const Expr *Idx = ArraySub->getIdx();
3254 std::stringstream SS;
3255 bool IdxIsLitZero =
false;
3258 if ((*ICE).isZero())
3259 IdxIsLitZero =
true;
3260 std::optional<StringRef> DreString =
getExprText(DRE,
SM, LangOpts);
3262 return std::nullopt;
3266 SS << (*DreString).str() <<
".data()";
3268 std::optional<StringRef> IndexString =
getExprText(Idx,
SM, LangOpts);
3270 return std::nullopt;
3272 SS <<
"&" << (*DreString).str() <<
".data()"
3273 <<
"[" << (*IndexString).str() <<
"]";
3279std::optional<FixItList>
3283 if (DREs.size() != 1)
3284 return std::nullopt;
3286 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3290 const Stmt *AddAssignNode = Node;
3291 StringRef varName = VD->
getName();
3295 return std::nullopt;
3299 (Offset->IgnoreParens()->getBeginLoc() == Offset->getBeginLoc());
3300 std::string SS = varName.str() +
" = " + varName.str() +
".subspan";
3304 std::optional<SourceLocation> AddAssignLocation =
getEndCharLoc(
3306 if (!AddAssignLocation)
3307 return std::nullopt;
3314 Offset->getEndLoc().getLocWithOffset(1),
")"));
3318 return std::nullopt;
3321std::optional<FixItList>
3325 if (DREs.size() != 1)
3326 return std::nullopt;
3328 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3331 std::stringstream SS;
3332 StringRef varName = VD->
getName();
3336 SS <<
"(" << varName.data() <<
" = " << varName.data()
3337 <<
".subspan(1)).data()";
3338 std::optional<SourceLocation> PreIncLocation =
3340 if (!PreIncLocation)
3341 return std::nullopt;
3344 SourceRange(Node->getBeginLoc(), *PreIncLocation), SS.str()));
3348 return std::nullopt;
3366static std::optional<FixItList>
3368 const StringRef UserFillPlaceHolder) {
3376 if (
Init->isNullPointerConstant(
3381 NPC_ValueDependentIsNotNull)) {
3382 std::optional<SourceLocation> InitLocation =
3385 return std::nullopt;
3393 std::string ExtentText = UserFillPlaceHolder.data();
3394 StringRef One =
"1";
3399 if (
auto CxxNew = dyn_cast<CXXNewExpr>(
Init->IgnoreImpCasts())) {
3404 if (
const Expr *Ext = CxxNew->getArraySize().value_or(
nullptr)) {
3405 if (!Ext->HasSideEffects(Ctx)) {
3406 std::optional<StringRef> ExtentString =
getExprText(Ext,
SM, LangOpts);
3408 return std::nullopt;
3409 ExtentText = *ExtentString;
3411 }
else if (!CxxNew->isArray())
3423 if (
auto AddrOfExpr = dyn_cast<UnaryOperator>(
Init->IgnoreImpCasts()))
3424 if (AddrOfExpr->getOpcode() == UnaryOperatorKind::UO_AddrOf &&
3425 isa_and_present<DeclRefExpr>(AddrOfExpr->getSubExpr()))
3432 std::optional<SourceLocation> LocPassInit =
getPastLoc(
Init,
SM, LangOpts);
3435 return std::nullopt;
3437 StrBuffer.append(
", ");
3438 StrBuffer.append(ExtentText);
3439 StrBuffer.append(
"}");
3445#define DEBUG_NOTE_DECL_FAIL(D, Msg) \
3446 Handler.addDebugNoteForVar((D), (D)->getBeginLoc(), \
3447 "failed to produce fixit for declaration '" + \
3448 (D)->getNameAsString() + "'" + (Msg))
3450#define DEBUG_NOTE_DECL_FAIL(D, Msg)
3456static std::optional<std::string>
3460 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3465 return std::nullopt;
3467 std::string SpanTyText =
"std::span<";
3469 SpanTyText.append(*PteTyText);
3471 if (PteTyQualifiers) {
3472 SpanTyText.append(
" ");
3473 SpanTyText.append(PteTyQualifiers->getAsString());
3475 SpanTyText.append(
">");
3494 const StringRef UserFillPlaceHolder,
3508 std::stringstream SS;
3513 std::optional<FixItList> InitFixIts =
3517 FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts->begin()),
3518 std::make_move_iterator(InitFixIts->end()));
3525 if (!EndLocForReplacement.
isValid()) {
3575static std::optional<FixItList>
3581 return std::nullopt;
3586 std::vector<std::string> NewTysTexts(NumParms);
3587 std::vector<bool> ParmsMask(NumParms,
false);
3588 bool AtLeastOneParmToFix =
false;
3590 for (
unsigned i = 0; i < NumParms; i++) {
3597 return std::nullopt;
3599 std::optional<Qualifiers> PteTyQuals = std::nullopt;
3600 std::optional<std::string> PteTyText =
3605 return std::nullopt;
3609 ParmsMask[i] =
true;
3610 AtLeastOneParmToFix =
true;
3612 if (!AtLeastOneParmToFix)
3619 const auto NewOverloadSignatureCreator =
3620 [&
SM, &LangOpts, &NewTysTexts,
3621 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3622 std::stringstream SS;
3630 SS << Prefix->str();
3632 return std::nullopt;
3636 for (
unsigned i = 0; i < NumParms; i++) {
3644 SS << NewTysTexts[i];
3647 SS <<
' ' << II->getName().str();
3648 }
else if (
auto ParmTypeText =
3652 SS << ParmTypeText->str();
3654 return std::nullopt;
3655 if (i != NumParms - 1)
3664 const auto OldOverloadDefCreator =
3665 [&Handler, &
SM, &LangOpts, &NewTysTexts,
3666 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3667 std::stringstream SS;
3675 << FDPrefix->str() <<
"{";
3677 return std::nullopt;
3680 SS <<
"return " << FunQualName->str() <<
"(";
3682 return std::nullopt;
3686 for (
unsigned i = 0; i < NumParms; i++) {
3695 return std::nullopt;
3702 if (i != NumParms - 1)
3713 std::optional<SourceLocation> Loc =
getPastLoc(FReDecl,
SM, LangOpts);
3717 if (FReDecl->isThisDeclarationADefinition()) {
3718 assert(FReDecl == FD &&
"inconsistent function definition");
3721 if (
auto OldOverloadDef = OldOverloadDefCreator(FReDecl))
3727 if (!FReDecl->hasAttr<UnsafeBufferUsageAttr>()) {
3730 FReDecl->getBeginLoc(),
" ")));
3733 if (
auto NewOverloadDecl = NewOverloadSignatureCreator(FReDecl))
3755 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3771 std::stringstream SS;
3774 if (PteTyQualifiers)
3783 SS <<
' ' << PVDNameText->str();
3789 const DeclUseTracker &Tracker,
3792 const DeclStmt *DS = Tracker.lookupDecl(VD);
3795 " : variables declared this way not implemented yet");
3819 const QualType &ArrayEltT = CAT->getElementType();
3820 assert(!ArrayEltT.
isNull() &&
"Trying to fix a non-array type variable!");
3829 auto MaybeElemTypeTxt =
3832 if (!MaybeElemTypeTxt)
3834 const llvm::StringRef ElemTypeTxt = MaybeElemTypeTxt->trim();
3839 while (NextTok && !NextTok->is(tok::l_square) &&
3852 if (!MaybeArraySizeTxt)
3854 const llvm::StringRef ArraySizeTxt = MaybeArraySizeTxt->trim();
3855 if (ArraySizeTxt.empty()) {
3866 std::optional<StringRef> IdentText =
3875 llvm::raw_svector_ostream OS(Replacement);
3876 OS <<
"std::array<" << ElemTypeTxt <<
", " << ArraySizeTxt <<
"> "
3877 << IdentText->str();
3887 const DeclUseTracker &Tracker,
3890 const DeclStmt *DS = Tracker.lookupDecl(VD);
3891 assert(DS &&
"Fixing non-local variables not implemented yet!");
3910 const DeclUseTracker &Tracker,
ASTContext &Ctx,
3912 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD)) {
3913 auto *FD = dyn_cast<clang::FunctionDecl>(PVD->getDeclContext());
3914 if (!FD || FD != D) {
3925 if (FD->isMain() || FD->isConstexpr() ||
3932 FD->isOverloadedOperator()) {
3941 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD))
3959 llvm_unreachable(
"FixitStrategy not implemented yet!");
3961 llvm_unreachable(
"Invalid strategy!");
3963 llvm_unreachable(
"Unknown strategy!");
3971 return llvm::any_of(FixIts, [](
const FixItHint &Hint) {
3973 if (Range.getBegin().isMacroID() || Range.getEnd().isMacroID())
3990 std::map<const VarDecl *, FixItList> &FixItsForVariable,
3995 for (
const auto &[VD, Ignore] : FixItsForVariable) {
3997 if (llvm::any_of(Grp,
3998 [&FixItsForVariable](
const VarDecl *GrpMember) ->
bool {
3999 return !FixItsForVariable.count(GrpMember);
4004 ToErase.push_back(
Member);
4007 for (
auto *VarToErase : ToErase)
4008 FixItsForVariable.erase(VarToErase);
4019 std::map<const VarDecl *, FixItList> &FixItsForVariable ,
4023 FixItList FixItsSharedByParms{};
4025 std::optional<FixItList> OverloadFixes =
4028 if (OverloadFixes) {
4029 FixItsSharedByParms.append(*OverloadFixes);
4035 FixItsForVariable.erase(
Member);
4037 return FixItsSharedByParms;
4041static std::map<const VarDecl *, FixItList>
4050 std::map<const VarDecl *, FixItList> FixItsForVariable;
4055 for (
const auto &[VD, Fixables] : FixablesForAllVars.
byVar) {
4056 FixItsForVariable[VD] =
4060 if (FixItsForVariable[VD].empty()) {
4061 FixItsForVariable.erase(VD);
4064 for (
const auto &F : Fixables) {
4065 std::optional<FixItList> Fixits = F->getFixits(S);
4068 FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
4069 Fixits->begin(), Fixits->end());
4074 VD, F->getSourceLoc(),
4075 (
"gadget '" + F->getDebugName() +
"' refused to produce a fix")
4078 FixItsForVariable.erase(VD);
4097 FixItList FixItsSharedByParms{};
4099 if (
auto *FD = dyn_cast<FunctionDecl>(D))
4101 FixItsForVariable, VarGrpMgr, FD, S, Ctx, Handler);
4105 std::map<const VarDecl *, FixItList> FinalFixItsForVariable{
4108 for (
auto &[Var, Ignore] : FixItsForVariable) {
4109 bool AnyParm =
false;
4110 const auto VarGroupForVD = VarGrpMgr.
getGroupOfVar(Var, &AnyParm);
4112 for (
const VarDecl *GrpMate : VarGroupForVD) {
4115 if (FixItsForVariable.count(GrpMate))
4116 FinalFixItsForVariable[Var].append(FixItsForVariable[GrpMate]);
4120 assert(!FixItsSharedByParms.empty() &&
4121 "Should not try to fix a parameter that does not belong to a "
4123 FinalFixItsForVariable[Var].append(FixItsSharedByParms);
4130 for (
auto Iter = FinalFixItsForVariable.begin();
4131 Iter != FinalFixItsForVariable.end();)
4134 Iter = FinalFixItsForVariable.erase(Iter);
4137 return FinalFixItsForVariable;
4140template <
typename VarDeclIterTy>
4144 for (
const VarDecl *VD : UnsafeVars) {
4155 const std::vector<VarGrpTy> Groups;
4156 const std::map<const VarDecl *, unsigned> &VarGrpMap;
4157 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms;
4161 const std::vector<VarGrpTy> &Groups,
4162 const std::map<const VarDecl *, unsigned> &VarGrpMap,
4163 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms)
4164 : Groups(Groups), VarGrpMap(VarGrpMap),
4165 GrpsUnionForParms(GrpsUnionForParms) {}
4168 if (GrpsUnionForParms.contains(Var)) {
4171 return GrpsUnionForParms.getArrayRef();
4176 auto It = VarGrpMap.find(Var);
4178 if (It == VarGrpMap.end())
4180 return Groups[It->second];
4184 return GrpsUnionForParms.getArrayRef();
4189 WarningGadgetList WarningGadgets,
4190 DeclUseTracker Tracker,
4192 bool EmitSuggestions) {
4193 if (!EmitSuggestions) {
4197 for (
const auto &G : WarningGadgets) {
4198 G->handleUnsafeOperation(Handler,
false,
4204 assert(FixableGadgets.empty() &&
4205 "Fixable gadgets found but suggestions not requested!");
4211 if (!WarningGadgets.empty()) {
4215 for (
const auto &G : FixableGadgets) {
4216 for (
const auto *DRE : G->getClaimedVarUseSites()) {
4217 Tracker.claimUse(DRE);
4233 if (WarningGadgets.empty())
4241 std::map<const VarDecl *, FixItList> FixItsForVariableGroup;
4244 for (
auto it = FixablesForAllVars.
byVar.cbegin();
4245 it != FixablesForAllVars.
byVar.cend();) {
4250 (
"failed to produce fixit for '" +
4251 it->first->getNameAsString() +
4252 "' : neither local nor a parameter"));
4254 it = FixablesForAllVars.
byVar.erase(it);
4255 }
else if (it->first->getType().getCanonicalType()->isReferenceType()) {
4258 (
"failed to produce fixit for '" +
4259 it->first->getNameAsString() +
4260 "' : has a reference type"));
4262 it = FixablesForAllVars.
byVar.erase(it);
4263 }
else if (Tracker.hasUnclaimedUses(it->first)) {
4264 it = FixablesForAllVars.
byVar.erase(it);
4265 }
else if (it->first->isInitCapture()) {
4268 (
"failed to produce fixit for '" +
4269 it->first->getNameAsString() +
4270 "' : init capture"));
4272 it = FixablesForAllVars.
byVar.erase(it);
4279 for (
const auto &it : UnsafeOps.
byVar) {
4280 const VarDecl *
const UnsafeVD = it.first;
4281 auto UnclaimedDREs = Tracker.getUnclaimedUses(UnsafeVD);
4282 if (UnclaimedDREs.empty())
4286 std::string UnclaimedUseTrace =
4291 (
"failed to produce fixit for '" + UnfixedVDName +
4292 "' : has an unclaimed use\nThe unclaimed DRE trace: " +
4293 UnclaimedUseTrace));
4300 llvm::DenseMap<const VarDecl *, llvm::SetVector<const VarDecl *>>;
4301 DepMapTy DependenciesMap{};
4302 DepMapTy PtrAssignmentGraph{};
4304 for (
const auto &it : FixablesForAllVars.
byVar) {
4305 for (
const FixableGadget *fixable : it.second) {
4306 std::optional<std::pair<const VarDecl *, const VarDecl *>> ImplPair =
4307 fixable->getStrategyImplications();
4309 std::pair<const VarDecl *, const VarDecl *> Impl = std::move(*ImplPair);
4310 PtrAssignmentGraph[Impl.first].insert(Impl.second);
4332 std::set<const VarDecl *> VisitedVarsDirected{};
4333 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4334 if (VisitedVarsDirected.find(Var) == VisitedVarsDirected.end()) {
4336 std::queue<const VarDecl *> QueueDirected{};
4337 QueueDirected.push(Var);
4338 while (!QueueDirected.empty()) {
4339 const VarDecl *CurrentVar = QueueDirected.front();
4340 QueueDirected.pop();
4341 VisitedVarsDirected.insert(CurrentVar);
4342 auto AdjacentNodes = PtrAssignmentGraph[CurrentVar];
4343 for (
const VarDecl *Adj : AdjacentNodes) {
4344 if (VisitedVarsDirected.find(Adj) == VisitedVarsDirected.end()) {
4345 QueueDirected.push(Adj);
4347 DependenciesMap[Var].insert(Adj);
4348 DependenciesMap[Adj].insert(Var);
4355 std::vector<VarGrpTy> Groups;
4359 std::map<const VarDecl *, unsigned> VarGrpMap;
4361 llvm::SetVector<const VarDecl *>
4366 std::set<const VarDecl *> VisitedVars{};
4367 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4368 if (VisitedVars.find(Var) == VisitedVars.end()) {
4369 VarGrpTy &VarGroup = Groups.emplace_back();
4370 std::queue<const VarDecl *> Queue{};
4373 while (!Queue.empty()) {
4374 const VarDecl *CurrentVar = Queue.front();
4376 VisitedVars.insert(CurrentVar);
4377 VarGroup.push_back(CurrentVar);
4378 auto AdjacentNodes = DependenciesMap[CurrentVar];
4379 for (
const VarDecl *Adj : AdjacentNodes) {
4380 if (VisitedVars.find(Adj) == VisitedVars.end()) {
4386 bool HasParm =
false;
4387 unsigned GrpIdx = Groups.size() - 1;
4389 for (
const VarDecl *
V : VarGroup) {
4390 VarGrpMap[
V] = GrpIdx;
4395 GrpsUnionForParms.insert_range(VarGroup);
4417 for (
auto I = FixablesForAllVars.
byVar.begin();
4418 I != FixablesForAllVars.
byVar.end();) {
4420 if (!VisitedVars.count((*I).first)) {
4422 I = FixablesForAllVars.
byVar.erase(I);
4430 VisitedVars, [&FixablesForAllVars](
const VarDecl *
V) {
4432 return FixablesForAllVars.
byVar.count(
V);
4439 FixItsForVariableGroup =
4441 Tracker, Handler, VarGrpMgr);
4443 for (
const auto &G : UnsafeOps.
noVar) {
4444 G->handleUnsafeOperation(Handler,
false,
4448 for (
const auto &[VD, WarningGadgets] : UnsafeOps.
byVar) {
4449 auto FixItsIt = FixItsForVariableGroup.find(VD);
4451 FixItsIt != FixItsForVariableGroup.end()
4452 ? std::move(FixItsIt->second)
4455 for (
const auto &G : WarningGadgets) {
4456 G->handleUnsafeOperation(Handler,
true,
4464 bool EmitSuggestions) {
4473 if (
const auto *FD = dyn_cast<FunctionDecl>(D)) {
4477 if (
const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
4478 if (MD->getParent()->isLambda() && MD->getParent()->isLocalClass())
4483 if (FReDecl->isExternC()) {
4486 EmitSuggestions =
false;
4491 Stmts.push_back(FD->getBody());
4493 if (
const auto *ID = dyn_cast<CXXConstructorDecl>(D)) {
4495 Stmts.push_back(CI->getInit());
4499 Stmts.push_back(D->
getBody());
4502 assert(!Stmts.empty());
4504 FixableGadgetList FixableGadgets;
4505 WarningGadgetList WarningGadgets;
4506 DeclUseTracker Tracker;
4507 for (
Stmt *S : Stmts) {
4509 WarningGadgets, Tracker);
4511 applyGadgets(D, std::move(FixableGadgets), std::move(WarningGadgets),
4512 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 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 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 bool isUnsafeVaListPrintfFunc(const FunctionDecl &Node)
static bool isUnsafeSprintfFunc(const FunctionDecl &Node)
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)