-
Notifications
You must be signed in to change notification settings - Fork 80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bounds checking for pointer dereferences and array subscripts #1176
Conversation
…ongs to an AbstractSet
…ripts in bounds-context.c
…pointer dereferences and array subscripts
…into pointer-bounds-checking
…ed in return bounds
… subscript expressions in UpdateAfterAssignment
…r expression to update memory
…nced member expressions to pointer-dereference-bounds.c
…dereferenced/subscripted member expressions to synthesized-members.c
// Observed bounds context after increment: { } | ||
++*p; | ||
// Observed bounds context after increment: { *p => bounds(*p - 1, (*p - 1) + 0) } | ||
++*p; // expected-warning {{cannot prove declared bounds for '*p' are valid after increment}} \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this behavior of the compiler is incorrect. Perhaps, at present, we should restrict the bounds validation for *p
and p[i]
when the type of *p
or p[i]
is a checked pointer type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this particular test case, *p
has type _Nt_array_ptr<int>
, since p
has type _Nt_array_ptr<int> *
.
In general, if e
is a pointer dereference *e1
or an array subscript e1[e2]
, we will only check the bounds of e
if e
fulfills one of two conditions:
e
has type_Ptr<T>
. In this case, the target bounds ofe
arebounds((_Array_ptr<T>)e, (_Array_ptr<T>)e + 1)
.e
has type_Nt_array_ptr<T>
. In this case, the target bounds ofe
arebounds(e, e + 0)
.
We do not explicitly check the type of e
in UpdateAfterAssignment
or ValidateBoundsContext
. Instead, the AbstractSet
containing e
is added to ObservedBounds
if and only if e
has target bounds, which will only happen in the two cases described above.
The methods UnaryOperatorTargetBounds
and ArraySubscriptExprTargetBounds
in SemaBounds.cpp include comments that state that "Currently, we don't know the target bounds of a pointer stored in a pointer dereference (or returned by a subscripting operation), unless it is a _Ptr type or an _Nt_array_ptr."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the clarification (I missed noticing the *
)!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Thank you!
clang/lib/Sema/BoundsUtils.cpp
Outdated
if (Lex.CompareExprSemantically(LValue, E)) { | ||
if (OriginalValue) | ||
return OriginalValue; | ||
else |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: else
is not needed after a return.
clang/lib/Sema/BoundsUtils.cpp
Outdated
return OriginalValue; | ||
else | ||
return ExprError(); | ||
} else |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
clang/lib/Sema/BoundsUtils.cpp
Outdated
if (Lex.CompareExprSemantically(LValue, E)) { | ||
if (OriginalValue) | ||
return OriginalValue; | ||
else |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comments here.
LGTM. |
…into pointer-bounds-checking
This PR updates bounds validation to handle the following cases:
*p
or array subscriptp[i]
.The behavior for synthesizing member expressions whose bounds depend on a member expression that is being modified via an assignment has been extended: we now synthesize member expressions whose bounds depend on an lvalue expression that uses a member expression to update memory via an assignment. For example:
The lvalue expression
*s->ptr_to_len
uses the member expressions->ptr_to_len
to write to memory. We synthesize the member expressions->f
whose declared boundsbounds(s->f, s->f + *s->ptr_to_len)
depend on*s->ptr_to_len
.There is also a minor fix included in this PR that the pointer bounds checking depends on: in PreorderAST, the canonical form of
e1[e2]
is now*(e1 + e2 + 0)
rather than*(e1 + e2)
. This enables bounds validation to treat expressions such asp[i]
and*(p + i)
as equivalent, since PreorderAST canonicalizes*(p + i)
to*(p + i + 0)
.