@@ -426,23 +426,37 @@ getDependentValuesFromCall(const CountAttributedType *CAT,
426
426
// Other kinds of function calls are not supported, so an expression of the
427
427
// form `f(...)` is not supported.
428
428
struct CompatibleCountExprVisitor
429
- : public ConstStmtVisitor<CompatibleCountExprVisitor, bool , const Expr *> {
429
+ : public ConstStmtVisitor<CompatibleCountExprVisitor, bool , const Expr *,
430
+ bool > {
431
+ // The third 'bool' type parameter for each visit method indicates whether the
432
+ // current visiting expression is the result of the formal parameter to actual
433
+ // argument substitution. Since the argument expression may contain DREs
434
+ // referencing to back to those parameters (in cases of recursive calls), the
435
+ // analysis may hit an infinite loop if not knowing whether the substitution
436
+ // has happened. A typical example that could introduce infinite loop without
437
+ // this knowledge is shown below.
438
+ // ```
439
+ // void f(int * __counted_by(n) p, size_t n) {
440
+ // f(p, n);
441
+ // }
442
+ // ```
430
443
using BaseVisitor =
431
- ConstStmtVisitor<CompatibleCountExprVisitor, bool , const Expr *>;
444
+ ConstStmtVisitor<CompatibleCountExprVisitor, bool , const Expr *, bool >;
432
445
433
446
const Expr *MemberBase;
434
447
const DependentValuesTy *DependentValues;
435
448
ASTContext &Ctx;
436
449
437
450
// If `Deref` has the form `*&e`, return `e`; otherwise return nullptr.
438
- const Expr *trySimplifyDerefAddressof (const UnaryOperator *Deref) {
451
+ const Expr *trySimplifyDerefAddressof (const UnaryOperator *Deref,
452
+ bool hasBeenSubstituted) {
439
453
const Expr *DerefOperand = Deref->getSubExpr ()->IgnoreParenImpCasts ();
440
454
441
455
if (const auto *UO = dyn_cast<UnaryOperator>(DerefOperand))
442
456
if (UO->getOpcode () == UO_AddrOf)
443
457
return UO->getSubExpr ();
444
458
if (const auto *DRE = dyn_cast<DeclRefExpr>(DerefOperand)) {
445
- if (!DependentValues)
459
+ if (!DependentValues || hasBeenSubstituted )
446
460
return nullptr ;
447
461
448
462
auto I = DependentValues->find (DRE->getDecl ());
@@ -460,18 +474,22 @@ struct CompatibleCountExprVisitor
460
474
ASTContext &Ctx)
461
475
: MemberBase(MemberBase), DependentValues(DependentValues), Ctx(Ctx) {}
462
476
463
- bool VisitStmt (const Stmt *S, const Expr *E) { return false ; }
477
+ bool VisitStmt (const Stmt *S, const Expr *E, bool hasBeenSubstituted) {
478
+ return false ;
479
+ }
464
480
465
- bool VisitImplicitCastExpr (const ImplicitCastExpr *SelfICE,
466
- const Expr *Other ) {
467
- return Visit (SelfICE->getSubExpr (), Other);
481
+ bool VisitImplicitCastExpr (const ImplicitCastExpr *SelfICE, const Expr *Other,
482
+ bool hasBeenSubstituted ) {
483
+ return Visit (SelfICE->getSubExpr (), Other, hasBeenSubstituted );
468
484
}
469
485
470
- bool VisitParenExpr (const ParenExpr *SelfPE, const Expr *Other) {
471
- return Visit (SelfPE->getSubExpr (), Other);
486
+ bool VisitParenExpr (const ParenExpr *SelfPE, const Expr *Other,
487
+ bool hasBeenSubstituted) {
488
+ return Visit (SelfPE->getSubExpr (), Other, hasBeenSubstituted);
472
489
}
473
490
474
- bool VisitIntegerLiteral (const IntegerLiteral *SelfIL, const Expr *Other) {
491
+ bool VisitIntegerLiteral (const IntegerLiteral *SelfIL, const Expr *Other,
492
+ bool hasBeenSubstituted) {
475
493
if (const auto *IntLit =
476
494
dyn_cast<IntegerLiteral>(Other->IgnoreParenImpCasts ())) {
477
495
return SelfIL == IntLit ||
@@ -481,7 +499,8 @@ struct CompatibleCountExprVisitor
481
499
}
482
500
483
501
bool VisitUnaryExprOrTypeTraitExpr (const UnaryExprOrTypeTraitExpr *Self,
484
- const Expr *Other) {
502
+ const Expr *Other,
503
+ bool hasBeenSubstituted) {
485
504
// If `Self` is a `sizeof` expression, try to evaluate and compare the two
486
505
// expressions as constants:
487
506
if (Self->getKind () == UnaryExprOrTypeTrait::UETT_SizeOf) {
@@ -498,17 +517,19 @@ struct CompatibleCountExprVisitor
498
517
return false ;
499
518
}
500
519
501
- bool VisitCXXThisExpr (const CXXThisExpr *SelfThis, const Expr *Other) {
520
+ bool VisitCXXThisExpr (const CXXThisExpr *SelfThis, const Expr *Other,
521
+ bool hasBeenSubstituted) {
502
522
return isa<CXXThisExpr>(Other->IgnoreParenImpCasts ());
503
523
}
504
524
505
- bool VisitDeclRefExpr (const DeclRefExpr *SelfDRE, const Expr *Other) {
525
+ bool VisitDeclRefExpr (const DeclRefExpr *SelfDRE, const Expr *Other,
526
+ bool hasBeenSubstituted) {
506
527
const ValueDecl *SelfVD = SelfDRE->getDecl ();
507
528
508
- if (DependentValues) {
529
+ if (DependentValues && !hasBeenSubstituted ) {
509
530
const auto It = DependentValues->find (SelfVD);
510
531
if (It != DependentValues->end ())
511
- return Visit (It->second , Other);
532
+ return Visit (It->second , Other, true );
512
533
}
513
534
514
535
const auto *O = Other->IgnoreParenImpCasts ();
@@ -523,58 +544,63 @@ struct CompatibleCountExprVisitor
523
544
const auto *OtherME = dyn_cast<MemberExpr>(O);
524
545
if (MemberBase && OtherME) {
525
546
return OtherME->getMemberDecl () == SelfVD &&
526
- Visit (OtherME->getBase (), MemberBase);
547
+ Visit (OtherME->getBase (), MemberBase, hasBeenSubstituted );
527
548
}
528
549
529
550
return false ;
530
551
}
531
552
532
- bool VisitMemberExpr (const MemberExpr *Self, const Expr *Other) {
553
+ bool VisitMemberExpr (const MemberExpr *Self, const Expr *Other,
554
+ bool hasBeenSubstituted) {
533
555
// Even though we don't support member expression in counted-by, actual
534
556
// arguments can be member expressions.
535
557
if (Self == Other)
536
558
return true ;
537
559
if (const auto *DRE = dyn_cast<DeclRefExpr>(Other->IgnoreParenImpCasts ()))
538
560
return MemberBase && Self->getMemberDecl () == DRE->getDecl () &&
539
- Visit (Self->getBase (), MemberBase);
561
+ Visit (Self->getBase (), MemberBase, hasBeenSubstituted );
540
562
if (const auto *OtherME =
541
563
dyn_cast<MemberExpr>(Other->IgnoreParenImpCasts ())) {
542
564
return Self->getMemberDecl () == OtherME->getMemberDecl () &&
543
- Visit (Self->getBase (), OtherME->getBase ());
565
+ Visit (Self->getBase (), OtherME->getBase (), hasBeenSubstituted );
544
566
}
545
567
return false ;
546
568
}
547
569
548
- bool VisitUnaryOperator (const UnaryOperator *SelfUO, const Expr *Other) {
570
+ bool VisitUnaryOperator (const UnaryOperator *SelfUO, const Expr *Other,
571
+ bool hasBeenSubstituted) {
549
572
if (SelfUO->getOpcode () != UO_Deref)
550
573
return false ; // We don't support any other unary operator
551
574
552
575
if (const auto *OtherUO =
553
576
dyn_cast<UnaryOperator>(Other->IgnoreParenImpCasts ())) {
554
577
if (SelfUO->getOpcode () == OtherUO->getOpcode ())
555
- return Visit (SelfUO->getSubExpr (), OtherUO->getSubExpr ());
578
+ return Visit (SelfUO->getSubExpr (), OtherUO->getSubExpr (),
579
+ hasBeenSubstituted);
556
580
}
557
581
// If `Other` is not a dereference expression, try to simplify `SelfUO`:
558
- if (const auto *SimplifiedSelf = trySimplifyDerefAddressof (SelfUO)) {
559
- return Visit (SimplifiedSelf, Other);
582
+ if (const auto *SimplifiedSelf =
583
+ trySimplifyDerefAddressof (SelfUO, hasBeenSubstituted)) {
584
+ return Visit (SimplifiedSelf, Other, hasBeenSubstituted);
560
585
}
561
586
return false ;
562
587
}
563
588
564
- bool VisitBinaryOperator (const BinaryOperator *SelfBO, const Expr *Other) {
589
+ bool VisitBinaryOperator (const BinaryOperator *SelfBO, const Expr *Other,
590
+ bool hasBeenSubstituted) {
565
591
const auto *OtherBO =
566
592
dyn_cast<BinaryOperator>(Other->IgnoreParenImpCasts ());
567
593
if (OtherBO && OtherBO->getOpcode () == SelfBO->getOpcode ()) {
568
- return Visit (SelfBO->getLHS (), OtherBO->getLHS ()) &&
569
- Visit (SelfBO->getRHS (), OtherBO->getRHS ());
594
+ return Visit (SelfBO->getLHS (), OtherBO->getLHS (), hasBeenSubstituted ) &&
595
+ Visit (SelfBO->getRHS (), OtherBO->getRHS (), hasBeenSubstituted );
570
596
}
571
597
572
598
return false ;
573
599
}
574
600
575
601
// Support any overloaded operator[] so long as it is a const method.
576
602
bool VisitCXXOperatorCallExpr (const CXXOperatorCallExpr *SelfOpCall,
577
- const Expr *Other) {
603
+ const Expr *Other, bool hasBeenSubstituted ) {
578
604
if (SelfOpCall->getOperator () != OverloadedOperatorKind::OO_Subscript)
579
605
return false ;
580
606
@@ -585,8 +611,10 @@ struct CompatibleCountExprVisitor
585
611
if (const auto *OtherOpCall =
586
612
dyn_cast<CXXOperatorCallExpr>(Other->IgnoreParenImpCasts ()))
587
613
if (SelfOpCall->getOperator () == OtherOpCall->getOperator ()) {
588
- return Visit (SelfOpCall->getArg (0 ), OtherOpCall->getArg (0 )) &&
589
- Visit (SelfOpCall->getArg (1 ), OtherOpCall->getArg (1 ));
614
+ return Visit (SelfOpCall->getArg (0 ), OtherOpCall->getArg (0 ),
615
+ hasBeenSubstituted) &&
616
+ Visit (SelfOpCall->getArg (1 ), OtherOpCall->getArg (1 ),
617
+ hasBeenSubstituted);
590
618
}
591
619
return false ;
592
620
}
@@ -595,17 +623,17 @@ struct CompatibleCountExprVisitor
595
623
// considered unsafe, they can be safely used on constant arrays with
596
624
// known-safe literal indexes.
597
625
bool VisitArraySubscriptExpr (const ArraySubscriptExpr *SelfAS,
598
- const Expr *Other) {
626
+ const Expr *Other, bool hasBeenSubstituted ) {
599
627
if (const auto *OtherAS =
600
628
dyn_cast<ArraySubscriptExpr>(Other->IgnoreParenImpCasts ()))
601
- return Visit (SelfAS->getLHS (), OtherAS->getLHS ()) &&
602
- Visit (SelfAS->getRHS (), OtherAS->getRHS ());
629
+ return Visit (SelfAS->getLHS (), OtherAS->getLHS (), hasBeenSubstituted ) &&
630
+ Visit (SelfAS->getRHS (), OtherAS->getRHS (), hasBeenSubstituted );
603
631
return false ;
604
632
}
605
633
606
634
// Support non-static member call:
607
635
bool VisitCXXMemberCallExpr (const CXXMemberCallExpr *SelfCall,
608
- const Expr *Other) {
636
+ const Expr *Other, bool hasBeenSubstituted ) {
609
637
const CXXMethodDecl *MD = SelfCall->getMethodDecl ();
610
638
611
639
// The callee member function must be a const function with no parameter:
@@ -614,7 +642,8 @@ struct CompatibleCountExprVisitor
614
642
dyn_cast<CXXMemberCallExpr>(Other->IgnoreParenImpCasts ())) {
615
643
return OtherCall->getMethodDecl () == MD &&
616
644
Visit (SelfCall->getImplicitObjectArgument (),
617
- OtherCall->getImplicitObjectArgument ());
645
+ OtherCall->getImplicitObjectArgument (),
646
+ hasBeenSubstituted);
618
647
}
619
648
}
620
649
return false ;
@@ -660,7 +689,7 @@ bool isCompatibleWithCountExpr(const Expr *E, const Expr *ExpectedCountExpr,
660
689
const DependentValuesTy *DependentValues,
661
690
ASTContext &Ctx) {
662
691
CompatibleCountExprVisitor Visitor (MemberBase, DependentValues, Ctx);
663
- return Visitor.Visit (ExpectedCountExpr, E);
692
+ return Visitor.Visit (ExpectedCountExpr, E, /* hasBeenSubstituted */ false );
664
693
}
665
694
666
695
// Returns if a pair of expressions contain method calls to .data()/.c_str() and
0 commit comments