|
| 1 | +#![deny(improper_ctypes, improper_c_fn_definitions)] |
| 2 | +#![deny(improper_c_callbacks)] |
| 3 | + |
| 4 | +//@ aux-build: extern_crate_types.rs |
| 5 | +//@ compile-flags:--extern extern_crate_types |
| 6 | +extern crate extern_crate_types as ext_crate; |
| 7 | + |
| 8 | +// //////////////////////////////////////////////////////// |
| 9 | +// first, the same bank of types as in the extern crate |
| 10 | + |
| 11 | +// FIXME: maybe re-introduce improper_ctype_definitions (ctype singular) |
| 12 | +// as a way to mark ADTs as "let's ignore that they are not actually FFI-unsafe" |
| 13 | + |
| 14 | +#[repr(C)] |
| 15 | +struct SafeStruct (i32); |
| 16 | + |
| 17 | +#[repr(C)] |
| 18 | +struct UnsafeStruct (String); |
| 19 | + |
| 20 | +#[repr(C)] |
| 21 | +//#[allow(improper_ctype_definitions)] |
| 22 | +struct AllowedUnsafeStruct (String); |
| 23 | + |
| 24 | +// refs are only unsafe if the value comes from the other side of the FFI boundary |
| 25 | +// due to the non-null assumption |
| 26 | +// (technically there are also assumptions about non-dandling, alignment, |
| 27 | +// aliasing, lifetimes, etc...) |
| 28 | +// the lint is not raised here, but will be if used in the wrong place |
| 29 | +#[repr(C)] |
| 30 | +struct UnsafeFromForeignStruct<'a> (&'a u32); |
| 31 | + |
| 32 | +#[repr(C)] |
| 33 | +//#[allow(improper_ctype_definitions)] |
| 34 | +struct AllowedUnsafeFromForeignStruct<'a> (&'a u32); |
| 35 | + |
| 36 | + |
| 37 | +type SafeFnPtr = extern "C" fn(i32)->i32; |
| 38 | + |
| 39 | +type UnsafeFnPtr = extern "C" fn((i32, i32))->i32; |
| 40 | +//~^ ERROR: `extern` callback uses type `(i32, i32)` |
| 41 | + |
| 42 | + |
| 43 | +// for now, let's not lint on the nonzero assumption, |
| 44 | +// because: |
| 45 | +// - we don't know if the callback is rust-callee-foreign-caller or the other way around |
| 46 | +// - having to cast around function signatures to get function pointers |
| 47 | +// would be an awful experience |
| 48 | +// so, let's assume that the unsafety in this fnptr |
| 49 | +// will be pointed out indirectly by a lint elsewhere |
| 50 | +// (note: there's one case where the error would be missed altogether: |
| 51 | +// a rust-caller,non-rust-callee callback where the fnptr |
| 52 | +// is given as an argument to a rust-callee,non-rust-caller |
| 53 | +// FFI boundary) |
| 54 | +#[allow(improper_c_callbacks)] |
| 55 | +type AllowedUnsafeFnPtr = extern "C" fn(&[i32])->i32; |
| 56 | + |
| 57 | +type UnsafeRustCalleeFnPtr = extern "C" fn(i32)->&'static i32; |
| 58 | + |
| 59 | +#[allow(improper_c_callbacks)] |
| 60 | +type AllowedUnsafeRustCalleeFnPtr = extern "C" fn(i32)->&'static i32; |
| 61 | + |
| 62 | +type UnsafeForeignCalleeFnPtr = extern "C" fn(&i32); |
| 63 | + |
| 64 | +#[allow(improper_c_callbacks)] |
| 65 | +type AllowedUnsafeForeignCalleeFnPtr = extern "C" fn(&i32); |
| 66 | + |
| 67 | + |
| 68 | +// //////////////////////////////////////////////////////// |
| 69 | +// then, some functions that use them |
| 70 | + |
| 71 | +static INT: u32 = 42; |
| 72 | + |
| 73 | +#[allow(improper_c_fn_definitions)] |
| 74 | +extern "C" fn fn1a(e: &String) -> &str {&*e} |
| 75 | +extern "C" fn fn1u(e: &String) -> &str {&*e} |
| 76 | +//~^ ERROR: `extern` fn uses type `&str` |
| 77 | +// | FIXME: not warning about the &String feels wrong, but it's behind a FFI-safe reference so... |
| 78 | + |
| 79 | +#[allow(improper_c_fn_definitions)] |
| 80 | +extern "C" fn fn2a(e: UnsafeStruct) {} |
| 81 | +extern "C" fn fn2u(e: UnsafeStruct) {} |
| 82 | +//~^ ERROR: `extern` fn uses type `UnsafeStruct` |
| 83 | +#[allow(improper_c_fn_definitions)] |
| 84 | +extern "C" fn fn2oa(e: ext_crate::UnsafeStruct) {} |
| 85 | +extern "C" fn fn2ou(e: ext_crate::UnsafeStruct) {} |
| 86 | +//~^ ERROR: `extern` fn uses type `ext_crate::UnsafeStruct` |
| 87 | + |
| 88 | +#[allow(improper_c_fn_definitions)] |
| 89 | +extern "C" fn fn3a(e: AllowedUnsafeStruct) {} |
| 90 | +extern "C" fn fn3u(e: AllowedUnsafeStruct) {} |
| 91 | +//~^ ERROR: `extern` fn uses type `AllowedUnsafeStruct` |
| 92 | +// ^^ FIXME: ...ideally the lint should not trigger here |
| 93 | +#[allow(improper_c_fn_definitions)] |
| 94 | +extern "C" fn fn3oa(e: ext_crate::AllowedUnsafeStruct) {} |
| 95 | +extern "C" fn fn3ou(e: ext_crate::AllowedUnsafeStruct) {} |
| 96 | +//~^ ERROR: `extern` fn uses type `ext_crate::AllowedUnsafeStruct` |
| 97 | +// ^^ FIXME: ...ideally the lint should not trigger here |
| 98 | + |
| 99 | +#[allow(improper_c_fn_definitions)] |
| 100 | +extern "C" fn fn4a(e: UnsafeFromForeignStruct) {} |
| 101 | +extern "C" fn fn4u(e: UnsafeFromForeignStruct) {} |
| 102 | +#[allow(improper_c_fn_definitions)] |
| 103 | +extern "C" fn fn4oa(e: ext_crate::UnsafeFromForeignStruct) {} |
| 104 | +extern "C" fn fn4ou(e: ext_crate::UnsafeFromForeignStruct) {} |
| 105 | +// the block above might become unsafe if/once we lint on the value assumptions of types |
| 106 | + |
| 107 | +#[allow(improper_c_fn_definitions)] |
| 108 | +extern "C" fn fn5a() -> UnsafeFromForeignStruct<'static> { UnsafeFromForeignStruct(&INT)} |
| 109 | +extern "C" fn fn5u() -> UnsafeFromForeignStruct<'static> { UnsafeFromForeignStruct(&INT)} |
| 110 | +#[allow(improper_c_fn_definitions)] |
| 111 | +extern "C" fn fn5oa() -> ext_crate::UnsafeFromForeignStruct<'static> { |
| 112 | + ext_crate::UnsafeFromForeignStruct(&INT) |
| 113 | +} |
| 114 | +extern "C" fn fn5ou() -> ext_crate::UnsafeFromForeignStruct<'static> { |
| 115 | + ext_crate::UnsafeFromForeignStruct(&INT) |
| 116 | +} |
| 117 | + |
| 118 | +#[allow(improper_c_fn_definitions)] |
| 119 | +extern "C" fn fn6a() -> AllowedUnsafeFromForeignStruct<'static> { |
| 120 | + AllowedUnsafeFromForeignStruct(&INT) |
| 121 | +} |
| 122 | +extern "C" fn fn6u() -> AllowedUnsafeFromForeignStruct<'static> { |
| 123 | + AllowedUnsafeFromForeignStruct(&INT) |
| 124 | +} |
| 125 | +#[allow(improper_c_fn_definitions)] |
| 126 | +extern "C" fn fn6oa() -> ext_crate::AllowedUnsafeFromForeignStruct<'static> { |
| 127 | + ext_crate::AllowedUnsafeFromForeignStruct(&INT) |
| 128 | +} |
| 129 | +extern "C" fn fn6ou() -> ext_crate::AllowedUnsafeFromForeignStruct<'static> { |
| 130 | + ext_crate::AllowedUnsafeFromForeignStruct(&INT) |
| 131 | +} |
| 132 | + |
| 133 | +// //////////////////////////////////////////////////////// |
| 134 | +// special cases: struct-in-fnptr and fnptr-in-struct |
| 135 | + |
| 136 | +#[repr(C)] |
| 137 | +struct FakeVTable<A>{ |
| 138 | + make_new: extern "C" fn() -> A, |
| 139 | + combine: extern "C" fn(&[A]) -> A, |
| 140 | + //~^ ERROR: `extern` callback uses type `&[A]` |
| 141 | + drop: extern "C" fn(A), |
| 142 | + something_else: (A, usize), |
| 143 | +} |
| 144 | + |
| 145 | +type FakeVTableMaker = extern "C" fn() -> FakeVTable<u32>; |
| 146 | +//~^ ERROR: `extern` callback uses type `FakeVTable<u32>` |
| 147 | + |
| 148 | +#[repr(C)] |
| 149 | +#[allow(improper_c_callbacks)] |
| 150 | +struct FakeVTableAllowed<A>{ |
| 151 | + make_new: extern "C" fn() -> A, |
| 152 | + combine: extern "C" fn(&[A]) -> A, |
| 153 | + drop: extern "C" fn(A), |
| 154 | + something_else: (A, usize), |
| 155 | +} |
| 156 | + |
| 157 | +#[allow(improper_c_callbacks)] |
| 158 | +type FakeVTableMakerAllowed = extern "C" fn() -> FakeVTable<u32>; |
| 159 | + |
| 160 | +fn main(){} |
0 commit comments