immunant / c2rust

Migrate C code to Rust
https://c2rust.com/
Other
3.95k stars 234 forks source link

(`c2rust-analyze`) Add `known_fns!` for declaring the permissions on ptrs in known (i.e. `libc`) `UnknownDef` `fn`s #978

Closed kkysen closed 1 year ago

kkysen commented 1 year ago

I wrote this as a macro_rules! macro so that we can write the pointer permission annotations inline with what the normal extern declaration would look like. The macro checks that the declaration matches libc's (or wherever it could be from) and that there are the correct number of PermissionSets on each type corresponding to the number of pointers directly in that type (i.e., the number of *).

The syntax for this is an optional : [PERM1a | PERM1b, PERM2a | PERM2b | PERM2c] after each type in a fn signature, where the order of the PermissionSets corresponds to the pointers in the type in left-to-right order. For example:

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];

        fn _exit(
            status: c_int,
        ) -> !;

        fn abort() -> !;

        fn abs(
            i: c_int,
        ) -> c_int;

        fn accept(
            socket: c_int,
            address: *mut sockaddr: [WRITE],
            address_len: *mut socklen_t: [READ | WRITE],
        ) -> c_int;

        fn read(
            fd: c_int,
            buf: *mut c_void: [WRITE | OFFSET_ADD],
            count: size_t,
        ) -> ssize_t;

        fn write(
            fd: c_int,
            buf: *const c_void: [READ | OFFSET_ADD],
            count: size_t,
        ) -> ssize_t;

        fn strtol(
            s: *const c_char: [READ | OFFSET_ADD],
            endp: *mut *mut c_char: [WRITE, WRITE | OFFSET_ADD],
            base: c_int,
        ) -> c_long;

    }
};

I'm still working on the integration of these KnownFns into fn_sigs as LFnSigs, but I wanted to open a separate PR for how they are declared in the first place.

kkysen commented 1 year ago

It's a bit unfortunate that the annotations have to be written out-of-line (*mut *mut T: [A, B] rather than *mut {A} *mut {B} T or similar), but parsing the latter with macro_rules would be a real pain.

Yeah, I agree that would be ideal, but that would be quite complex to parse and it'd probably mess up other nice-to-have stuff like syntax highlighting.