From dafc665db39445e85d8c6fda10e342874b00dc53 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Mon, 3 Jul 2023 12:31:44 -0700 Subject: [PATCH 01/10] (`c2rust-analyze`) Add `PermissionSet::union_all` as a `const fn` for use in known (`libc`) `fn` permission annotations. --- c2rust-analyze/src/context.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/c2rust-analyze/src/context.rs b/c2rust-analyze/src/context.rs index 75fd00758..0c53c505c 100644 --- a/c2rust-analyze/src/context.rs +++ b/c2rust-analyze/src/context.rs @@ -134,6 +134,17 @@ impl PermissionSet { // // `.union` is used here since it's a `const fn`, unlike `BitOr::bitor`. pub const STRING_LITERAL: Self = Self::READ.union(Self::OFFSET_ADD); + + #[allow(unused)] + pub const fn union_all(a: [Self; N]) -> Self { + let mut this = Self::empty(); + let mut i = 0; + while i < N { + this = this.union(a[i]); + i += 1; + } + this + } } bitflags! { From e347d281ad7e45404455fcb30301340f0e629be3 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Mon, 3 Jul 2023 12:38:45 -0700 Subject: [PATCH 02/10] (`c2rust-analyze`) Add `perms_annotation!` for `PermissionSet` annotations on known (`libc`) `fn`s' ptrs. --- c2rust-analyze/src/context.rs | 2 +- c2rust-analyze/src/known_fn.rs | 33 +++++++++++++++++++++++++++++++++ c2rust-analyze/src/main.rs | 1 + 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 c2rust-analyze/src/known_fn.rs diff --git a/c2rust-analyze/src/context.rs b/c2rust-analyze/src/context.rs index 0c53c505c..f84af9c21 100644 --- a/c2rust-analyze/src/context.rs +++ b/c2rust-analyze/src/context.rs @@ -135,7 +135,7 @@ impl PermissionSet { // `.union` is used here since it's a `const fn`, unlike `BitOr::bitor`. pub const STRING_LITERAL: Self = Self::READ.union(Self::OFFSET_ADD); - #[allow(unused)] + #[cfg(test)] pub const fn union_all(a: [Self; N]) -> Self { let mut this = Self::empty(); let mut i = 0; diff --git a/c2rust-analyze/src/known_fn.rs b/c2rust-analyze/src/known_fn.rs new file mode 100644 index 000000000..a664ffc69 --- /dev/null +++ b/c2rust-analyze/src/known_fn.rs @@ -0,0 +1,33 @@ +#[cfg(test)] +use crate::context::PermissionSet; + +#[cfg(test)] +macro_rules! perms_annotation { + ([$($($perm:ident)|*),*]) => {{ + [$(PermissionSet::union_all([$(PermissionSet::$perm,)*]),)*] + }}; +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn one_perms_annotation() { + assert_eq!( + perms_annotation!([WRITE | OFFSET_ADD]), + [PermissionSet::WRITE | PermissionSet::OFFSET_ADD] + ); + } + + #[test] + fn two_perms_annotations() { + assert_eq!( + perms_annotation!([WRITE, WRITE | OFFSET_ADD]), + [ + PermissionSet::WRITE, + PermissionSet::WRITE | PermissionSet::OFFSET_ADD + ] + ); + } +} diff --git a/c2rust-analyze/src/main.rs b/c2rust-analyze/src/main.rs index 3f305323f..34b1c12d6 100644 --- a/c2rust-analyze/src/main.rs +++ b/c2rust-analyze/src/main.rs @@ -50,6 +50,7 @@ mod c_void_casts; mod context; mod dataflow; mod equiv; +mod known_fn; mod labeled_ty; mod log; mod panic_detail; From 8290ec5d9cc3fff647e1ae8704984dbb6c146e6f Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Mon, 3 Jul 2023 12:45:21 -0700 Subject: [PATCH 03/10] (`c2rust-analyze`) Add `const_slice!` to make `'static` slices at `const`-time so we don't need to `Box` `const`-known data. --- c2rust-analyze/src/known_fn.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/c2rust-analyze/src/known_fn.rs b/c2rust-analyze/src/known_fn.rs index a664ffc69..d0d5b8b05 100644 --- a/c2rust-analyze/src/known_fn.rs +++ b/c2rust-analyze/src/known_fn.rs @@ -1,6 +1,17 @@ #[cfg(test)] use crate::context::PermissionSet; +#[allow(unused)] +macro_rules! const_slice { + ($ty:ty, []) => {{ + &[] + }}; + ($ty:ty, $array:expr) => {{ + const ARRAY: [$ty; $array.len()] = $array; + &ARRAY + }}; +} + #[cfg(test)] macro_rules! perms_annotation { ([$($($perm:ident)|*),*]) => {{ From 2bd8fca14feaeb9747258783492f0f2bc0fc9a08 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Mon, 3 Jul 2023 12:46:26 -0700 Subject: [PATCH 04/10] (`c2rust-analyze`) Add `struct KnownFnTy` and `known_fn_ty!` to represent an permission-annotated type on a known `fn`. --- c2rust-analyze/src/known_fn.rs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/c2rust-analyze/src/known_fn.rs b/c2rust-analyze/src/known_fn.rs index d0d5b8b05..5034a4f62 100644 --- a/c2rust-analyze/src/known_fn.rs +++ b/c2rust-analyze/src/known_fn.rs @@ -1,4 +1,3 @@ -#[cfg(test)] use crate::context::PermissionSet; #[allow(unused)] @@ -19,6 +18,31 @@ macro_rules! perms_annotation { }}; } +#[derive(Debug, PartialEq, Eq)] +pub struct KnownFnTy { + name: &'static str, + ty: &'static str, + perms: &'static [PermissionSet], +} + +#[allow(unused)] +macro_rules! known_fn_ty { + ($ty:ty: $perms:tt) => {{ + KnownFnTy { + name: "", + ty: stringify!($ty), + perms: const_slice!(PermissionSet, perms_annotation!($perms)), + } + }}; + ($ty:ty) => {{ + KnownFnTy { + name: "", + ty: stringify!($ty), + perms: &[], + } + }}; +} + #[cfg(test)] mod tests { use super::*; From 31734f028106753099eca435c28522d57624922e Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Wed, 5 Jul 2023 15:33:27 -0700 Subject: [PATCH 05/10] (`c2rust-analyze`) Add `const fn KnownFnTy::checked` checking that the number of perms match the number of ptrs in a type. --- c2rust-analyze/src/known_fn.rs | 69 +++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/c2rust-analyze/src/known_fn.rs b/c2rust-analyze/src/known_fn.rs index 5034a4f62..7974a3e39 100644 --- a/c2rust-analyze/src/known_fn.rs +++ b/c2rust-analyze/src/known_fn.rs @@ -1,6 +1,6 @@ use crate::context::PermissionSet; -#[allow(unused)] +#[cfg(test)] macro_rules! const_slice { ($ty:ty, []) => {{ &[] @@ -25,7 +25,26 @@ pub struct KnownFnTy { perms: &'static [PermissionSet], } -#[allow(unused)] +impl KnownFnTy { + /// Check that we annotated the right number of [`PermissionSet`]s + /// that corresponds to the number of raw pointers in [`Self::ty`]. + #[cfg(test)] + const fn checked(self) -> Self { + let ty = self.ty.as_bytes(); + let mut num_ptrs = 0; + let mut i = 0; + while i < ty.len() { + if ty[i] == b'*' { + num_ptrs += 1; + } + i += 1; + } + assert!(self.perms.len() == num_ptrs); + self + } +} + +#[cfg(test)] macro_rules! known_fn_ty { ($ty:ty: $perms:tt) => {{ KnownFnTy { @@ -33,6 +52,7 @@ macro_rules! known_fn_ty { ty: stringify!($ty), perms: const_slice!(PermissionSet, perms_annotation!($perms)), } + .checked() }}; ($ty:ty) => {{ KnownFnTy { @@ -40,6 +60,7 @@ macro_rules! known_fn_ty { ty: stringify!($ty), perms: &[], } + .checked() }}; } @@ -65,4 +86,48 @@ mod tests { ] ); } + + #[test] + fn check_known_fn_ty_eq() { + KnownFnTy { + name: "", + ty: "*mut *const", + perms: const_slice!(PermissionSet, [PermissionSet::empty(); 2]), + } + .checked(); + } + + #[test] + #[should_panic] + fn check_known_fn_ty_lt() { + KnownFnTy { + name: "", + ty: "*const", + perms: const_slice!(PermissionSet, [PermissionSet::empty(); 2]), + } + .checked(); + } + + #[test] + #[should_panic] + fn check_known_fn_ty_gt() { + KnownFnTy { + name: "", + ty: "*const *const *mut", + perms: const_slice!(PermissionSet, [PermissionSet::empty(); 2]), + } + .checked(); + } + + #[test] + fn known_fn_ty() { + assert_eq!( + known_fn_ty!(*const i32: [READ]), + KnownFnTy { + name: "", + ty: "*const i32", + perms: const_slice!(PermissionSet, [PermissionSet::READ]), + } + ); + } } From fd7de166dd60254d654eef9bbb84a0faeba35009 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Wed, 5 Jul 2023 15:38:21 -0700 Subject: [PATCH 06/10] (`c2rust-analyze`) Add more `known_fn_ty!` tests. --- c2rust-analyze/src/known_fn.rs | 44 ++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/c2rust-analyze/src/known_fn.rs b/c2rust-analyze/src/known_fn.rs index 7974a3e39..3acb405be 100644 --- a/c2rust-analyze/src/known_fn.rs +++ b/c2rust-analyze/src/known_fn.rs @@ -120,13 +120,49 @@ mod tests { } #[test] - fn known_fn_ty() { + fn known_fn_ty_no_perms() { assert_eq!( - known_fn_ty!(*const i32: [READ]), + known_fn_ty!(()), KnownFnTy { name: "", - ty: "*const i32", - perms: const_slice!(PermissionSet, [PermissionSet::READ]), + ty: "()", + perms: &[], + } + ); + } + + #[test] + fn known_fn_ty_with_one_perms() { + assert_eq!( + known_fn_ty!(*mut c_char: [WRITE | OFFSET_ADD]), + KnownFnTy { + name: "", + ty: "*mut c_char", + perms: const_slice!( + PermissionSet, + [PermissionSet::union_all([ + PermissionSet::WRITE, + PermissionSet::OFFSET_ADD + ]),] + ), + } + ); + } + + #[test] + fn known_fn_ty_with_two_perms() { + assert_eq!( + known_fn_ty!(*mut *mut c_char: [WRITE, WRITE | OFFSET_ADD]), + KnownFnTy { + name: "", + ty: "*mut *mut c_char", + perms: const_slice!( + PermissionSet, + [ + PermissionSet::union_all([PermissionSet::WRITE,]), + PermissionSet::union_all([PermissionSet::WRITE, PermissionSet::OFFSET_ADD]) + ] + ), } ); } From fdbbcf9691b1980d4bde25ae2a65b52c64d3f504 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Wed, 5 Jul 2023 15:47:45 -0700 Subject: [PATCH 07/10] (`c2rust-analyze`) Add `known_fns` for declaring the permissions of known (`libc`) `fn`s while also checking these definitions match `libc`'s. --- Cargo.lock | 5 +- c2rust-analyze/Cargo.toml | 1 + c2rust-analyze/src/known_fn.rs | 193 +++++++++++++++++++++++++++++++++ 3 files changed, 197 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ee069b980..70b6316ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -214,6 +214,7 @@ dependencies = [ "env_logger", "indexmap", "itertools", + "libc", "log", "polonius-engine", "print_bytes", @@ -918,9 +919,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.144" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libloading" diff --git a/c2rust-analyze/Cargo.toml b/c2rust-analyze/Cargo.toml index e0b41cb01..0c0c63eff 100644 --- a/c2rust-analyze/Cargo.toml +++ b/c2rust-analyze/Cargo.toml @@ -24,6 +24,7 @@ env_logger = "0.10.0" log = "0.4.17" backtrace = "0.3.67" itertools = "0.10" +libc = "0.2.147" [build-dependencies] c2rust-build-paths = { path = "../c2rust-build-paths", version = "0.18.0" } diff --git a/c2rust-analyze/src/known_fn.rs b/c2rust-analyze/src/known_fn.rs index 3acb405be..fc9cacb64 100644 --- a/c2rust-analyze/src/known_fn.rs +++ b/c2rust-analyze/src/known_fn.rs @@ -42,6 +42,12 @@ impl KnownFnTy { assert!(self.perms.len() == num_ptrs); self } + + #[cfg(test)] + const fn named(self, name: &'static str) -> Self { + let Self { name: _, ty, perms } = self; + Self { name, ty, perms } + } } #[cfg(test)] @@ -64,6 +70,45 @@ macro_rules! known_fn_ty { }}; } +#[derive(Debug, PartialEq, Eq)] +pub struct KnownFn { + name: &'static str, + inputs: &'static [KnownFnTy], + output: KnownFnTy, +} + +#[cfg(test)] +macro_rules! known_fns { + { + mod $module:ident { + + $( + fn $name:ident( + $($arg_name:ident: $arg_ty:ty$(: $arg_perms:tt)?,)* + ) -> $return_ty:ty$(: $return_perms:tt)? + );*; + + } + } => {{ + use $module::*; + + const_slice!(KnownFn, [$({ + unsafe extern "C" fn $name($($arg_name: $arg_ty,)*) -> $return_ty { + $(let _ = $arg_name;)* + todo!() + } + // ensure the definitions match + [$name, $module::$name]; + + KnownFn { + name: stringify!($name), + inputs: const_slice!(KnownFnTy, [$(known_fn_ty!($arg_ty$(: $arg_perms)?).named(stringify!($arg_name)),)*]), + output: known_fn_ty!($return_ty$(: $return_perms)?), + } + },)*]) + }}; +} + #[cfg(test)] mod tests { use super::*; @@ -166,4 +211,152 @@ mod tests { } ); } + + #[test] + fn __errno_location() { + assert_eq!( + known_fns! { + mod libc { + + fn __errno_location() -> *mut c_int: [READ | WRITE]; + + } + }, + const_slice!( + KnownFn, + [KnownFn { + name: "__errno_location", + inputs: &[], + output: KnownFnTy { + name: "", + ty: "*mut c_int", + perms: const_slice!( + PermissionSet, + [PermissionSet::union_all([ + PermissionSet::READ, + PermissionSet::WRITE + ])] + ) + } + }] + ) + ); + } + + #[test] + fn read() { + assert_eq!( + known_fns! { + mod libc { + + fn read( + fd: c_int, + buf: *mut c_void: [WRITE | OFFSET_ADD], + count: size_t, + ) -> ssize_t; + + } + }, + const_slice!( + KnownFn, + [KnownFn { + name: "read", + inputs: const_slice!( + KnownFnTy, + [ + KnownFnTy { + name: "fd", + ty: "c_int", + perms: &[], + }, + KnownFnTy { + name: "buf", + ty: "*mut c_void", + perms: const_slice!( + PermissionSet, + [PermissionSet::union_all([ + PermissionSet::WRITE, + PermissionSet::OFFSET_ADD + ])] + ), + }, + KnownFnTy { + name: "count", + ty: "size_t", + perms: &[], + }, + ] + ), + output: KnownFnTy { + name: "", + ty: "ssize_t", + perms: &[], + } + }] + ) + ); + } + + #[test] + fn strtol() { + assert_eq!( + known_fns! { + mod libc { + + fn strtol( + s: *const c_char: [READ | OFFSET_ADD], + endp: *mut *mut c_char: [WRITE, WRITE | OFFSET_ADD], + base: c_int, + ) -> c_long; + + } + }, + const_slice!( + KnownFn, + [KnownFn { + name: "strtol", + inputs: const_slice!( + KnownFnTy, + [ + KnownFnTy { + name: "s", + ty: "*const c_char", + perms: const_slice!( + PermissionSet, + [PermissionSet::union_all([ + PermissionSet::READ, + PermissionSet::OFFSET_ADD + ])] + ), + }, + KnownFnTy { + name: "endp", + ty: "*mut *mut c_char", + perms: const_slice!( + PermissionSet, + [ + PermissionSet::union_all([PermissionSet::WRITE,]), + PermissionSet::union_all([ + PermissionSet::WRITE, + PermissionSet::OFFSET_ADD + ]) + ] + ), + }, + KnownFnTy { + name: "base", + ty: "c_int", + perms: &[], + }, + ] + ), + output: KnownFnTy { + name: "", + ty: "c_long", + perms: &[], + } + }] + ) + ); + } } From 24ce9591efc8a2db42d23fb9484375bb8149a05b Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Wed, 5 Jul 2023 16:43:49 -0700 Subject: [PATCH 08/10] (`c2rust-analyze`) Allow `#[]` attributes on each `known_fns!` `fn` so platform specific things can be represented, such as Linux's `__errno_location` and macOS' `__error`. --- c2rust-analyze/src/known_fn.rs | 36 ++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/c2rust-analyze/src/known_fn.rs b/c2rust-analyze/src/known_fn.rs index fc9cacb64..1871f1039 100644 --- a/c2rust-analyze/src/known_fn.rs +++ b/c2rust-analyze/src/known_fn.rs @@ -83,6 +83,7 @@ macro_rules! known_fns { mod $module:ident { $( + $(#[$attr:meta])? fn $name:ident( $($arg_name:ident: $arg_ty:ty$(: $arg_perms:tt)?,)* ) -> $return_ty:ty$(: $return_perms:tt)? @@ -92,20 +93,23 @@ macro_rules! known_fns { } => {{ use $module::*; - const_slice!(KnownFn, [$({ - unsafe extern "C" fn $name($($arg_name: $arg_ty,)*) -> $return_ty { - $(let _ = $arg_name;)* - todo!() - } - // ensure the definitions match - [$name, $module::$name]; + const_slice!(KnownFn, [$( + $(#[$attr])? + { + unsafe extern "C" fn $name($($arg_name: $arg_ty,)*) -> $return_ty { + $(let _ = $arg_name;)* + todo!() + } + // ensure the definitions match + [$name, $module::$name]; - KnownFn { - name: stringify!($name), - inputs: const_slice!(KnownFnTy, [$(known_fn_ty!($arg_ty$(: $arg_perms)?).named(stringify!($arg_name)),)*]), - output: known_fn_ty!($return_ty$(: $return_perms)?), + KnownFn { + name: stringify!($name), + inputs: const_slice!(KnownFnTy, [$(known_fn_ty!($arg_ty$(: $arg_perms)?).named(stringify!($arg_name)),)*]), + output: known_fn_ty!($return_ty$(: $return_perms)?), + } } - },)*]) + ,)*]) }}; } @@ -212,20 +216,28 @@ mod tests { ); } + #[cfg(any(target_os = "linux", target_os = "macos"))] #[test] fn __errno_location() { assert_eq!( known_fns! { mod libc { + #[cfg(target_os = "linux")] fn __errno_location() -> *mut c_int: [READ | WRITE]; + #[cfg(target_os = "macos")] + fn __error() -> *mut c_int: [READ | WRITE]; + } }, const_slice!( KnownFn, [KnownFn { + #[cfg(target_os = "linux")] name: "__errno_location", + #[cfg(target_os = "macos")] + name: "__error", inputs: &[], output: KnownFnTy { name: "", From 04ffe900e1ebb59b5b3e320d71f3aedf75f991c9 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Fri, 7 Jul 2023 03:14:02 -0700 Subject: [PATCH 09/10] (`c2rust-analyze`) Make fields of `struct KnownFn{,Ty}` `pub`. --- c2rust-analyze/src/known_fn.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/c2rust-analyze/src/known_fn.rs b/c2rust-analyze/src/known_fn.rs index 1871f1039..85d251dee 100644 --- a/c2rust-analyze/src/known_fn.rs +++ b/c2rust-analyze/src/known_fn.rs @@ -20,9 +20,9 @@ macro_rules! perms_annotation { #[derive(Debug, PartialEq, Eq)] pub struct KnownFnTy { - name: &'static str, - ty: &'static str, - perms: &'static [PermissionSet], + pub name: &'static str, + pub ty: &'static str, + pub perms: &'static [PermissionSet], } impl KnownFnTy { @@ -72,9 +72,9 @@ macro_rules! known_fn_ty { #[derive(Debug, PartialEq, Eq)] pub struct KnownFn { - name: &'static str, - inputs: &'static [KnownFnTy], - output: KnownFnTy, + pub name: &'static str, + pub inputs: &'static [KnownFnTy], + pub output: KnownFnTy, } #[cfg(test)] From b9ef5a043e3a83e872c637ea750aa51e917c25d0 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Fri, 7 Jul 2023 03:20:02 -0700 Subject: [PATCH 10/10] (`c2rust-analyze`) Add source code fields to `struct KnownFn{,Ty}` to help with debug output. --- c2rust-analyze/src/known_fn.rs | 107 ++++++++++++++++++++++++++++++--- 1 file changed, 99 insertions(+), 8 deletions(-) diff --git a/c2rust-analyze/src/known_fn.rs b/c2rust-analyze/src/known_fn.rs index 85d251dee..ed9695805 100644 --- a/c2rust-analyze/src/known_fn.rs +++ b/c2rust-analyze/src/known_fn.rs @@ -1,3 +1,7 @@ +use std::fmt; +use std::fmt::Display; +use std::fmt::Formatter; + use crate::context::PermissionSet; #[cfg(test)] @@ -18,11 +22,36 @@ macro_rules! perms_annotation { }}; } -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, Eq)] pub struct KnownFnTy { pub name: &'static str, pub ty: &'static str, pub perms: &'static [PermissionSet], + pub source: &'static str, +} + +impl KnownFnTy { + fn eq_fields(&self) -> impl Eq + '_ { + let Self { + name, + ty, + perms, + source: _, + } = self; + (name, ty, perms) + } +} + +impl PartialEq for KnownFnTy { + fn eq(&self, other: &Self) -> bool { + self.eq_fields() == other.eq_fields() + } +} + +impl Display for KnownFnTy { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.write_str(self.source) + } } impl KnownFnTy { @@ -45,8 +74,18 @@ impl KnownFnTy { #[cfg(test)] const fn named(self, name: &'static str) -> Self { - let Self { name: _, ty, perms } = self; - Self { name, ty, perms } + let Self { + name: _, + ty, + perms, + source, + } = self; + Self { + name, + ty, + perms, + source, + } } } @@ -57,6 +96,7 @@ macro_rules! known_fn_ty { name: "", ty: stringify!($ty), perms: const_slice!(PermissionSet, perms_annotation!($perms)), + source: stringify!($ty: $perms), } .checked() }}; @@ -65,16 +105,42 @@ macro_rules! known_fn_ty { name: "", ty: stringify!($ty), perms: &[], + source: stringify!($ty), } .checked() }}; } -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, Eq)] pub struct KnownFn { pub name: &'static str, pub inputs: &'static [KnownFnTy], pub output: KnownFnTy, + pub source: &'static str, +} + +impl KnownFn { + fn eq_fields(&self) -> impl Eq + '_ { + let Self { + name, + inputs, + output, + source: _, + } = self; + (name, inputs, output) + } +} + +impl PartialEq for KnownFn { + fn eq(&self, other: &Self) -> bool { + self.eq_fields() == other.eq_fields() + } +} + +impl Display for KnownFn { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.write_str(&self.source.replace('\n', "")) + } } #[cfg(test)] @@ -103,10 +169,17 @@ macro_rules! known_fns { // ensure the definitions match [$name, $module::$name]; + let source = stringify!( + fn $name( + $($arg_name: $arg_ty$(: $arg_perms)?,)* + ) -> $return_ty$(: $return_perms)? + ); + KnownFn { name: stringify!($name), inputs: const_slice!(KnownFnTy, [$(known_fn_ty!($arg_ty$(: $arg_perms)?).named(stringify!($arg_name)),)*]), output: known_fn_ty!($return_ty$(: $return_perms)?), + source, } } ,)*]) @@ -142,6 +215,7 @@ mod tests { name: "", ty: "*mut *const", perms: const_slice!(PermissionSet, [PermissionSet::empty(); 2]), + source: "", } .checked(); } @@ -153,6 +227,7 @@ mod tests { name: "", ty: "*const", perms: const_slice!(PermissionSet, [PermissionSet::empty(); 2]), + source: "", } .checked(); } @@ -164,6 +239,7 @@ mod tests { name: "", ty: "*const *const *mut", perms: const_slice!(PermissionSet, [PermissionSet::empty(); 2]), + source: "", } .checked(); } @@ -176,6 +252,7 @@ mod tests { name: "", ty: "()", perms: &[], + source: "", } ); } @@ -194,6 +271,7 @@ mod tests { PermissionSet::OFFSET_ADD ]),] ), + source: "", } ); } @@ -212,6 +290,7 @@ mod tests { PermissionSet::union_all([PermissionSet::WRITE, PermissionSet::OFFSET_ADD]) ] ), + source: "", } ); } @@ -248,8 +327,10 @@ mod tests { PermissionSet::READ, PermissionSet::WRITE ])] - ) - } + ), + source: "", + }, + source: "", }] ) ); @@ -280,6 +361,7 @@ mod tests { name: "fd", ty: "c_int", perms: &[], + source: "", }, KnownFnTy { name: "buf", @@ -291,11 +373,13 @@ mod tests { PermissionSet::OFFSET_ADD ])] ), + source: "", }, KnownFnTy { name: "count", ty: "size_t", perms: &[], + source: "", }, ] ), @@ -303,7 +387,9 @@ mod tests { name: "", ty: "ssize_t", perms: &[], - } + source: "", + }, + source: "", }] ) ); @@ -340,6 +426,7 @@ mod tests { PermissionSet::OFFSET_ADD ])] ), + source: "", }, KnownFnTy { name: "endp", @@ -354,11 +441,13 @@ mod tests { ]) ] ), + source: "", }, KnownFnTy { name: "base", ty: "c_int", perms: &[], + source: "", }, ] ), @@ -366,7 +455,9 @@ mod tests { name: "", ty: "c_long", perms: &[], - } + source: "", + }, + source: "", }] ) );