28#include "llvm/ADT/APInt.h"
29#include "llvm/ADT/APSInt.h"
30#include "llvm/ADT/STLFunctionalExtras.h"
31#include "llvm/ADT/SmallSet.h"
32#include "llvm/ADT/SmallVector.h"
33#include "llvm/ADT/StringRef.h"
49 std::string VisitBinaryOperator(
const BinaryOperator *BO) {
50 return "BinaryOperator(" + BO->
getOpcodeStr().str() +
")";
53 std::string VisitUnaryOperator(
const UnaryOperator *UO) {
57 std::string VisitImplicitCastExpr(
const ImplicitCastExpr *ICE) {
64static std::string getDREAncestorString(
const DeclRefExpr *DRE,
68 StmtDebugPrinter StmtPriner;
71 SS << StmtPriner.Visit(St);
75 if (StParents.
size() > 1)
76 return "unavailable due to multiple parents";
77 if (StParents.
empty())
96 virtual bool matches(
const DynTypedNode &DynNode, ASTContext &Ctx,
97 const UnsafeBufferUsageHandler &Handler) = 0;
98 virtual ~FastMatcher() =
default;
104 template <
typename T>
const T *getNodeAs(StringRef ID)
const {
105 auto It =
Nodes.find(ID);
106 if (It ==
Nodes.end()) {
109 return It->second.get<
T>();
112 void addNode(StringRef ID,
const DynTypedNode &Node) {
Nodes[
ID] = Node; }
115 llvm::StringMap<DynTypedNode>
Nodes;
119#define SIZED_CONTAINER_OR_VIEW_LIST \
120 "span", "array", "vector", "basic_string_view", "basic_string", \
131 bool FindAll,
bool ignoreUnevaluatedContext,
133 : Matcher(&Matcher), FindAll(FindAll), Matches(
false),
134 ignoreUnevaluatedContext(ignoreUnevaluatedContext),
135 ActiveASTContext(&Context), Handler(&NewHandler) {
172 if (ignoreUnevaluatedContext)
174 return DynamicRecursiveASTVisitor::TraverseGenericSelectionExpr(Node);
180 if (ignoreUnevaluatedContext)
182 return DynamicRecursiveASTVisitor::TraverseUnaryExprOrTypeTraitExpr(Node);
186 bool TraverseQualifier)
override {
188 if (ignoreUnevaluatedContext)
190 return DynamicRecursiveASTVisitor::TraverseTypeOfExprTypeLoc(
191 Node, TraverseQualifier);
195 bool TraverseQualifier)
override {
197 if (ignoreUnevaluatedContext)
199 return DynamicRecursiveASTVisitor::TraverseDecltypeTypeLoc(
200 Node, TraverseQualifier);
205 if (ignoreUnevaluatedContext)
207 return DynamicRecursiveASTVisitor::TraverseCXXNoexceptExpr(Node);
212 if (ignoreUnevaluatedContext)
214 return DynamicRecursiveASTVisitor::TraverseCXXTypeidExpr(Node);
220 return DynamicRecursiveASTVisitor::TraverseCXXDefaultInitExpr(Node);
236 template <
typename T>
bool match(
const T &Node) {
246 FastMatcher *
const Matcher;
250 bool ignoreUnevaluatedContext;
251 ASTContext *ActiveASTContext;
252 const UnsafeBufferUsageHandler *Handler;
267 FastMatcher &Matcher) {
275 FastMatcher &Matcher) {
303 const Stmt *S,
const llvm::function_ref<
void(
const Expr *)> OnResult) {
304 if (
const auto *CE = dyn_cast<ImplicitCastExpr>(S);
305 CE && CE->getCastKind() == CastKind::CK_LValueToRValue)
306 OnResult(CE->getSubExpr());
307 if (
const auto *BO = dyn_cast<BinaryOperator>(S);
315 const Stmt *S, llvm::function_ref<
void(
const Stmt *)> InnerMatcher) {
324 if (
auto *CE = dyn_cast<CallExpr>(S)) {
325 if (
const auto *FnDecl = CE->getDirectCallee();
326 FnDecl && FnDecl->hasAttr<UnsafeBufferUsageAttr>())
335 if (
auto *CE = dyn_cast<CastExpr>(S)) {
336 if (CE->getCastKind() != CastKind::CK_PointerToIntegral &&
337 CE->getCastKind() != CastKind::CK_PointerToBoolean)
341 InnerMatcher(CE->getSubExpr());
345 if (
const auto *BO = dyn_cast<BinaryOperator>(S);
359 if (
const auto *BO = dyn_cast<BinaryOperator>(S);
365 InnerMatcher(BO->
getLHS());
366 InnerMatcher(BO->
getRHS());
384 const Stmt *S, llvm::function_ref<
void(
const Stmt *)> InnerMatcher) {
389 if (
auto *CS = dyn_cast<CompoundStmt>(S)) {
390 for (
auto *Child : CS->body())
393 if (
auto *IfS = dyn_cast<IfStmt>(S)) {
395 InnerMatcher(IfS->getThen());
397 InnerMatcher(IfS->getElse());
448 case Stmt::DeclRefExprClass:
450 case Stmt::BinaryOperatorClass: {
453 BO2->getLHS(), BO2->getOpcode(),
479 dyn_cast<CXXMemberCallExpr>(Size->IgnoreParenImpCasts())) {
480 auto *DREOfPtr = dyn_cast<DeclRefExpr>(
481 MCEPtr->getImplicitObjectArgument()->IgnoreParenImpCasts());
482 auto *DREOfSize = dyn_cast<DeclRefExpr>(
483 MCESize->getImplicitObjectArgument()->IgnoreParenImpCasts());
485 if (!DREOfPtr || !DREOfSize)
489 if (DREOfPtr->getDecl() != DREOfSize->getDecl())
491 if (MCEPtr->getMethodDecl()->getName() !=
"data")
494 if (!MCEPtr->getRecordDecl()->isInStdNamespace())
497 auto *ObjII = MCEPtr->getRecordDecl()->getIdentifier();
504 if (!((AcceptSizeBytes &&
505 MCESize->getMethodDecl()->getName() ==
"size_bytes") ||
510 MCESize->getMethodDecl()->getName() ==
"size"))
520 if (Size->EvaluateAsInt(ER, Ctx)) {
526 return llvm::APSInt::compareValues(
527 SizeInt, llvm::APSInt(CAT->getSize(),
true)) == 0;
535 return UO && UO->
getOpcode() == UnaryOperator::Opcode::UO_AddrOf;
537 auto *FnDecl = CE->getDirectCallee();
539 return FnDecl && FnDecl->getNameAsString() ==
"addressof" &&
540 FnDecl->isInStdNamespace();
568 "expecting a two-parameter std::span constructor");
571 auto HaveEqualConstantValues = [&Ctx](
const Expr *E0,
const Expr *E1) {
573 if (
auto E1CV = E1->getIntegerConstantExpr(Ctx)) {
574 return llvm::APSInt::compareValues(*E0CV, *E1CV) == 0;
578 auto AreSameDRE = [](
const Expr *E0,
const Expr *E1) {
579 if (
auto *DRE0 = dyn_cast<DeclRefExpr>(E0))
580 if (
auto *DRE1 = dyn_cast<DeclRefExpr>(E1)) {
581 return DRE0->getDecl() == DRE1->getDecl();
587 if (Arg1CV && Arg1CV->isZero())
593 case Stmt::CXXNewExprClass:
596 return AreSameDRE((*Size)->IgnoreImplicit(), Arg1) ||
597 HaveEqualConstantValues(*Size, Arg1);
602 return Arg1CV && Arg1CV->isOne();
610 if (
auto CCast = dyn_cast<CStyleCastExpr>(Arg0)) {
611 if (!CCast->getType()->isPointerType())
619 if (
const auto *
Call = dyn_cast<CallExpr>(CCast->getSubExpr())) {
621 if (
auto *AllocAttr = FD->getAttr<AllocSizeAttr>()) {
622 const Expr *EleSizeExpr =
623 Call->getArg(AllocAttr->getElemSizeParam().getASTIndex());
625 ParamIdx NumElemIdx = AllocAttr->getNumElemsParam();
632 if (
auto BO = dyn_cast<BinaryOperator>(Arg1))
639 auto IsMethodCallToSizedObject = [](
const Stmt *Node, StringRef MethodName) {
640 if (
const auto *MC = dyn_cast<CXXMemberCallExpr>(Node)) {
641 const auto *MD = MC->getMethodDecl();
642 const auto *RD = MC->getRecordDecl();
645 if (
auto *II = RD->getDeclName().getAsIdentifierInfo();
646 II && RD->isInStdNamespace())
649 MD->getName() == MethodName;
654 if (IsMethodCallToSizedObject(Arg0,
"begin") &&
655 IsMethodCallToSizedObject(Arg1,
"end"))
659 ->getImplicitObjectArgument()
660 ->IgnoreParenImpCasts(),
662 ->getImplicitObjectArgument()
663 ->IgnoreParenImpCasts());
679 if (
const auto *CATy =
680 dyn_cast<ConstantArrayType>(Node.
getBase()
684 limit = CATy->getLimitedSize();
685 }
else if (
const auto *SLiteral = dyn_cast<clang::StringLiteral>(
687 limit = SLiteral->getLength() + 1;
696 llvm::APSInt ArrIdx = EVResult.
Val.
getInt();
699 if (ArrIdx.isNonNegative() && ArrIdx.getLimitedValue() < limit)
701 }
else if (
const auto *BE = dyn_cast<BinaryOperator>(IndexExpr)) {
704 if (BE->getOpcode() != BO_And && BE->getOpcode() != BO_Rem)
707 const Expr *LHS = BE->getLHS();
708 const Expr *RHS = BE->getRHS();
710 if (BE->getOpcode() == BO_Rem) {
717 llvm::APSInt result = EVResult.
Val.
getInt();
718 if (result.isNonNegative() && result.getLimitedValue() <= limit)
729 llvm::APSInt result = EVResult.
Val.
getInt();
730 if (result.isNonNegative() && result.getLimitedValue() < limit)
754 StringRef
matchName(StringRef FunName,
bool isBuiltin) {
756 if (isBuiltin && FunName.starts_with(
"__builtin_"))
760 FunName.drop_front(10 ));
762 if (FunName.starts_with(
"__asan_"))
770 if (Name.starts_with(
"__") && Name.ends_with(
"_chk"))
772 Name.drop_front(2).drop_back(4) );
777 if (Name.ends_with(
"_s"))
778 return Name.drop_back(2 );
811 bool isKprintf =
false) {
812 class StringFormatStringHandler
816 const Expr *&UnsafeArg;
830 unsigned PArgIdx = -1;
834 if (0 < PArgIdx && PArgIdx < Call->getNumArgs()) {
835 const Expr *PArg =
Call->getArg(PArgIdx);
838 if (
auto *CE = dyn_cast<CastExpr>(PArg);
839 CE && CE->getType()->isSignedIntegerType())
840 PArg = CE->getSubExpr();
844 analyze_printf::OptionalAmount::HowSpecified::Constant) {
846 llvm::APSInt PArgVal = llvm::APSInt(
856 StringFormatStringHandler(
const CallExpr *
Call,
unsigned FmtArgIdx,
858 :
Call(
Call), FmtArgIdx(FmtArgIdx), UnsafeArg(UnsafeArg), Ctx(Ctx) {}
861 const char *startSpecifier,
862 unsigned specifierLen,
870 if (!(0 < ArgIdx && ArgIdx < Call->getNumArgs()))
874 const Expr *Arg =
Call->getArg(ArgIdx);
884 bool IsArgTypeValid =
887 ?
ArgType->getPointeeType()->isWideCharType()
888 :
ArgType->getPointeeType()->isCharType());
891 Precision && IsArgTypeValid)
895 UnsafeArg =
Call->getArg(ArgIdx);
900 const Expr *Fmt =
Call->getArg(FmtArgIdx);
905 if (SL->getCharByteWidth() == 1)
906 FmtStr = SL->getString();
907 else if (
auto EvaledFmtStr = SL->tryEvaluateString(Ctx))
908 FmtStr = *EvaledFmtStr;
910 goto CHECK_UNSAFE_PTR;
912 StringFormatStringHandler Handler(
Call, FmtArgIdx, UnsafeArg, Ctx);
915 Handler, FmtStr.begin(), FmtStr.end(), Ctx.
getLangOpts(),
923 llvm::make_range(
Call->arg_begin() + FmtArgIdx,
Call->arg_end()),
924 [&UnsafeArg](
const Expr *Arg) ->
bool {
925 if (Arg->getType()->isPointerType() && !isNullTermPointer(Arg)) {
943 static std::unique_ptr<std::set<StringRef>> PredefinedNames =
nullptr;
944 if (!PredefinedNames)
946 std::make_unique<std::set<StringRef>, std::set<StringRef>>({
1027 if (PredefinedNames->find(Name) != PredefinedNames->end())
1030 std::string NameWCS = Name.str();
1031 size_t WcsPos = NameWCS.find(
"wcs");
1033 while (WcsPos != std::string::npos) {
1034 NameWCS[WcsPos++] =
's';
1035 NameWCS[WcsPos++] =
't';
1036 NameWCS[WcsPos++] =
'r';
1037 WcsPos = NameWCS.find(
"wcs", WcsPos);
1039 if (PredefinedNames->find(NameWCS) != PredefinedNames->end())
1043 return Name.ends_with(
"scanf");
1058 if (!Name.ends_with(
"printf"))
1060 return Name.starts_with(
"v");
1074 if (!Name.ends_with(
"printf") ||
1076 Name.starts_with(
"v"))
1079 StringRef Prefix = Name.drop_back(6);
1081 if (Prefix.ends_with(
"w"))
1082 Prefix = Prefix.drop_back(1);
1083 return Prefix ==
"s";
1098 if (!Name.ends_with(
"printf") || Name.starts_with(
"v"))
1101 StringRef Prefix = Name.drop_back(6);
1103 if (Prefix.ends_with(
"w"))
1104 Prefix = Prefix.drop_back(1);
1106 return Prefix.empty() || Prefix ==
"k" || Prefix ==
"f" || Prefix ==
"sn";
1114 MatchResult &Result, llvm::StringRef Tag) {
1118 assert(FD &&
"It should have been checked that FD is non-null.");
1136 const Expr *UnsafeArg;
1147 bool isKprintf =
false;
1148 const Expr *UnsafeArg;
1151 isKprintf = II->getName() ==
"kprintf";
1165 const Expr *UnsafeArg;
1176 for (
const auto *Arg : Node.
arguments())
1191 assert(FD &&
"It should have been checked that FD is non-null.");
1206 !Size->getType()->isUnsignedIntegerType())
1235#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1238 Gadget(Kind K) : K(K) {}
1240 Kind
getKind()
const {
return K; }
1243 StringRef getDebugName()
const {
1248#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1250 llvm_unreachable(
"Unhandled Gadget::Kind enum");
1254 virtual bool isWarningGadget()
const = 0;
1257 virtual SourceLocation getSourceLoc()
const = 0;
1262 virtual DeclUseList getClaimedVarUseSites()
const = 0;
1264 virtual ~Gadget() =
default;
1272class WarningGadget :
public Gadget {
1274 WarningGadget(Kind K) : Gadget(K) {}
1276 static bool classof(
const Gadget *G) {
return G->isWarningGadget(); }
1277 bool isWarningGadget() const final {
return true; }
1279 virtual void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1280 bool IsRelatedToDecl,
1281 ASTContext &Ctx)
const = 0;
1283 virtual SmallVector<const Expr *, 1> getUnsafePtrs()
const = 0;
1290class FixableGadget :
public Gadget {
1292 FixableGadget(Kind K) : Gadget(K) {}
1294 static bool classof(
const Gadget *G) {
return !G->isWarningGadget(); }
1295 bool isWarningGadget() const final {
return false; }
1300 virtual std::optional<FixItList> getFixits(
const FixitStrategy &)
const {
1301 return std::nullopt;
1310 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1311 getStrategyImplications()
const {
1312 return std::nullopt;
1316static bool isSupportedVariable(
const DeclRefExpr &Node) {
1321using FixableGadgetList = std::vector<std::unique_ptr<FixableGadget>>;
1322using WarningGadgetList = std::vector<std::unique_ptr<WarningGadget>>;
1326class IncrementGadget :
public WarningGadget {
1327 static constexpr const char *
const OpTag =
"op";
1328 const UnaryOperator *Op;
1332 : WarningGadget(
Kind::Increment),
1333 Op(
Result.getNodeAs<UnaryOperator>(OpTag)) {}
1335 static bool classof(
const Gadget *G) {
1336 return G->getKind() == Kind::Increment;
1339 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1341 const auto *UO = dyn_cast<UnaryOperator>(S);
1346 Result.addNode(OpTag, DynTypedNode::create(*UO));
1350 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1351 bool IsRelatedToDecl,
1352 ASTContext &Ctx)
const override {
1355 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1357 DeclUseList getClaimedVarUseSites()
const override {
1358 SmallVector<const DeclRefExpr *, 2> Uses;
1359 if (
const auto *DRE =
1360 dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
1361 Uses.push_back(DRE);
1364 return std::move(Uses);
1367 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1368 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1374class DecrementGadget :
public WarningGadget {
1375 static constexpr const char *
const OpTag =
"op";
1376 const UnaryOperator *Op;
1380 : WarningGadget(
Kind::Decrement),
1381 Op(
Result.getNodeAs<UnaryOperator>(OpTag)) {}
1383 static bool classof(
const Gadget *G) {
1384 return G->getKind() == Kind::Decrement;
1387 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1389 const auto *UO = dyn_cast<UnaryOperator>(S);
1394 Result.addNode(OpTag, DynTypedNode::create(*UO));
1398 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1399 bool IsRelatedToDecl,
1400 ASTContext &Ctx)
const override {
1403 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1405 DeclUseList getClaimedVarUseSites()
const override {
1406 if (
const auto *DRE =
1407 dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
1414 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1415 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1421class ArraySubscriptGadget :
public WarningGadget {
1422 static constexpr const char *
const ArraySubscrTag =
"ArraySubscript";
1423 const ArraySubscriptExpr *ASE;
1428 ASE(
Result.getNodeAs<ArraySubscriptExpr>(ArraySubscrTag)) {}
1430 static bool classof(
const Gadget *G) {
1431 return G->getKind() == Kind::ArraySubscript;
1434 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1436 const auto *ASE = dyn_cast<ArraySubscriptExpr>(S);
1439 const auto *
const Base = ASE->getBase()->IgnoreParenImpCasts();
1442 const auto *Idx = dyn_cast<IntegerLiteral>(ASE->getIdx());
1443 bool IsSafeIndex = (Idx && Idx->getValue().isZero()) ||
1447 Result.addNode(ArraySubscrTag, DynTypedNode::create(*ASE));
1451 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1452 bool IsRelatedToDecl,
1453 ASTContext &Ctx)
const override {
1456 SourceLocation getSourceLoc()
const override {
return ASE->getBeginLoc(); }
1458 DeclUseList getClaimedVarUseSites()
const override {
1459 if (
const auto *DRE =
1460 dyn_cast<DeclRefExpr>(ASE->getBase()->IgnoreParenImpCasts())) {
1467 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1468 return {ASE->getBase()->IgnoreParenImpCasts()};
1476class PointerArithmeticGadget :
public WarningGadget {
1477 static constexpr const char *
const PointerArithmeticTag =
"ptrAdd";
1478 static constexpr const char *
const PointerArithmeticPointerTag =
"ptrAddPtr";
1479 const BinaryOperator *PA;
1484 : WarningGadget(
Kind::PointerArithmetic),
1485 PA(
Result.getNodeAs<BinaryOperator>(PointerArithmeticTag)),
1486 Ptr(
Result.getNodeAs<Expr>(PointerArithmeticPointerTag)) {}
1488 static bool classof(
const Gadget *G) {
1489 return G->getKind() == Kind::PointerArithmetic;
1492 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1494 const auto *BO = dyn_cast<BinaryOperator>(S);
1497 const auto *LHS = BO->
getLHS();
1498 const auto *RHS = BO->
getRHS();
1503 RHS->getType()->isEnumeralType())) {
1504 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*LHS));
1505 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1511 (LHS->getType()->isIntegerType() || LHS->getType()->isEnumeralType())) {
1512 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*RHS));
1513 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1519 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1520 bool IsRelatedToDecl,
1521 ASTContext &Ctx)
const override {
1524 SourceLocation getSourceLoc()
const override {
return PA->getBeginLoc(); }
1526 DeclUseList getClaimedVarUseSites()
const override {
1527 if (
const auto *DRE = dyn_cast<DeclRefExpr>(Ptr->IgnoreParenImpCasts())) {
1534 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
1535 return {Ptr->IgnoreParenImpCasts()};
1542class SpanTwoParamConstructorGadget :
public WarningGadget {
1543 static constexpr const char *
const SpanTwoParamConstructorTag =
1544 "spanTwoParamConstructor";
1545 const CXXConstructExpr *Ctor;
1549 : WarningGadget(
Kind::SpanTwoParamConstructor),
1550 Ctor(
Result.getNodeAs<CXXConstructExpr>(SpanTwoParamConstructorTag)) {}
1552 static bool classof(
const Gadget *G) {
1553 return G->getKind() == Kind::SpanTwoParamConstructor;
1557 const auto *CE = dyn_cast<CXXConstructExpr>(S);
1560 const auto *CDecl = CE->getConstructor();
1561 const auto *CRecordDecl = CDecl->getParent();
1562 auto HasTwoParamSpanCtorDecl =
1563 CRecordDecl->isInStdNamespace() &&
1564 CDecl->getDeclName().getAsString() ==
"span" && CE->getNumArgs() == 2;
1567 Result.addNode(SpanTwoParamConstructorTag, DynTypedNode::create(*CE));
1571 static bool matches(
const Stmt *S, ASTContext &Ctx,
1572 const UnsafeBufferUsageHandler *Handler,
1579 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1580 bool IsRelatedToDecl,
1581 ASTContext &Ctx)
const override {
1584 SourceLocation getSourceLoc()
const override {
return Ctor->getBeginLoc(); }
1586 DeclUseList getClaimedVarUseSites()
const override {
1589 if (
auto *DRE = dyn_cast<DeclRefExpr>(Ctor->getArg(0))) {
1596 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1603class PointerInitGadget :
public FixableGadget {
1605 static constexpr const char *
const PointerInitLHSTag =
"ptrInitLHS";
1606 static constexpr const char *
const PointerInitRHSTag =
"ptrInitRHS";
1607 const VarDecl *PtrInitLHS;
1608 const DeclRefExpr *PtrInitRHS;
1612 : FixableGadget(
Kind::PointerInit),
1613 PtrInitLHS(
Result.getNodeAs<VarDecl>(PointerInitLHSTag)),
1614 PtrInitRHS(
Result.getNodeAs<DeclRefExpr>(PointerInitRHSTag)) {}
1616 static bool classof(
const Gadget *G) {
1617 return G->getKind() == Kind::PointerInit;
1620 static bool matches(
const Stmt *S,
1621 llvm::SmallVectorImpl<MatchResult> &Results) {
1622 const DeclStmt *DS = dyn_cast<DeclStmt>(S);
1631 const auto *DRE = dyn_cast<DeclRefExpr>(
Init->IgnoreImpCasts());
1632 if (!DRE || !
hasPointerType(*DRE) || !isSupportedVariable(*DRE)) {
1636 R.addNode(PointerInitLHSTag, DynTypedNode::create(*VD));
1637 R.addNode(PointerInitRHSTag, DynTypedNode::create(*DRE));
1638 Results.emplace_back(std::move(R));
1642 virtual std::optional<FixItList>
1643 getFixits(
const FixitStrategy &S)
const override;
1644 SourceLocation getSourceLoc()
const override {
1645 return PtrInitRHS->getBeginLoc();
1648 virtual DeclUseList getClaimedVarUseSites()
const override {
1649 return DeclUseList{PtrInitRHS};
1652 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1653 getStrategyImplications()
const override {
1654 return std::make_pair(PtrInitLHS,
cast<VarDecl>(PtrInitRHS->getDecl()));
1663class PtrToPtrAssignmentGadget :
public FixableGadget {
1665 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1666 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1667 const DeclRefExpr *PtrLHS;
1668 const DeclRefExpr *PtrRHS;
1672 : FixableGadget(
Kind::PtrToPtrAssignment),
1673 PtrLHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
1674 PtrRHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
1676 static bool classof(
const Gadget *G) {
1677 return G->getKind() == Kind::PtrToPtrAssignment;
1680 static bool matches(
const Stmt *S,
1681 llvm::SmallVectorImpl<MatchResult> &Results) {
1682 size_t SizeBefore = Results.size();
1684 const auto *BO = dyn_cast<BinaryOperator>(S);
1685 if (!BO || BO->
getOpcode() != BO_Assign)
1688 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1690 !isSupportedVariable(*RHSRef)) {
1693 const auto *LHS = BO->
getLHS();
1694 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1696 !isSupportedVariable(*LHSRef)) {
1700 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
1701 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
1702 Results.emplace_back(std::move(R));
1704 return SizeBefore != Results.size();
1707 virtual std::optional<FixItList>
1708 getFixits(
const FixitStrategy &S)
const override;
1709 SourceLocation getSourceLoc()
const override {
return PtrLHS->getBeginLoc(); }
1711 virtual DeclUseList getClaimedVarUseSites()
const override {
1712 return DeclUseList{PtrLHS, PtrRHS};
1715 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1716 getStrategyImplications()
const override {
1727class CArrayToPtrAssignmentGadget :
public FixableGadget {
1729 static constexpr const char *
const PointerAssignLHSTag =
"ptrLHS";
1730 static constexpr const char *
const PointerAssignRHSTag =
"ptrRHS";
1731 const DeclRefExpr *PtrLHS;
1732 const DeclRefExpr *PtrRHS;
1736 : FixableGadget(
Kind::CArrayToPtrAssignment),
1737 PtrLHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
1738 PtrRHS(
Result.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
1740 static bool classof(
const Gadget *G) {
1741 return G->getKind() == Kind::CArrayToPtrAssignment;
1744 static bool matches(
const Stmt *S,
1745 llvm::SmallVectorImpl<MatchResult> &Results) {
1746 size_t SizeBefore = Results.size();
1748 const auto *BO = dyn_cast<BinaryOperator>(S);
1749 if (!BO || BO->
getOpcode() != BO_Assign)
1752 if (
const auto *RHSRef = dyn_cast<DeclRefExpr>(RHS);
1755 !isSupportedVariable(*RHSRef)) {
1758 const auto *LHS = BO->
getLHS();
1759 if (
const auto *LHSRef = dyn_cast<DeclRefExpr>(LHS);
1761 !isSupportedVariable(*LHSRef)) {
1765 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
1766 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
1767 Results.emplace_back(std::move(R));
1769 return SizeBefore != Results.size();
1772 virtual std::optional<FixItList>
1773 getFixits(
const FixitStrategy &S)
const override;
1774 SourceLocation getSourceLoc()
const override {
return PtrLHS->getBeginLoc(); }
1776 virtual DeclUseList getClaimedVarUseSites()
const override {
1777 return DeclUseList{PtrLHS, PtrRHS};
1780 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1781 getStrategyImplications()
const override {
1788class UnsafeBufferUsageAttrGadget :
public WarningGadget {
1789 constexpr static const char *
const OpTag =
"attr_expr";
1794 : WarningGadget(
Kind::UnsafeBufferUsageAttr),
1795 Op(
Result.getNodeAs<Expr>(OpTag)) {}
1797 static bool classof(
const Gadget *G) {
1798 return G->getKind() == Kind::UnsafeBufferUsageAttr;
1801 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1803 if (
auto *CE = dyn_cast<CallExpr>(S)) {
1804 if (CE->getDirectCallee() &&
1805 CE->getDirectCallee()->hasAttr<UnsafeBufferUsageAttr>()) {
1806 Result.addNode(OpTag, DynTypedNode::create(*CE));
1810 if (
auto *ME = dyn_cast<MemberExpr>(S)) {
1813 if (ME->getMemberDecl()->hasAttr<UnsafeBufferUsageAttr>()) {
1814 Result.addNode(OpTag, DynTypedNode::create(*ME));
1821 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1822 bool IsRelatedToDecl,
1823 ASTContext &Ctx)
const override {
1826 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1828 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1830 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1836class UnsafeBufferUsageCtorAttrGadget :
public WarningGadget {
1837 constexpr static const char *
const OpTag =
"cxx_construct_expr";
1838 const CXXConstructExpr *Op;
1842 : WarningGadget(
Kind::UnsafeBufferUsageCtorAttr),
1843 Op(
Result.getNodeAs<CXXConstructExpr>(OpTag)) {}
1845 static bool classof(
const Gadget *G) {
1846 return G->getKind() == Kind::UnsafeBufferUsageCtorAttr;
1850 const auto *CE = dyn_cast<CXXConstructExpr>(S);
1851 if (!CE || !CE->getConstructor()->hasAttr<UnsafeBufferUsageAttr>())
1855 if (SpanTwoParamConstructorGadget::matches(CE, Ctx, Tmp))
1857 Result.addNode(OpTag, DynTypedNode::create(*CE));
1861 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1862 bool IsRelatedToDecl,
1863 ASTContext &Ctx)
const override {
1866 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1868 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1870 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1877class DataInvocationGadget :
public WarningGadget {
1878 constexpr static const char *
const OpTag =
"data_invocation_expr";
1879 const ExplicitCastExpr *Op;
1883 : WarningGadget(
Kind::DataInvocation),
1884 Op(
Result.getNodeAs<ExplicitCastExpr>(OpTag)) {}
1886 static bool classof(
const Gadget *G) {
1887 return G->getKind() == Kind::DataInvocation;
1890 static bool matches(
const Stmt *S,
const ASTContext &Ctx,
1892 auto *CE = dyn_cast<ExplicitCastExpr>(S);
1895 for (
auto *Child : CE->children()) {
1896 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(Child);
1897 MCE && isDataFunction(MCE)) {
1898 Result.addNode(OpTag, DynTypedNode::create(*CE));
1901 if (
auto *
Paren = dyn_cast<ParenExpr>(Child)) {
1902 if (
auto *MCE = dyn_cast<CXXMemberCallExpr>(
Paren->getSubExpr());
1903 MCE && isDataFunction(MCE)) {
1904 Result.addNode(OpTag, DynTypedNode::create(*CE));
1912 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1913 bool IsRelatedToDecl,
1914 ASTContext &Ctx)
const override {
1917 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
1919 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
1922 static bool isDataFunction(
const CXXMemberCallExpr *call) {
1929 if (method->getNameAsString() ==
"data" &&
1930 method->getParent()->isInStdNamespace() &&
1931 llvm::is_contained({SIZED_CONTAINER_OR_VIEW_LIST},
1932 method->getParent()->getName()))
1937 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
1940class UnsafeLibcFunctionCallGadget :
public WarningGadget {
1941 const CallExpr *
const Call;
1942 const Expr *UnsafeArg =
nullptr;
1943 constexpr static const char *
const Tag =
"UnsafeLibcFunctionCall";
1945 constexpr static const char *
const UnsafeSprintfTag =
1946 "UnsafeLibcFunctionCall_sprintf";
1947 constexpr static const char *
const UnsafeSizedByTag =
1948 "UnsafeLibcFunctionCall_sized_by";
1949 constexpr static const char *
const UnsafeStringTag =
1950 "UnsafeLibcFunctionCall_string";
1951 constexpr static const char *
const UnsafeVaListTag =
1952 "UnsafeLibcFunctionCall_va_list";
1964 } WarnedFunKind = OTHERS;
1968 : WarningGadget(
Kind::UnsafeLibcFunctionCall),
1969 Call(
Result.getNodeAs<CallExpr>(Tag)) {
1970 if (
Result.getNodeAs<Decl>(UnsafeSprintfTag))
1971 WarnedFunKind = SPRINTF;
1972 else if (
auto *E =
Result.getNodeAs<Expr>(UnsafeStringTag)) {
1973 WarnedFunKind = STRING;
1975 }
else if (
Result.getNodeAs<CallExpr>(UnsafeSizedByTag)) {
1976 WarnedFunKind = SIZED_BY;
1977 UnsafeArg = Call->getArg(0);
1978 }
else if (
Result.getNodeAs<Decl>(UnsafeVaListTag))
1979 WarnedFunKind = VA_LIST;
1982 static bool matches(
const Stmt *S, ASTContext &Ctx,
1983 const UnsafeBufferUsageHandler *Handler,
1987 auto *CE = dyn_cast<CallExpr>(S);
1988 if (!CE || !CE->getDirectCallee())
1990 const auto *FD = dyn_cast<FunctionDecl>(CE->getDirectCallee());
1994 bool IsGlobalAndNotInAnyNamespace =
1995 FD->isGlobal() && !FD->getEnclosingNamespaceContext()->isNamespace();
1999 if (!FD->isInStdNamespace() && !IsGlobalAndNotInAnyNamespace)
2001 auto isSingleStringLiteralArg =
false;
2002 if (CE->getNumArgs() == 1) {
2003 isSingleStringLiteralArg =
2006 if (!isSingleStringLiteralArg) {
2009 Result.addNode(Tag, DynTypedNode::create(*CE));
2013 Result.addNode(Tag, DynTypedNode::create(*CE));
2014 Result.addNode(UnsafeVaListTag, DynTypedNode::create(*FD));
2018 Result.addNode(Tag, DynTypedNode::create(*CE));
2019 Result.addNode(UnsafeSprintfTag, DynTypedNode::create(*FD));
2025 Result.addNode(Tag, DynTypedNode::create(*CE));
2026 Result.addNode(UnsafeSizedByTag, DynTypedNode::create(*CE));
2031 Result.addNode(Tag, DynTypedNode::create(*CE));
2038 const Stmt *getBaseStmt()
const {
return Call; }
2040 SourceLocation getSourceLoc()
const override {
return Call->getBeginLoc(); }
2042 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2043 bool IsRelatedToDecl,
2044 ASTContext &Ctx)
const override {
2048 DeclUseList getClaimedVarUseSites()
const override {
return {}; }
2050 SmallVector<const Expr *, 1> getUnsafePtrs()
const override {
return {}; }
2056class ULCArraySubscriptGadget :
public FixableGadget {
2058 static constexpr const char *
const ULCArraySubscriptTag =
2059 "ArraySubscriptUnderULC";
2060 const ArraySubscriptExpr *Node;
2064 : FixableGadget(
Kind::ULCArraySubscript),
2065 Node(
Result.getNodeAs<ArraySubscriptExpr>(ULCArraySubscriptTag)) {
2066 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2069 static bool classof(
const Gadget *G) {
2070 return G->getKind() == Kind::ULCArraySubscript;
2073 static bool matches(
const Stmt *S,
2074 llvm::SmallVectorImpl<MatchResult> &Results) {
2075 size_t SizeBefore = Results.size();
2077 const auto *ASE = dyn_cast<ArraySubscriptExpr>(E);
2083 !isSupportedVariable(*DRE))
2086 R.addNode(ULCArraySubscriptTag, DynTypedNode::create(*ASE));
2087 Results.emplace_back(std::move(R));
2089 return SizeBefore != Results.size();
2092 virtual std::optional<FixItList>
2093 getFixits(
const FixitStrategy &S)
const override;
2094 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2096 virtual DeclUseList getClaimedVarUseSites()
const override {
2097 if (
const auto *DRE =
2098 dyn_cast<DeclRefExpr>(Node->getBase()->IgnoreImpCasts())) {
2108class UPCStandalonePointerGadget :
public FixableGadget {
2110 static constexpr const char *
const DeclRefExprTag =
"StandalonePointer";
2111 const DeclRefExpr *Node;
2115 : FixableGadget(
Kind::UPCStandalonePointer),
2116 Node(
Result.getNodeAs<DeclRefExpr>(DeclRefExprTag)) {
2117 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2120 static bool classof(
const Gadget *G) {
2121 return G->getKind() == Kind::UPCStandalonePointer;
2124 static bool matches(
const Stmt *S,
2125 llvm::SmallVectorImpl<MatchResult> &Results) {
2126 size_t SizeBefore = Results.size();
2128 auto *E = dyn_cast<Expr>(S);
2133 !isSupportedVariable(*DRE))
2136 R.addNode(DeclRefExprTag, DynTypedNode::create(*DRE));
2137 Results.emplace_back(std::move(R));
2139 return SizeBefore != Results.size();
2142 virtual std::optional<FixItList>
2143 getFixits(
const FixitStrategy &S)
const override;
2144 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2146 virtual DeclUseList getClaimedVarUseSites()
const override {
return {Node}; }
2149class PointerDereferenceGadget :
public FixableGadget {
2150 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2151 static constexpr const char *
const OperatorTag =
"op";
2153 const DeclRefExpr *BaseDeclRefExpr =
nullptr;
2154 const UnaryOperator *Op =
nullptr;
2158 : FixableGadget(
Kind::PointerDereference),
2159 BaseDeclRefExpr(
Result.getNodeAs<DeclRefExpr>(BaseDeclRefExprTag)),
2160 Op(
Result.getNodeAs<UnaryOperator>(OperatorTag)) {}
2162 static bool classof(
const Gadget *G) {
2163 return G->getKind() == Kind::PointerDereference;
2166 static bool matches(
const Stmt *S,
2167 llvm::SmallVectorImpl<MatchResult> &Results) {
2168 size_t SizeBefore = Results.size();
2170 const auto *UO = dyn_cast<UnaryOperator>(S);
2173 const auto *CE = dyn_cast<Expr>(UO->
getSubExpr());
2176 CE = CE->IgnoreParenImpCasts();
2177 const auto *DRE = dyn_cast<DeclRefExpr>(CE);
2178 if (!DRE || !isSupportedVariable(*DRE))
2181 R.addNode(BaseDeclRefExprTag, DynTypedNode::create(*DRE));
2182 R.addNode(OperatorTag, DynTypedNode::create(*UO));
2183 Results.emplace_back(std::move(R));
2185 return SizeBefore != Results.size();
2188 DeclUseList getClaimedVarUseSites()
const override {
2189 return {BaseDeclRefExpr};
2192 virtual std::optional<FixItList>
2193 getFixits(
const FixitStrategy &S)
const override;
2194 SourceLocation getSourceLoc()
const override {
return Op->getBeginLoc(); }
2200class UPCAddressofArraySubscriptGadget :
public FixableGadget {
2202 static constexpr const char *
const UPCAddressofArraySubscriptTag =
2203 "AddressofArraySubscriptUnderUPC";
2204 const UnaryOperator *Node;
2208 : FixableGadget(
Kind::ULCArraySubscript),
2209 Node(
Result.getNodeAs<UnaryOperator>(UPCAddressofArraySubscriptTag)) {
2210 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2213 static bool classof(
const Gadget *G) {
2214 return G->getKind() == Kind::UPCAddressofArraySubscript;
2217 static bool matches(
const Stmt *S,
2218 llvm::SmallVectorImpl<MatchResult> &Results) {
2219 size_t SizeBefore = Results.size();
2221 auto *E = dyn_cast<Expr>(S);
2225 if (!UO || UO->
getOpcode() != UO_AddrOf)
2227 const auto *ASE = dyn_cast<ArraySubscriptExpr>(UO->
getSubExpr());
2232 if (!DRE || !isSupportedVariable(*DRE))
2235 R.addNode(UPCAddressofArraySubscriptTag, DynTypedNode::create(*UO));
2236 Results.emplace_back(std::move(R));
2238 return SizeBefore != Results.size();
2241 virtual std::optional<FixItList>
2242 getFixits(
const FixitStrategy &)
const override;
2243 SourceLocation getSourceLoc()
const override {
return Node->getBeginLoc(); }
2245 virtual DeclUseList getClaimedVarUseSites()
const override {
2258class DeclUseTracker {
2259 using UseSetTy = llvm::SmallPtrSet<const DeclRefExpr *, 16>;
2260 using DefMapTy = llvm::DenseMap<const VarDecl *, const DeclStmt *>;
2263 std::unique_ptr<UseSetTy> Uses{std::make_unique<UseSetTy>()};
2267 DeclUseTracker() =
default;
2268 DeclUseTracker(
const DeclUseTracker &) =
delete;
2269 DeclUseTracker &operator=(
const DeclUseTracker &) =
delete;
2270 DeclUseTracker(DeclUseTracker &&) =
default;
2271 DeclUseTracker &operator=(DeclUseTracker &&) =
default;
2274 void discoverUse(
const DeclRefExpr *DRE) { Uses->insert(DRE); }
2277 void claimUse(
const DeclRefExpr *DRE) {
2278 assert(Uses->count(DRE) &&
2279 "DRE not found or claimed by multiple matchers!");
2284 bool hasUnclaimedUses(
const VarDecl *VD)
const {
2286 return any_of(*Uses, [VD](
const DeclRefExpr *DRE) {
2291 UseSetTy getUnclaimedUses(
const VarDecl *VD)
const {
2293 for (
auto use : *Uses) {
2295 ReturnSet.insert(use);
2301 void discoverDecl(
const DeclStmt *DS) {
2302 for (
const Decl *D : DS->
decls()) {
2303 if (
const auto *VD = dyn_cast<VarDecl>(D)) {
2314 const DeclStmt *lookupDecl(
const VarDecl *VD)
const {
2315 return Defs.lookup(VD);
2324 static constexpr const char *
const UPCPreIncrementTag =
2325 "PointerPreIncrementUnderUPC";
2330 : FixableGadget(Kind::UPCPreIncrement),
2332 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2336 return G->getKind() == Kind::UPCPreIncrement;
2345 size_t SizeBefore = Results.size();
2347 auto *E = dyn_cast<Expr>(S);
2351 if (!UO || UO->
getOpcode() != UO_PreInc)
2353 const auto *DRE = dyn_cast<DeclRefExpr>(UO->
getSubExpr());
2354 if (!DRE || !isSupportedVariable(*DRE))
2358 Results.emplace_back(std::move(R));
2360 return SizeBefore != Results.size();
2363 virtual std::optional<FixItList>
2368 return {dyn_cast<DeclRefExpr>(Node->getSubExpr())};
2376 static constexpr const char *
const UUCAddAssignTag =
2377 "PointerAddAssignUnderUUC";
2378 static constexpr const char *
const OffsetTag =
"Offset";
2381 const Expr *Offset =
nullptr;
2385 : FixableGadget(Kind::UUCAddAssign),
2388 assert(Node !=
nullptr &&
"Expecting a non-null matching result");
2392 return G->getKind() == Kind::UUCAddAssign;
2397 size_t SizeBefore = Results.size();
2399 const auto *E = dyn_cast<Expr>(S);
2403 if (!BO || BO->
getOpcode() != BO_AddAssign)
2405 const auto *DRE = dyn_cast<DeclRefExpr>(BO->
getLHS());
2411 Results.emplace_back(std::move(R));
2413 return SizeBefore != Results.size();
2416 virtual std::optional<FixItList>
2421 return {dyn_cast<DeclRefExpr>(Node->getLHS())};
2428 static constexpr const char *
const BaseDeclRefExprTag =
"BaseDRE";
2429 static constexpr const char *
const DerefOpTag =
"DerefOp";
2430 static constexpr const char *
const AddOpTag =
"AddOp";
2431 static constexpr const char *
const OffsetTag =
"Offset";
2440 : FixableGadget(Kind::DerefSimplePtrArithFixable),
2448 auto IsPtr = [](
const Expr *E, MatchResult &R) {
2452 if (!DRE || !isSupportedVariable(*DRE))
2457 const auto IsPlusOverPtrAndInteger = [&IsPtr](
const Expr *E,
2459 const auto *BO = dyn_cast<BinaryOperator>(E);
2463 const auto *LHS = BO->
getLHS();
2464 const auto *RHS = BO->
getRHS();
2477 size_t SizeBefore = Results.size();
2478 const auto InnerMatcher = [&IsPlusOverPtrAndInteger,
2479 &Results](
const Expr *E) {
2480 const auto *UO = dyn_cast<UnaryOperator>(E);
2486 if (IsPlusOverPtrAndInteger(Operand, R)) {
2488 Results.emplace_back(std::move(R));
2492 return SizeBefore != Results.size();
2495 virtual std::optional<FixItList>
2498 return DerefOp->getBeginLoc();
2502 return {BaseDeclRefExpr};
2510 : WarningGadgets(WarningGadgets) {}
2519#define WARNING_GADGET(name) \
2520 if (name##Gadget::matches(S, Ctx, Result) && \
2521 notInSafeBufferOptOut(*S, &Handler)) { \
2522 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2525#define WARNING_OPTIONAL_GADGET(name) \
2526 if (name##Gadget::matches(S, Ctx, &Handler, Result) && \
2527 notInSafeBufferOptOut(*S, &Handler)) { \
2528 WarningGadgets.push_back(std::make_unique<name##Gadget>(Result)); \
2531#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2536 WarningGadgetList &WarningGadgets;
2543 DeclUseTracker &Tracker)
2544 : FixableGadgets(FixableGadgets), Tracker(Tracker) {}
2548 bool matchFound =
false;
2555#define FIXABLE_GADGET(name) \
2556 if (name##Gadget::matches(S, Results)) { \
2557 for (const auto &R : Results) { \
2558 FixableGadgets.push_back(std::make_unique<name##Gadget>(R)); \
2559 matchFound = true; \
2563#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2566 if (
auto *DRE = findDeclRefExpr(S); DRE) {
2567 Tracker.discoverUse(DRE);
2573 if (
auto *DS = findDeclStmt(S); DS) {
2574 Tracker.discoverDecl(DS);
2582 const auto *DRE = dyn_cast<DeclRefExpr>(S);
2590 const DeclStmt *findDeclStmt(
const Stmt *S) {
2591 const auto *DS = dyn_cast<DeclStmt>(S);
2596 FixableGadgetList &FixableGadgets;
2597 DeclUseTracker &Tracker;
2603 bool EmitSuggestions, FixableGadgetList &FixableGadgets,
2604 WarningGadgetList &WarningGadgets,
2605 DeclUseTracker &Tracker) {
2608 if (EmitSuggestions) {
2617 return N1->getBeginLoc().getRawEncoding() <
2618 N2->getBeginLoc().getRawEncoding();
2628 const Expr *UnsafeArg =
nullptr)
override {}
2650 FixableGadgetList FixableGadgets;
2651 WarningGadgetList WarningGadgets;
2652 DeclUseTracker Tracker;
2653 MockReporter IgnoreHandler;
2656 FixableGadgets, WarningGadgets, Tracker);
2658 std::set<const Expr *>
Result;
2659 for (
auto &G : WarningGadgets) {
2660 for (
const Expr *E : G->getUnsafePtrs()) {
2669 std::map<const VarDecl *, std::set<const WarningGadget *>,
2683 for (
auto &G : AllUnsafeOperations) {
2684 DeclUseList ClaimedVarUseSites = G->getClaimedVarUseSites();
2686 bool AssociatedWithVarDecl =
false;
2687 for (
const DeclRefExpr *DRE : ClaimedVarUseSites) {
2688 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2689 result.
byVar[VD].insert(G.get());
2690 AssociatedWithVarDecl =
true;
2694 if (!AssociatedWithVarDecl) {
2695 result.
noVar.push_back(G.get());
2703 std::map<const VarDecl *, std::set<const FixableGadget *>,
2713 for (
auto &F : AllFixableOperations) {
2714 DeclUseList DREs = F->getClaimedVarUseSites();
2717 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2718 FixablesForUnsafeVars.
byVar[VD].insert(F.get());
2722 return FixablesForUnsafeVars;
2729 std::vector<const FixItHint *>
All;
2733 std::sort(
All.begin(),
All.end(),
2735 return SM.isBeforeInTranslationUnit(H1->RemoveRange.getBegin(),
2736 H2->RemoveRange.getBegin());
2744 Hint->RemoveRange.getBegin())) {
2756std::optional<FixItList>
2757PtrToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
2760 switch (S.
lookup(LeftVD)) {
2764 return std::nullopt;
2766 return std::nullopt;
2769 return std::nullopt;
2771 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2773 return std::nullopt;
2777static inline std::optional<FixItList>
createDataFixit(
const ASTContext &Ctx,
2778 const DeclRefExpr *DRE);
2780std::optional<FixItList>
2781CArrayToPtrAssignmentGadget::getFixits(
const FixitStrategy &S)
const {
2800 if (S.
lookup(LeftVD) == FixitStrategy::Kind::Span) {
2801 if (S.
lookup(RightVD) == FixitStrategy::Kind::Wontfix) {
2804 }
else if (S.
lookup(LeftVD) == FixitStrategy::Kind::Wontfix) {
2805 if (S.
lookup(RightVD) == FixitStrategy::Kind::Array) {
2809 return std::nullopt;
2812std::optional<FixItList>
2813PointerInitGadget::getFixits(
const FixitStrategy &S)
const {
2814 const auto *LeftVD = PtrInitLHS;
2816 switch (S.
lookup(LeftVD)) {
2817 case FixitStrategy::Kind::Span:
2818 if (S.
lookup(RightVD) == FixitStrategy::Kind::Span)
2820 return std::nullopt;
2821 case FixitStrategy::Kind::Wontfix:
2822 return std::nullopt;
2823 case FixitStrategy::Kind::Iterator:
2824 case FixitStrategy::Kind::Array:
2825 return std::nullopt;
2826 case FixitStrategy::Kind::Vector:
2827 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2829 return std::nullopt;
2835 if (ConstVal->isNegative())
2842std::optional<FixItList>
2843ULCArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
2844 if (
const auto *DRE =
2846 if (
const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl())) {
2848 case FixitStrategy::Kind::Span: {
2852 const ASTContext &Ctx =
2855 return std::nullopt;
2859 case FixitStrategy::Kind::Array:
2861 case FixitStrategy::Kind::Wontfix:
2862 case FixitStrategy::Kind::Iterator:
2863 case FixitStrategy::Kind::Vector:
2864 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2867 return std::nullopt;
2870static std::optional<FixItList>
2873std::optional<FixItList>
2874UPCAddressofArraySubscriptGadget::getFixits(
const FixitStrategy &S)
const {
2875 auto DREs = getClaimedVarUseSites();
2879 case FixitStrategy::Kind::Span:
2881 case FixitStrategy::Kind::Wontfix:
2882 case FixitStrategy::Kind::Iterator:
2883 case FixitStrategy::Kind::Array:
2884 return std::nullopt;
2885 case FixitStrategy::Kind::Vector:
2886 llvm_unreachable(
"unsupported strategies for FixableGadgets");
2888 return std::nullopt;
2893 static const char *
const EOL =
"\n";
2900 std::string
s = std::string(
"<# ");
2901 s += HintTextToUser;
2907template <
typename NodeTy>
2908static std::optional<SourceLocation>
2911 if (
unsigned TkLen =
2918 return std::nullopt;
2931 bool AttrRangeOverlapping = llvm::any_of(VD->
attrs(), [&](
Attr *At) ->
bool {
2932 return !(SM.isBeforeInTranslationUnit(At->getRange().getEnd(),
2933 VD->getBeginLoc())) &&
2934 !(SM.isBeforeInTranslationUnit(VD->getEndLoc(),
2935 At->getRange().getBegin()));
2939 AttrRangeOverlapping;
2981 std::optional<Qualifiers> Quals = std::nullopt) {
2982 const char *
const SpanOpen =
"std::span<";
2985 return SpanOpen + EltTyText.str() +
' ' + Quals->getAsString() +
'>';
2986 return SpanOpen + EltTyText.str() +
'>';
2989std::optional<FixItList>
2991 const VarDecl *VD = dyn_cast<VarDecl>(BaseDeclRefExpr->getDecl());
2996 if (
auto ConstVal = Offset->getIntegerConstantExpr(Ctx))
2997 if (ConstVal->isNegative())
2998 return std::nullopt;
3019 const Expr *LHS = AddOp->getLHS(), *RHS = AddOp->getRHS();
3026 std::optional<SourceLocation> LHSLocation =
getPastLoc(LHS,
SM, LangOpts);
3028 return std::nullopt;
3033 std::optional<SourceLocation> AddOpLocation =
3035 std::optional<SourceLocation> DerefOpLocation =
3038 if (!AddOpLocation || !DerefOpLocation)
3039 return std::nullopt;
3049 return std::nullopt;
3052std::optional<FixItList>
3053PointerDereferenceGadget::getFixits(
const FixitStrategy &S)
const {
3064 if (
auto LocPastOperand =
3071 case FixitStrategy::Kind::Iterator:
3072 case FixitStrategy::Kind::Array:
3073 return std::nullopt;
3074 case FixitStrategy::Kind::Vector:
3075 llvm_unreachable(
"FixitStrategy not implemented yet!");
3076 case FixitStrategy::Kind::Wontfix:
3077 llvm_unreachable(
"Invalid strategy!");
3080 return std::nullopt;
3087 std::optional<SourceLocation> EndOfOperand =
3093 return std::nullopt;
3098std::optional<FixItList>
3099UPCStandalonePointerGadget::getFixits(
const FixitStrategy &S)
const {
3102 case FixitStrategy::Kind::Array:
3103 case FixitStrategy::Kind::Span: {
3108 case FixitStrategy::Kind::Wontfix:
3109 case FixitStrategy::Kind::Iterator:
3110 return std::nullopt;
3111 case FixitStrategy::Kind::Vector:
3112 llvm_unreachable(
"unsupported strategies for FixableGadgets");
3115 return std::nullopt;
3120static std::optional<FixItList>
3127 const Expr *Idx = ArraySub->getIdx();
3130 std::stringstream SS;
3131 bool IdxIsLitZero =
false;
3134 if ((*ICE).isZero())
3135 IdxIsLitZero =
true;
3136 std::optional<StringRef> DreString =
getExprText(DRE,
SM, LangOpts);
3138 return std::nullopt;
3142 SS << (*DreString).str() <<
".data()";
3144 std::optional<StringRef> IndexString =
getExprText(Idx,
SM, LangOpts);
3146 return std::nullopt;
3148 SS <<
"&" << (*DreString).str() <<
".data()"
3149 <<
"[" << (*IndexString).str() <<
"]";
3155std::optional<FixItList>
3159 if (DREs.size() != 1)
3160 return std::nullopt;
3162 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3166 const Stmt *AddAssignNode = Node;
3167 StringRef varName = VD->
getName();
3171 return std::nullopt;
3175 (Offset->IgnoreParens()->getBeginLoc() == Offset->getBeginLoc());
3176 std::string SS = varName.str() +
" = " + varName.str() +
".subspan";
3180 std::optional<SourceLocation> AddAssignLocation =
getEndCharLoc(
3182 if (!AddAssignLocation)
3183 return std::nullopt;
3190 Offset->getEndLoc().getLocWithOffset(1),
")"));
3194 return std::nullopt;
3197std::optional<FixItList>
3201 if (DREs.size() != 1)
3202 return std::nullopt;
3204 if (
const VarDecl *VD = dyn_cast<VarDecl>(DREs.front()->getDecl())) {
3207 std::stringstream SS;
3208 StringRef varName = VD->
getName();
3212 SS <<
"(" << varName.data() <<
" = " << varName.data()
3213 <<
".subspan(1)).data()";
3214 std::optional<SourceLocation> PreIncLocation =
3216 if (!PreIncLocation)
3217 return std::nullopt;
3220 SourceRange(Node->getBeginLoc(), *PreIncLocation), SS.str()));
3224 return std::nullopt;
3242static std::optional<FixItList>
3244 const StringRef UserFillPlaceHolder) {
3252 if (
Init->isNullPointerConstant(
3257 NPC_ValueDependentIsNotNull)) {
3258 std::optional<SourceLocation> InitLocation =
3261 return std::nullopt;
3269 std::string ExtentText = UserFillPlaceHolder.data();
3270 StringRef One =
"1";
3275 if (
auto CxxNew = dyn_cast<CXXNewExpr>(
Init->IgnoreImpCasts())) {
3280 if (
const Expr *Ext = CxxNew->getArraySize().value_or(
nullptr)) {
3281 if (!Ext->HasSideEffects(Ctx)) {
3282 std::optional<StringRef> ExtentString =
getExprText(Ext,
SM, LangOpts);
3284 return std::nullopt;
3285 ExtentText = *ExtentString;
3287 }
else if (!CxxNew->isArray())
3299 if (
auto AddrOfExpr = dyn_cast<UnaryOperator>(
Init->IgnoreImpCasts()))
3300 if (AddrOfExpr->getOpcode() == UnaryOperatorKind::UO_AddrOf &&
3301 isa_and_present<DeclRefExpr>(AddrOfExpr->getSubExpr()))
3308 std::optional<SourceLocation> LocPassInit =
getPastLoc(
Init,
SM, LangOpts);
3311 return std::nullopt;
3313 StrBuffer.append(
", ");
3314 StrBuffer.append(ExtentText);
3315 StrBuffer.append(
"}");
3321#define DEBUG_NOTE_DECL_FAIL(D, Msg) \
3322 Handler.addDebugNoteForVar((D), (D)->getBeginLoc(), \
3323 "failed to produce fixit for declaration '" + \
3324 (D)->getNameAsString() + "'" + (Msg))
3326#define DEBUG_NOTE_DECL_FAIL(D, Msg)
3332static std::optional<std::string>
3336 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3341 return std::nullopt;
3343 std::string SpanTyText =
"std::span<";
3345 SpanTyText.append(*PteTyText);
3347 if (PteTyQualifiers) {
3348 SpanTyText.append(
" ");
3349 SpanTyText.append(PteTyQualifiers->getAsString());
3351 SpanTyText.append(
">");
3370 const StringRef UserFillPlaceHolder,
3384 std::stringstream SS;
3389 std::optional<FixItList> InitFixIts =
3393 FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts->begin()),
3394 std::make_move_iterator(InitFixIts->end()));
3401 if (!EndLocForReplacement.
isValid()) {
3451static std::optional<FixItList>
3457 return std::nullopt;
3462 std::vector<std::string> NewTysTexts(NumParms);
3463 std::vector<bool> ParmsMask(NumParms,
false);
3464 bool AtLeastOneParmToFix =
false;
3466 for (
unsigned i = 0; i < NumParms; i++) {
3473 return std::nullopt;
3475 std::optional<Qualifiers> PteTyQuals = std::nullopt;
3476 std::optional<std::string> PteTyText =
3481 return std::nullopt;
3485 ParmsMask[i] =
true;
3486 AtLeastOneParmToFix =
true;
3488 if (!AtLeastOneParmToFix)
3495 const auto NewOverloadSignatureCreator =
3496 [&
SM, &LangOpts, &NewTysTexts,
3497 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3498 std::stringstream SS;
3506 SS << Prefix->str();
3508 return std::nullopt;
3512 for (
unsigned i = 0; i < NumParms; i++) {
3520 SS << NewTysTexts[i];
3523 SS <<
' ' << II->getName().str();
3524 }
else if (
auto ParmTypeText =
3528 SS << ParmTypeText->str();
3530 return std::nullopt;
3531 if (i != NumParms - 1)
3540 const auto OldOverloadDefCreator =
3541 [&Handler, &
SM, &LangOpts, &NewTysTexts,
3542 &ParmsMask](
const FunctionDecl *FD) -> std::optional<std::string> {
3543 std::stringstream SS;
3551 << FDPrefix->str() <<
"{";
3553 return std::nullopt;
3556 SS <<
"return " << FunQualName->str() <<
"(";
3558 return std::nullopt;
3562 for (
unsigned i = 0; i < NumParms; i++) {
3571 return std::nullopt;
3578 if (i != NumParms - 1)
3589 std::optional<SourceLocation> Loc =
getPastLoc(FReDecl,
SM, LangOpts);
3593 if (FReDecl->isThisDeclarationADefinition()) {
3594 assert(FReDecl == FD &&
"inconsistent function definition");
3597 if (
auto OldOverloadDef = OldOverloadDefCreator(FReDecl))
3603 if (!FReDecl->hasAttr<UnsafeBufferUsageAttr>()) {
3606 FReDecl->getBeginLoc(),
" ")));
3609 if (
auto NewOverloadDecl = NewOverloadSignatureCreator(FReDecl))
3631 std::optional<Qualifiers> PteTyQualifiers = std::nullopt;
3647 std::stringstream SS;
3650 if (PteTyQualifiers)
3659 SS <<
' ' << PVDNameText->str();
3665 const DeclUseTracker &Tracker,
3668 const DeclStmt *DS = Tracker.lookupDecl(VD);
3671 " : variables declared this way not implemented yet");
3695 const QualType &ArrayEltT = CAT->getElementType();
3696 assert(!ArrayEltT.
isNull() &&
"Trying to fix a non-array type variable!");
3705 auto MaybeElemTypeTxt =
3708 if (!MaybeElemTypeTxt)
3710 const llvm::StringRef ElemTypeTxt = MaybeElemTypeTxt->trim();
3715 while (NextTok && !NextTok->is(tok::l_square) &&
3728 if (!MaybeArraySizeTxt)
3730 const llvm::StringRef ArraySizeTxt = MaybeArraySizeTxt->trim();
3731 if (ArraySizeTxt.empty()) {
3742 std::optional<StringRef> IdentText =
3751 llvm::raw_svector_ostream OS(Replacement);
3752 OS <<
"std::array<" << ElemTypeTxt <<
", " << ArraySizeTxt <<
"> "
3753 << IdentText->str();
3763 const DeclUseTracker &Tracker,
3766 const DeclStmt *DS = Tracker.lookupDecl(VD);
3767 assert(DS &&
"Fixing non-local variables not implemented yet!");
3786 const DeclUseTracker &Tracker,
ASTContext &Ctx,
3788 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD)) {
3789 auto *FD = dyn_cast<clang::FunctionDecl>(PVD->getDeclContext());
3790 if (!FD || FD != D) {
3801 if (FD->isMain() || FD->isConstexpr() ||
3808 FD->isOverloadedOperator()) {
3817 if (
const auto *PVD = dyn_cast<ParmVarDecl>(VD))
3835 llvm_unreachable(
"FixitStrategy not implemented yet!");
3837 llvm_unreachable(
"Invalid strategy!");
3839 llvm_unreachable(
"Unknown strategy!");
3847 return llvm::any_of(FixIts, [](
const FixItHint &Hint) {
3849 if (Range.getBegin().isMacroID() || Range.getEnd().isMacroID())
3866 std::map<const VarDecl *, FixItList> &FixItsForVariable,
3871 for (
const auto &[VD, Ignore] : FixItsForVariable) {
3873 if (llvm::any_of(Grp,
3874 [&FixItsForVariable](
const VarDecl *GrpMember) ->
bool {
3875 return !FixItsForVariable.count(GrpMember);
3880 ToErase.push_back(
Member);
3883 for (
auto *VarToErase : ToErase)
3884 FixItsForVariable.erase(VarToErase);
3895 std::map<const VarDecl *, FixItList> &FixItsForVariable ,
3899 FixItList FixItsSharedByParms{};
3901 std::optional<FixItList> OverloadFixes =
3904 if (OverloadFixes) {
3905 FixItsSharedByParms.append(*OverloadFixes);
3911 FixItsForVariable.erase(
Member);
3913 return FixItsSharedByParms;
3917static std::map<const VarDecl *, FixItList>
3926 std::map<const VarDecl *, FixItList> FixItsForVariable;
3931 for (
const auto &[VD, Fixables] : FixablesForAllVars.
byVar) {
3932 FixItsForVariable[VD] =
3936 if (FixItsForVariable[VD].empty()) {
3937 FixItsForVariable.erase(VD);
3940 for (
const auto &F : Fixables) {
3941 std::optional<FixItList> Fixits = F->getFixits(S);
3944 FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
3945 Fixits->begin(), Fixits->end());
3950 VD, F->getSourceLoc(),
3951 (
"gadget '" + F->getDebugName() +
"' refused to produce a fix")
3954 FixItsForVariable.erase(VD);
3973 FixItList FixItsSharedByParms{};
3975 if (
auto *FD = dyn_cast<FunctionDecl>(D))
3977 FixItsForVariable, VarGrpMgr, FD, S, Ctx, Handler);
3981 std::map<const VarDecl *, FixItList> FinalFixItsForVariable{
3984 for (
auto &[Var, Ignore] : FixItsForVariable) {
3985 bool AnyParm =
false;
3986 const auto VarGroupForVD = VarGrpMgr.
getGroupOfVar(Var, &AnyParm);
3988 for (
const VarDecl *GrpMate : VarGroupForVD) {
3991 if (FixItsForVariable.count(GrpMate))
3992 FinalFixItsForVariable[Var].append(FixItsForVariable[GrpMate]);
3996 assert(!FixItsSharedByParms.empty() &&
3997 "Should not try to fix a parameter that does not belong to a "
3999 FinalFixItsForVariable[Var].append(FixItsSharedByParms);
4006 for (
auto Iter = FinalFixItsForVariable.begin();
4007 Iter != FinalFixItsForVariable.end();)
4010 Iter = FinalFixItsForVariable.erase(Iter);
4013 return FinalFixItsForVariable;
4016template <
typename VarDeclIterTy>
4020 for (
const VarDecl *VD : UnsafeVars) {
4031 const std::vector<VarGrpTy> Groups;
4032 const std::map<const VarDecl *, unsigned> &VarGrpMap;
4033 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms;
4037 const std::vector<VarGrpTy> &Groups,
4038 const std::map<const VarDecl *, unsigned> &VarGrpMap,
4039 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms)
4040 : Groups(Groups), VarGrpMap(VarGrpMap),
4041 GrpsUnionForParms(GrpsUnionForParms) {}
4044 if (GrpsUnionForParms.contains(Var)) {
4047 return GrpsUnionForParms.getArrayRef();
4052 auto It = VarGrpMap.find(Var);
4054 if (It == VarGrpMap.end())
4056 return Groups[It->second];
4060 return GrpsUnionForParms.getArrayRef();
4065 WarningGadgetList WarningGadgets,
4066 DeclUseTracker Tracker,
4068 bool EmitSuggestions) {
4069 if (!EmitSuggestions) {
4073 for (
const auto &G : WarningGadgets) {
4074 G->handleUnsafeOperation(Handler,
false,
4080 assert(FixableGadgets.empty() &&
4081 "Fixable gadgets found but suggestions not requested!");
4087 if (!WarningGadgets.empty()) {
4091 for (
const auto &G : FixableGadgets) {
4092 for (
const auto *DRE : G->getClaimedVarUseSites()) {
4093 Tracker.claimUse(DRE);
4109 if (WarningGadgets.empty())
4117 std::map<const VarDecl *, FixItList> FixItsForVariableGroup;
4120 for (
auto it = FixablesForAllVars.
byVar.cbegin();
4121 it != FixablesForAllVars.
byVar.cend();) {
4126 (
"failed to produce fixit for '" +
4127 it->first->getNameAsString() +
4128 "' : neither local nor a parameter"));
4130 it = FixablesForAllVars.
byVar.erase(it);
4131 }
else if (it->first->getType().getCanonicalType()->isReferenceType()) {
4134 (
"failed to produce fixit for '" +
4135 it->first->getNameAsString() +
4136 "' : has a reference type"));
4138 it = FixablesForAllVars.
byVar.erase(it);
4139 }
else if (Tracker.hasUnclaimedUses(it->first)) {
4140 it = FixablesForAllVars.
byVar.erase(it);
4141 }
else if (it->first->isInitCapture()) {
4144 (
"failed to produce fixit for '" +
4145 it->first->getNameAsString() +
4146 "' : init capture"));
4148 it = FixablesForAllVars.
byVar.erase(it);
4155 for (
const auto &it : UnsafeOps.
byVar) {
4156 const VarDecl *
const UnsafeVD = it.first;
4157 auto UnclaimedDREs = Tracker.getUnclaimedUses(UnsafeVD);
4158 if (UnclaimedDREs.empty())
4162 std::string UnclaimedUseTrace =
4167 (
"failed to produce fixit for '" + UnfixedVDName +
4168 "' : has an unclaimed use\nThe unclaimed DRE trace: " +
4169 UnclaimedUseTrace));
4176 llvm::DenseMap<const VarDecl *, llvm::SetVector<const VarDecl *>>;
4177 DepMapTy DependenciesMap{};
4178 DepMapTy PtrAssignmentGraph{};
4180 for (
const auto &it : FixablesForAllVars.
byVar) {
4181 for (
const FixableGadget *fixable : it.second) {
4182 std::optional<std::pair<const VarDecl *, const VarDecl *>> ImplPair =
4183 fixable->getStrategyImplications();
4185 std::pair<const VarDecl *, const VarDecl *> Impl = std::move(*ImplPair);
4186 PtrAssignmentGraph[Impl.first].insert(Impl.second);
4208 std::set<const VarDecl *> VisitedVarsDirected{};
4209 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4210 if (VisitedVarsDirected.find(Var) == VisitedVarsDirected.end()) {
4212 std::queue<const VarDecl *> QueueDirected{};
4213 QueueDirected.push(Var);
4214 while (!QueueDirected.empty()) {
4215 const VarDecl *CurrentVar = QueueDirected.front();
4216 QueueDirected.pop();
4217 VisitedVarsDirected.insert(CurrentVar);
4218 auto AdjacentNodes = PtrAssignmentGraph[CurrentVar];
4219 for (
const VarDecl *Adj : AdjacentNodes) {
4220 if (VisitedVarsDirected.find(Adj) == VisitedVarsDirected.end()) {
4221 QueueDirected.push(Adj);
4223 DependenciesMap[Var].insert(Adj);
4224 DependenciesMap[Adj].insert(Var);
4231 std::vector<VarGrpTy> Groups;
4235 std::map<const VarDecl *, unsigned> VarGrpMap;
4237 llvm::SetVector<const VarDecl *>
4242 std::set<const VarDecl *> VisitedVars{};
4243 for (
const auto &[Var, ignore] : UnsafeOps.
byVar) {
4244 if (VisitedVars.find(Var) == VisitedVars.end()) {
4245 VarGrpTy &VarGroup = Groups.emplace_back();
4246 std::queue<const VarDecl *> Queue{};
4249 while (!Queue.empty()) {
4250 const VarDecl *CurrentVar = Queue.front();
4252 VisitedVars.insert(CurrentVar);
4253 VarGroup.push_back(CurrentVar);
4254 auto AdjacentNodes = DependenciesMap[CurrentVar];
4255 for (
const VarDecl *Adj : AdjacentNodes) {
4256 if (VisitedVars.find(Adj) == VisitedVars.end()) {
4262 bool HasParm =
false;
4263 unsigned GrpIdx = Groups.size() - 1;
4265 for (
const VarDecl *
V : VarGroup) {
4266 VarGrpMap[
V] = GrpIdx;
4271 GrpsUnionForParms.insert_range(VarGroup);
4293 for (
auto I = FixablesForAllVars.
byVar.begin();
4294 I != FixablesForAllVars.
byVar.end();) {
4296 if (!VisitedVars.count((*I).first)) {
4298 I = FixablesForAllVars.
byVar.erase(I);
4306 VisitedVars, [&FixablesForAllVars](
const VarDecl *
V) {
4308 return FixablesForAllVars.
byVar.count(
V);
4315 FixItsForVariableGroup =
4317 Tracker, Handler, VarGrpMgr);
4319 for (
const auto &G : UnsafeOps.
noVar) {
4320 G->handleUnsafeOperation(Handler,
false,
4324 for (
const auto &[VD, WarningGadgets] : UnsafeOps.
byVar) {
4325 auto FixItsIt = FixItsForVariableGroup.find(VD);
4327 FixItsIt != FixItsForVariableGroup.end()
4328 ? std::move(FixItsIt->second)
4331 for (
const auto &G : WarningGadgets) {
4332 G->handleUnsafeOperation(Handler,
true,
4340 bool EmitSuggestions) {
4349 if (
const auto *FD = dyn_cast<FunctionDecl>(D)) {
4353 if (
const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
4354 if (MD->getParent()->isLambda() && MD->getParent()->isLocalClass())
4359 if (FReDecl->isExternC()) {
4362 EmitSuggestions =
false;
4367 Stmts.push_back(FD->getBody());
4369 if (
const auto *ID = dyn_cast<CXXConstructorDecl>(D)) {
4371 Stmts.push_back(CI->getInit());
4375 Stmts.push_back(D->
getBody());
4378 assert(!Stmts.empty());
4380 FixableGadgetList FixableGadgets;
4381 WarningGadgetList WarningGadgets;
4382 DeclUseTracker Tracker;
4383 for (
Stmt *S : Stmts) {
4385 WarningGadgets, Tracker);
4387 applyGadgets(D, std::move(FixableGadgets), std::move(WarningGadgets),
4388 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 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]).
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.
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
bool isSingleResult() const
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
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.
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...
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 isNullTermPointer(const Expr *Ptr)
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)