clang: lib/Analysis/UnsafeBufferUsage.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
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"
35#include
36#include
37#include
38#include
39#include
40
41using namespace clang;
42
43#ifndef NDEBUG
44namespace {
45class StmtDebugPrinter
47public:
48 std::string VisitStmt(const Stmt *S) { return S->getStmtClassName(); }
49
50 std::string VisitBinaryOperator(const BinaryOperator *BO) {
51 return "BinaryOperator(" + BO->getOpcodeStr().str() + ")";
52 }
53
54 std::string VisitUnaryOperator(const UnaryOperator *UO) {
56 }
57
58 std::string VisitImplicitCastExpr(const ImplicitCastExpr *ICE) {
59 return "ImplicitCastExpr(" + std::string(ICE->getCastKindName()) + ")";
60 }
61};
62
63
64
65static std::string getDREAncestorString(const DeclRefExpr *DRE,
67 std::stringstream SS;
68 const Stmt *St = DRE;
69 StmtDebugPrinter StmtPriner;
70
71 do {
72 SS << StmtPriner.Visit(St);
73
75
76 if (StParents.size() > 1)
77 return "unavailable due to multiple parents";
78 if (StParents.empty())
79 break;
81 if (St)
82 SS << " ==> ";
83 } while (St);
84 return SS.str();
85}
86
87}
88#endif
89
90namespace {
91
92
93
94
95class FastMatcher {
96public:
97 virtual bool matches(const DynTypedNode &DynNode, ASTContext &Ctx,
98 const UnsafeBufferUsageHandler &Handler) = 0;
99 virtual ~FastMatcher() = default;
100};
101
102class MatchResult {
103
104public:
105 template const T *getNodeAs(StringRef ID) const {
106 auto It = Nodes.find(ID);
107 if (It == Nodes.end()) {
108 return nullptr;
109 }
110 return It->second.get<T>();
111 }
112
113 void addNode(StringRef ID, const DynTypedNode &Node) { Nodes[ID] = Node; }
114
115private:
116 llvm::StringMap Nodes;
117};
118}
119
120#define SIZED_CONTAINER_OR_VIEW_LIST \
121 "span", "array", "vector", "basic_string_view", "basic_string", \
122 "initializer_list",
123
124
125
127public:
128
129
130
132 bool FindAll, bool ignoreUnevaluatedContext,
134 : Matcher(&Matcher), FindAll(FindAll), Matches(false),
135 ignoreUnevaluatedContext(ignoreUnevaluatedContext),
136 ActiveASTContext(&Context), Handler(&NewHandler) {
139 }
140
141
142
144 Matches = false;
145 if (const Stmt *StmtNode = DynNode.get<Stmt>()) {
147 return Matches;
148 }
149 return false;
150 }
151
152
153
154
155
156
157
158
160 if (!Node)
161 return true;
162 if (!match(*Node))
163 return false;
164
166 return true;
167
169 }
170
172
173 if (ignoreUnevaluatedContext)
175 return DynamicRecursiveASTVisitor::TraverseGenericSelectionExpr(Node);
176 }
177
178 bool
180
181 if (ignoreUnevaluatedContext)
182 return true;
183 return DynamicRecursiveASTVisitor::TraverseUnaryExprOrTypeTraitExpr(Node);
184 }
185
187 bool TraverseQualifier) override {
188
189 if (ignoreUnevaluatedContext)
190 return true;
191 return DynamicRecursiveASTVisitor::TraverseTypeOfExprTypeLoc(
192 Node, TraverseQualifier);
193 }
194
196 bool TraverseQualifier) override {
197
198 if (ignoreUnevaluatedContext)
199 return true;
200 return DynamicRecursiveASTVisitor::TraverseDecltypeTypeLoc(
201 Node, TraverseQualifier);
202 }
203
205
206 if (ignoreUnevaluatedContext)
207 return true;
208 return DynamicRecursiveASTVisitor::TraverseCXXNoexceptExpr(Node);
209 }
210
212
213 if (ignoreUnevaluatedContext)
214 return true;
215 return DynamicRecursiveASTVisitor::TraverseCXXTypeidExpr(Node);
216 }
217
220 return false;
221 return DynamicRecursiveASTVisitor::TraverseCXXDefaultInitExpr(Node);
222 }
223
225 if (!Node)
226 return true;
227 if (!match(*Node))
228 return false;
230 }
231
232private:
233
234
235
236
237 template bool match(const T &Node) {
239 *Handler)) {
240 Matches = true;
241 if (!FindAll)
242 return false;
243 }
244 return true;
245 }
246
247 FastMatcher *const Matcher;
248
249 const bool FindAll;
250 bool Matches;
251 bool ignoreUnevaluatedContext;
252 ASTContext *ActiveASTContext;
253 const UnsafeBufferUsageHandler *Handler;
254};
255
256
260
264
265static void
268 FastMatcher &Matcher) {
270 true, Handler);
272}
273
276 FastMatcher &Matcher) {
278 false, Handler);
280}
281
282
287
288static bool
293
300
301
302
304 const Stmt *S, const llvm::function_ref<void(const Expr *)> OnResult) {
305 if (const auto *CE = dyn_cast(S);
306 CE && CE->getCastKind() == CastKind::CK_LValueToRValue)
307 OnResult(CE->getSubExpr());
308 if (const auto *BO = dyn_cast(S);
309 BO && BO->getOpcode() == BO_Assign)
310 OnResult(BO->getLHS());
311}
312
313
314
316 const Stmt *S, llvm::function_ref<void(const Stmt *)> InnerMatcher) {
317
318
319
320
321
322
323
324
325 if (auto *CE = dyn_cast(S)) {
326 if (const auto *FnDecl = CE->getDirectCallee();
327 FnDecl && FnDecl->hasAttr())
328 return;
332 InnerMatcher(Arg);
333 });
334 }
335
336 if (auto *CE = dyn_cast(S)) {
337 if (CE->getCastKind() != CastKind::CK_PointerToIntegral &&
338 CE->getCastKind() != CastKind::CK_PointerToBoolean)
339 return;
341 return;
342 InnerMatcher(CE->getSubExpr());
343 }
344
345
346 if (const auto *BO = dyn_cast(S);
350 auto *LHS = BO->getLHS();
352 InnerMatcher(LHS);
353
354 auto *RHS = BO->getRHS();
356 InnerMatcher(RHS);
357 }
358
359
360 if (const auto *BO = dyn_cast(S);
363
364
365
366 InnerMatcher(BO->getLHS());
367 InnerMatcher(BO->getRHS());
368 }
369
370
371}
372
373
374
375
376
377
378
379
380
381
382
383
385 const Stmt *S, llvm::function_ref<void(const Stmt *)> InnerMatcher) {
386
387
388
389
390 if (auto *CS = dyn_cast(S)) {
391 for (auto *Child : CS->body())
392 InnerMatcher(Child);
393 }
394 if (auto *IfS = dyn_cast(S)) {
395 if (IfS->getThen())
396 InnerMatcher(IfS->getThen());
397 if (IfS->getElse())
398 InnerMatcher(IfS->getElse());
399 }
400
401}
402
403
404
405
406
407
408
409
410
413 const Expr *E2_LHS,
415 const Expr *E2_RHS,
418 switch (BOP) {
419
420 case BO_Mul:
421 case BO_Add:
426 default:
427 return false;
428 }
429 }
430 return false;
431}
432
437 return false;
438
440
441
444
445
447 return false;
449 case Stmt::DeclRefExprClass:
451 case Stmt::BinaryOperatorClass: {
454 BO2->getLHS(), BO2->getOpcode(),
455 BO2->getRHS(), Ctx);
456 }
457 default:
458 return false;
459 }
460}
461
462
463
464
465
466
467
468
469
470
471
472
473
474
477
478 if (auto *MCEPtr = dyn_cast(Ptr->IgnoreParenImpCasts()))
479 if (auto *MCESize =
480 dyn_cast(Size->IgnoreParenImpCasts())) {
481 auto *DREOfPtr = dyn_cast(
482 MCEPtr->getImplicitObjectArgument()->IgnoreParenImpCasts());
483 auto *DREOfSize = dyn_cast(
484 MCESize->getImplicitObjectArgument()->IgnoreParenImpCasts());
485
486 if (!DREOfPtr || !DREOfSize)
487 return false;
488
489
490 if (DREOfPtr->getDecl() != DREOfSize->getDecl())
491 return false;
492 if (MCEPtr->getMethodDecl()->getName() != "data")
493 return false;
494
495 if (!MCEPtr->getRecordDecl()->isInStdNamespace())
496 return false;
497
498 auto *ObjII = MCEPtr->getRecordDecl()->getIdentifier();
499
500 if (!ObjII)
501 return false;
502
504
505 if (!((AcceptSizeBytes &&
506 MCESize->getMethodDecl()->getName() == "size_bytes") ||
507
508
509
510
511 MCESize->getMethodDecl()->getName() == "size"))
512 return false;
513
515 ObjII->getName());
516 }
517
519
520
521 if (Size->EvaluateAsInt(ER, Ctx)) {
522
525 llvm::APSInt SizeInt = ER.Val.getInt();
526
527 return llvm::APSInt::compareValues(
528 SizeInt, llvm::APSInt(CAT->getSize(), true)) == 0;
529 }
530 return false;
531 }
532
533
536 return UO && UO->getOpcode() == UnaryOperator::Opcode::UO_AddrOf;
538 auto *FnDecl = CE->getDirectCallee();
539
540 return FnDecl && FnDecl->getNameAsString() == "addressof" &&
541 FnDecl->isInStdNamespace();
542 }
543 return false;
544 }
545
547 return true;
548 }
549 return false;
550}
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
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;
576 }
577 return false;
578 };
579 auto AreSameDRE = [](const Expr *E0, const Expr *E1) {
580 if (auto *DRE0 = dyn_cast(E0))
581 if (auto *DRE1 = dyn_cast(E1)) {
582 return DRE0->getDecl() == DRE1->getDecl();
583 }
584 return false;
585 };
587
588 if (Arg1CV && Arg1CV->isZero())
589
590 return true;
591
592
594 case Stmt::CXXNewExprClass:
596
597 return AreSameDRE((*Size)->IgnoreImplicit(), Arg1) ||
598 HaveEqualConstantValues(*Size, Arg1);
599 }
600
602
603 return Arg1CV && Arg1CV->isOne();
604 }
605 break;
606 default:
607 break;
608 }
609
610
611 if (auto CCast = dyn_cast(Arg0)) {
612 if (!CCast->getType()->isPointerType())
613 return false;
614
616
618 return false;
619
620 if (const auto *Call = dyn_cast(CCast->getSubExpr())) {
622 if (auto *AllocAttr = FD->getAttr()) {
623 const Expr *EleSizeExpr =
624 Call->getArg(AllocAttr->getElemSizeParam().getASTIndex());
625
626 ParamIdx NumElemIdx = AllocAttr->getNumElemsParam();
627
628 if (!NumElemIdx.isValid())
630
632
633 if (auto BO = dyn_cast(Arg1))
635 EleSizeExpr, Ctx);
636 }
637 }
638 }
639
640 auto IsMethodCallToSizedObject = [](const Stmt *Node, StringRef MethodName) {
641 if (const auto *MC = dyn_cast(Node)) {
642 const auto *MD = MC->getMethodDecl();
643 const auto *RD = MC->getRecordDecl();
644
645 if (RD && MD)
646 if (auto *II = RD->getDeclName().getAsIdentifierInfo();
647 II && RD->isInStdNamespace())
649 II->getName()) &&
650 MD->getName() == MethodName;
651 }
652 return false;
653 };
654
655 if (IsMethodCallToSizedObject(Arg0, "begin") &&
656 IsMethodCallToSizedObject(Arg1, "end"))
657 return AreSameDRE(
658
660 ->getImplicitObjectArgument()
661 ->IgnoreParenImpCasts(),
663 ->getImplicitObjectArgument()
664 ->IgnoreParenImpCasts());
665
666
668}
669
672
673
674
675
676
677
678
679 uint64_t limit;
680 if (const auto *CATy =
681 dyn_cast(Node.getBase()
685 limit = CATy->getLimitedSize();
686 } else if (const auto *SLiteral = dyn_castclang::StringLiteral(
688 limit = SLiteral->getLength() + 1;
689 } else {
690 return false;
691 }
692
694 const Expr *IndexExpr = Node.getIdx();
697 llvm::APSInt ArrIdx = EVResult.Val.getInt();
698
699
700 if (ArrIdx.isNonNegative() && ArrIdx.getLimitedValue() < limit)
701 return true;
702 } else if (const auto *BE = dyn_cast(IndexExpr)) {
703
704
705 if (BE->getOpcode() != BO_And && BE->getOpcode() != BO_Rem)
706 return false;
707
708 const Expr *LHS = BE->getLHS();
709 const Expr *RHS = BE->getRHS();
710
711 if (BE->getOpcode() == BO_Rem) {
712
714 return false;
715 }
716
718 llvm::APSInt result = EVResult.Val.getInt();
719 if (result.isNonNegative() && result.getLimitedValue() <= limit)
720 return true;
721 }
722
723 return false;
724 }
725
727 LHS->EvaluateAsInt(EVResult, Ctx)) ||
730 llvm::APSInt result = EVResult.Val.getInt();
731 if (result.isNonNegative() && result.getLimitedValue() < limit)
732 return true;
733 }
734 return false;
735 }
736 return false;
737}
738
739
740
741
744
745 if (const auto *CE = dyn_cast(E)) {
746 bool CondEval;
747 const auto *Cond = CE->getCond();
748
749 if (->isValueDependent() &&
750 Cond->EvaluateAsBooleanCondition(CondEval, Ctx))
751 return CondEval ? CE->getLHS() : CE->getRHS();
752 }
753 return E;
754}
755
756
757
761 return true;
763 return true;
764 if (auto *MCE = dyn_cast(Ptr->IgnoreParenImpCasts())) {
767
769 if (MD->getName() == "c_str" && RD->getName() == "basic_string")
770 return true;
771 }
772 return false;
773}
774
776
777
778
779
780
781
782
783
784
785
786
787
788
789
791 StringRef matchName(StringRef FunName, bool isBuiltin) {
792
793 if (isBuiltin && FunName.starts_with("__builtin_"))
794
795
797 FunName.drop_front(10 ));
798
799 if (FunName.starts_with("__asan_"))
800 return matchLibcName(FunName.drop_front(7 ));
802 }
803
804
805
807 if (Name.starts_with("__") && Name.ends_with("_chk"))
809 Name.drop_front(2).drop_back(4) );
811 }
812
814 if (Name.ends_with("_s"))
815 return Name.drop_back(2 );
816 return Name;
817 }
818};
819
820
821
822
823
824
825
826
827
829 const unsigned FmtArgIdx, ASTContext &Ctx,
830 bool isKprintf = false) {
831 class StringFormatStringHandler
834 unsigned FmtArgIdx;
835 const Expr *&UnsafeArg;
837 bool UnsafeArgSet;
838
839
840
841
842
843
844
845
846
850 unsigned PArgIdx = -1;
851
854 if (0 < PArgIdx && PArgIdx < Call->getNumArgs()) {
855 const Expr *PArg = Call->getArg(PArgIdx);
856
857
858 if (auto *CE = dyn_cast(PArg);
859 CE && CE->getType()->isSignedIntegerType())
860 PArg = CE->getSubExpr();
861 return PArg;
862 }
864 analyze_printf::OptionalAmount::HowSpecified::Constant) {
866 llvm::APSInt PArgVal = llvm::APSInt(
868 true);
869
871 }
872 return nullptr;
873 }
874
875 public:
876 StringFormatStringHandler(const CallExpr *Call, unsigned FmtArgIdx,
878 : Call(Call), FmtArgIdx(FmtArgIdx), UnsafeArg(UnsafeArg), Ctx(Ctx),
879 UnsafeArgSet(false) {}
880
882 const char *startSpecifier,
883 unsigned specifierLen,
887 return true;
888
890
891 if (!(0 < ArgIdx && ArgIdx < Call->getNumArgs()))
892
893 return true;
894
895 const Expr *Arg = Call->getArg(ArgIdx);
896
898
899 return true;
900
901
902
905 bool IsArgTypeValid =
906 ArgType->isPointerType() &&
908 ? ArgType->getPointeeType()->isWideCharType()
909 : ArgType->getPointeeType()->isCharType());
910
911 if (auto *Precision = getPrecisionAsExpr(FS.getPrecision(), Call);
912 Precision && IsArgTypeValid)
914 return true;
915
916 UnsafeArg = Call->getArg(ArgIdx);
917 UnsafeArgSet = true;
918 return false;
919 }
920
921 bool isUnsafeArgSet() { return UnsafeArgSet; }
922 };
923
924 const Expr *Fmt = Call->getArg(FmtArgIdx);
925
926 if (auto *SL = dyn_castclang::StringLiteral(Fmt->IgnoreParenImpCasts())) {
927 if (SL->getCharByteWidth() == 1) {
928 StringRef FmtStr = SL->getString();
929 StringFormatStringHandler Handler(Call, FmtArgIdx, UnsafeArg, Ctx);
930
932 Handler, FmtStr.begin(), FmtStr.end(), Ctx.getLangOpts(),
934 Handler.isUnsafeArgSet();
935 }
936
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();
943 }
944 }
945
946
947
948 return llvm::any_of(
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)) {
952 UnsafeArg = Arg;
953 return true;
954 }
955 return false;
956 });
957}
958
959
960
961
962
963
964
965
966
967
969 static std::unique_ptr<std::set> PredefinedNames = nullptr;
970 if (!PredefinedNames)
971 PredefinedNames =
972 std::make_unique<std::set, std::set>({
973
974 "atof",
975 "atoi",
976 "atol",
977 "atoll",
978 "strtol",
979 "strtoll",
980 "strtoul",
981 "strtoull",
982 "strtof",
983 "strtod",
984 "strtold",
985 "strtoimax",
986 "strtoumax",
987
988
989 "strcpy",
990 "strncpy",
991 "strlcpy",
992 "strcat",
993 "strncat",
994 "strlcat",
995 "strxfrm",
996 "strdup",
997 "strndup",
998
999 "strlen",
1000 "strnlen",
1001 "strcmp",
1002 "strncmp",
1003 "stricmp",
1004 "strcasecmp",
1005 "strcoll",
1006 "strchr",
1007 "strrchr",
1008 "strspn",
1009 "strcspn",
1010 "strpbrk",
1011 "strstr",
1012 "strtok",
1013
1014 "memchr",
1015 "wmemchr",
1016 "memcmp",
1017 "wmemcmp",
1018 "memcpy",
1019 "memccpy",
1020 "mempcpy",
1021 "wmemcpy",
1022 "memmove",
1023 "wmemmove",
1024 "memset",
1025 "wmemset",
1026
1027 "fread",
1028 "fwrite",
1029 "fgets",
1030 "fgetws",
1031 "gets",
1032 "fputs",
1033 "fputws",
1034 "puts",
1035
1036 "strerror_s",
1037 "strerror_r",
1038 "bcopy",
1039 "bzero",
1040 "bsearch",
1041 "qsort",
1042 });
1043
1045
1046 if (!II)
1047 return false;
1048
1051
1052
1053 if (PredefinedNames->find(Name) != PredefinedNames->end())
1054 return true;
1055
1056 std::string NameWCS = Name.str();
1057 size_t WcsPos = NameWCS.find("wcs");
1058
1059 while (WcsPos != std:🧵:npos) {
1060 NameWCS[WcsPos++] = 's';
1061 NameWCS[WcsPos++] = 't';
1062 NameWCS[WcsPos++] = 'r';
1063 WcsPos = NameWCS.find("wcs", WcsPos);
1064 }
1065 if (PredefinedNames->find(NameWCS) != PredefinedNames->end())
1066 return true;
1067
1068
1069 return Name.ends_with("scanf");
1070}
1071
1072
1073
1074
1077
1078 if (!II)
1079 return false;
1080
1083
1084 if (!Name.ends_with("printf"))
1085 return false;
1086 return Name.starts_with("v");
1087}
1088
1089
1090
1093
1094 if (!II)
1095 return false;
1096
1099
1100 if (!Name.ends_with("printf") ||
1101
1102 Name.starts_with("v"))
1103 return false;
1104
1105 StringRef Prefix = Name.drop_back(6);
1106
1107 if (Prefix.ends_with("w"))
1108 Prefix = Prefix.drop_back(1);
1109 return Prefix == "s";
1110}
1111
1112
1113
1114
1117
1118 if (!II)
1119 return false;
1120
1123
1124 if (!Name.ends_with("printf") || Name.starts_with("v"))
1125 return false;
1126
1127 StringRef Prefix = Name.drop_back(6);
1128
1129 if (Prefix.ends_with("w"))
1130 Prefix = Prefix.drop_back(1);
1131
1132 return Prefix.empty() || Prefix == "k" || Prefix == "f" || Prefix == "sn";
1133}
1134
1135
1136
1137
1138
1140 MatchResult &Result, llvm::StringRef Tag) {
1141
1143
1144 assert(FD && "It should have been checked that FD is non-null.");
1145
1147
1148 if (NumParms < 1)
1149 return false;
1150
1152
1154 return false;
1155
1157
1159 .isNull() &&
1161
1162 const Expr *UnsafeArg;
1163
1166 return true;
1167 }
1168 return false;
1169 }
1170
1172
1173 bool isKprintf = false;
1174 const Expr *UnsafeArg;
1175
1177 isKprintf = II->getName() == "kprintf";
1180 return true;
1181 }
1182 return false;
1183 }
1184
1185 if (NumParms > 2) {
1187
1189
1190
1191 const Expr *UnsafeArg;
1192
1195 return true;
1196 }
1197 return false;
1198 }
1199 }
1200
1201
1202 for (const auto *Arg : Node.arguments())
1203 if (Arg->getType()->isPointerType() && (Arg, Ctx)) {
1205 return true;
1206 }
1207 return false;
1208}
1209
1210
1211
1212
1213
1216
1217 assert(FD && "It should have been checked that FD is non-null.");
1218
1220 return false;
1221
1223
1225 return false;
1226
1229
1232 !Size->getType()->isUnsignedIntegerType())
1233 return false;
1234
1236}
1237}
1238
1239namespace {
1240
1241
1243
1244
1246}
1247
1248namespace {
1249
1250
1251
1252
1253
1254
1255
1256
1257class Gadget {
1258public:
1259 enum class Kind {
1260#define GADGET(x) x,
1261#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1262 };
1263
1264 Gadget(Kind K) : K(K) {}
1265
1266 Kind getKind() const { return K; }
1267
1268#ifndef NDEBUG
1269 StringRef getDebugName() const {
1270 switch (K) {
1271#define GADGET(x) \
1272 case Kind::x: \
1273 return #x;
1274#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
1275 }
1276 llvm_unreachable("Unhandled Gadget::Kind enum");
1277 }
1278#endif
1279
1280 virtual bool isWarningGadget() const = 0;
1281
1282
1283 virtual SourceLocation getSourceLoc() const = 0;
1284
1285
1286
1287
1288 virtual DeclUseList getClaimedVarUseSites() const = 0;
1289
1290 virtual ~Gadget() = default;
1291
1292private:
1293 Kind K;
1294};
1295
1296
1297
1298class WarningGadget : public Gadget {
1299public:
1300 WarningGadget(Kind K) : Gadget(K) {}
1301
1302 static bool classof(const Gadget *G) { return G->isWarningGadget(); }
1303 bool isWarningGadget() const final { return true; }
1304
1305 virtual void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1306 bool IsRelatedToDecl,
1307 ASTContext &Ctx) const = 0;
1308
1309 virtual SmallVector<const Expr *, 1> getUnsafePtrs() const = 0;
1310};
1311
1312
1313
1314
1315
1316class FixableGadget : public Gadget {
1317public:
1318 FixableGadget(Kind K) : Gadget(K) {}
1319
1320 static bool classof(const Gadget *G) { return !G->isWarningGadget(); }
1321 bool isWarningGadget() const final { return false; }
1322
1323
1324
1325
1326 virtual std::optional getFixits(const FixitStrategy &) const {
1327 return std::nullopt;
1328 }
1329
1330
1331
1332
1333
1334
1335
1336 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1337 getStrategyImplications() const {
1338 return std::nullopt;
1339 }
1340};
1341
1342static bool isSupportedVariable(const DeclRefExpr &Node) {
1345}
1346
1347
1351 return false;
1352
1354 dyn_cast(RecordDecl);
1355 if (!class_template_specialization_decl)
1356 return false;
1357
1360 if (template_args.size() == 0)
1361 return false;
1362
1365 return false;
1366
1369}
1370
1371class UniquePtrArrayAccessGadget : public WarningGadget {
1372private:
1373 static constexpr const char *const AccessorTag = "unique_ptr_array_access";
1374 const CXXOperatorCallExpr *AccessorExpr;
1375
1376public:
1378 : WarningGadget(Kind::UniquePtrArrayAccess),
1379 AccessorExpr(Result.getNodeAs(AccessorTag)) {
1380 assert(AccessorExpr &&
1381 "UniquePtrArrayAccessGadget requires a matched CXXOperatorCallExpr");
1382 }
1383
1384 static bool classof(const Gadget *G) {
1385 return G->getKind() == Kind::UniquePtrArrayAccess;
1386 }
1387
1388 static bool matches(const Stmt *S, const ASTContext &Ctx,
1390
1391 const CXXOperatorCallExpr *OpCall = dyn_cast(S);
1392 if (!OpCall || OpCall->getOperator() != OO_Subscript)
1393 return false;
1394
1396 if (!Callee)
1397 return false;
1398
1399 const CXXMethodDecl *Method =
1400 dyn_cast_or_null(OpCall->getDirectCallee());
1402 return false;
1403
1404 if (Method->getOverloadedOperator() != OO_Subscript)
1405 return false;
1406
1408 if (!isUniquePtrArray(RecordDecl))
1409 return false;
1410
1411 const Expr *IndexExpr = OpCall->getArg(1);
1412 clang::Expr::EvalResult Eval;
1413
1414
1416 return false;
1417
1418 Result.addNode(AccessorTag, DynTypedNode::create(*OpCall));
1419 return true;
1420 }
1421 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1422 bool IsRelatedToDecl,
1423 ASTContext &Ctx) const override {
1425 DynTypedNode::create(*AccessorExpr), IsRelatedToDecl, Ctx);
1426 }
1427
1428 SourceLocation getSourceLoc() const override {
1429 if (AccessorExpr)
1430 return AccessorExpr->getOperatorLoc();
1431 return SourceLocation();
1432 }
1433
1434 DeclUseList getClaimedVarUseSites() const override { return {}; }
1435 SmallVector<const Expr *, 1> getUnsafePtrs() const override { return {}; }
1436};
1437
1438using FixableGadgetList = std::vector<std::unique_ptr>;
1439using WarningGadgetList = std::vector<std::unique_ptr>;
1440
1441
1442
1443class IncrementGadget : public WarningGadget {
1444 static constexpr const char *const OpTag = "op";
1445 const UnaryOperator *Op;
1446
1447public:
1449 : WarningGadget(Kind::Increment),
1450 Op(Result.getNodeAs(OpTag)) {}
1451
1452 static bool classof(const Gadget *G) {
1453 return G->getKind() == Kind::Increment;
1454 }
1455
1456 static bool matches(const Stmt *S, const ASTContext &Ctx,
1458 const auto *UO = dyn_cast(S);
1460 return false;
1462 return false;
1463 Result.addNode(OpTag, DynTypedNode::create(*UO));
1464 return true;
1465 }
1466
1467 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1468 bool IsRelatedToDecl,
1469 ASTContext &Ctx) const override {
1471 }
1472 SourceLocation getSourceLoc() const override { return Op->getBeginLoc(); }
1473
1474 DeclUseList getClaimedVarUseSites() const override {
1475 SmallVector<const DeclRefExpr *, 2> Uses;
1476 if (const auto *DRE =
1477 dyn_cast(Op->getSubExpr()->IgnoreParenImpCasts())) {
1478 Uses.push_back(DRE);
1479 }
1480
1481 return std::move(Uses);
1482 }
1483
1484 SmallVector<const Expr *, 1> getUnsafePtrs() const override {
1485 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1486 }
1487};
1488
1489
1490
1491class DecrementGadget : public WarningGadget {
1492 static constexpr const char *const OpTag = "op";
1493 const UnaryOperator *Op;
1494
1495public:
1497 : WarningGadget(Kind::Decrement),
1498 Op(Result.getNodeAs(OpTag)) {}
1499
1500 static bool classof(const Gadget *G) {
1501 return G->getKind() == Kind::Decrement;
1502 }
1503
1504 static bool matches(const Stmt *S, const ASTContext &Ctx,
1506 const auto *UO = dyn_cast(S);
1508 return false;
1510 return false;
1511 Result.addNode(OpTag, DynTypedNode::create(*UO));
1512 return true;
1513 }
1514
1515 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1516 bool IsRelatedToDecl,
1517 ASTContext &Ctx) const override {
1519 }
1520 SourceLocation getSourceLoc() const override { return Op->getBeginLoc(); }
1521
1522 DeclUseList getClaimedVarUseSites() const override {
1523 if (const auto *DRE =
1524 dyn_cast(Op->getSubExpr()->IgnoreParenImpCasts())) {
1525 return {DRE};
1526 }
1527
1528 return {};
1529 }
1530
1531 SmallVector<const Expr *, 1> getUnsafePtrs() const override {
1532 return {Op->getSubExpr()->IgnoreParenImpCasts()};
1533 }
1534};
1535
1536
1537
1538class ArraySubscriptGadget : public WarningGadget {
1539 static constexpr const char *const ArraySubscrTag = "ArraySubscript";
1540 const ArraySubscriptExpr *ASE;
1541
1542public:
1545 ASE(Result.getNodeAs(ArraySubscrTag)) {}
1546
1547 static bool classof(const Gadget *G) {
1548 return G->getKind() == Kind::ArraySubscript;
1549 }
1550
1551 static bool matches(const Stmt *S, const ASTContext &Ctx,
1553 const auto *ASE = dyn_cast(S);
1554 if (!ASE)
1555 return false;
1556 const auto *const Base = ASE->getBase()->IgnoreParenImpCasts();
1558 return false;
1559 const auto *Idx = dyn_cast(ASE->getIdx());
1560 bool IsSafeIndex = (Idx && Idx->getValue().isZero()) ||
1563 return false;
1564 Result.addNode(ArraySubscrTag, DynTypedNode::create(*ASE));
1565 return true;
1566 }
1567
1568 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1569 bool IsRelatedToDecl,
1570 ASTContext &Ctx) const override {
1572 }
1573 SourceLocation getSourceLoc() const override { return ASE->getBeginLoc(); }
1574
1575 DeclUseList getClaimedVarUseSites() const override {
1576 if (const auto *DRE =
1577 dyn_cast(ASE->getBase()->IgnoreParenImpCasts())) {
1578 return {DRE};
1579 }
1580
1581 return {};
1582 }
1583
1584 SmallVector<const Expr *, 1> getUnsafePtrs() const override {
1585 return {ASE->getBase()->IgnoreParenImpCasts()};
1586 }
1587};
1588
1589
1590
1591
1592
1593class PointerArithmeticGadget : public WarningGadget {
1594 static constexpr const char *const PointerArithmeticTag = "ptrAdd";
1595 static constexpr const char *const PointerArithmeticPointerTag = "ptrAddPtr";
1596 const BinaryOperator *PA;
1597 const Expr *Ptr;
1598
1599public:
1601 : WarningGadget(Kind::PointerArithmetic),
1602 PA(Result.getNodeAs(PointerArithmeticTag)),
1603 Ptr(Result.getNodeAs(PointerArithmeticPointerTag)) {}
1604
1605 static bool classof(const Gadget *G) {
1606 return G->getKind() == Kind::PointerArithmetic;
1607 }
1608
1609 static bool matches(const Stmt *S, const ASTContext &Ctx,
1611 const auto *BO = dyn_cast(S);
1612 if (!BO)
1613 return false;
1614 const auto *LHS = BO->getLHS();
1615 const auto *RHS = BO->getRHS();
1616
1618 BO->getOpcode() == BO_AddAssign || BO->getOpcode() == BO_SubAssign) {
1619 if (hasPointerType(*LHS) && (RHS->getType()->isIntegerType() ||
1620 RHS->getType()->isEnumeralType())) {
1621 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*LHS));
1622 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1623 return true;
1624 }
1625 }
1626
1628 (LHS->getType()->isIntegerType() || LHS->getType()->isEnumeralType())) {
1629 Result.addNode(PointerArithmeticPointerTag, DynTypedNode::create(*RHS));
1630 Result.addNode(PointerArithmeticTag, DynTypedNode::create(*BO));
1631 return true;
1632 }
1633 return false;
1634 }
1635
1636 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1637 bool IsRelatedToDecl,
1638 ASTContext &Ctx) const override {
1640 }
1641 SourceLocation getSourceLoc() const override { return PA->getBeginLoc(); }
1642
1643 DeclUseList getClaimedVarUseSites() const override {
1644 if (const auto *DRE = dyn_cast(Ptr->IgnoreParenImpCasts())) {
1645 return {DRE};
1646 }
1647
1648 return {};
1649 }
1650
1651 SmallVector<const Expr *, 1> getUnsafePtrs() const override {
1652 return {Ptr->IgnoreParenImpCasts()};
1653 }
1654
1655
1656
1657};
1658
1659class SpanTwoParamConstructorGadget : public WarningGadget {
1660 static constexpr const char *const SpanTwoParamConstructorTag =
1661 "spanTwoParamConstructor";
1662 const CXXConstructExpr *Ctor;
1663
1664public:
1666 : WarningGadget(Kind::SpanTwoParamConstructor),
1667 Ctor(Result.getNodeAs(SpanTwoParamConstructorTag)) {}
1668
1669 static bool classof(const Gadget *G) {
1670 return G->getKind() == Kind::SpanTwoParamConstructor;
1671 }
1672
1674 const auto *CE = dyn_cast(S);
1675 if (!CE)
1676 return false;
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;
1683 return false;
1684 Result.addNode(SpanTwoParamConstructorTag, DynTypedNode::create(*CE));
1685 return true;
1686 }
1687
1688 static bool matches(const Stmt *S, ASTContext &Ctx,
1689 const UnsafeBufferUsageHandler *Handler,
1692 return false;
1694 }
1695
1696 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1697 bool IsRelatedToDecl,
1698 ASTContext &Ctx) const override {
1700 }
1701 SourceLocation getSourceLoc() const override { return Ctor->getBeginLoc(); }
1702
1703 DeclUseList getClaimedVarUseSites() const override {
1704
1705
1706 if (auto *DRE = dyn_cast(Ctor->getArg(0))) {
1708 return {DRE};
1709 }
1710 return {};
1711 }
1712
1713 SmallVector<const Expr *, 1> getUnsafePtrs() const override { return {}; }
1714};
1715
1716
1717
1718
1719
1720class PointerInitGadget : public FixableGadget {
1721private:
1722 static constexpr const char *const PointerInitLHSTag = "ptrInitLHS";
1723 static constexpr const char *const PointerInitRHSTag = "ptrInitRHS";
1724 const VarDecl *PtrInitLHS;
1725 const DeclRefExpr *PtrInitRHS;
1726
1727public:
1729 : FixableGadget(Kind::PointerInit),
1730 PtrInitLHS(Result.getNodeAs(PointerInitLHSTag)),
1731 PtrInitRHS(Result.getNodeAs(PointerInitRHSTag)) {}
1732
1733 static bool classof(const Gadget *G) {
1734 return G->getKind() == Kind::PointerInit;
1735 }
1736
1737 static bool matches(const Stmt *S,
1738 llvm::SmallVectorImpl &Results) {
1739 const DeclStmt *DS = dyn_cast(S);
1741 return false;
1742 const VarDecl *VD = dyn_cast(DS->getSingleDecl());
1743 if (!VD)
1744 return false;
1747 return false;
1748 const auto *DRE = dyn_cast(Init->IgnoreImpCasts());
1749 if (!DRE || (*DRE) || !isSupportedVariable(*DRE)) {
1750 return false;
1751 }
1753 R.addNode(PointerInitLHSTag, DynTypedNode::create(*VD));
1754 R.addNode(PointerInitRHSTag, DynTypedNode::create(*DRE));
1755 Results.emplace_back(std::move(R));
1756 return true;
1757 }
1758
1759 virtual std::optional
1760 getFixits(const FixitStrategy &S) const override;
1761 SourceLocation getSourceLoc() const override {
1762 return PtrInitRHS->getBeginLoc();
1763 }
1764
1765 virtual DeclUseList getClaimedVarUseSites() const override {
1766 return DeclUseList{PtrInitRHS};
1767 }
1768
1769 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1770 getStrategyImplications() const override {
1771 return std::make_pair(PtrInitLHS, cast(PtrInitRHS->getDecl()));
1772 }
1773};
1774
1775
1776
1777
1778
1779
1780class PtrToPtrAssignmentGadget : public FixableGadget {
1781private:
1782 static constexpr const char *const PointerAssignLHSTag = "ptrLHS";
1783 static constexpr const char *const PointerAssignRHSTag = "ptrRHS";
1784 const DeclRefExpr *PtrLHS;
1785 const DeclRefExpr *PtrRHS;
1786
1787public:
1789 : FixableGadget(Kind::PtrToPtrAssignment),
1790 PtrLHS(Result.getNodeAs(PointerAssignLHSTag)),
1791 PtrRHS(Result.getNodeAs(PointerAssignRHSTag)) {}
1792
1793 static bool classof(const Gadget *G) {
1794 return G->getKind() == Kind::PtrToPtrAssignment;
1795 }
1796
1797 static bool matches(const Stmt *S,
1798 llvm::SmallVectorImpl &Results) {
1799 size_t SizeBefore = Results.size();
1801 const auto *BO = dyn_cast(S);
1802 if (!BO || BO->getOpcode() != BO_Assign)
1803 return;
1805 if (const auto *RHSRef = dyn_cast(RHS);
1807 !isSupportedVariable(*RHSRef)) {
1808 return;
1809 }
1810 const auto *LHS = BO->getLHS();
1811 if (const auto *LHSRef = dyn_cast(LHS);
1813 !isSupportedVariable(*LHSRef)) {
1814 return;
1815 }
1817 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
1818 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
1819 Results.emplace_back(std::move(R));
1820 });
1821 return SizeBefore != Results.size();
1822 }
1823
1824 virtual std::optional
1825 getFixits(const FixitStrategy &S) const override;
1826 SourceLocation getSourceLoc() const override { return PtrLHS->getBeginLoc(); }
1827
1828 virtual DeclUseList getClaimedVarUseSites() const override {
1829 return DeclUseList{PtrLHS, PtrRHS};
1830 }
1831
1832 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1833 getStrategyImplications() const override {
1834 return std::make_pair(cast(PtrLHS->getDecl()),
1836 }
1837};
1838
1839
1840
1841
1842
1843
1844class CArrayToPtrAssignmentGadget : public FixableGadget {
1845private:
1846 static constexpr const char *const PointerAssignLHSTag = "ptrLHS";
1847 static constexpr const char *const PointerAssignRHSTag = "ptrRHS";
1848 const DeclRefExpr *PtrLHS;
1849 const DeclRefExpr *PtrRHS;
1850
1851public:
1853 : FixableGadget(Kind::CArrayToPtrAssignment),
1854 PtrLHS(Result.getNodeAs(PointerAssignLHSTag)),
1855 PtrRHS(Result.getNodeAs(PointerAssignRHSTag)) {}
1856
1857 static bool classof(const Gadget *G) {
1858 return G->getKind() == Kind::CArrayToPtrAssignment;
1859 }
1860
1861 static bool matches(const Stmt *S,
1862 llvm::SmallVectorImpl &Results) {
1863 size_t SizeBefore = Results.size();
1865 const auto *BO = dyn_cast(S);
1866 if (!BO || BO->getOpcode() != BO_Assign)
1867 return;
1869 if (const auto *RHSRef = dyn_cast(RHS);
1870 !RHSRef ||
1872 !isSupportedVariable(*RHSRef)) {
1873 return;
1874 }
1875 const auto *LHS = BO->getLHS();
1876 if (const auto *LHSRef = dyn_cast(LHS);
1878 !isSupportedVariable(*LHSRef)) {
1879 return;
1880 }
1882 R.addNode(PointerAssignLHSTag, DynTypedNode::create(*LHS));
1883 R.addNode(PointerAssignRHSTag, DynTypedNode::create(*RHS));
1884 Results.emplace_back(std::move(R));
1885 });
1886 return SizeBefore != Results.size();
1887 }
1888
1889 virtual std::optional
1890 getFixits(const FixitStrategy &S) const override;
1891 SourceLocation getSourceLoc() const override { return PtrLHS->getBeginLoc(); }
1892
1893 virtual DeclUseList getClaimedVarUseSites() const override {
1894 return DeclUseList{PtrLHS, PtrRHS};
1895 }
1896
1897 virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
1898 getStrategyImplications() const override {
1899 return {};
1900 }
1901};
1902
1903
1904
1905class UnsafeBufferUsageAttrGadget : public WarningGadget {
1906 constexpr static const char *const OpTag = "attr_expr";
1907 const Expr *Op;
1908
1909public:
1911 : WarningGadget(Kind::UnsafeBufferUsageAttr),
1912 Op(Result.getNodeAs(OpTag)) {}
1913
1914 static bool classof(const Gadget *G) {
1915 return G->getKind() == Kind::UnsafeBufferUsageAttr;
1916 }
1917
1918 static bool matches(const Stmt *S, const ASTContext &Ctx,
1920 if (auto *CE = dyn_cast(S)) {
1921 if (CE->getDirectCallee() &&
1922 CE->getDirectCallee()->hasAttr()) {
1923 Result.addNode(OpTag, DynTypedNode::create(*CE));
1924 return true;
1925 }
1926 }
1927 if (auto *ME = dyn_cast(S)) {
1929 return false;
1930 if (ME->getMemberDecl()->hasAttr()) {
1931 Result.addNode(OpTag, DynTypedNode::create(*ME));
1932 return true;
1933 }
1934 }
1935 return false;
1936 }
1937
1938 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1939 bool IsRelatedToDecl,
1940 ASTContext &Ctx) const override {
1942 }
1943 SourceLocation getSourceLoc() const override { return Op->getBeginLoc(); }
1944
1945 DeclUseList getClaimedVarUseSites() const override { return {}; }
1946
1947 SmallVector<const Expr *, 1> getUnsafePtrs() const override { return {}; }
1948};
1949
1950
1951
1952
1953class UnsafeBufferUsageCtorAttrGadget : public WarningGadget {
1954 constexpr static const char *const OpTag = "cxx_construct_expr";
1955 const CXXConstructExpr *Op;
1956
1957public:
1959 : WarningGadget(Kind::UnsafeBufferUsageCtorAttr),
1960 Op(Result.getNodeAs(OpTag)) {}
1961
1962 static bool classof(const Gadget *G) {
1963 return G->getKind() == Kind::UnsafeBufferUsageCtorAttr;
1964 }
1965
1967 const auto *CE = dyn_cast(S);
1968 if (!CE || !CE->getConstructor()->hasAttr())
1969 return false;
1970
1972 if (SpanTwoParamConstructorGadget::matches(CE, Ctx, Tmp))
1973 return false;
1974 Result.addNode(OpTag, DynTypedNode::create(*CE));
1975 return true;
1976 }
1977
1978 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
1979 bool IsRelatedToDecl,
1980 ASTContext &Ctx) const override {
1982 }
1983 SourceLocation getSourceLoc() const override { return Op->getBeginLoc(); }
1984
1985 DeclUseList getClaimedVarUseSites() const override { return {}; }
1986
1987 SmallVector<const Expr *, 1> getUnsafePtrs() const override { return {}; }
1988};
1989
1990
1991
1992
1993
1994class DataInvocationGadget : public WarningGadget {
1995 constexpr static const char *const OpTag = "data_invocation_expr";
1996 const ExplicitCastExpr *Op;
1997
1998public:
2000 : WarningGadget(Kind::DataInvocation),
2001 Op(Result.getNodeAs(OpTag)) {}
2002
2003 static bool classof(const Gadget *G) {
2004 return G->getKind() == Kind::DataInvocation;
2005 }
2006
2007 static bool matches(const Stmt *S, const ASTContext &Ctx,
2009 auto *CE = dyn_cast(S);
2010 if (!CE)
2011 return false;
2012 for (auto *Child : CE->children()) {
2013 if (auto *MCE = dyn_cast(Child);
2014 MCE && isDataFunction(MCE)) {
2015 Result.addNode(OpTag, DynTypedNode::create(*CE));
2016 return true;
2017 }
2018 if (auto *Paren = dyn_cast(Child)) {
2019 if (auto *MCE = dyn_cast(Paren->getSubExpr());
2020 MCE && isDataFunction(MCE)) {
2021 Result.addNode(OpTag, DynTypedNode::create(*CE));
2022 return true;
2023 }
2024 }
2025 }
2026 return false;
2027 }
2028
2029 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2030 bool IsRelatedToDecl,
2031 ASTContext &Ctx) const override {
2033 }
2034 SourceLocation getSourceLoc() const override { return Op->getBeginLoc(); }
2035
2036 DeclUseList getClaimedVarUseSites() const override { return {}; }
2037
2038private:
2039 static bool isDataFunction(const CXXMemberCallExpr *call) {
2040 if (!call)
2041 return false;
2044 return false;
2046 if (method->getNameAsString() == "data" &&
2047 method->getParent()->isInStdNamespace() &&
2048 llvm::is_contained({SIZED_CONTAINER_OR_VIEW_LIST},
2049 method->getParent()->getName()))
2050 return true;
2051 return false;
2052 }
2053
2054 SmallVector<const Expr *, 1> getUnsafePtrs() const override { return {}; }
2055};
2056
2057class UnsafeLibcFunctionCallGadget : public WarningGadget {
2058 const CallExpr *const Call;
2059 const Expr *UnsafeArg = nullptr;
2060 constexpr static const char *const Tag = "UnsafeLibcFunctionCall";
2061
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";
2070
2071 enum UnsafeKind {
2072 OTHERS = 0,
2073 SPRINTF = 1,
2074 SIZED_BY =
2075 2,
2076
2077 STRING = 3,
2078
2079 VA_LIST = 4,
2080
2081 } WarnedFunKind = OTHERS;
2082
2083public:
2085 : WarningGadget(Kind::UnsafeLibcFunctionCall),
2086 Call(Result.getNodeAs(Tag)) {
2087 if (Result.getNodeAs(UnsafeSprintfTag))
2088 WarnedFunKind = SPRINTF;
2089 else if (auto *E = Result.getNodeAs(UnsafeStringTag)) {
2090 WarnedFunKind = STRING;
2091 UnsafeArg = E;
2092 } else if (Result.getNodeAs(UnsafeSizedByTag)) {
2093 WarnedFunKind = SIZED_BY;
2094 UnsafeArg = Call->getArg(0);
2095 } else if (Result.getNodeAs(UnsafeVaListTag))
2096 WarnedFunKind = VA_LIST;
2097 }
2098
2099 static bool matches(const Stmt *S, ASTContext &Ctx,
2100 const UnsafeBufferUsageHandler *Handler,
2103 return false;
2104 auto *CE = dyn_cast(S);
2105 if (!CE || !CE->getDirectCallee())
2106 return false;
2107 const auto *FD = dyn_cast(CE->getDirectCallee());
2108 if (!FD)
2109 return false;
2110
2111 bool IsGlobalAndNotInAnyNamespace =
2112 FD->isGlobal() && !FD->getEnclosingNamespaceContext()->isNamespace();
2113
2114
2115
2116 if (!FD->isInStdNamespace() && !IsGlobalAndNotInAnyNamespace)
2117 return false;
2118
2119
2120 if (CE->getNumArgs() == 1 && isNullTermPointer(CE->getArg(0), Ctx))
2121 return false;
2122 auto isSingleStringLiteralArg = false;
2123 if (CE->getNumArgs() == 1) {
2124 isSingleStringLiteralArg =
2126 }
2127 if (!isSingleStringLiteralArg) {
2128
2130 Result.addNode(Tag, DynTypedNode::create(*CE));
2131 return true;
2132 }
2134 Result.addNode(Tag, DynTypedNode::create(*CE));
2135 Result.addNode(UnsafeVaListTag, DynTypedNode::create(*FD));
2136 return true;
2137 }
2139 Result.addNode(Tag, DynTypedNode::create(*CE));
2140 Result.addNode(UnsafeSprintfTag, DynTypedNode::create(*FD));
2141 return true;
2142 }
2143 }
2146 Result.addNode(Tag, DynTypedNode::create(*CE));
2147 Result.addNode(UnsafeSizedByTag, DynTypedNode::create(*CE));
2148 return true;
2149 }
2151 UnsafeStringTag)) {
2152 Result.addNode(Tag, DynTypedNode::create(*CE));
2153 return true;
2154 }
2155 }
2156 return false;
2157 }
2158
2159 const Stmt *getBaseStmt() const { return Call; }
2160
2161 SourceLocation getSourceLoc() const override { return Call->getBeginLoc(); }
2162
2163 void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
2164 bool IsRelatedToDecl,
2165 ASTContext &Ctx) const override {
2167 }
2168
2169 DeclUseList getClaimedVarUseSites() const override { return {}; }
2170
2171 SmallVector<const Expr *, 1> getUnsafePtrs() const override { return {}; }
2172};
2173
2174
2175
2176
2177class ULCArraySubscriptGadget : public FixableGadget {
2178private:
2179 static constexpr const char *const ULCArraySubscriptTag =
2180 "ArraySubscriptUnderULC";
2181 const ArraySubscriptExpr *Node;
2182
2183public:
2185 : FixableGadget(Kind::ULCArraySubscript),
2186 Node(Result.getNodeAs(ULCArraySubscriptTag)) {
2187 assert(Node != nullptr && "Expecting a non-null matching result");
2188 }
2189
2190 static bool classof(const Gadget *G) {
2191 return G->getKind() == Kind::ULCArraySubscript;
2192 }
2193
2194 static bool matches(const Stmt *S,
2195 llvm::SmallVectorImpl &Results) {
2196 size_t SizeBefore = Results.size();
2198 const auto *ASE = dyn_cast(E);
2199 if (!ASE)
2200 return;
2201 const auto *DRE =
2204 !isSupportedVariable(*DRE))
2205 return;
2207 R.addNode(ULCArraySubscriptTag, DynTypedNode::create(*ASE));
2208 Results.emplace_back(std::move(R));
2209 });
2210 return SizeBefore != Results.size();
2211 }
2212
2213 virtual std::optional
2214 getFixits(const FixitStrategy &S) const override;
2215 SourceLocation getSourceLoc() const override { return Node->getBeginLoc(); }
2216
2217 virtual DeclUseList getClaimedVarUseSites() const override {
2218 if (const auto *DRE =
2219 dyn_cast(Node->getBase()->IgnoreImpCasts())) {
2220 return {DRE};
2221 }
2222 return {};
2223 }
2224};
2225
2226
2227
2228
2229class UPCStandalonePointerGadget : public FixableGadget {
2230private:
2231 static constexpr const char *const DeclRefExprTag = "StandalonePointer";
2232 const DeclRefExpr *Node;
2233
2234public:
2236 : FixableGadget(Kind::UPCStandalonePointer),
2237 Node(Result.getNodeAs(DeclRefExprTag)) {
2238 assert(Node != nullptr && "Expecting a non-null matching result");
2239 }
2240
2241 static bool classof(const Gadget *G) {
2242 return G->getKind() == Kind::UPCStandalonePointer;
2243 }
2244
2245 static bool matches(const Stmt *S,
2246 llvm::SmallVectorImpl &Results) {
2247 size_t SizeBefore = Results.size();
2249 auto *E = dyn_cast(S);
2250 if (!E)
2251 return;
2254 !isSupportedVariable(*DRE))
2255 return;
2257 R.addNode(DeclRefExprTag, DynTypedNode::create(*DRE));
2258 Results.emplace_back(std::move(R));
2259 });
2260 return SizeBefore != Results.size();
2261 }
2262
2263 virtual std::optional
2264 getFixits(const FixitStrategy &S) const override;
2265 SourceLocation getSourceLoc() const override { return Node->getBeginLoc(); }
2266
2267 virtual DeclUseList getClaimedVarUseSites() const override { return {Node}; }
2268};
2269
2270class PointerDereferenceGadget : public FixableGadget {
2271 static constexpr const char *const BaseDeclRefExprTag = "BaseDRE";
2272 static constexpr const char *const OperatorTag = "op";
2273
2274 const DeclRefExpr *BaseDeclRefExpr = nullptr;
2275 const UnaryOperator *Op = nullptr;
2276
2277public:
2279 : FixableGadget(Kind::PointerDereference),
2280 BaseDeclRefExpr(Result.getNodeAs(BaseDeclRefExprTag)),
2281 Op(Result.getNodeAs(OperatorTag)) {}
2282
2283 static bool classof(const Gadget *G) {
2284 return G->getKind() == Kind::PointerDereference;
2285 }
2286
2287 static bool matches(const Stmt *S,
2288 llvm::SmallVectorImpl &Results) {
2289 size_t SizeBefore = Results.size();
2291 const auto *UO = dyn_cast(S);
2292 if (!UO || UO->getOpcode() != UO_Deref)
2293 return;
2294 const auto *CE = dyn_cast(UO->getSubExpr());
2295 if (!CE)
2296 return;
2297 CE = CE->IgnoreParenImpCasts();
2298 const auto *DRE = dyn_cast(CE);
2299 if (!DRE || !isSupportedVariable(*DRE))
2300 return;
2302 R.addNode(BaseDeclRefExprTag, DynTypedNode::create(*DRE));
2303 R.addNode(OperatorTag, DynTypedNode::create(*UO));
2304 Results.emplace_back(std::move(R));
2305 });
2306 return SizeBefore != Results.size();
2307 }
2308
2309 DeclUseList getClaimedVarUseSites() const override {
2310 return {BaseDeclRefExpr};
2311 }
2312
2313 virtual std::optional
2314 getFixits(const FixitStrategy &S) const override;
2315 SourceLocation getSourceLoc() const override { return Op->getBeginLoc(); }
2316};
2317
2318
2319
2320
2321class UPCAddressofArraySubscriptGadget : public FixableGadget {
2322private:
2323 static constexpr const char *const UPCAddressofArraySubscriptTag =
2324 "AddressofArraySubscriptUnderUPC";
2325 const UnaryOperator *Node;
2326
2327public:
2329 : FixableGadget(Kind::ULCArraySubscript),
2330 Node(Result.getNodeAs(UPCAddressofArraySubscriptTag)) {
2331 assert(Node != nullptr && "Expecting a non-null matching result");
2332 }
2333
2334 static bool classof(const Gadget *G) {
2335 return G->getKind() == Kind::UPCAddressofArraySubscript;
2336 }
2337
2338 static bool matches(const Stmt *S,
2339 llvm::SmallVectorImpl &Results) {
2340 size_t SizeBefore = Results.size();
2342 auto *E = dyn_cast(S);
2343 if (!E)
2344 return;
2345 const auto *UO = dyn_cast(E->IgnoreImpCasts());
2346 if (!UO || UO->getOpcode() != UO_AddrOf)
2347 return;
2348 const auto *ASE = dyn_cast(UO->getSubExpr());
2349 if (!ASE)
2350 return;
2351 const auto *DRE =
2353 if (!DRE || !isSupportedVariable(*DRE))
2354 return;
2356 R.addNode(UPCAddressofArraySubscriptTag, DynTypedNode::create(*UO));
2357 Results.emplace_back(std::move(R));
2358 });
2359 return SizeBefore != Results.size();
2360 }
2361
2362 virtual std::optional
2363 getFixits(const FixitStrategy &) const override;
2364 SourceLocation getSourceLoc() const override { return Node->getBeginLoc(); }
2365
2366 virtual DeclUseList getClaimedVarUseSites() const override {
2368 const auto *DRE =
2369 cast(ArraySubst->getBase()->IgnoreParenImpCasts());
2370 return {DRE};
2371 }
2372};
2373}
2374
2375namespace {
2376
2377
2378
2379class DeclUseTracker {
2380 using UseSetTy = llvm::SmallPtrSet<const DeclRefExpr *, 16>;
2381 using DefMapTy = llvm::DenseMap<const VarDecl *, const DeclStmt *>;
2382
2383
2384 std::unique_ptr Uses{std::make_unique()};
2385 DefMapTy Defs{};
2386
2387public:
2388 DeclUseTracker() = default;
2389 DeclUseTracker(const DeclUseTracker &) = delete;
2390 DeclUseTracker &operator=(const DeclUseTracker &) = delete;
2391 DeclUseTracker(DeclUseTracker &&) = default;
2392 DeclUseTracker &operator=(DeclUseTracker &&) = default;
2393
2394
2395 void discoverUse(const DeclRefExpr *DRE) { Uses->insert(DRE); }
2396
2397
2398 void claimUse(const DeclRefExpr *DRE) {
2399 assert(Uses->count(DRE) &&
2400 "DRE not found or claimed by multiple matchers!");
2401 Uses->erase(DRE);
2402 }
2403
2404
2405 bool hasUnclaimedUses(const VarDecl *VD) const {
2406
2407 return any_of(*Uses, [VD](const DeclRefExpr *DRE) {
2409 });
2410 }
2411
2412 UseSetTy getUnclaimedUses(const VarDecl *VD) const {
2413 UseSetTy ReturnSet;
2414 for (auto use : *Uses) {
2415 if (use->getDecl()->getCanonicalDecl() == VD->getCanonicalDecl()) {
2416 ReturnSet.insert(use);
2417 }
2418 }
2419 return ReturnSet;
2420 }
2421
2422 void discoverDecl(const DeclStmt *DS) {
2423 for (const Decl *D : DS->decls()) {
2424 if (const auto *VD = dyn_cast(D)) {
2425
2426
2427
2428
2429
2430 Defs[VD] = DS;
2431 }
2432 }
2433 }
2434
2435 const DeclStmt *lookupDecl(const VarDecl *VD) const {
2436 return Defs.lookup(VD);
2437 }
2438};
2439}
2440
2441
2442
2444private:
2445 static constexpr const char *const UPCPreIncrementTag =
2446 "PointerPreIncrementUnderUPC";
2448
2449public:
2451 : FixableGadget(Kind::UPCPreIncrement),
2453 assert(Node != nullptr && "Expecting a non-null matching result");
2454 }
2455
2457 return G->getKind() == Kind::UPCPreIncrement;
2458 }
2459
2462
2463
2464
2465
2466 size_t SizeBefore = Results.size();
2468 auto *E = dyn_cast(S);
2469 if (!E)
2470 return;
2471 const auto *UO = dyn_cast(E->IgnoreImpCasts());
2472 if (!UO || UO->getOpcode() != UO_PreInc)
2473 return;
2474 const auto *DRE = dyn_cast(UO->getSubExpr());
2475 if (!DRE || !isSupportedVariable(*DRE))
2476 return;
2477 MatchResult R;
2479 Results.emplace_back(std::move(R));
2480 });
2481 return SizeBefore != Results.size();
2482 }
2483
2484 virtual std::optional
2487
2489 return {dyn_cast(Node->getSubExpr())};
2490 }
2491};
2492
2493
2494
2496private:
2497 static constexpr const char *const UUCAddAssignTag =
2498 "PointerAddAssignUnderUUC";
2499 static constexpr const char *const OffsetTag = "Offset";
2500
2502 const Expr *Offset = nullptr;
2503
2504public:
2506 : FixableGadget(Kind::UUCAddAssign),
2508 Offset(Result.getNodeAs<Expr>(OffsetTag)) {
2509 assert(Node != nullptr && "Expecting a non-null matching result");
2510 }
2511
2513 return G->getKind() == Kind::UUCAddAssign;
2514 }
2515
2518 size_t SizeBefore = Results.size();
2520 const auto *E = dyn_cast(S);
2521 if (!E)
2522 return;
2523 const auto *BO = dyn_cast(E->IgnoreImpCasts());
2524 if (!BO || BO->getOpcode() != BO_AddAssign)
2525 return;
2526 const auto *DRE = dyn_cast(BO->getLHS());
2527 if (!DRE || (*DRE) || !isSupportedVariable(*DRE))
2528 return;
2529 MatchResult R;
2532 Results.emplace_back(std::move(R));
2533 });
2534 return SizeBefore != Results.size();
2535 }
2536
2537 virtual std::optional
2540
2542 return {dyn_cast(Node->getLHS())};
2543 }
2544};
2545
2546
2547
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";
2553
2554 const DeclRefExpr *BaseDeclRefExpr = nullptr;
2558
2559public:
2561 : FixableGadget(Kind::DerefSimplePtrArithFixable),
2562 BaseDeclRefExpr(Result.getNodeAs<DeclRefExpr>(BaseDeclRefExprTag)),
2566
2569 auto IsPtr = [](const Expr *E, MatchResult &R) {
2571 return false;
2572 const auto *DRE = dyn_cast(E->IgnoreImpCasts());
2573 if (!DRE || !isSupportedVariable(*DRE))
2574 return false;
2576 return true;
2577 };
2578 const auto IsPlusOverPtrAndInteger = [&IsPtr](const Expr *E,
2579 MatchResult &R) {
2580 const auto *BO = dyn_cast(E);
2581 if (!BO || BO->getOpcode() != BO_Add)
2582 return false;
2583
2584 const auto *LHS = BO->getLHS();
2585 const auto *RHS = BO->getRHS();
2589 return true;
2590 }
2594 return true;
2595 }
2596 return false;
2597 };
2598 size_t SizeBefore = Results.size();
2599 const auto InnerMatcher = [&IsPlusOverPtrAndInteger,
2600 &Results](const Expr *E) {
2601 const auto *UO = dyn_cast(E);
2602 if (!UO || UO->getOpcode() != UO_Deref)
2603 return;
2604
2606 MatchResult R;
2607 if (IsPlusOverPtrAndInteger(Operand, R)) {
2609 Results.emplace_back(std::move(R));
2610 }
2611 };
2613 return SizeBefore != Results.size();
2614 }
2615
2616 virtual std::optional
2619 return DerefOp->getBeginLoc();
2620 }
2621
2623 return {BaseDeclRefExpr};
2624 }
2625};
2626
2628
2629public:
2631 : WarningGadgets(WarningGadgets) {}
2632
2636 if (!S)
2637 return false;
2638
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)); \
2644 return true; \
2645 }
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)); \
2650 return true; \
2651 }
2652#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2653 return false;
2654 }
2655
2656private:
2657 WarningGadgetList &WarningGadgets;
2658};
2659
2661
2662public:
2664 DeclUseTracker &Tracker)
2665 : FixableGadgets(FixableGadgets), Tracker(Tracker) {}
2666
2669 bool matchFound = false;
2671 if (!S) {
2672 return matchFound;
2673 }
2674
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; \
2681 } \
2682 Results = {}; \
2683 }
2684#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
2685
2686
2687 if (auto *DRE = findDeclRefExpr(S); DRE) {
2688 Tracker.discoverUse(DRE);
2689 matchFound = true;
2690 }
2691
2692
2693
2694 if (auto *DS = findDeclStmt(S); DS) {
2695 Tracker.discoverDecl(DS);
2696 matchFound = true;
2697 }
2698 return matchFound;
2699 }
2700
2701private:
2703 const auto *DRE = dyn_cast(S);
2705 return nullptr;
2708 return nullptr;
2709 return DRE;
2710 }
2711 const DeclStmt *findDeclStmt(const Stmt *S) {
2712 const auto *DS = dyn_cast(S);
2713 if (!DS)
2714 return nullptr;
2715 return DS;
2716 }
2717 FixableGadgetList &FixableGadgets;
2718 DeclUseTracker &Tracker;
2719};
2720
2721
2724 bool EmitSuggestions, FixableGadgetList &FixableGadgets,
2725 WarningGadgetList &WarningGadgets,
2726 DeclUseTracker &Tracker) {
2729 if (EmitSuggestions) {
2732 }
2733}
2734
2735
2737 bool operator()(const NodeTy *N1, const NodeTy *N2) const {
2738 return N1->getBeginLoc().getRawEncoding() <
2739 N2->getBeginLoc().getRawEncoding();
2740 }
2741};
2742
2745 public:
2746 MockReporter() {}
2749 const Expr *UnsafeArg = nullptr) override {}
2754 const Decl *,
2757 bool IsRelatedToDecl,
2760 return false;
2761 }
2763 return false;
2764 }
2766 return false;
2767 }
2769 SourceLocation, StringRef WSSuffix = "") const override {
2770 return "";
2771 }
2772 };
2773
2774 FixableGadgetList FixableGadgets;
2775 WarningGadgetList WarningGadgets;
2776 DeclUseTracker Tracker;
2777 MockReporter IgnoreHandler;
2778
2780 FixableGadgets, WarningGadgets, Tracker);
2781
2782 std::set<const Expr *> Result;
2783 for (auto &G : WarningGadgets) {
2784 for (const Expr *E : G->getUnsafePtrs()) {
2786 }
2787 }
2788
2790}
2791
2793 std::map<const VarDecl *, std::set<const WarningGadget *>,
2794
2795
2798
2800};
2801
2805
2806
2807 for (auto &G : AllUnsafeOperations) {
2808 DeclUseList ClaimedVarUseSites = G->getClaimedVarUseSites();
2809
2810 bool AssociatedWithVarDecl = false;
2811 for (const DeclRefExpr *DRE : ClaimedVarUseSites) {
2812 if (const auto *VD = dyn_cast(DRE->getDecl())) {
2813 result.byVar[VD].insert(G.get());
2814 AssociatedWithVarDecl = true;
2815 }
2816 }
2817
2818 if (!AssociatedWithVarDecl) {
2819 result.noVar.push_back(G.get());
2820 continue;
2821 }
2822 }
2823 return result;
2824}
2825
2827 std::map<const VarDecl *, std::set<const FixableGadget *>,
2828
2829
2832};
2833
2837 for (auto &F : AllFixableOperations) {
2838 DeclUseList DREs = F->getClaimedVarUseSites();
2839
2841 if (const auto *VD = dyn_cast(DRE->getDecl())) {
2842 FixablesForUnsafeVars.byVar[VD].insert(F.get());
2843 }
2844 }
2845 }
2846 return FixablesForUnsafeVars;
2847}
2848
2851
2852
2853 std::vector<const FixItHint *> All;
2854
2855 for (const FixItHint &H : FixIts)
2856 All.push_back(&H);
2857 std::sort(All.begin(), All.end(),
2859 return SM.isBeforeInTranslationUnit(H1->RemoveRange.getBegin(),
2860 H2->RemoveRange.getBegin());
2861 });
2862
2863 const FixItHint *CurrHint = nullptr;
2864
2866 if (!CurrHint ||
2868 Hint->RemoveRange.getBegin())) {
2869
2870
2871 CurrHint = Hint;
2872 } else
2873
2874
2875 return true;
2876 }
2877 return false;
2878}
2879
2880std::optional
2881PtrToPtrAssignmentGadget::getFixits(const FixitStrategy &S) const {
2884 switch (S.lookup(LeftVD)) {
2887 return FixItList{};
2888 return std::nullopt;
2890 return std::nullopt;
2893 return std::nullopt;
2895 llvm_unreachable("unsupported strategies for FixableGadgets");
2896 }
2897 return std::nullopt;
2898}
2899
2900
2901static inline std::optional createDataFixit(const ASTContext &Ctx,
2902 const DeclRefExpr *DRE);
2903
2904std::optional
2905CArrayToPtrAssignmentGadget::getFixits(const FixitStrategy &S) const {
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924 if (S.lookup(LeftVD) == FixitStrategy::Kind::Span) {
2925 if (S.lookup(RightVD) == FixitStrategy::Kind::Wontfix) {
2926 return FixItList{};
2927 }
2928 } else if (S.lookup(LeftVD) == FixitStrategy::Kind::Wontfix) {
2929 if (S.lookup(RightVD) == FixitStrategy::Kind::Array) {
2930 return createDataFixit(RightVD->getASTContext(), PtrRHS);
2931 }
2932 }
2933 return std::nullopt;
2934}
2935
2936std::optional
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)
2943 return FixItList{};
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");
2952 }
2953 return std::nullopt;
2954}
2955
2959 if (ConstVal->isNegative())
2960 return false;
2962 return false;
2963 return true;
2964}
2965
2966std::optional
2967ULCArraySubscriptGadget::getFixits(const FixitStrategy &S) const {
2968 if (const auto *DRE =
2969 dyn_cast(Node->getBase()->IgnoreImpCasts()))
2970 if (const auto *VD = dyn_cast(DRE->getDecl())) {
2971 switch (S.lookup(VD)) {
2972 case FixitStrategy::Kind::Span: {
2973
2974
2975
2976 const ASTContext &Ctx =
2979 return std::nullopt;
2980
2981 return FixItList{};
2982 }
2983 case FixitStrategy::Kind::Array:
2984 return FixItList{};
2985 case FixitStrategy::Kind::Wontfix:
2986 case FixitStrategy::Kind::Iterator:
2987 case FixitStrategy::Kind::Vector:
2988 llvm_unreachable("unsupported strategies for FixableGadgets");
2989 }
2990 }
2991 return std::nullopt;
2992}
2993
2994static std::optional
2996
2997std::optional
2998UPCAddressofArraySubscriptGadget::getFixits(const FixitStrategy &S) const {
2999 auto DREs = getClaimedVarUseSites();
3000 const auto *VD = cast(DREs.front()->getDecl());
3001
3002 switch (S.lookup(VD)) {
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");
3011 }
3012 return std::nullopt;
3013}
3014
3015
3017 static const char *const EOL = "\n";
3018 return EOL;
3019}
3020
3021
3022static std::string
3024 std::string s = std::string("<# ");
3025 s += HintTextToUser;
3026 s += " #>";
3027 return s;
3028}
3029
3030
3031template
3032static std::optional
3035 if (unsigned TkLen =
3038
3040 return Loc;
3041 }
3042 return std::nullopt;
3043}
3044
3045
3046
3047
3048
3049
3050
3053
3054
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()));
3060 });
3063 AttrRangeOverlapping;
3064}
3065
3066
3067
3068
3069
3075 End =
3076
3078
3080}
3081
3082
3089
3090
3093 SourceRange NameRange{BeginLoc, EndLoc};
3094
3096}
3097
3098
3099
3100
3101
3102
3103static std::string
3105 std::optional Quals = std::nullopt) {
3106 const char *const SpanOpen = "std::span<";
3107
3108 if (Quals)
3109 return SpanOpen + EltTyText.str() + ' ' + Quals->getAsString() + '>';
3110 return SpanOpen + EltTyText.str() + '>';
3111}
3112
3113std::optional
3115 const VarDecl *VD = dyn_cast(BaseDeclRefExpr->getDecl());
3116
3119
3120 if (auto ConstVal = Offset->getIntegerConstantExpr(Ctx))
3121 if (ConstVal->isNegative())
3122 return std::nullopt;
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143 const Expr *LHS = AddOp->getLHS(), *RHS = AddOp->getRHS();
3149
3150 std::optional LHSLocation = getPastLoc(LHS, SM, LangOpts);
3151 if (!LHSLocation)
3152 return std::nullopt;
3153
3156
3157 std::optional AddOpLocation =
3159 std::optional DerefOpLocation =
3161
3162 if (!AddOpLocation || !DerefOpLocation)
3163 return std::nullopt;
3164
3167
3168 return FixItList{
3172 }
3173 return std::nullopt;
3174}
3175
3176std::optional
3177PointerDereferenceGadget::getFixits(const FixitStrategy &S) const {
3179 switch (S.lookup(VD)) {
3183
3184
3187
3188 if (auto LocPastOperand =
3192 }
3193 break;
3194 }
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!");
3202 }
3203
3204 return std::nullopt;
3205}
3206
3210
3211 std::optional EndOfOperand =
3213
3214 if (EndOfOperand)
3216
3217 return std::nullopt;
3218}
3219
3220
3221
3222std::optional
3223UPCStandalonePointerGadget::getFixits(const FixitStrategy &S) const {
3225 switch (S.lookup(VD)) {
3226 case FixitStrategy::Kind::Array:
3227 case FixitStrategy::Kind::Span: {
3229
3230 break;
3231 }
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");
3237 }
3238
3239 return std::nullopt;
3240}
3241
3242
3243
3244static std::optional
3247 const auto *DRE = cast(ArraySub->getBase()->IgnoreImpCasts());
3248
3249
3251 const Expr *Idx = ArraySub->getIdx();
3254 std::stringstream SS;
3255 bool IdxIsLitZero = false;
3256
3258 if ((*ICE).isZero())
3259 IdxIsLitZero = true;
3260 std::optional DreString = getExprText(DRE, SM, LangOpts);
3261 if (!DreString)
3262 return std::nullopt;
3263
3264 if (IdxIsLitZero) {
3265
3266 SS << (*DreString).str() << ".data()";
3267 } else {
3268 std::optional IndexString = getExprText(Idx, SM, LangOpts);
3269 if (!IndexString)
3270 return std::nullopt;
3271
3272 SS << "&" << (*DreString).str() << ".data()"
3273 << "[" << (*IndexString).str() << "]";
3274 }
3275 return FixItList{
3277}
3278
3279std::optional
3282
3283 if (DREs.size() != 1)
3284 return std::nullopt;
3285
3286 if (const VarDecl *VD = dyn_cast(DREs.front()->getDecl())) {
3288 FixItList Fixes;
3289
3290 const Stmt *AddAssignNode = Node;
3291 StringRef varName = VD->getName();
3293
3295 return std::nullopt;
3296
3297
3298 bool NotParenExpr =
3299 (Offset->IgnoreParens()->getBeginLoc() == Offset->getBeginLoc());
3300 std::string SS = varName.str() + " = " + varName.str() + ".subspan";
3301 if (NotParenExpr)
3302 SS += "(";
3303
3304 std::optional AddAssignLocation = getEndCharLoc(
3306 if (!AddAssignLocation)
3307 return std::nullopt;
3308
3311 SS));
3312 if (NotParenExpr)
3314 Offset->getEndLoc().getLocWithOffset(1), ")"));
3315 return Fixes;
3316 }
3317 }
3318 return std::nullopt;
3319}
3320
3321std::optional
3324
3325 if (DREs.size() != 1)
3326 return std::nullopt;
3327
3328 if (const VarDecl *VD = dyn_cast(DREs.front()->getDecl())) {
3330 FixItList Fixes;
3331 std::stringstream SS;
3332 StringRef varName = VD->getName();
3334
3335
3336 SS << "(" << varName.data() << " = " << varName.data()
3337 << ".subspan(1)).data()";
3338 std::optional PreIncLocation =
3340 if (!PreIncLocation)
3341 return std::nullopt;
3342
3344 SourceRange(Node->getBeginLoc(), *PreIncLocation), SS.str()));
3345 return Fixes;
3346 }
3347 }
3348 return std::nullopt;
3349}
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366static std::optional
3368 const StringRef UserFillPlaceHolder) {
3371
3372
3373
3374
3375
3376 if (Init->isNullPointerConstant(
3377 Ctx,
3378
3379
3381 NPC_ValueDependentIsNotNull)) {
3382 std::optional InitLocation =
3384 if (!InitLocation)
3385 return std::nullopt;
3386
3388
3390 }
3391
3392 FixItList FixIts{};
3393 std::string ExtentText = UserFillPlaceHolder.data();
3394 StringRef One = "1";
3395
3396
3398
3399 if (auto CxxNew = dyn_cast(Init->IgnoreImpCasts())) {
3400
3401
3402
3403
3404 if (const Expr *Ext = CxxNew->getArraySize().value_or(nullptr)) {
3405 if (!Ext->HasSideEffects(Ctx)) {
3406 std::optional ExtentString = getExprText(Ext, SM, LangOpts);
3407 if (!ExtentString)
3408 return std::nullopt;
3409 ExtentText = *ExtentString;
3410 }
3411 } else if (!CxxNew->isArray())
3412
3413
3414 ExtentText = One;
3416
3417
3418
3419 return FixItList{};
3420 } else {
3421
3422
3423 if (auto AddrOfExpr = dyn_cast(Init->IgnoreImpCasts()))
3424 if (AddrOfExpr->getOpcode() == UnaryOperatorKind::UO_AddrOf &&
3425 isa_and_present(AddrOfExpr->getSubExpr()))
3426 ExtentText = One;
3427
3428
3429 }
3430
3432 std::optional LocPassInit = getPastLoc(Init, SM, LangOpts);
3433
3434 if (!LocPassInit)
3435 return std::nullopt;
3436
3437 StrBuffer.append(", ");
3438 StrBuffer.append(ExtentText);
3439 StrBuffer.append("}");
3441 return FixIts;
3442}
3443
3444#ifndef NDEBUG
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))
3449#else
3450#define DEBUG_NOTE_DECL_FAIL(D, Msg)
3451#endif
3452
3453
3454
3455
3456static std::optionalstd::string
3459
3460 std::optional PteTyQualifiers = std::nullopt;
3463
3464 if (!PteTyText)
3465 return std::nullopt;
3466
3467 std::string SpanTyText = "std::span<";
3468
3469 SpanTyText.append(*PteTyText);
3470
3471 if (PteTyQualifiers) {
3472 SpanTyText.append(" ");
3473 SpanTyText.append(PteTyQualifiers->getAsString());
3474 }
3475 SpanTyText.append(">");
3476 return SpanTyText;
3477}
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3494 const StringRef UserFillPlaceHolder,
3497 return {};
3498
3499 FixItList FixIts{};
3501
3502 if (!SpanTyText) {
3504 return {};
3505 }
3506
3507
3508 std::stringstream SS;
3509
3510 SS << *SpanTyText;
3511
3513 std::optional InitFixIts =
3515 if (!InitFixIts)
3516 return {};
3517 FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts->begin()),
3518 std::make_move_iterator(InitFixIts->end()));
3519 }
3520
3521
3522
3523
3525 if (!EndLocForReplacement.isValid()) {
3527 return {};
3528 }
3529
3530
3531
3533 SS << " ";
3534
3537 return FixIts;
3538}
3539
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575static std::optional
3579
3581 return std::nullopt;
3582
3585 const unsigned NumParms = FD->getNumParams();
3586 std::vectorstd::string NewTysTexts(NumParms);
3587 std::vector ParmsMask(NumParms, false);
3588 bool AtLeastOneParmToFix = false;
3589
3590 for (unsigned i = 0; i < NumParms; i++) {
3592
3594 continue;
3596
3597 return std::nullopt;
3598
3599 std::optional PteTyQuals = std::nullopt;
3600 std::optionalstd::string PteTyText =
3602
3603 if (!PteTyText)
3604
3605 return std::nullopt;
3606
3607
3608 NewTysTexts[i] = getSpanTypeText(*PteTyText, PteTyQuals);
3609 ParmsMask[i] = true;
3610 AtLeastOneParmToFix = true;
3611 }
3612 if (!AtLeastOneParmToFix)
3613
3614 return {};
3615
3616
3617
3618
3619 const auto NewOverloadSignatureCreator =
3620 [&SM, &LangOpts, &NewTysTexts,
3621 &ParmsMask](const FunctionDecl *FD) -> std::optionalstd::string {
3622 std::stringstream SS;
3623
3624 SS << ";";
3626
3629 SM, LangOpts))
3630 SS << Prefix->str();
3631 else
3632 return std::nullopt;
3633
3634 const unsigned NumParms = FD->getNumParams();
3635
3636 for (unsigned i = 0; i < NumParms; i++) {
3638
3640 continue;
3641 if (ParmsMask[i]) {
3642
3643
3644 SS << NewTysTexts[i];
3645
3647 SS << ' ' << II->getName().str();
3648 } else if (auto ParmTypeText =
3650 SM, LangOpts)) {
3651
3652 SS << ParmTypeText->str();
3653 } else
3654 return std::nullopt;
3655 if (i != NumParms - 1)
3656 SS << ", ";
3657 }
3658 SS << ")";
3659 return SS.str();
3660 };
3661
3662
3663
3664 const auto OldOverloadDefCreator =
3665 [&Handler, &SM, &LangOpts, &NewTysTexts,
3666 &ParmsMask](const FunctionDecl *FD) -> std::optionalstd::string {
3667 std::stringstream SS;
3668
3670
3673 LangOpts))
3675 << FDPrefix->str() << "{";
3676 else
3677 return std::nullopt;
3678
3680 SS << "return " << FunQualName->str() << "(";
3681 else
3682 return std::nullopt;
3683
3684
3685 const unsigned NumParms = FD->getNumParams();
3686 for (unsigned i = 0; i < NumParms; i++) {
3688
3690 continue;
3691
3692
3694
3695 return std::nullopt;
3696 if (ParmsMask[i])
3697
3700 else
3702 if (i != NumParms - 1)
3703 SS << ", ";
3704 }
3705
3707
3708 return SS.str();
3709 };
3710
3711 FixItList FixIts{};
3713 std::optional Loc = getPastLoc(FReDecl, SM, LangOpts);
3714
3715 if (!Loc)
3716 return {};
3717 if (FReDecl->isThisDeclarationADefinition()) {
3718 assert(FReDecl == FD && "inconsistent function definition");
3719
3720
3721 if (auto OldOverloadDef = OldOverloadDefCreator(FReDecl))
3723 else
3724 return {};
3725 } else {
3726
3727 if (!FReDecl->hasAttr()) {
3730 FReDecl->getBeginLoc(), " ")));
3731 }
3732
3733 if (auto NewOverloadDecl = NewOverloadSignatureCreator(FReDecl))
3735 else
3736 return {};
3737 }
3738 }
3739 return FixIts;
3740}
3741
3742
3747 return {};
3748 }
3750
3752 return {};
3753 }
3754
3755 std::optional PteTyQualifiers = std::nullopt;
3758
3759 if (!PteTyText) {
3761 return {};
3762 }
3763
3765
3766 if (!PVDNameText) {
3768 return {};
3769 }
3770
3771 std::stringstream SS;
3773
3774 if (PteTyQualifiers)
3775
3777 else
3779
3782
3783 SS << ' ' << PVDNameText->str();
3784
3786}
3787
3789 const DeclUseTracker &Tracker,
3792 const DeclStmt *DS = Tracker.lookupDecl(VD);
3793 if (!DS) {
3795 " : variables declared this way not implemented yet");
3796 return {};
3797 }
3799
3801 return {};
3802 }
3803
3804
3805
3806 (void)DS;
3807
3808
3810}
3811
3814 FixItList FixIts{};
3815
3816
3817
3819 const QualType &ArrayEltT = CAT->getElementType();
3820 assert(!ArrayEltT.isNull() && "Trying to fix a non-array type variable!");
3821
3823 return {};
3824
3826
3827
3828
3829 auto MaybeElemTypeTxt =
3832 if (!MaybeElemTypeTxt)
3833 return {};
3834 const llvm::StringRef ElemTypeTxt = MaybeElemTypeTxt->trim();
3835
3836
3839 while (NextTok && !NextTok->is(tok::l_square) &&
3843 if (!NextTok)
3844 return {};
3845 const SourceLocation LSqBracketLoc = NextTok->getLocation();
3846
3847
3848
3852 if (!MaybeArraySizeTxt)
3853 return {};
3854 const llvm::StringRef ArraySizeTxt = MaybeArraySizeTxt->trim();
3855 if (ArraySizeTxt.empty()) {
3856
3857
3858
3859
3860
3861
3862
3863 return {};
3864 }
3865
3866 std::optional IdentText =
3868
3869 if (!IdentText) {
3871 return {};
3872 }
3873
3875 llvm::raw_svector_ostream OS(Replacement);
3876 OS << "std::array<" << ElemTypeTxt << ", " << ArraySizeTxt << "> "
3877 << IdentText->str();
3878
3881 }
3882
3883 return FixIts;
3884}
3885
3887 const DeclUseTracker &Tracker,
3890 const DeclStmt *DS = Tracker.lookupDecl(VD);
3891 assert(DS && "Fixing non-local variables not implemented yet!");
3893
3894 return {};
3895 }
3896
3897
3898
3899 (void)DS;
3900
3901
3903}
3904
3905
3906
3907static FixItList
3909 const Decl *D,
3910 const DeclUseTracker &Tracker, ASTContext &Ctx,
3912 if (const auto *PVD = dyn_cast(VD)) {
3913 auto *FD = dyn_castclang::FunctionDecl(PVD->getDeclContext());
3914 if (!FD || FD != D) {
3915
3916
3918 return {};
3919 }
3920
3921
3922
3923
3924
3925 if (FD->isMain() || FD->isConstexpr() ||
3927 FD->isVariadic() ||
3928
3930
3932 FD->isOverloadedOperator()) {
3934 return {};
3935 }
3936 }
3937
3938 switch (K) {
3941 if (const auto *PVD = dyn_cast(VD))
3943
3946 }
3948 return {};
3949 }
3953
3955 return {};
3956 }
3959 llvm_unreachable("FixitStrategy not implemented yet!");
3961 llvm_unreachable("Invalid strategy!");
3962 }
3963 llvm_unreachable("Unknown strategy!");
3964}
3965
3966
3967
3969
3970
3971 return llvm::any_of(FixIts, [](const FixItHint &Hint) {
3973 if (Range.getBegin().isMacroID() || Range.getEnd().isMacroID())
3974
3975 return true;
3976 return false;
3977 });
3978}
3979
3980
3985
3986
3987
3988
3990 std::map<const VarDecl *, FixItList> &FixItsForVariable,
3992
3994
3995 for (const auto &[VD, Ignore] : FixItsForVariable) {
3997 if (llvm::any_of(Grp,
3998 [&FixItsForVariable](const VarDecl *GrpMember) -> bool {
3999 return !FixItsForVariable.count(GrpMember);
4000 })) {
4001
4002
4004 ToErase.push_back(Member);
4005 }
4006 }
4007 for (auto *VarToErase : ToErase)
4008 FixItsForVariable.erase(VarToErase);
4009}
4010
4011
4012
4013
4014
4015
4016
4017
4019 std::map<const VarDecl *, FixItList> &FixItsForVariable ,
4023 FixItList FixItsSharedByParms{};
4024
4025 std::optional OverloadFixes =
4027
4028 if (OverloadFixes) {
4029 FixItsSharedByParms.append(*OverloadFixes);
4030 } else {
4031
4032
4033
4035 FixItsForVariable.erase(Member);
4036 }
4037 return FixItsSharedByParms;
4038}
4039
4040
4041static std::map<const VarDecl *, FixItList>
4044 const Decl *D,
4047
4048
4049
4050 std::map<const VarDecl *, FixItList> FixItsForVariable;
4051
4052
4053
4054
4055 for (const auto &[VD, Fixables] : FixablesForAllVars.byVar) {
4056 FixItsForVariable[VD] =
4058
4059
4060 if (FixItsForVariable[VD].empty()) {
4061 FixItsForVariable.erase(VD);
4062 continue;
4063 }
4064 for (const auto &F : Fixables) {
4065 std::optional Fixits = F->getFixits(S);
4066
4067 if (Fixits) {
4068 FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
4069 Fixits->begin(), Fixits->end());
4070 continue;
4071 }
4072#ifndef NDEBUG
4074 VD, F->getSourceLoc(),
4075 ("gadget '" + F->getDebugName() + "' refused to produce a fix")
4076 .str());
4077#endif
4078 FixItsForVariable.erase(VD);
4079 break;
4080 }
4081 }
4082
4083
4084
4085
4086
4087
4088
4090
4091
4092
4093
4094
4095
4096
4097 FixItList FixItsSharedByParms{};
4098
4099 if (auto *FD = dyn_cast(D))
4101 FixItsForVariable, VarGrpMgr, FD, S, Ctx, Handler);
4102
4103
4104
4105 std::map<const VarDecl *, FixItList> FinalFixItsForVariable{
4106 FixItsForVariable};
4107
4108 for (auto &[Var, Ignore] : FixItsForVariable) {
4109 bool AnyParm = false;
4110 const auto VarGroupForVD = VarGrpMgr.getGroupOfVar(Var, &AnyParm);
4111
4112 for (const VarDecl *GrpMate : VarGroupForVD) {
4113 if (Var == GrpMate)
4114 continue;
4115 if (FixItsForVariable.count(GrpMate))
4116 FinalFixItsForVariable[Var].append(FixItsForVariable[GrpMate]);
4117 }
4118 if (AnyParm) {
4119
4120 assert(!FixItsSharedByParms.empty() &&
4121 "Should not try to fix a parameter that does not belong to a "
4122 "FunctionDecl");
4123 FinalFixItsForVariable[Var].append(FixItsSharedByParms);
4124 }
4125 }
4126
4127
4128
4129
4130 for (auto Iter = FinalFixItsForVariable.begin();
4131 Iter != FinalFixItsForVariable.end();)
4134 Iter = FinalFixItsForVariable.erase(Iter);
4135 } else
4136 Iter++;
4137 return FinalFixItsForVariable;
4138}
4139
4140template
4141static FixitStrategy
4144 for (const VarDecl *VD : UnsafeVars) {
4147 else
4149 }
4150 return S;
4151}
4152
4153
4155 const std::vector Groups;
4156 const std::map<const VarDecl *, unsigned> &VarGrpMap;
4157 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms;
4158
4159public:
4161 const std::vector &Groups,
4162 const std::map<const VarDecl *, unsigned> &VarGrpMap,
4163 const llvm::SetVector<const VarDecl *> &GrpsUnionForParms)
4164 : Groups(Groups), VarGrpMap(VarGrpMap),
4165 GrpsUnionForParms(GrpsUnionForParms) {}
4166
4168 if (GrpsUnionForParms.contains(Var)) {
4169 if (HasParm)
4170 *HasParm = true;
4171 return GrpsUnionForParms.getArrayRef();
4172 }
4173 if (HasParm)
4174 *HasParm = false;
4175
4176 auto It = VarGrpMap.find(Var);
4177
4178 if (It == VarGrpMap.end())
4179 return {};
4180 return Groups[It->second];
4181 }
4182
4184 return GrpsUnionForParms.getArrayRef();
4185 }
4186};
4187
4189 WarningGadgetList WarningGadgets,
4190 DeclUseTracker Tracker,
4192 bool EmitSuggestions) {
4193 if (!EmitSuggestions) {
4194
4195
4196
4197 for (const auto &G : WarningGadgets) {
4198 G->handleUnsafeOperation(Handler, false,
4200 }
4201
4202
4203
4204 assert(FixableGadgets.empty() &&
4205 "Fixable gadgets found but suggestions not requested!");
4206 return;
4207 }
4208
4209
4210
4211 if (!WarningGadgets.empty()) {
4212
4213
4214
4215 for (const auto &G : FixableGadgets) {
4216 for (const auto *DRE : G->getClaimedVarUseSites()) {
4217 Tracker.claimUse(DRE);
4218 }
4219 }
4220 }
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233 if (WarningGadgets.empty())
4234 return;
4235
4240
4241 std::map<const VarDecl *, FixItList> FixItsForVariableGroup;
4242
4243
4244 for (auto it = FixablesForAllVars.byVar.cbegin();
4245 it != FixablesForAllVars.byVar.cend();) {
4246
4247 if ((!it->first->isLocalVarDecl() && (it->first))) {
4248#ifndef NDEBUG
4250 ("failed to produce fixit for '" +
4251 it->first->getNameAsString() +
4252 "' : neither local nor a parameter"));
4253#endif
4254 it = FixablesForAllVars.byVar.erase(it);
4255 } else if (it->first->getType().getCanonicalType()->isReferenceType()) {
4256#ifndef NDEBUG
4258 ("failed to produce fixit for '" +
4259 it->first->getNameAsString() +
4260 "' : has a reference type"));
4261#endif
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()) {
4266#ifndef NDEBUG
4268 ("failed to produce fixit for '" +
4269 it->first->getNameAsString() +
4270 "' : init capture"));
4271#endif
4272 it = FixablesForAllVars.byVar.erase(it);
4273 } else {
4274 ++it;
4275 }
4276 }
4277
4278#ifndef NDEBUG
4279 for (const auto &it : UnsafeOps.byVar) {
4280 const VarDecl *const UnsafeVD = it.first;
4281 auto UnclaimedDREs = Tracker.getUnclaimedUses(UnsafeVD);
4282 if (UnclaimedDREs.empty())
4283 continue;
4286 std::string UnclaimedUseTrace =
4287 getDREAncestorString(UnclaimedDRE, D->getASTContext());
4288
4291 ("failed to produce fixit for '" + UnfixedVDName +
4292 "' : has an unclaimed use\nThe unclaimed DRE trace: " +
4293 UnclaimedUseTrace));
4294 }
4295 }
4296#endif
4297
4298
4299 using DepMapTy =
4300 llvm::DenseMap<const VarDecl *, llvm::SetVector<const VarDecl *>>;
4301 DepMapTy DependenciesMap{};
4302 DepMapTy PtrAssignmentGraph{};
4303
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();
4308 if (ImplPair) {
4309 std::pair<const VarDecl *, const VarDecl *> Impl = std::move(*ImplPair);
4310 PtrAssignmentGraph[Impl.first].insert(Impl.second);
4311 }
4312 }
4313 }
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332 std::set<const VarDecl *> VisitedVarsDirected{};
4333 for (const auto &[Var, ignore] : UnsafeOps.byVar) {
4334 if (VisitedVarsDirected.find(Var) == VisitedVarsDirected.end()) {
4335
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);
4346 }
4347 DependenciesMap[Var].insert(Adj);
4348 DependenciesMap[Adj].insert(Var);
4349 }
4350 }
4351 }
4352 }
4353
4354
4355 std::vector Groups;
4356
4357
4358
4359 std::map<const VarDecl *, unsigned> VarGrpMap;
4360
4361 llvm::SetVector<const VarDecl *>
4362 GrpsUnionForParms;
4363
4364
4365
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{};
4371
4372 Queue.push(Var);
4373 while (!Queue.empty()) {
4374 const VarDecl *CurrentVar = Queue.front();
4375 Queue.pop();
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()) {
4381 Queue.push(Adj);
4382 }
4383 }
4384 }
4385
4386 bool HasParm = false;
4387 unsigned GrpIdx = Groups.size() - 1;
4388
4389 for (const VarDecl *V : VarGroup) {
4390 VarGrpMap[V] = GrpIdx;
4392 HasParm = true;
4393 }
4394 if (HasParm)
4395 GrpsUnionForParms.insert_range(VarGroup);
4396 }
4397 }
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417 for (auto I = FixablesForAllVars.byVar.begin();
4418 I != FixablesForAllVars.byVar.end();) {
4419
4420 if (!VisitedVars.count((*I).first)) {
4421
4422 I = FixablesForAllVars.byVar.erase(I);
4423 } else
4424 ++I;
4425 }
4426
4427
4428
4430 VisitedVars, [&FixablesForAllVars](const VarDecl *V) {
4431
4432 return FixablesForAllVars.byVar.count(V);
4433 }));
4435
4437
4438
4439 FixItsForVariableGroup =
4441 Tracker, Handler, VarGrpMgr);
4442
4443 for (const auto &G : UnsafeOps.noVar) {
4444 G->handleUnsafeOperation(Handler, false,
4446 }
4447
4448 for (const auto &[VD, WarningGadgets] : UnsafeOps.byVar) {
4449 auto FixItsIt = FixItsForVariableGroup.find(VD);
4451 FixItsIt != FixItsForVariableGroup.end()
4452 ? std::move(FixItsIt->second)
4453 : FixItList{},
4454 D, NaiveStrategy);
4455 for (const auto &G : WarningGadgets) {
4456 G->handleUnsafeOperation(Handler, true,
4458 }
4459 }
4460}
4461
4464 bool EmitSuggestions) {
4465#ifndef NDEBUG
4467#endif
4468
4469 assert(D);
4470
4472
4473 if (const auto *FD = dyn_cast(D)) {
4474
4475
4476
4477 if (const auto *MD = dyn_cast(D)) {
4478 if (MD->getParent()->isLambda() && MD->getParent()->isLocalClass())
4479 return;
4480 }
4481
4483 if (FReDecl->isExternC()) {
4484
4485
4486 EmitSuggestions = false;
4487 break;
4488 }
4489 }
4490
4491 Stmts.push_back(FD->getBody());
4492
4493 if (const auto *ID = dyn_cast(D)) {
4495 Stmts.push_back(CI->getInit());
4496 }
4497 }
4499 Stmts.push_back(D->getBody());
4500 }
4501
4502 assert(!Stmts.empty());
4503
4504 FixableGadgetList FixableGadgets;
4505 WarningGadgetList WarningGadgets;
4506 DeclUseTracker Tracker;
4507 for (Stmt *S : Stmts) {
4509 WarningGadgets, Tracker);
4510 }
4511 applyGadgets(D, std::move(FixableGadgets), std::move(WarningGadgets),
4512 std::move(Tracker), Handler, EmitSuggestions);
4513}
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)
Definition UnsafeBufferUsage.cpp:294
static void findStmtsInUnspecifiedLvalueContext(const Stmt *S, const llvm::function_ref< void(const Expr *)> OnResult)
Definition UnsafeBufferUsage.cpp:303
static bool isSafeArraySubscript(const ArraySubscriptExpr &Node, const ASTContext &Ctx)
Definition UnsafeBufferUsage.cpp:670
static std::string getUserFillPlaceHolder(StringRef HintTextToUser="placeholder")
Definition UnsafeBufferUsage.cpp:3023
static FixItList fixVariableWithSpan(const VarDecl *VD, const DeclUseTracker &Tracker, ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
Definition UnsafeBufferUsage.cpp:3788
static std::optional< FixItList > fixUPCAddressofArraySubscriptWithSpan(const UnaryOperator *Node)
Definition UnsafeBufferUsage.cpp:3245
static bool ignoreUnsafeBufferInContainer(const Stmt &Node, const UnsafeBufferUsageHandler *Handler)
Definition UnsafeBufferUsage.cpp:289
static WarningGadgetSets groupWarningGadgetsByVar(const WarningGadgetList &AllUnsafeOperations)
Definition UnsafeBufferUsage.cpp:2803
static bool hasArrayType(const Expr &E)
Definition UnsafeBufferUsage.cpp:261
static StringRef getEndOfLine()
Definition UnsafeBufferUsage.cpp:3016
static bool notInSafeBufferOptOut(const Stmt &Node, const UnsafeBufferUsageHandler *Handler)
Definition UnsafeBufferUsage.cpp:283
static std::optional< FixItList > FixVarInitializerWithSpan(const Expr *Init, ASTContext &Ctx, const StringRef UserFillPlaceHolder)
Definition UnsafeBufferUsage.cpp:3367
static std::optional< SourceLocation > getEndCharLoc(const NodeTy *Node, const SourceManager &SM, const LangOptions &LangOpts)
Definition UnsafeBufferUsage.cpp:3033
static FixItList fixVariableWithArray(const VarDecl *VD, const DeclUseTracker &Tracker, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
Definition UnsafeBufferUsage.cpp:3886
static bool areEqualIntegralBinaryOperators(const BinaryOperator *E1, const Expr *E2_LHS, BinaryOperatorKind BOP, const Expr *E2_RHS, ASTContext &Ctx)
Definition UnsafeBufferUsage.cpp:412
static bool hasPointerType(const Expr &E)
Definition UnsafeBufferUsage.cpp:257
static std::string getSpanTypeText(StringRef EltTyText, std::optional< Qualifiers > Quals=std::nullopt)
Definition UnsafeBufferUsage.cpp:3104
static SourceRange getSourceRangeToTokenEnd(const Decl *D, const SourceManager &SM, const LangOptions &LangOpts)
Definition UnsafeBufferUsage.cpp:3070
static FixItList fixLocalVarDeclWithSpan(const VarDecl *D, ASTContext &Ctx, const StringRef UserFillPlaceHolder, UnsafeBufferUsageHandler &Handler)
Definition UnsafeBufferUsage.cpp:3493
static std::optional< FixItList > createDataFixit(const ASTContext &Ctx, const DeclRefExpr *DRE)
Definition UnsafeBufferUsage.cpp:3207
static FixItList createFunctionOverloadsForParms(std::map< const VarDecl *, FixItList > &FixItsForVariable, const VariableGroupsManager &VarGrpMgr, const FunctionDecl *FD, const FixitStrategy &S, ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
Definition UnsafeBufferUsage.cpp:4018
static bool isNullTermPointer(const Expr *Ptr, ASTContext &Ctx)
Definition UnsafeBufferUsage.cpp:758
static bool isSafeSpanTwoParamConstruct(const CXXConstructExpr &Node, ASTContext &Ctx)
Definition UnsafeBufferUsage.cpp:566
static FixItList fixVarDeclWithArray(const VarDecl *D, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
Definition UnsafeBufferUsage.cpp:3812
static FixItList fixVariable(const VarDecl *VD, FixitStrategy::Kind K, const Decl *D, const DeclUseTracker &Tracker, ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
Definition UnsafeBufferUsage.cpp:3908
static FixItList fixParamWithSpan(const ParmVarDecl *PVD, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
Definition UnsafeBufferUsage.cpp:3743
static FixitStrategy getNaiveStrategy(llvm::iterator_range< VarDeclIterTy > UnsafeVars)
Definition UnsafeBufferUsage.cpp:4142
static std::optional< std::string > createSpanTypeForVarDecl(const VarDecl *VD, const ASTContext &Ctx)
Definition UnsafeBufferUsage.cpp:3457
static bool hasConflictingOverload(const FunctionDecl *FD)
Definition UnsafeBufferUsage.cpp:3540
static void findStmtsInUnspecifiedPointerContext(const Stmt *S, llvm::function_ref< void(const Stmt *)> InnerMatcher)
Definition UnsafeBufferUsage.cpp:315
static bool isNonNegativeIntegerExpr(const Expr *Expr, const VarDecl *VD, const ASTContext &Ctx)
Definition UnsafeBufferUsage.cpp:2956
static bool overlapWithMacro(const FixItList &FixIts)
Definition UnsafeBufferUsage.cpp:3968
static void forEachDescendantStmt(const Stmt *S, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler, FastMatcher &Matcher)
Definition UnsafeBufferUsage.cpp:274
static bool hasUnsupportedSpecifiers(const VarDecl *VD, const SourceManager &SM)
Definition UnsafeBufferUsage.cpp:3051
static const Expr * tryConstantFoldConditionalExpr(const Expr *E, const ASTContext &Ctx)
Definition UnsafeBufferUsage.cpp:742
#define DEBUG_NOTE_DECL_FAIL(D, Msg)
Definition UnsafeBufferUsage.cpp:3445
static void applyGadgets(const Decl *D, FixableGadgetList FixableGadgets, WarningGadgetList WarningGadgets, DeclUseTracker Tracker, UnsafeBufferUsageHandler &Handler, bool EmitSuggestions)
Definition UnsafeBufferUsage.cpp:4188
static bool areEqualIntegers(const Expr *E1, const Expr *E2, ASTContext &Ctx)
Definition UnsafeBufferUsage.cpp:433
static void findGadgets(const Stmt *S, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler, bool EmitSuggestions, FixableGadgetList &FixableGadgets, WarningGadgetList &WarningGadgets, DeclUseTracker &Tracker)
Definition UnsafeBufferUsage.cpp:2722
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)
Definition UnsafeBufferUsage.cpp:4042
static bool isPtrBufferSafe(const Expr *Ptr, const Expr *Size, ASTContext &Ctx)
Definition UnsafeBufferUsage.cpp:475
static void forEachDescendantEvaluatedStmt(const Stmt *S, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler, FastMatcher &Matcher)
Definition UnsafeBufferUsage.cpp:266
static void findStmtsInUnspecifiedUntypedContext(const Stmt *S, llvm::function_ref< void(const Stmt *)> InnerMatcher)
Definition UnsafeBufferUsage.cpp:384
static std::optional< FixItList > createOverloadsForFixedParams(const FixitStrategy &S, const FunctionDecl *FD, const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler)
Definition UnsafeBufferUsage.cpp:3576
static void eraseVarsForUnfixableGroupMates(std::map< const VarDecl *, FixItList > &FixItsForVariable, const VariableGroupsManager &VarGrpMgr)
Definition UnsafeBufferUsage.cpp:3989
static FixableGadgetSets groupFixablesByVar(FixableGadgetList &&AllFixableOperations)
Definition UnsafeBufferUsage.cpp:2835
static bool isParameterOf(const VarDecl *VD, const Decl *D)
Definition UnsafeBufferUsage.cpp:3981
#define SIZED_CONTAINER_OR_VIEW_LIST
Definition UnsafeBufferUsage.cpp:120
static std::optional< StringRef > getFunNameText(const FunctionDecl *FD, const SourceManager &SM, const LangOptions &LangOpts)
Definition UnsafeBufferUsage.cpp:3083
__device__ __2f16 float __ockl_bool s
virtual std::optional< FixItList > getFixits(const FixitStrategy &s) const final
Definition UnsafeBufferUsage.cpp:3114
static bool matches(const Stmt *S, llvm::SmallVectorImpl< MatchResult > &Results)
Definition UnsafeBufferUsage.cpp:2567
DerefSimplePtrArithFixableGadget(const MatchResult &Result)
Definition UnsafeBufferUsage.cpp:2560
SourceLocation getSourceLoc() const override
Definition UnsafeBufferUsage.cpp:2618
virtual DeclUseList getClaimedVarUseSites() const final
Definition UnsafeBufferUsage.cpp:2622
FixableGadgetMatcher(FixableGadgetList &FixableGadgets, DeclUseTracker &Tracker)
Definition UnsafeBufferUsage.cpp:2663
bool matches(const DynTypedNode &DynNode, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler) override
Definition UnsafeBufferUsage.cpp:2667
Represents the length modifier in a format string in scanf/printf.
bool TraverseCXXTypeidExpr(CXXTypeidExpr *Node) override
Definition UnsafeBufferUsage.cpp:211
MatchDescendantVisitor(ASTContext &Context, FastMatcher &Matcher, bool FindAll, bool ignoreUnevaluatedContext, const UnsafeBufferUsageHandler &NewHandler)
Definition UnsafeBufferUsage.cpp:131
bool TraverseDecltypeTypeLoc(DecltypeTypeLoc Node, bool TraverseQualifier) override
Definition UnsafeBufferUsage.cpp:195
bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc Node, bool TraverseQualifier) override
Definition UnsafeBufferUsage.cpp:186
bool TraverseGenericSelectionExpr(GenericSelectionExpr *Node) override
Definition UnsafeBufferUsage.cpp:171
bool TraverseDecl(Decl *Node) override
Definition UnsafeBufferUsage.cpp:159
bool TraverseUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node) override
Definition UnsafeBufferUsage.cpp:179
bool findMatch(const DynTypedNode &DynNode)
Definition UnsafeBufferUsage.cpp:143
bool TraverseCXXDefaultInitExpr(CXXDefaultInitExpr *Node) override
Definition UnsafeBufferUsage.cpp:218
bool TraverseCXXNoexceptExpr(CXXNoexceptExpr *Node) override
Definition UnsafeBufferUsage.cpp:204
bool TraverseStmt(Stmt *Node) override
Definition UnsafeBufferUsage.cpp:224
virtual std::optional< FixItList > getFixits(const FixitStrategy &S) const override
Definition UnsafeBufferUsage.cpp:3322
static bool matches(const Stmt *S, llvm::SmallVectorImpl< MatchResult > &Results)
Definition UnsafeBufferUsage.cpp:2460
SourceLocation getSourceLoc() const override
Definition UnsafeBufferUsage.cpp:2486
virtual DeclUseList getClaimedVarUseSites() const override
Definition UnsafeBufferUsage.cpp:2488
UPCPreIncrementGadget(const MatchResult &Result)
Definition UnsafeBufferUsage.cpp:2450
static bool classof(const Gadget *G)
Definition UnsafeBufferUsage.cpp:2456
static bool classof(const Gadget *G)
Definition UnsafeBufferUsage.cpp:2512
UUCAddAssignGadget(const MatchResult &Result)
Definition UnsafeBufferUsage.cpp:2505
virtual std::optional< FixItList > getFixits(const FixitStrategy &S) const override
Definition UnsafeBufferUsage.cpp:3280
static bool matches(const Stmt *S, llvm::SmallVectorImpl< MatchResult > &Results)
Definition UnsafeBufferUsage.cpp:2516
virtual DeclUseList getClaimedVarUseSites() const override
Definition UnsafeBufferUsage.cpp:2541
SourceLocation getSourceLoc() const override
Definition UnsafeBufferUsage.cpp:2539
VariableGroupsManagerImpl(const std::vector< VarGrpTy > &Groups, const std::map< const VarDecl *, unsigned > &VarGrpMap, const llvm::SetVector< const VarDecl * > &GrpsUnionForParms)
Definition UnsafeBufferUsage.cpp:4160
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.
Definition UnsafeBufferUsage.cpp:4167
VarGrpRef getGroupOfParms() const override
Returns the non-empty group of variables that include parameters of the analyzing function,...
Definition UnsafeBufferUsage.cpp:4183
bool matches(const DynTypedNode &DynNode, ASTContext &Ctx, const UnsafeBufferUsageHandler &Handler) override
Definition UnsafeBufferUsage.cpp:2633
WarningGadgetMatcher(WarningGadgetList &WarningGadgets)
Definition UnsafeBufferUsage.cpp:2630
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.
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,...
unsigned getPositionalArgIndex() const
const LengthModifier & getLengthModifier() const
bool hasDataArgument() const
HowSpecified getHowSpecified() const
unsigned getConstantAmount() const
unsigned getPositionalArgIndex() const
const OptionalAmount & getPrecision() const
const PrintfConversionSpecifier & getConversionSpecifier() const
bool ParsePrintfString(FormatStringHandler &H, const char *beg, const char *end, const LangOptions &LO, const TargetInfo &Target, bool isFreeBSDKPrintf)
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)
Definition UnsafeBufferUsage.cpp:2849
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)
Definition UnsafeBufferUsage.cpp:4462
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)
Definition UnsafeBufferUsage.cpp:2743
ArrayRef< const VarDecl * > VarGrpRef
static bool hasUnsafePrintfStringArg(const CallExpr &Node, ASTContext &Ctx, MatchResult &Result, llvm::StringRef Tag)
Definition UnsafeBufferUsage.cpp:1139
static bool hasUnsafeFormatOrSArg(const CallExpr *Call, const Expr *&UnsafeArg, const unsigned FmtArgIdx, ASTContext &Ctx, bool isKprintf=false)
Definition UnsafeBufferUsage.cpp:828
static bool isPredefinedUnsafeLibcFunc(const FunctionDecl &Node)
Definition UnsafeBufferUsage.cpp:968
static bool hasUnsafeSnprintfBuffer(const CallExpr &Node, ASTContext &Ctx)
Definition UnsafeBufferUsage.cpp:1214
static bool isUnsafeVaListPrintfFunc(const FunctionDecl &Node)
Definition UnsafeBufferUsage.cpp:1075
static bool isUnsafeSprintfFunc(const FunctionDecl &Node)
Definition UnsafeBufferUsage.cpp:1091
static bool isNormalPrintfFunc(const FunctionDecl &Node)
Definition UnsafeBufferUsage.cpp:1115
bool operator()(const NodeTy *N1, const NodeTy *N2) const
Definition UnsafeBufferUsage.cpp:2737
std::map< const VarDecl *, std::set< const FixableGadget * >, CompareNode< VarDecl > > byVar
Definition UnsafeBufferUsage.cpp:2831
std::map< const VarDecl *, std::set< const WarningGadget * >, CompareNode< VarDecl > > byVar
Definition UnsafeBufferUsage.cpp:2797
llvm::SmallVector< const WarningGadget *, 16 > noVar
Definition UnsafeBufferUsage.cpp:2799
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)
Definition UnsafeBufferUsage.cpp:813
StringRef matchName(StringRef FunName, bool isBuiltin)
Definition UnsafeBufferUsage.cpp:791
StringRef matchLibcNameOrBuiltinChk(StringRef Name)
Definition UnsafeBufferUsage.cpp:806