Skip to content

Commit 2022d74

Browse files
committed
Don't derive Copy in FFI structs/unions that contain pointers
Clone is still derived to as explicitly cloning the structs is less of a problem, but implicitly copying them can easily cause double frees. Fixes #1048
1 parent cbdc2e4 commit 2022d74

File tree

2 files changed

+139
-3
lines changed

2 files changed

+139
-3
lines changed

src/analysis/types.rs

Lines changed: 130 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,10 +233,137 @@ pub trait DerivesCopy {
233233
fn derives_copy(&self, lib: &Library) -> bool;
234234
}
235235

236-
impl<T: IsIncomplete> DerivesCopy for T {
236+
impl DerivesCopy for Fundamental {
237237
fn derives_copy(&self, lib: &Library) -> bool {
238-
// Copy is derived for all complete types.
239-
!self.is_incomplete(lib)
238+
if self.is_incomplete(lib) {
239+
return false;
240+
}
241+
242+
// None of the pointer types
243+
!matches!(
244+
self,
245+
Fundamental::Pointer
246+
| Fundamental::VarArgs
247+
| Fundamental::Utf8
248+
| Fundamental::Filename
249+
| Fundamental::IntPtr
250+
| Fundamental::UIntPtr
251+
| Fundamental::OsString
252+
| Fundamental::Unsupported
253+
)
254+
}
255+
}
256+
257+
impl DerivesCopy for Alias {
258+
fn derives_copy(&self, lib: &Library) -> bool {
259+
if self.is_incomplete(lib) {
260+
return false;
261+
}
262+
263+
!self.is_ptr()
264+
}
265+
}
266+
267+
impl DerivesCopy for Field {
268+
fn derives_copy(&self, lib: &Library) -> bool {
269+
if self.is_incomplete(lib) {
270+
return false;
271+
}
272+
273+
!self.is_ptr()
274+
}
275+
}
276+
277+
impl<'a> DerivesCopy for &'a [Field] {
278+
fn derives_copy(&self, lib: &Library) -> bool {
279+
if self.is_incomplete(lib) {
280+
return false;
281+
}
282+
283+
for field in self.iter() {
284+
if field.is_ptr() {
285+
return false;
286+
}
287+
}
288+
289+
true
290+
}
291+
}
292+
293+
impl DerivesCopy for Class {
294+
fn derives_copy(&self, lib: &Library) -> bool {
295+
if self.is_incomplete(lib) {
296+
return false;
297+
}
298+
299+
self.fields.as_slice().derives_copy(lib)
300+
}
301+
}
302+
303+
impl DerivesCopy for Record {
304+
#[allow(clippy::if_same_then_else)]
305+
fn derives_copy(&self, lib: &Library) -> bool {
306+
if self.is_incomplete(lib) {
307+
return false;
308+
}
309+
310+
self.fields.as_slice().derives_copy(lib)
311+
}
312+
}
313+
314+
impl DerivesCopy for Union {
315+
fn derives_copy(&self, lib: &Library) -> bool {
316+
if self.is_incomplete(lib) {
317+
return false;
318+
}
319+
320+
self.fields.as_slice().derives_copy(lib)
321+
}
322+
}
323+
324+
impl DerivesCopy for Function {
325+
fn derives_copy(&self, lib: &Library) -> bool {
326+
if self.is_incomplete(lib) {
327+
return false;
328+
}
329+
330+
true
331+
}
332+
}
333+
334+
impl DerivesCopy for TypeId {
335+
fn derives_copy(&self, lib: &Library) -> bool {
336+
if self.is_incomplete(lib) {
337+
return false;
338+
}
339+
340+
lib.type_(*self).derives_copy(lib)
341+
}
342+
}
343+
344+
impl DerivesCopy for Type {
345+
fn derives_copy(&self, lib: &Library) -> bool {
346+
if self.is_incomplete(lib) {
347+
return false;
348+
}
349+
350+
match *self {
351+
Type::Fundamental(ref fundamental) => fundamental.derives_copy(lib),
352+
Type::Alias(ref alias) => alias.derives_copy(lib),
353+
Type::FixedArray(tid, ..) => tid.derives_copy(lib),
354+
Type::Class(ref klass) => klass.derives_copy(lib),
355+
Type::Record(ref record) => record.derives_copy(lib),
356+
Type::Union(ref union) => union.derives_copy(lib),
357+
Type::Function(ref function) => function.derives_copy(lib),
358+
Type::Enumeration(..) | Type::Bitfield(..) | Type::Interface(..) => true,
359+
Type::Custom(..)
360+
| Type::Array(..)
361+
| Type::CArray(..)
362+
| Type::PtrArray(..)
363+
| Type::HashTable(..)
364+
| Type::List(..)
365+
| Type::SList(..) => false,
366+
}
240367
}
241368
}
242369

src/codegen/sys/fields.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub struct Fields {
1313
pub external: bool,
1414
/// Reason for truncating the representation, if any.
1515
pub truncated: Option<String>,
16+
derives_clone: bool,
1617
derives_copy: bool,
1718
/// "struct" or "union"
1819
pub kind: &'static str,
@@ -38,6 +39,8 @@ impl Fields {
3839
let mut traits = Vec::new();
3940
if self.derives_copy {
4041
traits.push("Copy");
42+
}
43+
if self.derives_clone {
4144
traits.push("Clone");
4245
}
4346
traits
@@ -58,11 +61,13 @@ impl FieldInfo {
5861
pub fn from_record(env: &Env, record: &Record) -> Fields {
5962
let (fields, truncated) = analyze_fields(env, false, &record.fields);
6063
let derives_copy = truncated.is_none() && record.derives_copy(&env.library);
64+
let derives_clone = truncated.is_none() && !record.is_incomplete(&env.library);
6165
Fields {
6266
name: record.c_type.clone(),
6367
external: record.is_external(&env.library),
6468
truncated,
6569
derives_copy,
70+
derives_clone,
6671
kind: "struct",
6772
cfg_condition: get_gobject_cfg_condition(env, &record.name),
6873
fields,
@@ -72,11 +77,13 @@ pub fn from_record(env: &Env, record: &Record) -> Fields {
7277
pub fn from_class(env: &Env, klass: &Class) -> Fields {
7378
let (fields, truncated) = analyze_fields(env, false, &klass.fields);
7479
let derives_copy = truncated.is_none() && klass.derives_copy(&env.library);
80+
let derives_clone = truncated.is_none() && !klass.is_incomplete(&env.library);
7581
Fields {
7682
name: klass.c_type.clone(),
7783
external: klass.is_external(&env.library),
7884
truncated,
7985
derives_copy,
86+
derives_clone,
8087
kind: "struct",
8188
cfg_condition: get_gobject_cfg_condition(env, &klass.name),
8289
fields,
@@ -86,11 +93,13 @@ pub fn from_class(env: &Env, klass: &Class) -> Fields {
8693
pub fn from_union(env: &Env, union: &Union) -> Fields {
8794
let (fields, truncated) = analyze_fields(env, true, &union.fields);
8895
let derives_copy = truncated.is_none() && union.derives_copy(&env.library);
96+
let derives_clone = truncated.is_none() && !union.is_incomplete(&env.library);
8997
Fields {
9098
name: union.c_type.as_ref().unwrap().clone(),
9199
external: union.is_external(&env.library),
92100
truncated,
93101
derives_copy,
102+
derives_clone,
94103
kind: "union",
95104
cfg_condition: None,
96105
fields,

0 commit comments

Comments
 (0)