Skip to content

Commit 82b7208

Browse files
authored
Member expression bounds checking in multiple assignments (checkedc#1181)
* 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
1 parent ce4831a commit 82b7208

File tree

2 files changed

+125
-6
lines changed

2 files changed

+125
-6
lines changed

clang/lib/Sema/SemaBounds.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4890,7 +4890,8 @@ namespace {
48904890
// to LValue means that a member expression is being used to write to
48914891
// memory), get the set of AbstractSets whose target bounds depend on
48924892
// LValue. The observed bounds of each of these AbstractSets are recorded
4893-
// in ObservedBounds.
4893+
// in ObservedBounds. If they are not already present in ObservedBounds,
4894+
// their observed bounds are initialized to their target bounds.
48944895
MemberExpr *M = GetAssignmentTargetMemberExpr(LValue);
48954896
if (M) {
48964897
AbstractSetSetTy AbstractSets;
@@ -4900,9 +4901,18 @@ namespace {
49004901
DumpSynthesizedMemberAbstractSets(llvm::outs(), AbstractSets);
49014902

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

clang/test/CheckedC/inferred-bounds/bounds-context-members.c

Lines changed: 111 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88

99
struct S {
1010
int len;
11-
array_ptr<int> p : count(len); // expected-note 4 {{(expanded) declared bounds are 'bounds(s->p, s->p + s->len)'}}
11+
array_ptr<int> p : count(len); // expected-note 5 {{(expanded) declared bounds are 'bounds(s->p, s->p + s->len)'}}
1212
int i;
1313
array_ptr<int> q : count(i); // expected-note 2 {{(expanded) declared bounds are 'bounds(s[3].q, s[3].q + s[3].i)'}} \
1414
// expected-note {{(expanded) declared bounds are 'bounds(s[4].q, s[4].q + s[4].i)'}}
1515
array_ptr<int> r : count(i); // expected-note 2 {{(expanded) declared bounds are 'bounds(s[3].r, s[3].r + s[3].i)'}}
1616
array_ptr<int> f : count(3); // expected-note 2 {{(expanded) declared bounds are 'bounds(s->f, s->f + 3)'}}
1717
array_ptr<int> g : bounds(f, f + 3); // expected-note 2 {{(expanded) declared bounds are 'bounds(s->f, s->f + 3)'}}
18-
array_ptr<int> a : count(2);
18+
array_ptr<int> a : count(2); // expected-note 2 {{(expanded) declared bounds are 'bounds(s->a, s->a + 2)'}}
1919
array_ptr<int> b : count(2);
2020
};
2121

@@ -360,6 +360,115 @@ void updated_source_bounds3(struct S *s) {
360360
// CHECK-NEXT: }
361361
}
362362

363+
void multiple_assignments1(struct S *s, _Array_ptr<int> arr : count(3)) {
364+
// Observed bounds context after statement: { s->p => bounds(arr, arr + 3), arr => bounds(arr, arr + 3) }
365+
s->p = arr, s->len = 3;
366+
// CHECK: Statement S:
367+
// CHECK-NEXT: BinaryOperator {{.*}} ','
368+
// CHECK: Observed bounds context after checking S:
369+
// CHECK-NEXT: {
370+
// CHECK-NEXT: LValue Expression:
371+
// CHECK-NEXT: MemberExpr {{.*}} ->p
372+
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
373+
// CHECK-NEXT: DeclRefExpr {{.*}} 's'
374+
// CHECK-NEXT: Bounds:
375+
// CHECK-NEXT: RangeBoundsExpr
376+
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
377+
// CHECK-NEXT: DeclRefExpr {{.*}} 'arr'
378+
// CHECK-NEXT: BinaryOperator {{.*}} '+'
379+
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
380+
// CHECK-NEXT: DeclRefExpr {{.*}} 'arr'
381+
// CHECK-NEXT: IntegerLiteral {{.*}} 3
382+
// CHECK-NEXT: LValue Expression:
383+
// CHECK-NEXT: DeclRefExpr {{.*}} 'arr'
384+
// CHECK-NEXT: Bounds:
385+
// CHECK-NEXT: RangeBoundsExpr
386+
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
387+
// CHECK-NEXT: DeclRefExpr {{.*}} 'arr'
388+
// CHECK-NEXT: BinaryOperator {{.*}} '+'
389+
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
390+
// CHECK-NEXT: DeclRefExpr {{.*}} 'arr'
391+
// CHECK-NEXT: IntegerLiteral {{.*}} 3
392+
// CHECK-NEXT: }
393+
394+
// Observed bounds context after assignment: { s->p => bounds(unknown), arr => bounds(arr, arr + 3) }
395+
s[0].len = 0; // expected-error {{inferred bounds for 's->p' are unknown after assignment}} \
396+
// 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'}}
397+
// CHECK: Statement S:
398+
// CHECK-NEXT: BinaryOperator {{.*}} '='
399+
// CHECK: Observed bounds context after checking S:
400+
// CHECK-NEXT: {
401+
// CHECK-NEXT: LValue Expression:
402+
// CHECK-NEXT: MemberExpr {{.*}} ->p
403+
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
404+
// CHECK-NEXT: DeclRefExpr {{.*}} 's'
405+
// CHECK-NEXT: Bounds:
406+
// CHECK-NEXT: NullaryBoundsExpr {{.*}} Unknown
407+
// CHECK-NEXT: LValue Expression:
408+
// CHECK-NEXT: DeclRefExpr {{.*}} 'arr'
409+
// CHECK-NEXT: Bounds:
410+
// CHECK-NEXT: RangeBoundsExpr
411+
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
412+
// CHECK-NEXT: DeclRefExpr {{.*}} 'arr'
413+
// CHECK-NEXT: BinaryOperator {{.*}} '+'
414+
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
415+
// CHECK-NEXT: DeclRefExpr {{.*}} 'arr'
416+
// CHECK-NEXT: IntegerLiteral {{.*}} 3
417+
// CHECK-NEXT: }
418+
}
419+
420+
void multiple_assignments2(struct S *s) {
421+
// Observed bounds context after statement: { s->a => bounds(s->a - 1, (s->a - 1) + 2) }
422+
s->a = s->b, s->a++; // expected-warning {{cannot prove declared bounds for 's->a' are valid after increment}} \
423+
// expected-note {{(expanded) inferred bounds are 'bounds(s->a - 1, s->a - 1 + 2)'}}
424+
// CHECK: Statement S:
425+
// CHECK-NEXT: BinaryOperator {{.*}} ','
426+
// CHECK: Observed bounds context after checking S:
427+
// CHECK-NEXT: {
428+
// CHECK-NEXT: LValue Expression:
429+
// CHECK-NEXT: MemberExpr {{.*}} ->a
430+
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
431+
// CHECK-NEXT: DeclRefExpr {{.*}} 's'
432+
// CHECK-NEXT: Bounds:
433+
// CHECK-NEXT: RangeBoundsExpr
434+
// CHECK-NEXT: BinaryOperator {{.*}} '-'
435+
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
436+
// CHECK-NEXT: MemberExpr {{.*}} ->a
437+
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
438+
// CHECK-NEXT: DeclRefExpr {{.*}} 's'
439+
// CHECK-NEXT: IntegerLiteral {{.*}} 1
440+
// CHECK-NEXT: BinaryOperator {{.*}} '+'
441+
// CHECK-NEXT: BinaryOperator {{.*}} '-'
442+
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
443+
// CHECK-NEXT: MemberExpr {{.*}} ->a
444+
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
445+
// CHECK-NEXT: DeclRefExpr {{.*}} 's'
446+
// CHECK-NEXT: IntegerLiteral {{.*}} 1
447+
// CHECK-NEXT: IntegerLiteral {{.*}} 2
448+
// CHECK-NEXT: }
449+
450+
// Observed bounds context after statement: { s->a => bounds(unknown), s->b = bounds(any) }
451+
s->a = s->b, s->b = 0; // expected-error {{inferred bounds for 's->a' are unknown after assignment}} \
452+
// 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'}}
453+
// CHECK: Statement S:
454+
// CHECK-NEXT: BinaryOperator {{.*}} ','
455+
// CHECK: Observed bounds context after checking S:
456+
// CHECK-NEXT: {
457+
// CHECK-NEXT: LValue Expression:
458+
// CHECK-NEXT: MemberExpr {{.*}} ->a
459+
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
460+
// CHECK-NEXT: DeclRefExpr {{.*}} 's'
461+
// CHECK-NEXT: Bounds:
462+
// CHECK-NEXT: NullaryBoundsExpr {{.*}} Unknown
463+
// CHECK-NEXT: LValue Expression:
464+
// CHECK-NEXT: MemberExpr {{.*}} ->b
465+
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
466+
// CHECK-NEXT: DeclRefExpr {{.*}} 's'
467+
// CHECK-NEXT: Bounds:
468+
// CHECK-NEXT: NullaryBoundsExpr {{.*}} Any
469+
// CHECK-NEXT: }
470+
}
471+
363472
struct C {
364473
int len;
365474
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)'}}

0 commit comments

Comments
 (0)