From 95aa444265390c443ead23a9911f46129c4f0157 Mon Sep 17 00:00:00 2001 From: David Tarditi Date: Mon, 21 May 2018 15:19:06 -0700 Subject: [PATCH] Test restrictions on taking addresses of members and variables. (#284) Checked C restricts taking the addresses of: 1. Members with member bounds declarations. 2. Members used in member bounds declarations. 3. Variables with bounds declarations. 4. Variables/variable members used in bounds declarations. This add tests of restrictions 1-3, as part of implementing https://github.com/Microsoft/checkedc-clang/issues/213 and https://github.com/Microsoft/checkedc-clang/issues/212: - Taking the address of non-array members with or used in bounds declarations is now an error. - Taking the address of non-array members with or used in bounds-safe interfaces is allowed in unchecked scopes. It is an error in checked scopes. - Taking the address of non-array variables with bounds declaration is now an error. It is OK to take the address of an array variable or member because you can't use the resulting pointer to modify the pointer that the array converts to. The trickier cases to test involve nested members. Given ``` struct NestedLen { int len; }; struct S { struct NestedLen n; _Array_ptr p : count(n.len); } ``` we don't allow the addresses of `n` or `n.len` to be taken. However, if `NestedLen` is not embedded in `S`, we allow the address of a struct of type NestedLen to be taken. --- tests/static_checking/address_of.c | 394 +++++++++++++++++++ tests/static_checking/bounds_decl_checking.c | 8 +- 2 files changed, 400 insertions(+), 2 deletions(-) create mode 100644 tests/static_checking/address_of.c diff --git a/tests/static_checking/address_of.c b/tests/static_checking/address_of.c new file mode 100644 index 0000000..c6ba56e --- /dev/null +++ b/tests/static_checking/address_of.c @@ -0,0 +1,394 @@ +// Feature tests of restrictions on taking the addresses of: +// +// (1) members used in member bounds +// (2) members with member bounds. +// (3) variables with bounds. +// TODO: write tests of lvalue expressions used in variable bounds. +// +// The following lines are for the LLVM test harness: +// +// RUN: %clang_cc1 -Wno-check-bounds-decls-checked-scope -verify -verify-ignore-unexpected=note %s + +#include + +// Test taking addresses of members using in bounds expressions for checked members. +struct S1 { + _Array_ptr p : count(len); + int len; +}; + +struct S2 { + int padding; + struct S1 s; +}; + +struct Nested_Len { + int len; +}; + +struct S1_Nested { + _Array_ptr p : count(child.len); + struct Nested_Len child; +}; + +extern void f1(struct S1 s1, struct S2 s2, struct S1_Nested s1_nested, struct Nested_Len nested_len) { + int *p1 = &s1.len; // expected-error {{cannot take address of member used in member bounds}} + int *p2 = &(s1.len); // expected-error {{cannot take address of member used in member bounds}} + int *p3 = &(s1).len; // expected-error {{cannot take address of member used in member bounds}} + int *p4 = &s2.s.len; // expected-error {{cannot take address of member used in member bounds}} + int *p5 = &(s2.s.len); // expected-error {{cannot take address of member used in member bounds}} + int *p6 = &(s2.s).len; // expected-error {{cannot take address of member used in member bounds}} + + int *p7 = &s1_nested.child.len; // expected-error {{cannot take address of member used in member bounds}} + int *p8 = &(s1_nested.child.len); // expected-error {{cannot take address of member used in member bounds}} + int *p9 = &(s1_nested.child).len; // expected-error {{cannot take address of member used in member bounds}} + struct Nested_Len *p10 = &s1_nested.child; // expected-error {{cannot take address of member used in member bounds}} + struct Nested_Len *p11 = &(s1_nested).child; // expected-error {{cannot take address of member used in member bounds}} + struct Nested_Len *p12 = &(s1_nested.child); // expected-error {{cannot take address of member used in member bounds}} + + struct Nested_Len *p13 = &nested_len; + int *p14 = &nested_len.len; + +} + +extern void f2(struct S1 *s1, struct S2 *s2, struct S1_Nested *s1_nested, struct Nested_Len *nested_len) { + int *p1 = &s1->len; // expected-error {{cannot take address of member used in member bounds}} + int *p2 = &(s1->len); // expected-error {{cannot take address of member used in member bounds}} + int *p3 = &(s1)->len; // expected-error {{cannot take address of member used in member bounds}} + int *p4 = &s2->s.len; // expected-error {{cannot take address of member used in member bounds}} + int *p5 = &(s2->s.len); // expected-error {{cannot take address of member used in member bounds}} + int *p6 = &(s2->s).len; // expected-error {{cannot take address of member used in member bounds}} + + int *p7 = &s1_nested->child.len; // expected-error {{cannot take address of member used in member bounds}} + int *p8 = &(s1_nested->child.len); // expected-error {{cannot take address of member used in member bounds}} + int *p9 = &(s1_nested->child).len; // expected-error {{cannot take address of member used in member bounds}} + struct Nested_Len *p10 = &s1_nested->child; // expected-error {{cannot take address of member used in member bounds}} + struct Nested_Len *p11 = &(s1_nested)->child; // expected-error {{cannot take address of member used in member bounds}} + struct Nested_Len *p12 = &(s1_nested->child); // expected-error {{cannot take address of member used in member bounds}} + + struct Nested_Len *p13 = &*nested_len; + int *p14 = &nested_len->len; +} + +extern void f3(struct S1 *s1, struct S2 *s2, struct S1_Nested *s1_nested, struct Nested_Len *nested_len) { + _Array_ptr *p1 = &s1->p; // expected-error {{cannot take address of member with bounds}} + _Array_ptr *p2 = &(s1->p); // expected-error {{cannot take address of member with bounds}} + _Array_ptr *p3 = &(s1)->p; // expected-error {{cannot take address of member with bounds}} + _Array_ptr *p4 = &s2->s.p; // expected-error {{cannot take address of member with bounds}} + _Array_ptr *p5 = &(s2->s.p); // expected-error {{cannot take address of member with bounds}} + _Array_ptr *p6 = &(s2->s).p; // expected-error {{cannot take address of member with bounds}} + _Array_ptr *p7 = &s1_nested->p; // expected-error {{cannot take address of member with bounds}} + _Array_ptr *p8 = &(s1_nested->p); // expected-error {{cannot take address of member with bounds}} + _Array_ptr *p9 = &(s1_nested)->p; // expected-error {{cannot take address of member with bounds}} +} + +// Test taking addresses of members with bounds-safe interfaces. +struct S3 { + int *p : count(len); + int len; +}; + +struct S4 { + int padding; + struct S3 s; +}; + +struct S3_Nested { + int *p : count(child.len); + struct Nested_Len child; +}; + +extern void f4(struct S3 s3, struct S4 s4, struct S3_Nested s3_nested) { + int *p1 = &s3.len; + int *p2 = &(s3.len); + int *p3 = &(s3).len; + int *p4 = &s4.s.len; + int *p5 = &(s4.s.len); + int *p6 = &(s4.s).len; + + int *p7 = &s3_nested.child.len; + int *p8 = &(s3_nested.child.len); + int *p9 = &(s3_nested.child).len; + struct Nested_Len *p10 = &s3_nested.child; + struct Nested_Len *p11 = &(s3_nested).child; + struct Nested_Len *p12 = &(s3_nested.child); +} + +extern checked void f5(struct S3 s3, struct S4 s4, struct S3_Nested s3_nested) { + _Ptr p1 = &s3.len; // expected-error {{cannot take address of member used in member bounds}} + _Ptr p2 = &(s3.len); // expected-error {{cannot take address of member used in member bounds}} + _Ptr p3 = &(s3).len; // expected-error {{cannot take address of member used in member bounds}} + _Ptr p4 = &s4.s.len; // expected-error {{cannot take address of member used in member bounds}} + _Ptr p5 = &(s4.s.len); // expected-error {{cannot take address of member used in member bounds}} + _Ptr p6 = &(s4.s).len; // expected-error {{cannot take address of member used in member bounds}} + + + _Ptr p7 = &s3_nested.child.len; // expected-error {{cannot take address of member used in member bounds}} + _Ptr p8 = &(s3_nested.child.len); // expected-error {{cannot take address of member used in member bounds}} + _Ptr p9 = &(s3_nested.child).len; // expected-error {{cannot take address of member used in member bounds}} + _Ptr p10 = &s3_nested.child; // expected-error {{cannot take address of member used in member bounds}} + _Ptr p11 = &(s3_nested).child; // expected-error {{cannot take address of member used in member bounds}} + _Ptr p12 = &(s3_nested.child); // expected-error {{cannot take address of member used in member bounds}} +} + +extern void f6(struct S3 *s3, struct S4 *s4, struct S3_Nested *s3_nested) { + int *p1 = &s3->len; + int *p2 = &(s3->len); + int *p3 = &(s3)->len; + int *p4 = &s4->s.len; + int *p5 = &(s4->s.len); + int *p6 = &(s4->s).len; + int *p7 = &s3_nested->child.len; + int *p8 = &(s3_nested->child.len); + int *p9 = &(s3_nested->child).len; + struct Nested_Len *p10 = &s3_nested->child; + struct Nested_Len *p11 = &(s3_nested)->child; + struct Nested_Len *p12 = &(s3_nested->child); +} + +extern checked void f7(_Ptr s3, _Ptr s4, _Ptr s3_nested) { + _Ptr p1 = &s3->len; // expected-error {{cannot take address of member used in member bounds}} + _Ptr p2 = &(s3->len); // expected-error {{cannot take address of member used in member bounds}} + _Ptr p3 = &(s3)->len; // expected-error {{cannot take address of member used in member bounds}} + _Ptr p4 = &s4->s.len; // expected-error {{cannot take address of member used in member bounds}} + _Ptr p5 = &(s4->s.len); // expected-error {{cannot take address of member used in member bounds}} + _Ptr p6 = &(s4->s).len; // expected-error {{cannot take address of member used in member bounds}} + + _Ptr p7 = &s3_nested->child.len; // expected-error {{cannot take address of member used in member bounds}} + _Ptr p8 = &(s3_nested->child.len); // expected-error {{cannot take address of member used in member bounds}} + _Ptr p9 = &(s3_nested->child).len; // expected-error {{cannot take address of member used in member bounds}} + _Ptr p10 = &s3_nested->child; // expected-error {{cannot take address of member used in member bounds}} + _Ptr p11 = &(s3_nested)->child; // expected-error {{cannot take address of member used in member bounds}} + _Ptr p12 = &(s3_nested->child); // expected-error {{cannot take address of member used in member bounds}} +} + +extern void f8(struct S3 s3, struct S4 s4, struct S3_Nested s3_nested) { + int **p1 = &s3.p; + int **p2 = &(s3.p); + int **p3 = &(s3).p; + int **p4 = &s4.s.p; + int **p5 = &(s4.s.p); + int **p6 = &(s4.s).p; + int **p7 = &s3_nested.p; + int **p8 = &(s3_nested.p); + int **p9 = &(s3_nested).p; +} + +extern void f9(struct S3 *s3, struct S4 *s4, struct S3_Nested *s3_nested) { + int **p1 = &s3->p; + int **p2 = &(s3->p); + int **p3 = &(s3)->p; + int **p4 = &s4->s.p; + int **p5 = &(s4->s.p); + int **p6 = &(s4->s).p; + int **p7 = &s3_nested->p; + int **p8 = &(s3_nested->p); + int **p9 = &(s3_nested)->p; +} + +extern checked void f10(struct S3 s3, struct S4 s4, struct S3_Nested s3_nested) { + _Ptr<_Array_ptr> p1 = &s3.p; // expected-error {{cannot take address of member with bounds}} + _Ptr<_Array_ptr> p2 = &(s3.p); // expected-error {{cannot take address of member with bounds}} + _Ptr<_Array_ptr> p3 = &(s3).p; // expected-error {{cannot take address of member with bounds}} + _Ptr<_Array_ptr> p4 = &s4.s.p; // expected-error {{cannot take address of member with bounds}} + _Ptr<_Array_ptr> p5 = &(s4.s.p); // expected-error {{cannot take address of member with bounds}} + _Ptr<_Array_ptr> p6 = &(s4.s).p; // expected-error {{cannot take address of member with bounds}} + _Ptr<_Array_ptr> p7 = &s3_nested.p; // expected-error {{cannot take address of member with bounds}} + _Ptr<_Array_ptr> p8 = &(s3_nested.p); // expected-error {{cannot take address of member with bounds}} + _Ptr<_Array_ptr> p9 = &(s3_nested).p; // expected-error {{cannot take address of member with bounds}} +} + +extern checked void f11(_Ptr s3, _Ptr s4, _Ptr s3_nested) { + _Ptr<_Array_ptr> p1 = &s3->p; // expected-error {{cannot take address of member with bounds}} + _Ptr<_Array_ptr> p2 = &(s3->p); // expected-error {{cannot take address of member with bounds}} + _Ptr<_Array_ptr> p3 = &(s3)->p; // expected-error {{cannot take address of member with bounds}} + _Ptr<_Array_ptr> p4 = &s4->s.p; // expected-error {{cannot take address of member with bounds}} + _Ptr<_Array_ptr> p5 = &(s4->s.p); // expected-error {{cannot take address of member with bounds}} + _Ptr<_Array_ptr> p6 = &(s4->s).p; // expected-error {{cannot take address of member with bounds}} + _Ptr<_Array_ptr> p7 = &s3_nested->p; // expected-error {{cannot take address of member with bounds}} + _Ptr<_Array_ptr> p8 = &(s3_nested->p); // expected-error {{cannot take address of member with bounds}} + _Ptr<_Array_ptr> p9 = &(s3_nested)->p; // expected-error {{cannot take address of member with bounds}} +} + +// +// Check taking address of array members and member used in bounds for array members. +// + +struct S5 { + int arr _Checked[10]; +}; + +struct S6 { + int len; + int arr _Checked[10] : count(len); +}; + +struct S7 { + int arr[10] : count(10); +}; + +struct S8 { + int len; + int arr[10] : count(len); +}; + + +extern void f30(struct S5 *s5) { + _Ptr p1 = &s5->arr; // this is OK because arr can't be modified. +} + +extern void f31(struct S6 *s6) { + _Ptr p1 = &s6->len; // expected-error {{cannot take address of member used in member bounds}} + _Ptr p2 = &s6->arr; // this is OK because arr can't be modified. +} + + +extern void f32(struct S7 *s7) { + _Ptr p1 = &s7->arr; // this is OK because arr can't be modified. +} + +extern checked void f33(_Ptr s7) { + _Ptr p1 = &s7->arr; // this is OK because arr can't be modified. +} + +extern checked void f33a(struct S7 *s7 : itype(_Ptr)) { + _Ptr p1 = &s7->arr; // this is OK because arr can't be modified. +} + + +extern void f34(struct S8 *s8) { + _Ptr p1 = &s8->len; + _Ptr p2 = &s8->arr; // this is OK because arr can't be modified. +} + +extern checked void f35(_Ptr s8) { + _Ptr p1 = &s8->len; // expected-error {{cannot take address of member used in member bounds}} + _Ptr p2 = &s8->arr; // this is OK because arr can't be modified. +} + +extern checked void f35a(struct S8 *s8 : itype(_Ptr)) { + _Ptr p1 = &s8->len; // expected-error {{cannot take address of member used in member bounds}} + _Ptr p2 = &s8->arr; // this is OK because arr can't be modified. +} + +// Spot check bounds for a flexible array member. + +struct S9 { + int padding; + int arr _Checked[] : count(0); +}; + +struct S10 { + int len; + int arr _Checked[] : count(len); +}; + +struct S11 { + int padding; + int arr[] : count(0); +}; + +struct S12 { + int len; + int arr[] : count(len); +}; + +extern void f40(struct S9 *s9) { + _Ptr p1 = &s9->arr; // this is OK because arr can't be modified. +} + + +extern void f41(struct S10 *s10) { + _Ptr p1 = &s10->len; // expected-error {{cannot take address of member used in member bounds}} + _Ptr p2 = &s10->arr; // this is OK because arr can't be modified. +} + +extern void f42(struct S11 *s11) { + int (*p1) _Checked[] = &s11->arr; // this is OK because arr can't be modified. +} + +extern checked void f43(_Ptr s11) { + _Ptr p1 = &s11->arr; // this is OK because arr can't be modified. +} + +extern void f44(struct S12 *s12) { + int *p1 = &s12->len; + int (*p2) _Checked[] = &s12->arr; // this is OK because arr can't be modified. +} + +extern checked void f45(_Ptr s12) { + _Ptr p1 = &s12->len; // expected-error {{cannot take address of member used in member bounds}} + _Ptr p2 = &s12->arr; // this is OK because arr can't be modified. +} + +// +// Spot check taking address of members used other bounds expressions besides count. +// + +struct S20 { + _Array_ptr p : bounds(p, p + 5); + _Array_ptr mid : bounds(upper, lower); + _Array_ptr upper, lower; + _Array_ptr q : byte_count(len); + int len; +}; + +void f46(struct S20 s) { + _Ptr<_Array_ptr> p1 = &s.p; // expected-error {{cannot take address of member with bounds}} expected-error {{cannot take address of member used in member bounds}} + _Ptr<_Array_ptr> p2 = &s.mid; // expected-error {{cannot take address of member with bounds}} + _Ptr<_Array_ptr> p3 = &s.upper; // expected-error {{cannot take address of member used in member bounds}} + _Ptr<_Array_ptr> p4 = &s.upper; // expected-error {{cannot take address of member used in member bounds}} + _Ptr<_Array_ptr> p5 = &s.q; // expected-error {{cannot take address of member with bounds}} + _Ptr p6 = &s.len; // expected-error {{cannot take address of member used in member bounds}} +} + + +// +// Check taking the address of variables with bounds. +// + +// Checked variables with bounds declarations. +int global_len1; +_Array_ptr global_var1 : count(global_len1); +_Ptr<_Array_ptr> pglobal1 = &global_var1; // expected-error {{cannot take address of variable 'global_var1' with bounds}} + +extern int global_arr1 _Checked[] : count(global_len1); +_Ptr parr = &global_arr1; + +extern void f60(_Array_ptr x : count(len), int len) { + _Ptr<_Array_ptr> px1 = &x; // expected-error {{cannot take address of variable 'x' with bounds}} + _Ptr<_Array_ptr> px2 = &(x); // expected-error {{cannot take address of variable 'x' with bounds}} + _Array_ptr y : count(len) = x; + _Ptr<_Array_ptr> py = &y; // expected-error {{cannot take address of variable 'y' with bounds}} + _Ptr<_Array_ptr> pg = &global_var1; // expected-error {{cannot take address of variable 'global_var1' with bounds}} + _Ptr parr1 = &global_arr1; + _Ptr parr2 = &(global_arr1); + + if (len >= 0 && len < 10) { + int arr _Checked[10] : count(len); + _Ptr parr = &arr; + } +} + +// Variables with bounds-safe interfaces +int global_len2; +int *global_var2 : count(global_len2); +int **pglobal2 = &global_var2; + +extern int global_arr2[] : count(global_len1); +int (*parr2) _Checked[] = &global_arr2; + +extern void f61(int *x : count(len), int len) { + int **px = &x; + int **pg = &global_var2; +} + +extern _Checked void f62(int *x : count(len), int len) { + _Ptr<_Array_ptr> px1 = &x; // expected-error {{cannot take address of variable 'x' with bounds}} + _Ptr<_Array_ptr> px2 = &(x); // expected-error {{cannot take address of variable 'x' with bounds}} + _Ptr<_Array_ptr> px3 = (&x); // expected-error {{cannot take address of variable 'x' with bounds}} + _Ptr<_Array_ptr> pg = &global_var2; // expected-error {{cannot take address of variable 'global_var2' with bounds}} + + _Ptr parr1 = &global_arr2; + _Ptr parr2 = &(global_arr2); +} diff --git a/tests/static_checking/bounds_decl_checking.c b/tests/static_checking/bounds_decl_checking.c index cb10ca0..287e1eb 100644 --- a/tests/static_checking/bounds_decl_checking.c +++ b/tests/static_checking/bounds_decl_checking.c @@ -383,13 +383,17 @@ extern void check_exprs_nullterm(nt_array_ptr arg1 : bounds(unknown), t3 = s.f3; nt_array_ptr ntp = (int nt_checked[]) { 0, 1, 2, 3, 0 }; +/* HACK: + Taking the address of pointers with bounds is not allowed. Disable this code and + stop the verification checking by converting "expected-error" to "expected error". ptr> pntp = &ntp; - *pntp = arg1; // expected-error {{expression has unknown bounds}} + *pntp = arg1; // expected error {{expression has unknown bounds}} *pntp = arg2; *pntp = arg3; arg1 = *pntp; arg2 = *pntp; - arg3 = *pntp; // expected-error {{declared bounds for arg3 are invalid after assignment}} + arg3 = *pntp; // expected error {{declared bounds for arg3 are invalid after assignment}} +*/ } extern void test_f1(int *p);