@@ -475,6 +475,10 @@ namespace {
475
475
}
476
476
477
477
namespace {
478
+ // BoundsContextTy denotes a map of a variable or parameter declaration
479
+ // to the variable or parameter's current known bounds.
480
+ using BoundsContextTy = llvm::DenseMap<DeclaratorDecl *, BoundsExpr *>;
481
+
478
482
// EqualExprTy denotes a set of expressions that produce the same value
479
483
// as an expression e.
480
484
using EqualExprTy = SmallVector<Expr *, 4 >;
@@ -488,6 +492,9 @@ namespace {
488
492
// and are updated while checking individual expressions.
489
493
class CheckingState {
490
494
public:
495
+ // UC is a map of variables or parameters to their current known bounds.
496
+ BoundsContextTy UC;
497
+
491
498
// UEQ stores sets of expressions that are equivalent to each other
492
499
// after checking an expression e.
493
500
EquivExprSets UEQ;
@@ -498,6 +505,35 @@ namespace {
498
505
};
499
506
}
500
507
508
+ namespace {
509
+ class DeclaredBoundsHelper : public RecursiveASTVisitor <DeclaredBoundsHelper> {
510
+ private:
511
+ Sema &SemaRef;
512
+ BoundsContextTy &BoundsContextRef;
513
+
514
+ public:
515
+ DeclaredBoundsHelper (Sema &SemaRef, BoundsContextTy &Context) :
516
+ SemaRef (SemaRef),
517
+ BoundsContextRef (Context) {}
518
+
519
+ bool VisitDeclaratorDecl (DeclaratorDecl *D) {
520
+ if (!D)
521
+ return true ;
522
+ BoundsExpr *Bounds = D->getBoundsExpr ();
523
+ if (Bounds)
524
+ BoundsContextRef[D] = Bounds;
525
+ return true ;
526
+ }
527
+ };
528
+
529
+ // GetDeclaredBounds modifies the bounds context to map any variables
530
+ // declared in S to their declared bounds (if any).
531
+ void GetDeclaredBounds (Sema &SemaRef, BoundsContextTy &Context, Stmt *S) {
532
+ DeclaredBoundsHelper Declared (SemaRef, Context);
533
+ Declared.TraverseStmt (S);
534
+ }
535
+ }
536
+
501
537
namespace {
502
538
class CheckBoundsDeclarations {
503
539
private:
@@ -598,6 +634,9 @@ namespace {
598
634
OS << " \n Statement S:\n " ;
599
635
S->dump (OS);
600
636
637
+ OS << " Bounds context after checking S:\n " ;
638
+ DumpBoundsContext (OS, State.UC );
639
+
601
640
OS << " Sets of equivalent expressions after checking S:\n " ;
602
641
if (State.UEQ .size () == 0 )
603
642
OS << " { }\n " ;
@@ -614,6 +653,39 @@ namespace {
614
653
DumpEqualExpr (OS, State.G );
615
654
}
616
655
656
+ void DumpBoundsContext (raw_ostream &OS, BoundsContextTy UC) {
657
+ if (UC.empty ())
658
+ OS << " { }\n " ;
659
+ else {
660
+ // The keys in an llvm::DenseMap are unordered. Create a set of
661
+ // variable declarations in the context ordered first by name,
662
+ // then by location in order to guarantee a deterministic output
663
+ // so that printing the bounds context can be tested.
664
+ std::vector<DeclaratorDecl *> OrderedDecls;
665
+ for (auto Pair : UC)
666
+ OrderedDecls.push_back (Pair.first );
667
+ llvm::sort (OrderedDecls.begin (), OrderedDecls.end (),
668
+ [] (DeclaratorDecl *A, DeclaratorDecl *B) {
669
+ if (A->getNameAsString () == B->getNameAsString ())
670
+ return A->getLocation () < B->getLocation ();
671
+ else
672
+ return A->getNameAsString () < B->getNameAsString ();
673
+ });
674
+
675
+ OS << " {\n " ;
676
+ for (auto I = OrderedDecls.begin (); I != OrderedDecls.end (); ++I) {
677
+ DeclaratorDecl *Variable = *I;
678
+ if (!UC[Variable])
679
+ continue ;
680
+ OS << " Variable:\n " ;
681
+ Variable->dump (OS);
682
+ OS << " Bounds:\n " ;
683
+ UC[Variable]->dump (OS);
684
+ }
685
+ OS << " }\n " ;
686
+ }
687
+ }
688
+
617
689
void DumpEqualExpr (raw_ostream &OS, EqualExprTy G) {
618
690
if (G.size () == 0 )
619
691
OS << " { }\n " ;
@@ -1887,7 +1959,7 @@ namespace {
1887
1959
// Walk the CFG, traversing basic blocks in reverse post-oder.
1888
1960
// For each element of a block, check bounds declarations. Skip
1889
1961
// CFG elements that are subexpressions of other CFG elements.
1890
- void TraverseCFG (AvailableFactsAnalysis& AFA) {
1962
+ void TraverseCFG (AvailableFactsAnalysis& AFA, FunctionDecl *FD ) {
1891
1963
assert (Cfg && " expected CFG to exist" );
1892
1964
#if TRACE_CFG
1893
1965
llvm::outs () << " Dumping AST" ;
@@ -1896,6 +1968,23 @@ namespace {
1896
1968
Cfg->print (llvm::outs (), S.getLangOpts (), true );
1897
1969
llvm::outs () << " Traversing CFG:\n " ;
1898
1970
#endif
1971
+
1972
+ // Map each function parameter to its declared bounds (if any) before
1973
+ // checking the body of the function. The context formed by the declared
1974
+ // parameter bounds is the initial context for checking the function body.
1975
+ CheckingState ParamsState;
1976
+ for (auto I = FD->param_begin (); I != FD->param_end (); ++I) {
1977
+ ParmVarDecl *Param = *I;
1978
+ BoundsExpr *Bounds = Param->getBoundsExpr ();
1979
+ if (Bounds)
1980
+ ParamsState.UC [Param] = Bounds;
1981
+ }
1982
+
1983
+ // Store a checking state for each CFG block in order to track
1984
+ // the variables with bounds declarations that are in scope.
1985
+ llvm::DenseMap<unsigned int , CheckingState> BlockStates;
1986
+ BlockStates[Cfg->getEntry ().getBlockID ()] = ParamsState;
1987
+
1899
1988
StmtSet NestedElements;
1900
1989
FindNestedElements (NestedElements);
1901
1990
StmtSet MemoryCheckedStmts;
@@ -1905,6 +1994,7 @@ namespace {
1905
1994
ResetFacts ();
1906
1995
for (const CFGBlock *Block : POView) {
1907
1996
AFA.GetFacts (Facts);
1997
+ CheckingState BlockState = GetIncomingBlockState (Block, BlockStates);
1908
1998
for (CFGElement Elem : *Block) {
1909
1999
if (Elem.getKind () == CFGElement::Statement) {
1910
2000
CFGStmt CS = Elem.castAs <CFGStmt>();
@@ -1934,10 +2024,20 @@ namespace {
1934
2024
S->dump (llvm::outs ());
1935
2025
llvm::outs ().flush ();
1936
2026
#endif
1937
- Check (S, CSS);
2027
+ // Incorporate any bounds declared in S into the initial bounds
2028
+ // context before checking S. TODO: save this context in a
2029
+ // declared context DC.
2030
+ GetDeclaredBounds (this ->S , BlockState.UC , S);
2031
+ Check (S, CSS, BlockState);
2032
+ // TODO: validate the updated context BlockState.UC against
2033
+ // the declared context DC.
2034
+ if (DumpState)
2035
+ DumpCheckingState (llvm::outs (), S, BlockState);
1938
2036
}
1939
2037
}
1940
2038
AFA.Next ();
2039
+ if (Block->getBlockID () != Cfg->getEntry ().getBlockID ())
2040
+ BlockStates[Block->getBlockID ()] = BlockState;
1941
2041
}
1942
2042
}
1943
2043
@@ -2075,9 +2175,6 @@ namespace {
2075
2175
break ;
2076
2176
}
2077
2177
2078
- if (DumpState)
2079
- DumpCheckingState (llvm::outs (), S, State);
2080
-
2081
2178
if (Expr *E = dyn_cast<Expr>(S)) {
2082
2179
// Bounds expressions are not null ptrs.
2083
2180
if (isa<BoundsExpr>(E))
@@ -2156,9 +2253,6 @@ namespace {
2156
2253
break ;
2157
2254
}
2158
2255
2159
- if (DumpState)
2160
- DumpCheckingState (llvm::outs (), E, State);
2161
-
2162
2256
// The type for inferring the target bounds cannot ever be an array
2163
2257
// type, as these are dealt with by an array conversion, not an lvalue
2164
2258
// conversion. The bounds for an array conversion are the same as the
@@ -2867,7 +2961,10 @@ namespace {
2867
2961
BoundsExpr *B = nullptr ;
2868
2962
InteropTypeExpr *IT = nullptr ;
2869
2963
if (VD) {
2870
- B = VD->getBoundsExpr ();
2964
+ if (State.UC .count (VD))
2965
+ B = State.UC [VD];
2966
+ else
2967
+ B = VD->getBoundsExpr ();
2871
2968
IT = VD->getInteropTypeExpr ();
2872
2969
}
2873
2970
@@ -3315,6 +3412,51 @@ namespace {
3315
3412
G.push_back (CreateTemporaryUse (Temp));
3316
3413
}
3317
3414
3415
+ // GetIncomingBlockState returns the checking state that is true at
3416
+ // the beginning of the block by taking the intersection of the UC
3417
+ // contexts that were true after each of the block's predecessors.
3418
+ //
3419
+ // BlockStates stores the checking state including the bounds context
3420
+ // for each CFG block in order to track the variables with bounds
3421
+ // declarations that are in scope. This preserves lexically scoped
3422
+ // information that is otherwise lost during CFG traversal.
3423
+ CheckingState GetIncomingBlockState (const CFGBlock *Block,
3424
+ llvm::DenseMap<unsigned int , CheckingState> BlockStates) {
3425
+ CheckingState BlockState;
3426
+ bool IntersectionEmpty = true ;
3427
+ for (const CFGBlock *PredBlock : Block->preds ()) {
3428
+ // Prevent null or non-traversed (e.g. unreachable) blocks from
3429
+ // causing the incoming UC for a block to be empty.
3430
+ if (!PredBlock)
3431
+ continue ;
3432
+ if (BlockStates.find (PredBlock->getBlockID ()) == BlockStates.end ())
3433
+ continue ;
3434
+ CheckingState PredState = BlockStates[PredBlock->getBlockID ()];
3435
+ if (IntersectionEmpty) {
3436
+ BlockState.UC = PredState.UC ;
3437
+ IntersectionEmpty = false ;
3438
+ }
3439
+ else
3440
+ BlockState.UC = IntersectUC (PredState.UC , BlockState.UC );
3441
+ }
3442
+ return BlockState;
3443
+ }
3444
+
3445
+ // IntersectUC returns a bounds context resulting from taking the
3446
+ // intersection of the contexts UC1 and UC2.
3447
+ BoundsContextTy IntersectUC (BoundsContextTy UC1, BoundsContextTy UC2) {
3448
+ BoundsContextTy IntersectedUC;
3449
+ for (auto Pair : UC1) {
3450
+ if (!Pair.second || !UC2[Pair.first ])
3451
+ continue ;
3452
+ if (Pair.second ->isUnknown () || UC2[Pair.first ]->isUnknown ())
3453
+ IntersectedUC[Pair.first ] = CreateBoundsUnknown ();
3454
+ else if (EqualValue (S.Context , Pair.second , UC2[Pair.first ], nullptr ))
3455
+ IntersectedUC[Pair.first ] = Pair.second ;
3456
+ }
3457
+ return IntersectedUC;
3458
+ }
3459
+
3318
3460
// If E appears in a set F in EQ, GetEqualExprSetContainingExpr
3319
3461
// returns F. Otherwise, it returns an empty set.
3320
3462
EqualExprTy GetEqualExprSetContainingExpr (Expr *E, EquivExprSets EQ) {
@@ -4124,7 +4266,7 @@ void Sema::CheckFunctionBodyBoundsDecls(FunctionDecl *FD, Stmt *Body) {
4124
4266
Collector.Analyze ();
4125
4267
if (getLangOpts ().DumpExtractedComparisonFacts )
4126
4268
Collector.DumpComparisonFacts (llvm::outs (), FD->getNameInfo ().getName ().getAsString ());
4127
- Checker.TraverseCFG (Collector);
4269
+ Checker.TraverseCFG (Collector, FD );
4128
4270
}
4129
4271
else {
4130
4272
// A CFG couldn't be constructed. CFG construction doesn't support
0 commit comments