|
13 | 13 | #include "clang/AST/Attr.h" |
14 | 14 | #include "clang/AST/Decl.h" |
15 | 15 | #include "clang/AST/DeclCXX.h" |
| 16 | +#include "clang/AST/DeclTemplate.h" |
16 | 17 | #include "clang/AST/DynamicRecursiveASTVisitor.h" |
17 | 18 | #include "clang/AST/Expr.h" |
18 | 19 | #include "clang/AST/FormatString.h" |
@@ -1318,6 +1319,105 @@ static bool isSupportedVariable(const DeclRefExpr &Node) { |
1318 | 1319 | return D != nullptr && isa<VarDecl>(D); |
1319 | 1320 | } |
1320 | 1321 |
|
| 1322 | +static bool isUniquePtrArray(const CXXRecordDecl *RecordDecl) { |
| 1323 | + if (!RecordDecl || !RecordDecl->isInStdNamespace() || |
| 1324 | + RecordDecl->getNameAsString() != "unique_ptr") { |
| 1325 | + return false; |
| 1326 | + } |
| 1327 | + |
| 1328 | + const ClassTemplateSpecializationDecl *class_template_specialization_decl = |
| 1329 | + dyn_cast<ClassTemplateSpecializationDecl>(RecordDecl); |
| 1330 | + if (!class_template_specialization_decl) { |
| 1331 | + return false; |
| 1332 | + } |
| 1333 | + |
| 1334 | + const TemplateArgumentList &template_args = |
| 1335 | + class_template_specialization_decl->getTemplateArgs(); |
| 1336 | + |
| 1337 | + if (template_args.size() == 0) { |
| 1338 | + return false; |
| 1339 | + } |
| 1340 | + |
| 1341 | + const TemplateArgument &first_arg = template_args[0]; |
| 1342 | + |
| 1343 | + if (first_arg.getKind() != TemplateArgument::Type) { |
| 1344 | + return false; |
| 1345 | + } |
| 1346 | + |
| 1347 | + QualType referred_type = first_arg.getAsType(); |
| 1348 | + |
| 1349 | + if (referred_type->isArrayType()) { |
| 1350 | + return true; |
| 1351 | + } |
| 1352 | + |
| 1353 | + return false; |
| 1354 | +} |
| 1355 | + |
| 1356 | +class UniquePtrArrayAccessGadget : public WarningGadget { |
| 1357 | + static constexpr const char *const AccessorTag = "unique_ptr_array_access"; |
| 1358 | + const CXXOperatorCallExpr *TheAccessorExpr; |
| 1359 | + |
| 1360 | +public: |
| 1361 | + UniquePtrArrayAccessGadget(const MatchResult &Result) |
| 1362 | + : WarningGadget(Kind::UniquePtrArrayAccess), |
| 1363 | + TheAccessorExpr(Result.getNodeAs<CXXOperatorCallExpr>(AccessorTag)) { |
| 1364 | + assert(TheAccessorExpr && |
| 1365 | + "UniquePtrArrayAccessGadget requires a matched CXXOperatorCallExpr"); |
| 1366 | + } |
| 1367 | + |
| 1368 | + static bool classof(const Gadget *G) { |
| 1369 | + return G->getKind() == Kind::UniquePtrArrayAccess; |
| 1370 | + } |
| 1371 | + |
| 1372 | + static bool matches(const Stmt *S, const ASTContext &Ctx, |
| 1373 | + MatchResult &Result) { |
| 1374 | + |
| 1375 | + const CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(S); |
| 1376 | + if (!OpCall || OpCall->getOperator() != OO_Subscript) { |
| 1377 | + return false; |
| 1378 | + } |
| 1379 | + |
| 1380 | + const Expr *Callee = OpCall->getCallee()->IgnoreParenImpCasts(); |
| 1381 | + if (!Callee) { |
| 1382 | + return false; |
| 1383 | + } |
| 1384 | + |
| 1385 | + const CXXMethodDecl *Method = |
| 1386 | + dyn_cast_or_null<CXXMethodDecl>(OpCall->getDirectCallee()); |
| 1387 | + if (!Method) { |
| 1388 | + return false; |
| 1389 | + } |
| 1390 | + |
| 1391 | + if (Method->getNameAsString() != "operator[]") { |
| 1392 | + return false; |
| 1393 | + } |
| 1394 | + |
| 1395 | + const CXXRecordDecl *RecordDecl = Method->getParent(); |
| 1396 | + if (!isUniquePtrArray(RecordDecl)) { |
| 1397 | + return false; |
| 1398 | + } |
| 1399 | + |
| 1400 | + Result.addNode(AccessorTag, DynTypedNode::create(*OpCall)); |
| 1401 | + return true; |
| 1402 | + } |
| 1403 | + void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler, |
| 1404 | + bool IsRelatedToDecl, |
| 1405 | + ASTContext &Ctx) const override { |
| 1406 | + Handler.handleUnsafeUniquePtrArrayAccess( |
| 1407 | + DynTypedNode::create(*TheAccessorExpr), IsRelatedToDecl, Ctx); |
| 1408 | + } |
| 1409 | + |
| 1410 | + SourceLocation getSourceLoc() const override { |
| 1411 | + if (TheAccessorExpr) { |
| 1412 | + return TheAccessorExpr->getOperatorLoc(); |
| 1413 | + } |
| 1414 | + return SourceLocation(); |
| 1415 | + } |
| 1416 | + |
| 1417 | + DeclUseList getClaimedVarUseSites() const override { return {}; } |
| 1418 | + SmallVector<const Expr *, 1> getUnsafePtrs() const override { return {}; } |
| 1419 | +}; |
| 1420 | + |
1321 | 1421 | using FixableGadgetList = std::vector<std::unique_ptr<FixableGadget>>; |
1322 | 1422 | using WarningGadgetList = std::vector<std::unique_ptr<WarningGadget>>; |
1323 | 1423 |
|
@@ -2647,6 +2747,10 @@ std::set<const Expr *> clang::findUnsafePointers(const FunctionDecl *FD) { |
2647 | 2747 | } |
2648 | 2748 | }; |
2649 | 2749 |
|
| 2750 | + void handleUnsafeUniquePtrArrayAccess(const DynTypedNode &Node, |
| 2751 | + bool IsRelatedToDecl, |
| 2752 | + ASTContext &Ctx) override {} |
| 2753 | + |
2650 | 2754 | FixableGadgetList FixableGadgets; |
2651 | 2755 | WarningGadgetList WarningGadgets; |
2652 | 2756 | DeclUseTracker Tracker; |
|
0 commit comments