From 4fb458b1a453dfb1fbedc004255190e2e638d289 Mon Sep 17 00:00:00 2001 From: Sam Elliott Date: Thu, 2 Feb 2017 16:18:48 -0800 Subject: [PATCH] Adds tests for function pointer casts (#102) These are the tests for Microsoft/checkedc-clang#125 --- tests/typechecking/function_casts.c | 231 ++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) create mode 100644 tests/typechecking/function_casts.c diff --git a/tests/typechecking/function_casts.c b/tests/typechecking/function_casts.c new file mode 100644 index 0000000..7c482bd --- /dev/null +++ b/tests/typechecking/function_casts.c @@ -0,0 +1,231 @@ +// Unit tests for typechecking new Checked C function pointers +// +// The following line is for the LLVM test harness: +// RUN: %clang_cc1 -fcheckedc-extension -verify %s +// + +#include +#include "../../include/stdchecked.h" + +int f0(int a) { + return a; +} +float g0(float a) { + return a; +} +int (*bad_f0)(int) = (int(*)(int))0xdeadbeef; + +void takes_safe(_Ptr fun) { + return; +} + +// Nulls are specifically allowed +ptr allowed_convert_null0 = 0; +ptr allowed_convert_null1 = (int(*)(int))0; +ptr allowed_convert_null3 = *(int(*)(int))0; +ptr allowed_convert_null4 = &*(int(*)(int))0; +ptr allowed_convert_null6 = ***(int(*)(int))0; + +// Named Functions are specifically allowed +ptr allowed_convert1 = f0; +// Pointers to named functions are specifically allowed +ptr allowed_convert2 = &f0; +ptr allowed_convert3 = *f0; +ptr allowed_convert4 = &*f0; +ptr allowed_convert5 = *&f0; +ptr allowed_convert6 = ***f0; + +// Arbitrary Data is definitely not allowed +ptr bad_convert1 = (int(*)(int))0xdeadbeef; // expected-error {{can only cast function names or null pointers to checked function pointer type '_Ptr'}} +ptr bad_convert2 = (int(*)(int))g0; // expected-error {{cast to checked function pointer type '_Ptr' from incompatible type 'float (float)'}} + +// Now locally within a function body +void local_convert(int(*f1)(int), ptr f2) { + + // + // Casts at assignment-time + // + + ptr local_safe = 0; + + // Nulls are specifically allowed + ptr safe_null0 = 0; + ptr safe_null1 = (int(*)(int))0; + ptr safe_null3 = *(int(*)(int))0; + ptr safe_null4 = &*(int(*)(int))0; + ptr safe_null6 = ***(int(*)(int))0; + + // Top-level declared functions are allowed + ptr safe_f1 = f0; + ptr safe_f2 = &f0; + ptr safe_f3 = *f0; + ptr safe_f4 = &*f0; + ptr safe_f5 = *&f0; + ptr safe_f6 = ***f0; + + // Top-level declared functions are allowed + ptr safe_f7 = f2; + ptr safe_f8 = *f2; + ptr safe_f9 = &*f2; + ptr safe_f10 = *&f2; + ptr safe_f11 = ***f2; + + // Top-level declared functions are allowed + ptr safe_f12 = local_safe; + ptr safe_f13 = *local_safe; + ptr safe_f14 = &*local_safe; + ptr safe_f15 = *&local_safe; + ptr safe_f16 = ***local_safe; + + // Parameter functions are not allowed + ptr unsafe_f1 = f1; // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + ptr unsafe_f3 = *f1; // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + ptr unsafe_f4 = &*f1; // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + ptr unsafe_f5 = *&f1; // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + ptr unsafe_f6 = ***f1; // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + + // Arbitary data is definitely not allowed + ptr bad_convert1 = (int(*)(int))0xdeadbeef; // expected-error {{can only cast function names or null pointers to checked function pointer type '_Ptr'}} + ptr bad_convert2 = bad_f0; // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + ptr bad_convert3 = *bad_f0; // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + ptr bad_convert4 = ***bad_f0; // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + + // + // Casts in a Call + // + + // Nulls are specifically allowed + takes_safe(0); + takes_safe((int(*)(int))0); + takes_safe(*(int(*)(int))0); + takes_safe(&*(int(*)(int))0); + takes_safe(***(int(*)(int))0); + + // Top-level declared functions are allowed + takes_safe(f0); + takes_safe(*f0); + takes_safe(&*f0); + takes_safe(*&f0); + takes_safe(***f0); + + // Local checked functions are allowed + takes_safe(local_safe); + takes_safe(*local_safe); + takes_safe(&*local_safe); + takes_safe(*&local_safe); + takes_safe(***local_safe); + + // Unchecked parameter functions are not allowed + takes_safe(f1); // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + takes_safe(*f1); // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + takes_safe(&*f1); // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + takes_safe(*&f1); // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + takes_safe(***f1); // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + + // Arbitrary data is definitely not allowed + takes_safe((int(*)(int))0xdeadbeef); // expected-error {{can only cast function names or null pointers to checked function pointer type '_Ptr'}} + takes_safe(bad_f0); // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + takes_safe(*bad_f0); // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + takes_safe(***bad_f0); // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + + // + // Explicit User Casts + // + + int(*local_unsafe)(int) = f0; // This is a valid unchecked to unchecked assignment + + ptr safe_cast_null0 = (ptr)0; + ptr safe_cast_null1 = (ptr)((int(*)(int))0); + ptr safe_cast_null3 = (ptr)(*(int(*)(int))0); + ptr safe_cast_null4 = (ptr)(&*(int(*)(int))0); + ptr safe_cast_null6 = (ptr)(***(int(*)(int))0); + + // Top-level declared functions are allowed + ptr safe_cast_f1 = (ptr)(f0); + ptr safe_cast_f2 = (ptr)(&f0); + ptr safe_cast_f3 = (ptr)(*f0); + ptr safe_cast_f4 = (ptr)(&*f0); + ptr safe_cast_f5 = (ptr)(*&f0); + ptr safe_cast_f6 = (ptr)(***f0); + + // Checked Parameters are allowed + ptr safe_cast_f7 = (ptr)(f2); + ptr safe_cast_f8 = (ptr)(*f2); + ptr safe_cast_f9 = (ptr)(&*f2); + ptr safe_cast_f10 = (ptr)(*&f2); + ptr safe_cast_f11 = (ptr)(***f2); + + // Top-level declared functions are allowed + ptr safe_cast_f12 = (ptr)(local_safe); + ptr safe_cast_f13 = (ptr)(*local_safe); + ptr safe_cast_f14 = (ptr)(&*local_safe); + ptr safe_cast_f15 = (ptr)(*&local_safe); + ptr safe_cast_f16 = (ptr)(***local_safe); + + // Parameter functions are not allowed + ptr unsafe_cast_f1 = (ptr)(f1); // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + ptr unsafe_cast_f3 = (ptr)(*f1); // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + ptr unsafe_cast_f4 = (ptr)(&*f1); // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + ptr unsafe_cast_f5 = (ptr)(*&f1); // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + ptr unsafe_cast_f6 = (ptr)(***f1); // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + + // Arbitary data is definitely not allowed + ptr bad_cast_1 = (ptr)((int(*)(int))0xdeadbeef); // expected-error {{can only cast function names or null pointers to checked function pointer type '_Ptr'}} + ptr bad_cast_2 = (ptr)(bad_f0); // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + ptr bad_cast_3 = (ptr)(*bad_f0); // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + ptr bad_cast_4 = (ptr)(***bad_f0); // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + + // + // Weird Casts + // + + ptr local_safe2 = 0; + int(*local_odd)(int) = local_unsafe; + ptr local_super_unsafe1 = local_unsafe; // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + ptr local_super_unsafe2 = (ptr)local_unsafe; // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + + // + // Weird Unary Operators + // + + // There's no good reason to do this to any function pointers + // and it's definitely not safe. + ptr local_weird_unsafe1 = (ptr)~(intptr_t)f1; // expected-error {{can only cast function names or null pointers to checked function pointer type '_Ptr'}} + ptr local_weird_unsafe2 = (ptr)~(intptr_t)f2; // expected-error {{can only cast function names or null pointers to checked function pointer type '_Ptr'}} + ptr local_weird_unsafe3 = (ptr)~(intptr_t)f0; // expected-error {{can only cast function names or null pointers to checked function pointer type '_Ptr'}} + ptr local_weird_unsafe4 = (ptr)!(intptr_t)f1; // expected-error {{can only cast function names or null pointers to checked function pointer type '_Ptr'}} + ptr local_weird_unsafe5 = (ptr)!(intptr_t)f2; // expected-error {{can only cast function names or null pointers to checked function pointer type '_Ptr'}} + ptr local_weird_unsafe6 = (ptr)!(intptr_t)f0; // expected-error {{can only cast function names or null pointers to checked function pointer type '_Ptr'}} + ptr local_weird_unsafe7 = (ptr)+(intptr_t)f1; // expected-error {{can only cast function names or null pointers to checked function pointer type '_Ptr'}} + ptr local_weird_unsafe8 = (ptr)+(intptr_t)f2; // expected-error {{can only cast function names or null pointers to checked function pointer type '_Ptr'}} + ptr local_weird_unsafe9 = (ptr)+(intptr_t)f0; // expected-error {{can only cast function names or null pointers to checked function pointer type '_Ptr'}} + ptr local_weird_unsafe10 = (ptr)-(intptr_t)f1; // expected-error {{can only cast function names or null pointers to checked function pointer type '_Ptr'}} + ptr local_weird_unsafe11 = (ptr)-(intptr_t)f2; // expected-error {{can only cast function names or null pointers to checked function pointer type '_Ptr'}} + ptr local_weird_unsafe12 = (ptr)-(intptr_t)f0; // expected-error {{can only cast function names or null pointers to checked function pointer type '_Ptr'}} + + int(**local_more_unsafe1)(int) = &local_unsafe; + ptr local_more_unsafe2 = *local_more_unsafe1; // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + + int local_not_fn; + ptr local_not_fn2 = (int(*)(int))&local_not_fn; // expected-error {{cast to checked function pointer type '_Ptr' may only take the address of expressions with function type}} + +} + +struct S1 { + ptr f1; + int(*f2)(int, int); +}; + +union U1 { + ptr f1; + int(*f2)(int, int); +}; + +void field_access(struct S1 s1, union U1 u1) { + ptr safe1 = s1.f1; + ptr unsafe1 = s1.f2; // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} + + // safe2 should probably not be allowed, but it is. + ptr safe2 = u1.f1; + ptr unsafe2 = u1.f2; // expected-error {{cannot guarantee operand of cast to checked function pointer type '_Ptr' is a function pointer}} +} \ No newline at end of file