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.
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.
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:
ehas type_Ptr<T>. In this case, the target bounds ofearebounds((_Array_ptr<T>)e, (_Array_ptr<T>)e + 1).ehas type_Nt_array_ptr<T>. In this case, the target bounds ofearebounds(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.
Thanks for the clarification (I missed noticing the *)!
| if (Lex.CompareExprSemantically(LValue, E)) { | ||
| if (OriginalValue) | ||
| return OriginalValue; | ||
| else |
| return OriginalValue; | ||
| else | ||
| return ExprError(); | ||
| } else |
| if (Lex.CompareExprSemantically(LValue, E)) { | ||
| if (OriginalValue) | ||
| return OriginalValue; | ||
| else |
|
LGTM. |
This PR updates bounds validation to handle the following cases:
*por 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_lenuses the member expressions->ptr_to_lento write to memory. We synthesize the member expressions->fwhose 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).