Skip to content

Commit

Permalink
Member expression bounds checking in multiple assignments (checkedc#1181
Browse files Browse the repository at this point in the history
)

* For a synthesized AbstractSet A containing a member expression, only set the observed bounds of A to its target bounds if it does not already have observed bounds recorded

* Add tests for multiple (comma-separated) assignments to member expressions

* Update comment
  • Loading branch information
kkjeer authored Sep 7, 2021
1 parent ce4831a commit 82b7208
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 6 deletions.
18 changes: 14 additions & 4 deletions clang/lib/Sema/SemaBounds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4890,7 +4890,8 @@ namespace {
// to LValue means that a member expression is being used to write to
// memory), get the set of AbstractSets whose target bounds depend on
// LValue. The observed bounds of each of these AbstractSets are recorded
// in ObservedBounds.
// in ObservedBounds. If they are not already present in ObservedBounds,
// their observed bounds are initialized to their target bounds.
MemberExpr *M = GetAssignmentTargetMemberExpr(LValue);
if (M) {
AbstractSetSetTy AbstractSets;
Expand All @@ -4900,9 +4901,18 @@ namespace {
DumpSynthesizedMemberAbstractSets(llvm::outs(), AbstractSets);

for (const AbstractSet *A : AbstractSets) {
BoundsExpr *TargetBounds =
S.GetLValueDeclaredBounds(A->GetRepresentative(), CSS);
State.ObservedBounds[A] = TargetBounds;
// We only set the observed bounds of A to the target bounds of A
// if A is not already present in ObservedBounds. If A is already
// present in ObservedBounds, then there was an assignment in the
// current top-level statement (or bundled block) that updated the
// observed bounds of A. These observed bounds may or may not depend
// on LValue. If A currently has observed bounds that do not use the
// value of LValue, then the current assignment to LValue should
// have no effect on the observed bounds of A.
if (!State.ObservedBounds.count(A)) {
State.ObservedBounds[A] =
S.GetLValueDeclaredBounds(A->GetRepresentative(), CSS);
}
}
}

Expand Down
113 changes: 111 additions & 2 deletions clang/test/CheckedC/inferred-bounds/bounds-context-members.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@

struct S {
int len;
array_ptr<int> p : count(len); // expected-note 4 {{(expanded) declared bounds are 'bounds(s->p, s->p + s->len)'}}
array_ptr<int> p : count(len); // expected-note 5 {{(expanded) declared bounds are 'bounds(s->p, s->p + s->len)'}}
int i;
array_ptr<int> q : count(i); // expected-note 2 {{(expanded) declared bounds are 'bounds(s[3].q, s[3].q + s[3].i)'}} \
// expected-note {{(expanded) declared bounds are 'bounds(s[4].q, s[4].q + s[4].i)'}}
array_ptr<int> r : count(i); // expected-note 2 {{(expanded) declared bounds are 'bounds(s[3].r, s[3].r + s[3].i)'}}
array_ptr<int> f : count(3); // expected-note 2 {{(expanded) declared bounds are 'bounds(s->f, s->f + 3)'}}
array_ptr<int> g : bounds(f, f + 3); // expected-note 2 {{(expanded) declared bounds are 'bounds(s->f, s->f + 3)'}}
array_ptr<int> a : count(2);
array_ptr<int> a : count(2); // expected-note 2 {{(expanded) declared bounds are 'bounds(s->a, s->a + 2)'}}
array_ptr<int> b : count(2);
};

Expand Down Expand Up @@ -360,6 +360,115 @@ void updated_source_bounds3(struct S *s) {
// CHECK-NEXT: }
}

void multiple_assignments1(struct S *s, _Array_ptr<int> arr : count(3)) {
// Observed bounds context after statement: { s->p => bounds(arr, arr + 3), arr => bounds(arr, arr + 3) }
s->p = arr, s->len = 3;
// CHECK: Statement S:
// CHECK-NEXT: BinaryOperator {{.*}} ','
// CHECK: Observed bounds context after checking S:
// CHECK-NEXT: {
// CHECK-NEXT: LValue Expression:
// CHECK-NEXT: MemberExpr {{.*}} ->p
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 's'
// CHECK-NEXT: Bounds:
// CHECK-NEXT: RangeBoundsExpr
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 'arr'
// CHECK-NEXT: BinaryOperator {{.*}} '+'
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 'arr'
// CHECK-NEXT: IntegerLiteral {{.*}} 3
// CHECK-NEXT: LValue Expression:
// CHECK-NEXT: DeclRefExpr {{.*}} 'arr'
// CHECK-NEXT: Bounds:
// CHECK-NEXT: RangeBoundsExpr
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 'arr'
// CHECK-NEXT: BinaryOperator {{.*}} '+'
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 'arr'
// CHECK-NEXT: IntegerLiteral {{.*}} 3
// CHECK-NEXT: }

// Observed bounds context after assignment: { s->p => bounds(unknown), arr => bounds(arr, arr + 3) }
s[0].len = 0; // expected-error {{inferred bounds for 's->p' are unknown after assignment}} \
// expected-note {{lost the value of the expression 's[0].len' which is used in the (expanded) inferred bounds 'bounds(s->p, s->p + s->len)' of 's->p'}}
// CHECK: Statement S:
// CHECK-NEXT: BinaryOperator {{.*}} '='
// CHECK: Observed bounds context after checking S:
// CHECK-NEXT: {
// CHECK-NEXT: LValue Expression:
// CHECK-NEXT: MemberExpr {{.*}} ->p
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 's'
// CHECK-NEXT: Bounds:
// CHECK-NEXT: NullaryBoundsExpr {{.*}} Unknown
// CHECK-NEXT: LValue Expression:
// CHECK-NEXT: DeclRefExpr {{.*}} 'arr'
// CHECK-NEXT: Bounds:
// CHECK-NEXT: RangeBoundsExpr
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 'arr'
// CHECK-NEXT: BinaryOperator {{.*}} '+'
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 'arr'
// CHECK-NEXT: IntegerLiteral {{.*}} 3
// CHECK-NEXT: }
}

void multiple_assignments2(struct S *s) {
// Observed bounds context after statement: { s->a => bounds(s->a - 1, (s->a - 1) + 2) }
s->a = s->b, s->a++; // expected-warning {{cannot prove declared bounds for 's->a' are valid after increment}} \
// expected-note {{(expanded) inferred bounds are 'bounds(s->a - 1, s->a - 1 + 2)'}}
// CHECK: Statement S:
// CHECK-NEXT: BinaryOperator {{.*}} ','
// CHECK: Observed bounds context after checking S:
// CHECK-NEXT: {
// CHECK-NEXT: LValue Expression:
// CHECK-NEXT: MemberExpr {{.*}} ->a
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 's'
// CHECK-NEXT: Bounds:
// CHECK-NEXT: RangeBoundsExpr
// CHECK-NEXT: BinaryOperator {{.*}} '-'
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
// CHECK-NEXT: MemberExpr {{.*}} ->a
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 's'
// CHECK-NEXT: IntegerLiteral {{.*}} 1
// CHECK-NEXT: BinaryOperator {{.*}} '+'
// CHECK-NEXT: BinaryOperator {{.*}} '-'
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
// CHECK-NEXT: MemberExpr {{.*}} ->a
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 's'
// CHECK-NEXT: IntegerLiteral {{.*}} 1
// CHECK-NEXT: IntegerLiteral {{.*}} 2
// CHECK-NEXT: }

// Observed bounds context after statement: { s->a => bounds(unknown), s->b = bounds(any) }
s->a = s->b, s->b = 0; // expected-error {{inferred bounds for 's->a' are unknown after assignment}} \
// expected-note {{lost the value of the expression 's->b' which is used in the (expanded) inferred bounds 'bounds(s->b, s->b + 2)' of 's->a'}}
// CHECK: Statement S:
// CHECK-NEXT: BinaryOperator {{.*}} ','
// CHECK: Observed bounds context after checking S:
// CHECK-NEXT: {
// CHECK-NEXT: LValue Expression:
// CHECK-NEXT: MemberExpr {{.*}} ->a
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 's'
// CHECK-NEXT: Bounds:
// CHECK-NEXT: NullaryBoundsExpr {{.*}} Unknown
// CHECK-NEXT: LValue Expression:
// CHECK-NEXT: MemberExpr {{.*}} ->b
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 's'
// CHECK-NEXT: Bounds:
// CHECK-NEXT: NullaryBoundsExpr {{.*}} Any
// CHECK-NEXT: }
}

struct C {
int len;
array_ptr<int> r : count(len); // expected-note {{(expanded) declared bounds are 'bounds(a.b.c.r, a.b.c.r + a.b.c.len)'}}
Expand Down

0 comments on commit 82b7208

Please sign in to comment.