Skip to content

Commit e59daae

Browse files
mbyxtgross35
authored andcommitted
ctest: check incompatible pointer types for public fields.
1 parent 320e0ee commit e59daae

11 files changed

Lines changed: 154 additions & 1 deletion

ctest/src/generator.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ pub enum GenerationError {
124124
OsError(std::io::Error),
125125
#[error("one of {0} environment variable(s) not set")]
126126
EnvVarNotFound(String),
127+
#[error("unable to compile C tests {0}")]
128+
CompileError(cc::Error),
127129
}
128130

129131
impl TestGenerator {

ctest/src/runner.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ pub fn generate_test(
9292

9393
let stem: &str = output_file_path.file_stem().unwrap().to_str().unwrap();
9494
cfg.out_dir(output_file_path.parent().unwrap())
95-
.compile(stem);
95+
.try_compile(stem)
96+
.map_err(GenerationError::CompileError)?;
9697

9798
Ok(output_file_path)
9899
}

ctest/templates/test.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,14 @@ CTEST_EXTERN uint64_t ctest_size_of__{{ item.id }}__{{ item.field.ident() }}(voi
104104
typedef {{ item.volatile_keyword }}{{ item.field_return_type }};
105105
CTEST_EXTERN ctest_field_ty__{{ item.id }}__{{ item.field.ident() }}
106106
ctest_field_ptr__{{ item.id }}__{{ item.field.ident() }}({{ item.c_ty }} *b) {
107+
{#
108+
// In order to trigger -Wincompatible-pointer-types, we need to attempt to create a
109+
// pointer to the given struct or field type, but using the type translated from Rust.
110+
#}
111+
ctest_field_ty__{{ item.id }}__{{ item.field.ident() }} ptr;
112+
ptr = &b->{{ item.c_field }};
113+
(void)ptr; {# avoid unused warnings #}
114+
107115
return &b->{{ item.c_field }};
108116
}
109117
{%- endfor +%}

ctest/tests/basic.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,3 +210,35 @@ fn test_raw_identifier_field() {
210210
assert!(result.is_ok());
211211
}
212212
}
213+
214+
#[test]
215+
fn test_mismatched_union_field_ty() {
216+
let include_path = PathBuf::from("tests/input");
217+
let crate_path = include_path.join("mismatched_union_field_ty.rs");
218+
let library_path = "mismatched_union_field_ty.out.a";
219+
220+
let (mut gen_, _out_dir) = default_generator(1, Some("mismatched_union_field_ty.h")).unwrap();
221+
222+
if env::var("TARGET_PLATFORM") == env::var("HOST_PLATFORM") {
223+
let result = generate_test(&mut gen_, &crate_path, library_path);
224+
assert!(result.is_err());
225+
// As cc prints its warning/error messages to stderr, we cannot access them from cc::Error,
226+
// and so cannot assert that the error was actually due to -Wincompatible-pointer-types.
227+
}
228+
}
229+
230+
#[test]
231+
fn test_mismatched_struct_field_ty() {
232+
let include_path = PathBuf::from("tests/input");
233+
let crate_path = include_path.join("mismatched_struct_field_ty.rs");
234+
let library_path = "mismatched_struct_field_ty.out.a";
235+
236+
let (mut gen_, _out_dir) = default_generator(1, Some("mismatched_struct_field_ty.h")).unwrap();
237+
238+
if env::var("TARGET_PLATFORM") == env::var("HOST_PLATFORM") {
239+
let result = generate_test(&mut gen_, &crate_path, library_path);
240+
assert!(result.is_err());
241+
// FIXME(ctest): As cc prints its warning/error messages to stderr, we cannot access them from cc::Error,
242+
// and so cannot assert that the error was actually due to -Wincompatible-pointer-types.
243+
}
244+
}

ctest/tests/input/macro.out.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,27 +90,47 @@ CTEST_EXTERN uint64_t ctest_size_of__VecU16__y(void) {
9090
typedef uint8_t *ctest_field_ty__VecU8__x;
9191
CTEST_EXTERN ctest_field_ty__VecU8__x
9292
ctest_field_ptr__VecU8__x(struct VecU8 *b) {
93+
94+
ctest_field_ty__VecU8__x ptr;
95+
ptr = &b->x;
96+
(void)ptr;
97+
9398
return &b->x;
9499
}
95100

96101

97102
typedef uint8_t *ctest_field_ty__VecU8__y;
98103
CTEST_EXTERN ctest_field_ty__VecU8__y
99104
ctest_field_ptr__VecU8__y(struct VecU8 *b) {
105+
106+
ctest_field_ty__VecU8__y ptr;
107+
ptr = &b->y;
108+
(void)ptr;
109+
100110
return &b->y;
101111
}
102112

103113

104114
typedef uint16_t *ctest_field_ty__VecU16__x;
105115
CTEST_EXTERN ctest_field_ty__VecU16__x
106116
ctest_field_ptr__VecU16__x(struct VecU16 *b) {
117+
118+
ctest_field_ty__VecU16__x ptr;
119+
ptr = &b->x;
120+
(void)ptr;
121+
107122
return &b->x;
108123
}
109124

110125

111126
typedef uint16_t *ctest_field_ty__VecU16__y;
112127
CTEST_EXTERN ctest_field_ty__VecU16__y
113128
ctest_field_ptr__VecU16__y(struct VecU16 *b) {
129+
130+
ctest_field_ty__VecU16__y ptr;
131+
ptr = &b->y;
132+
(void)ptr;
133+
114134
return &b->y;
115135
}
116136

ctest/tests/input/macro.out.edition-2024.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,27 +90,47 @@ CTEST_EXTERN uint64_t ctest_size_of__VecU16__y(void) {
9090
typedef uint8_t *ctest_field_ty__VecU8__x;
9191
CTEST_EXTERN ctest_field_ty__VecU8__x
9292
ctest_field_ptr__VecU8__x(struct VecU8 *b) {
93+
94+
ctest_field_ty__VecU8__x ptr;
95+
ptr = &b->x;
96+
(void)ptr;
97+
9398
return &b->x;
9499
}
95100

96101

97102
typedef uint8_t *ctest_field_ty__VecU8__y;
98103
CTEST_EXTERN ctest_field_ty__VecU8__y
99104
ctest_field_ptr__VecU8__y(struct VecU8 *b) {
105+
106+
ctest_field_ty__VecU8__y ptr;
107+
ptr = &b->y;
108+
(void)ptr;
109+
100110
return &b->y;
101111
}
102112

103113

104114
typedef uint16_t *ctest_field_ty__VecU16__x;
105115
CTEST_EXTERN ctest_field_ty__VecU16__x
106116
ctest_field_ptr__VecU16__x(struct VecU16 *b) {
117+
118+
ctest_field_ty__VecU16__x ptr;
119+
ptr = &b->x;
120+
(void)ptr;
121+
107122
return &b->x;
108123
}
109124

110125

111126
typedef uint16_t *ctest_field_ty__VecU16__y;
112127
CTEST_EXTERN ctest_field_ty__VecU16__y
113128
ctest_field_ptr__VecU16__y(struct VecU16 *b) {
129+
130+
ctest_field_ty__VecU16__y ptr;
131+
ptr = &b->y;
132+
(void)ptr;
133+
114134
return &b->y;
115135
}
116136

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#include <stdint.h>
2+
3+
// The struct and union must match the size and alignment of the Rust side,
4+
// otherwise different warnings are emitted that hide -Wincompatible-pointer-types.
5+
struct Bar {
6+
int16_t x;
7+
int16_t y;
8+
};
9+
10+
union Baz {
11+
int32_t x;
12+
float y;
13+
};
14+
15+
struct Foo {
16+
struct Bar a;
17+
union Baz b;
18+
};
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#[repr(C)]
2+
pub struct Foo {
3+
// We use a 4 byte type with 4 byte alignment.
4+
pub a: i32,
5+
pub b: i32,
6+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#include <stdint.h>
2+
3+
// The union must match the size and alignment of the Rust side,
4+
// otherwise different warnings are emitted that hide -Wincompatible-pointer-types.
5+
union Bar {
6+
int64_t x;
7+
int32_t y;
8+
};
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use core::ffi::c_float;
2+
3+
// Union size is 8 bytes.
4+
#[repr(C)]
5+
union Bar {
6+
pub x: i64,
7+
pub y: c_float,
8+
}

0 commit comments

Comments
 (0)