Skip to content

Commit 64ed5be

Browse files
d-e-s-odanielocfb
authored andcommitted
Implement Default for struct containing pointers
Rust does not implement Default for pointers, no matter if the pointee implements the trait. As such, a bunch of our generated code does not compile. Specifically, bindings for struct types with a Default auto-derive and which contain pointers do not compile. Adjust the generation logic to emit a Default impl when a struct contains a pointer. Signed-off-by: Daniel Müller <[email protected]>
1 parent 4b767a1 commit 64ed5be

File tree

3 files changed

+175
-7
lines changed

3 files changed

+175
-7
lines changed

libbpf-cargo/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
Unreleased
22
----------
3+
- Added `Default` impl for generated `struct` types containing pointers
34
- Improved error reporting in build script usage
45
- Bumped minimum Rust version to `1.64`
56

libbpf-cargo/src/gen/btf.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,15 @@ impl<'s> GenBtf<'s> {
357357
gen_impl_default = true
358358
}
359359
}
360+
361+
// Rust does not implement `Default` for pointers, no matter if
362+
// the pointee implements it.
363+
if self
364+
.type_by_id::<types::Ptr<'_>>(field_ty.type_id())
365+
.is_some()
366+
{
367+
gen_impl_default = true
368+
}
360369
}
361370

362371
match self.type_default(field_ty) {

libbpf-cargo/src/test.rs

Lines changed: 165 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -950,6 +950,91 @@ fn test_skeleton_builder_arrays_ptrs() {
950950
assert!(status.success());
951951
}
952952

953+
#[test]
954+
fn test_skeleton_generate_struct_with_pointer() {
955+
let (_dir, proj_dir, cargo_toml) = setup_temp_project();
956+
957+
// Add prog dir
958+
create_dir(proj_dir.join("src/bpf")).expect("failed to create prog dir");
959+
960+
// Add a prog
961+
let mut prog = OpenOptions::new()
962+
.write(true)
963+
.create(true)
964+
.open(proj_dir.join("src/bpf/prog.bpf.c"))
965+
.expect("failed to open prog.bpf.c");
966+
967+
write!(
968+
prog,
969+
r#"
970+
#include "vmlinux.h"
971+
#include <bpf/bpf_helpers.h>
972+
973+
struct list {{
974+
struct list *next;
975+
}};
976+
977+
struct list l;
978+
"#,
979+
)
980+
.expect("failed to write prog.bpf.c");
981+
982+
// Lay down the necessary header files
983+
add_vmlinux_header(&proj_dir);
984+
985+
make(true, Some(&cargo_toml), None, true, true, Vec::new(), None).unwrap();
986+
987+
let mut cargo = OpenOptions::new()
988+
.append(true)
989+
.open(&cargo_toml)
990+
.expect("failed to open Cargo.toml");
991+
992+
// Make test project use our development libbpf-rs version
993+
writeln!(
994+
cargo,
995+
r#"
996+
libbpf-rs = {{ path = "{}" }}
997+
"#,
998+
get_libbpf_rs_path().as_path().display()
999+
)
1000+
.expect("failed to write to Cargo.toml");
1001+
1002+
let mut source = OpenOptions::new()
1003+
.write(true)
1004+
.truncate(true)
1005+
.open(proj_dir.join("src/main.rs"))
1006+
.expect("failed to open main.rs");
1007+
1008+
write!(
1009+
source,
1010+
r#"
1011+
#![warn(elided_lifetimes_in_paths)]
1012+
mod bpf;
1013+
use bpf::*;
1014+
use libbpf_rs::skel::SkelBuilder;
1015+
1016+
fn main() {{
1017+
let builder = ProgSkelBuilder::default();
1018+
let _open_skel = builder
1019+
.open()
1020+
.expect("failed to open skel");
1021+
}}
1022+
"#,
1023+
)
1024+
.expect("failed to write to main.rs");
1025+
1026+
let status = Command::new("cargo")
1027+
.arg("build")
1028+
.arg("--quiet")
1029+
.arg("--manifest-path")
1030+
.arg(cargo_toml.into_os_string())
1031+
.env("RUSTFLAGS", "-Dwarnings")
1032+
.status()
1033+
.expect("failed to spawn cargo-build");
1034+
1035+
assert!(status.success());
1036+
}
1037+
9531038
/// Check that skeleton creation is deterministic, i.e., that no temporary paths
9541039
/// change the output between invocations.
9551040
#[test]
@@ -1158,13 +1243,22 @@ struct Foo foo = {{0}};
11581243
"#;
11591244

11601245
let expected_output = r#"
1161-
#[derive(Debug, Default, Copy, Clone)]
1246+
#[derive(Debug, Copy, Clone)]
11621247
#[repr(C)]
11631248
pub struct Foo {
11641249
pub x: i32,
11651250
pub y: [i8; 10],
11661251
pub z: *mut std::ffi::c_void,
11671252
}
1253+
impl Default for Foo {
1254+
fn default() -> Self {
1255+
Foo {
1256+
x: i32::default(),
1257+
y: [i8::default(); 10],
1258+
z: std::ptr::null_mut(),
1259+
}
1260+
}
1261+
}
11681262
"#;
11691263

11701264
let mmap = build_btf_mmap(prog_text);
@@ -1301,7 +1395,7 @@ struct Foo foo;
13011395
// Note how there's 6 bytes of padding. It's not necessary on 64 bit archs but
13021396
// we've assumed 32 bit arch during padding generation.
13031397
let expected_output = r#"
1304-
#[derive(Debug, Default, Copy, Clone)]
1398+
#[derive(Debug, Copy, Clone)]
13051399
#[repr(C)]
13061400
pub struct Foo {
13071401
pub ip: *mut i32,
@@ -1313,6 +1407,20 @@ pub struct Foo {
13131407
pub cv: i64,
13141408
pub r: *mut i8,
13151409
}
1410+
impl Default for Foo {
1411+
fn default() -> Self {
1412+
Foo {
1413+
ip: std::ptr::null_mut(),
1414+
ipp: std::ptr::null_mut(),
1415+
bar: Bar::default(),
1416+
__pad_18: [u8::default(); 6],
1417+
pb: std::ptr::null_mut(),
1418+
v: u64::default(),
1419+
cv: i64::default(),
1420+
r: std::ptr::null_mut(),
1421+
}
1422+
}
1423+
}
13161424
#[derive(Debug, Default, Copy, Clone)]
13171425
#[repr(C)]
13181426
pub struct Bar {
@@ -1356,7 +1464,7 @@ struct Foo foo;
13561464
// Note how there's 6 bytes of padding. It's not necessary on 64 bit archs but
13571465
// we've assumed 32 bit arch during padding generation.
13581466
let expected_output = r#"
1359-
#[derive(Debug, Default, Copy, Clone)]
1467+
#[derive(Debug, Copy, Clone)]
13601468
#[repr(C)]
13611469
pub struct Foo {
13621470
pub ip: *mut i32,
@@ -1368,6 +1476,20 @@ pub struct Foo {
13681476
pub cv: i64,
13691477
pub r: *mut i8,
13701478
}
1479+
impl Default for Foo {
1480+
fn default() -> Self {
1481+
Foo {
1482+
ip: std::ptr::null_mut(),
1483+
ipp: std::ptr::null_mut(),
1484+
bar: Bar::default(),
1485+
__pad_84: [u8::default(); 4],
1486+
pb: std::ptr::null_mut(),
1487+
v: u64::default(),
1488+
cv: i64::default(),
1489+
r: std::ptr::null_mut(),
1490+
}
1491+
}
1492+
}
13711493
#[derive(Debug, Copy, Clone)]
13721494
#[repr(C)]
13731495
pub struct Bar {
@@ -1637,13 +1759,22 @@ const int myconstglobal = 0;
16371759
pub struct bss {
16381760
pub foo: Foo,
16391761
}
1640-
#[derive(Debug, Default, Copy, Clone)]
1762+
#[derive(Debug, Copy, Clone)]
16411763
#[repr(C)]
16421764
pub struct Foo {
16431765
pub x: i32,
16441766
pub y: [i8; 10],
16451767
pub z: *mut std::ffi::c_void,
16461768
}
1769+
impl Default for Foo {
1770+
fn default() -> Self {
1771+
Foo {
1772+
x: i32::default(),
1773+
y: [i8::default(); 10],
1774+
z: std::ptr::null_mut(),
1775+
}
1776+
}
1777+
}
16471778
"#;
16481779

16491780
let rodata_output = r#"
@@ -1754,13 +1885,22 @@ pub struct bss {
17541885
pub foo2: Foo,
17551886
pub foo3: Foo,
17561887
}
1757-
#[derive(Debug, Default, Copy, Clone)]
1888+
#[derive(Debug, Copy, Clone)]
17581889
#[repr(C)]
17591890
pub struct Foo {
17601891
pub x: i32,
17611892
pub y: [i8; 10],
17621893
pub z: *mut std::ffi::c_void,
17631894
}
1895+
impl Default for Foo {
1896+
fn default() -> Self {
1897+
Foo {
1898+
x: i32::default(),
1899+
y: [i8::default(); 10],
1900+
z: std::ptr::null_mut(),
1901+
}
1902+
}
1903+
}
17641904
"#;
17651905

17661906
let rodata_output = r#"
@@ -1970,13 +2110,22 @@ pub struct __anon_1 {
19702110
pub y: [u8; 10],
19712111
pub z: [u16; 16],
19722112
}
1973-
#[derive(Debug, Default, Copy, Clone)]
2113+
#[derive(Debug, Copy, Clone)]
19742114
#[repr(C)]
19752115
pub struct __anon_2 {
19762116
pub w: u32,
19772117
pub __pad_4: [u8; 4],
19782118
pub u: *mut u64,
19792119
}
2120+
impl Default for __anon_2 {
2121+
fn default() -> Self {
2122+
__anon_2 {
2123+
w: u32::default(),
2124+
__pad_4: [u8::default(); 4],
2125+
u: std::ptr::null_mut(),
2126+
}
2127+
}
2128+
}
19802129
"#;
19812130

19822131
let mmap = build_btf_mmap(prog_text);
@@ -2054,13 +2203,22 @@ impl Default for __anon_2 {
20542203
}
20552204
}
20562205
}
2057-
#[derive(Debug, Default, Copy, Clone)]
2206+
#[derive(Debug, Copy, Clone)]
20582207
#[repr(C)]
20592208
pub struct __anon_3 {
20602209
pub w: u32,
20612210
pub __pad_4: [u8; 4],
20622211
pub u: *mut u64,
20632212
}
2213+
impl Default for __anon_3 {
2214+
fn default() -> Self {
2215+
__anon_3 {
2216+
w: u32::default(),
2217+
__pad_4: [u8::default(); 4],
2218+
u: std::ptr::null_mut(),
2219+
}
2220+
}
2221+
}
20642222
#[derive(Copy, Clone)]
20652223
#[repr(C)]
20662224
pub union __anon_4 {

0 commit comments

Comments
 (0)