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 (Cond->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() && isNullTermPointer(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 || hasPointerType(*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 || hasPointerType(*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() && isa<ParmVarDecl>(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