|
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,97 @@ static bool isSupportedVariable(const DeclRefExpr &Node) {
|
1318 | 1319 | return D != nullptr && isa<VarDecl>(D);
|
1319 | 1320 | }
|
1320 | 1321 |
|
| 1322 | +// Returns true for RecordDecl of type std::unique_ptr<T[]> |
| 1323 | +static bool isUniquePtrArray(const CXXRecordDecl *RecordDecl) { |
| 1324 | + if (!RecordDecl || !RecordDecl->isInStdNamespace() || |
| 1325 | + RecordDecl->getNameAsString() != "unique_ptr") |
| 1326 | + return false; |
| 1327 | + |
| 1328 | + const ClassTemplateSpecializationDecl *class_template_specialization_decl = |
| 1329 | + dyn_cast<ClassTemplateSpecializationDecl>(RecordDecl); |
| 1330 | + if (!class_template_specialization_decl) |
| 1331 | + return false; |
| 1332 | + |
| 1333 | + const TemplateArgumentList &template_args = |
| 1334 | + class_template_specialization_decl->getTemplateArgs(); |
| 1335 | + if (template_args.size() == 0) |
| 1336 | + return false; |
| 1337 | + |
| 1338 | + const TemplateArgument &first_arg = template_args[0]; |
| 1339 | + if (first_arg.getKind() != TemplateArgument::Type) |
| 1340 | + return false; |
| 1341 | + |
| 1342 | + QualType referred_type = first_arg.getAsType(); |
| 1343 | + return referred_type->isArrayType(); |
| 1344 | +} |
| 1345 | + |
| 1346 | +class UniquePtrArrayAccessGadget : public WarningGadget { |
| 1347 | +private: |
| 1348 | + static constexpr const char *const AccessorTag = "unique_ptr_array_access"; |
| 1349 | + const CXXOperatorCallExpr *AccessorExpr; |
| 1350 | + |
| 1351 | +public: |
| 1352 | + UniquePtrArrayAccessGadget(const MatchResult &Result) |
| 1353 | + : WarningGadget(Kind::UniquePtrArrayAccess), |
| 1354 | + AccessorExpr(Result.getNodeAs<CXXOperatorCallExpr>(AccessorTag)) { |
| 1355 | + assert(AccessorExpr && |
| 1356 | + "UniquePtrArrayAccessGadget requires a matched CXXOperatorCallExpr"); |
| 1357 | + } |
| 1358 | + |
| 1359 | + static bool classof(const Gadget *G) { |
| 1360 | + return G->getKind() == Kind::UniquePtrArrayAccess; |
| 1361 | + } |
| 1362 | + |
| 1363 | + static bool matches(const Stmt *S, const ASTContext &Ctx, |
| 1364 | + MatchResult &Result) { |
| 1365 | + |
| 1366 | + const CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(S); |
| 1367 | + if (!OpCall || OpCall->getOperator() != OO_Subscript) |
| 1368 | + return false; |
| 1369 | + |
| 1370 | + const Expr *Callee = OpCall->getCallee()->IgnoreParenImpCasts(); |
| 1371 | + if (!Callee) |
| 1372 | + return false; |
| 1373 | + |
| 1374 | + const CXXMethodDecl *Method = |
| 1375 | + dyn_cast_or_null<CXXMethodDecl>(OpCall->getDirectCallee()); |
| 1376 | + if (!Method) |
| 1377 | + return false; |
| 1378 | + |
| 1379 | + if (Method->getOverloadedOperator() != OO_Subscript) |
| 1380 | + return false; |
| 1381 | + |
| 1382 | + const CXXRecordDecl *RecordDecl = Method->getParent(); |
| 1383 | + if (!isUniquePtrArray(RecordDecl)) |
| 1384 | + return false; |
| 1385 | + |
| 1386 | + const Expr *IndexExpr = OpCall->getArg(1); |
| 1387 | + clang::Expr::EvalResult Eval; |
| 1388 | + |
| 1389 | + // Allow [0] |
| 1390 | + if (IndexExpr->EvaluateAsInt(Eval, Ctx) && Eval.Val.getInt().isZero()) |
| 1391 | + return false; |
| 1392 | + |
| 1393 | + Result.addNode(AccessorTag, DynTypedNode::create(*OpCall)); |
| 1394 | + return true; |
| 1395 | + } |
| 1396 | + void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler, |
| 1397 | + bool IsRelatedToDecl, |
| 1398 | + ASTContext &Ctx) const override { |
| 1399 | + Handler.handleUnsafeUniquePtrArrayAccess( |
| 1400 | + DynTypedNode::create(*AccessorExpr), IsRelatedToDecl, Ctx); |
| 1401 | + } |
| 1402 | + |
| 1403 | + SourceLocation getSourceLoc() const override { |
| 1404 | + if (AccessorExpr) |
| 1405 | + return AccessorExpr->getOperatorLoc(); |
| 1406 | + return SourceLocation(); |
| 1407 | + } |
| 1408 | + |
| 1409 | + DeclUseList getClaimedVarUseSites() const override { return {}; } |
| 1410 | + SmallVector<const Expr *, 1> getUnsafePtrs() const override { return {}; } |
| 1411 | +}; |
| 1412 | + |
1321 | 1413 | using FixableGadgetList = std::vector<std::unique_ptr<FixableGadget>>;
|
1322 | 1414 | using WarningGadgetList = std::vector<std::unique_ptr<WarningGadget>>;
|
1323 | 1415 |
|
@@ -2632,10 +2724,13 @@ std::set<const Expr *> clang::findUnsafePointers(const FunctionDecl *FD) {
|
2632 | 2724 | const VariableGroupsManager &, FixItList &&,
|
2633 | 2725 | const Decl *,
|
2634 | 2726 | const FixitStrategy &) override {}
|
2635 |
| - bool isSafeBufferOptOut(const SourceLocation &) const override { |
| 2727 | + void handleUnsafeUniquePtrArrayAccess(const DynTypedNode &Node, |
| 2728 | + bool IsRelatedToDecl, |
| 2729 | + ASTContext &Ctx) override {} |
| 2730 | + bool ignoreUnsafeBufferInContainer(const SourceLocation &) const override { |
2636 | 2731 | return false;
|
2637 | 2732 | }
|
2638 |
| - bool ignoreUnsafeBufferInContainer(const SourceLocation &) const override { |
| 2733 | + bool isSafeBufferOptOut(const SourceLocation &) const override { |
2639 | 2734 | return false;
|
2640 | 2735 | }
|
2641 | 2736 | bool ignoreUnsafeBufferInLibcCall(const SourceLocation &) const override {
|
|
0 commit comments