@@ -412,66 +412,55 @@ getDependentValuesFromCall(const CountAttributedType *CAT,
412
412
return {std::move (Values)};
413
413
}
414
414
415
- // Checks if Self and Other are the same member bases. This supports only very
416
- // simple forms of member bases.
417
- bool isSameMemberBase (const Expr *Self, const Expr *Other) {
418
- for (;;) {
419
- if (Self == Other)
420
- return true ;
421
-
422
- const auto *SelfICE = dyn_cast<ImplicitCastExpr>(Self);
423
- const auto *OtherICE = dyn_cast<ImplicitCastExpr>(Other);
424
- if (SelfICE && OtherICE &&
425
- SelfICE->getCastKind () == OtherICE->getCastKind () &&
426
- (SelfICE->getCastKind () == CK_LValueToRValue ||
427
- SelfICE->getCastKind () == CK_UncheckedDerivedToBase)) {
428
- Self = SelfICE->getSubExpr ();
429
- Other = OtherICE->getSubExpr ();
430
- }
431
-
432
- const auto *SelfDRE = dyn_cast<DeclRefExpr>(Self);
433
- const auto *OtherDRE = dyn_cast<DeclRefExpr>(Other);
434
- if (SelfDRE && OtherDRE)
435
- return SelfDRE->getDecl () == OtherDRE->getDecl ();
436
-
437
- if (isa<CXXThisExpr>(Self) && isa<CXXThisExpr>(Other)) {
438
- // `Self` and `Other` should be evaluated at the same state so `this` must
439
- // mean the same thing for both:
440
- return true ;
441
- }
442
-
443
- const auto *SelfME = dyn_cast<MemberExpr>(Self);
444
- const auto *OtherME = dyn_cast<MemberExpr>(Other);
445
- if (!SelfME || !OtherME ||
446
- SelfME->getMemberDecl () != OtherME->getMemberDecl ()) {
447
- return false ;
448
- }
449
-
450
- Self = SelfME->getBase ();
451
- Other = OtherME->getBase ();
452
- }
453
- }
454
-
455
415
// Impl of `isCompatibleWithCountExpr`. See `isCompatibleWithCountExpr` for
456
- // document.
416
+ // high-level document.
417
+ //
418
+ // This visitor compares two expressions in a tiny subset of the language,
419
+ // including DRE of VarDecls, constants, binary operators, subscripts,
420
+ // dereferences, member accesses, and member function calls.
421
+ //
422
+ // - For constants, they are literal constants and expressions have
423
+ // compile-time constant values.
424
+ // - For a supported dereference expression, it can be either of the forms '*e'
425
+ // or '*&e', where 'e' is a supported expression.
426
+ // - For a subscript expression, it can be either an array subscript or
427
+ // overloaded subscript operator.
428
+ // - For a member function call, it must be a call to a 'const' (non-static)
429
+ // member function with zero argument. This is to ensure side-effect free.
430
+ // Other kinds of function calls are not supported, so an expression of the
431
+ // form `f(...)` is not supported.
457
432
struct CompatibleCountExprVisitor
458
- : public ConstStmtVisitor<CompatibleCountExprVisitor, bool , const Expr *> {
433
+ : public ConstStmtVisitor<CompatibleCountExprVisitor, bool , const Expr *,
434
+ bool > {
435
+ // The third 'bool' type parameter for each visit method indicates whether a
436
+ // parameter has been substituted with its argument expression in the
437
+ // expression AST branch being visited. Since the argument expression may
438
+ // contain DREs referencing to the same parameter Decl, the analysis may hit
439
+ // an infinite loop of not knowing whether the substitution has happened. A
440
+ // typical example that could introduce infinite loop without this knowledge
441
+ // is shown below.
442
+ // ```
443
+ // void f(int * __counted_by(n) p, size_t n) {
444
+ // f(p, n);
445
+ // }
446
+ // ```
459
447
using BaseVisitor =
460
- ConstStmtVisitor<CompatibleCountExprVisitor, bool , const Expr *>;
448
+ ConstStmtVisitor<CompatibleCountExprVisitor, bool , const Expr *, bool >;
461
449
462
450
const Expr *MemberBase;
463
451
const DependentValuesTy *DependentValues;
464
452
ASTContext &Ctx;
465
453
466
454
// If `Deref` has the form `*&e`, return `e`; otherwise return nullptr.
467
- const Expr *trySimplifyDerefAddressof (const UnaryOperator *Deref) {
455
+ const Expr *trySimplifyDerefAddressof (const UnaryOperator *Deref,
456
+ bool hasBeenSubstituted) {
468
457
const Expr *DerefOperand = Deref->getSubExpr ()->IgnoreParenImpCasts ();
469
458
470
459
if (const auto *UO = dyn_cast<UnaryOperator>(DerefOperand))
471
460
if (UO->getOpcode () == UO_AddrOf)
472
461
return UO->getSubExpr ();
473
462
if (const auto *DRE = dyn_cast<DeclRefExpr>(DerefOperand)) {
474
- if (!DependentValues)
463
+ if (!DependentValues || hasBeenSubstituted )
475
464
return nullptr ;
476
465
477
466
auto I = DependentValues->find (DRE->getDecl ());
@@ -489,18 +478,22 @@ struct CompatibleCountExprVisitor
489
478
ASTContext &Ctx)
490
479
: MemberBase(MemberBase), DependentValues(DependentValues), Ctx(Ctx) {}
491
480
492
- bool VisitStmt (const Stmt *S, const Expr *E) { return false ; }
481
+ bool VisitStmt (const Stmt *S, const Expr *E, bool hasBeenSubstituted) {
482
+ return false ;
483
+ }
493
484
494
- bool VisitImplicitCastExpr (const ImplicitCastExpr *SelfICE,
495
- const Expr *Other ) {
496
- return Visit (SelfICE->getSubExpr (), Other);
485
+ bool VisitImplicitCastExpr (const ImplicitCastExpr *SelfICE, const Expr *Other,
486
+ bool hasBeenSubstituted ) {
487
+ return Visit (SelfICE->getSubExpr (), Other, hasBeenSubstituted );
497
488
}
498
489
499
- bool VisitParenExpr (const ParenExpr *SelfPE, const Expr *Other) {
500
- return Visit (SelfPE->getSubExpr (), Other);
490
+ bool VisitParenExpr (const ParenExpr *SelfPE, const Expr *Other,
491
+ bool hasBeenSubstituted) {
492
+ return Visit (SelfPE->getSubExpr (), Other, hasBeenSubstituted);
501
493
}
502
494
503
- bool VisitIntegerLiteral (const IntegerLiteral *SelfIL, const Expr *Other) {
495
+ bool VisitIntegerLiteral (const IntegerLiteral *SelfIL, const Expr *Other,
496
+ bool hasBeenSubstituted) {
504
497
if (const auto *IntLit =
505
498
dyn_cast<IntegerLiteral>(Other->IgnoreParenImpCasts ())) {
506
499
return SelfIL == IntLit ||
@@ -510,7 +503,8 @@ struct CompatibleCountExprVisitor
510
503
}
511
504
512
505
bool VisitUnaryExprOrTypeTraitExpr (const UnaryExprOrTypeTraitExpr *Self,
513
- const Expr *Other) {
506
+ const Expr *Other,
507
+ bool hasBeenSubstituted) {
514
508
// If `Self` is a `sizeof` expression, try to evaluate and compare the two
515
509
// expressions as constants:
516
510
if (Self->getKind () == UnaryExprOrTypeTrait::UETT_SizeOf) {
@@ -527,13 +521,19 @@ struct CompatibleCountExprVisitor
527
521
return false ;
528
522
}
529
523
530
- bool VisitDeclRefExpr (const DeclRefExpr *SelfDRE, const Expr *Other) {
524
+ bool VisitCXXThisExpr (const CXXThisExpr *SelfThis, const Expr *Other,
525
+ bool hasBeenSubstituted) {
526
+ return isa<CXXThisExpr>(Other->IgnoreParenImpCasts ());
527
+ }
528
+
529
+ bool VisitDeclRefExpr (const DeclRefExpr *SelfDRE, const Expr *Other,
530
+ bool hasBeenSubstituted) {
531
531
const ValueDecl *SelfVD = SelfDRE->getDecl ();
532
532
533
- if (DependentValues) {
533
+ if (DependentValues && !hasBeenSubstituted ) {
534
534
const auto It = DependentValues->find (SelfVD);
535
535
if (It != DependentValues->end ())
536
- return Visit (It->second , Other);
536
+ return Visit (It->second , Other, true );
537
537
}
538
538
539
539
const auto *O = Other->IgnoreParenImpCasts ();
@@ -548,49 +548,110 @@ struct CompatibleCountExprVisitor
548
548
const auto *OtherME = dyn_cast<MemberExpr>(O);
549
549
if (MemberBase && OtherME) {
550
550
return OtherME->getMemberDecl () == SelfVD &&
551
- isSameMemberBase (OtherME->getBase (), MemberBase);
551
+ Visit (OtherME->getBase (), MemberBase, hasBeenSubstituted );
552
552
}
553
553
554
554
return false ;
555
555
}
556
556
557
- bool VisitMemberExpr (const MemberExpr *Self, const Expr *Other) {
557
+ bool VisitMemberExpr (const MemberExpr *Self, const Expr *Other,
558
+ bool hasBeenSubstituted) {
558
559
// Even though we don't support member expression in counted-by, actual
559
560
// arguments can be member expressions.
560
561
if (Self == Other)
561
562
return true ;
562
563
if (const auto *DRE = dyn_cast<DeclRefExpr>(Other->IgnoreParenImpCasts ()))
563
564
return MemberBase && Self->getMemberDecl () == DRE->getDecl () &&
564
- isSameMemberBase (Self->getBase (), MemberBase);
565
+ Visit (Self->getBase (), MemberBase, hasBeenSubstituted);
566
+ if (const auto *OtherME =
567
+ dyn_cast<MemberExpr>(Other->IgnoreParenImpCasts ())) {
568
+ return Self->getMemberDecl () == OtherME->getMemberDecl () &&
569
+ Visit (Self->getBase (), OtherME->getBase (), hasBeenSubstituted);
570
+ }
565
571
return false ;
566
572
}
567
573
568
- bool VisitUnaryOperator (const UnaryOperator *SelfUO, const Expr *Other) {
574
+ bool VisitUnaryOperator (const UnaryOperator *SelfUO, const Expr *Other,
575
+ bool hasBeenSubstituted) {
569
576
if (SelfUO->getOpcode () != UO_Deref)
570
577
return false ; // We don't support any other unary operator
571
578
572
579
if (const auto *OtherUO =
573
580
dyn_cast<UnaryOperator>(Other->IgnoreParenImpCasts ())) {
574
581
if (SelfUO->getOpcode () == OtherUO->getOpcode ())
575
- return Visit (SelfUO->getSubExpr (), OtherUO->getSubExpr ());
582
+ return Visit (SelfUO->getSubExpr (), OtherUO->getSubExpr (),
583
+ hasBeenSubstituted);
576
584
}
577
585
// If `Other` is not a dereference expression, try to simplify `SelfUO`:
578
- if (const auto *SimplifiedSelf = trySimplifyDerefAddressof (SelfUO)) {
579
- return Visit (SimplifiedSelf, Other);
586
+ if (const auto *SimplifiedSelf =
587
+ trySimplifyDerefAddressof (SelfUO, hasBeenSubstituted)) {
588
+ return Visit (SimplifiedSelf, Other, hasBeenSubstituted);
580
589
}
581
590
return false ;
582
591
}
583
592
584
- bool VisitBinaryOperator (const BinaryOperator *SelfBO, const Expr *Other) {
593
+ bool VisitBinaryOperator (const BinaryOperator *SelfBO, const Expr *Other,
594
+ bool hasBeenSubstituted) {
585
595
const auto *OtherBO =
586
596
dyn_cast<BinaryOperator>(Other->IgnoreParenImpCasts ());
587
597
if (OtherBO && OtherBO->getOpcode () == SelfBO->getOpcode ()) {
588
- return Visit (SelfBO->getLHS (), OtherBO->getLHS ()) &&
589
- Visit (SelfBO->getRHS (), OtherBO->getRHS ());
598
+ return Visit (SelfBO->getLHS (), OtherBO->getLHS (), hasBeenSubstituted ) &&
599
+ Visit (SelfBO->getRHS (), OtherBO->getRHS (), hasBeenSubstituted );
590
600
}
591
601
592
602
return false ;
593
603
}
604
+
605
+ // Support any overloaded operator[] so long as it is a const method.
606
+ bool VisitCXXOperatorCallExpr (const CXXOperatorCallExpr *SelfOpCall,
607
+ const Expr *Other, bool hasBeenSubstituted) {
608
+ if (SelfOpCall->getOperator () != OverloadedOperatorKind::OO_Subscript)
609
+ return false ;
610
+
611
+ const auto *MD = dyn_cast<CXXMethodDecl>(SelfOpCall->getCalleeDecl ());
612
+
613
+ if (!MD || !MD->isConst ())
614
+ return false ;
615
+ if (const auto *OtherOpCall =
616
+ dyn_cast<CXXOperatorCallExpr>(Other->IgnoreParenImpCasts ()))
617
+ if (SelfOpCall->getOperator () == OtherOpCall->getOperator ()) {
618
+ return Visit (SelfOpCall->getArg (0 ), OtherOpCall->getArg (0 ),
619
+ hasBeenSubstituted) &&
620
+ Visit (SelfOpCall->getArg (1 ), OtherOpCall->getArg (1 ),
621
+ hasBeenSubstituted);
622
+ }
623
+ return false ;
624
+ }
625
+
626
+ // Support array/pointer subscript. Even though these operators are generally
627
+ // considered unsafe, they can be safely used on constant arrays with
628
+ // known-safe literal indexes.
629
+ bool VisitArraySubscriptExpr (const ArraySubscriptExpr *SelfAS,
630
+ const Expr *Other, bool hasBeenSubstituted) {
631
+ if (const auto *OtherAS =
632
+ dyn_cast<ArraySubscriptExpr>(Other->IgnoreParenImpCasts ()))
633
+ return Visit (SelfAS->getLHS (), OtherAS->getLHS (), hasBeenSubstituted) &&
634
+ Visit (SelfAS->getRHS (), OtherAS->getRHS (), hasBeenSubstituted);
635
+ return false ;
636
+ }
637
+
638
+ // Support non-static member call:
639
+ bool VisitCXXMemberCallExpr (const CXXMemberCallExpr *SelfCall,
640
+ const Expr *Other, bool hasBeenSubstituted) {
641
+ const CXXMethodDecl *MD = SelfCall->getMethodDecl ();
642
+
643
+ // The callee member function must be a const function with no parameter:
644
+ if (MD->isConst () && MD->param_empty ()) {
645
+ if (auto *OtherCall =
646
+ dyn_cast<CXXMemberCallExpr>(Other->IgnoreParenImpCasts ())) {
647
+ return OtherCall->getMethodDecl () == MD &&
648
+ Visit (SelfCall->getImplicitObjectArgument (),
649
+ OtherCall->getImplicitObjectArgument (),
650
+ hasBeenSubstituted);
651
+ }
652
+ }
653
+ return false ;
654
+ }
594
655
};
595
656
596
657
// TL'DR:
@@ -632,7 +693,7 @@ bool isCompatibleWithCountExpr(const Expr *E, const Expr *ExpectedCountExpr,
632
693
const DependentValuesTy *DependentValues,
633
694
ASTContext &Ctx) {
634
695
CompatibleCountExprVisitor Visitor (MemberBase, DependentValues, Ctx);
635
- return Visitor.Visit (ExpectedCountExpr, E);
696
+ return Visitor.Visit (ExpectedCountExpr, E, /* hasBeenSubstituted */ false );
636
697
}
637
698
638
699
// Returns if a pair of expressions contain method calls to .data()/.c_str() and
0 commit comments