Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[draft] bindgen poc - v1 #12018

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft

[draft] bindgen poc - v1 #12018

wants to merge 7 commits into from

Conversation

jasonish
Copy link
Member

@jasonish jasonish commented Oct 23, 2024

See if using bindgen to generate Rust bindings for C functions could have prevented the issues fixed in this PR: #12009

Ticket: https://redmine.openinfosecfoundation.org/issues/7341

And yes, it would.

  • First we define the function pointer type for SCAppLayerStateGetEventInfoByIdFn, and some others in app-layer-ext.h. Note that I had to bring back the definition of the AppLayerEventType enum to C from Rust to avoid circular dependency.
  • The header name app-layer-ext.h is a bad name, but I just needed a "clean" header.
  • Then we integrate C bindgen during build to generate Rust bindings to these functions.
  • Replace the hand written bindings with the generated bindings.
    • This happens at commit 3e4f196, and the Rust now compiles due to i8 and i32 discrepancies.
  • Finally, make Rust compile again by fixing the typing errors
  • I reverted the fix from rust ffi ints/v1 #12009 and sure enough the fixes forced on us prevent the ffi issue (that's why this can't be merged according to github)

Caveats:

  • As mentioned in the ticket, circular dependencies need to be resolved, a good rule to prevent this is in the ticket.
  • bindgen requires libclang. Many of the CI jobs will fail because clang is not installed
  • This build fresh bindings on every rust compile. The bindgen library requires a lower MSRV than the CLI tool, which requires a newer MSRV that we use right now, and adds another tool dependency. However, we could revert to a style like we do with cbindgen. Then bindgen-cli and libclang would not be needed on releases from dist, but dist builders would need newer rust (not bindgen is often found in system packages, so may be a non-issue).

Other notes:

  • This will detect mismatched sizes return value integers for C functions exported to Rust
  • But it won't catch the case where a different size integer is returned from a Rust function exported C, in the case where Rust might be returning an i8 and C is storing it in an int32_t for instance.

*/

#![allow(non_camel_case_types)]

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sys is used, as naming crates sometime-sys is idiomatic for crates that pull in a C library into Rust.

Copy link

codecov bot commented Oct 23, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 83.28%. Comparing base (1860aa8) to head (6bf01cd).
Report is 6 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #12018      +/-   ##
==========================================
+ Coverage   83.24%   83.28%   +0.03%     
==========================================
  Files         910      910              
  Lines      258136   258135       -1     
==========================================
+ Hits       214895   214988      +93     
+ Misses      43241    43147      -94     
Flag Coverage Δ
fuzzcorpus 61.55% <100.00%> (+0.06%) ⬆️
livemode 19.38% <93.10%> (-0.01%) ⬇️
pcap 44.45% <93.10%> (+0.01%) ⬆️
suricata-verify 62.74% <100.00%> (+<0.01%) ⬆️
unittests 59.29% <96.55%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

@suricata-qa
Copy link

ERROR:

ERROR: QA failed on build_opt.

Pipeline 23168

@suricata-qa
Copy link

Information: QA ran without warnings.

Pipeline 23171

@victorjulien
Copy link
Member

The header name app-layer-ext.h is a bad name, but I just needed a "clean" header.

app-layer-ffi.h? Or a ffi/app-layer.h or something?

@@ -0,0 +1,12 @@
fn main() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add some explanation here and also to the commit about why we need build.rs and what it does?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Broke the commit that introduced bindgen, and made use of the bindings into 2. Added some more comments to the code and the commit that introduces bindgen.

@jasonish
Copy link
Member Author

The header name app-layer-ext.h is a bad name, but I just needed a "clean" header.

app-layer-ffi.h? Or a ffi/app-layer.h or something?

Not really better names, they imply ffi where these are just normal headers as far as the C code is concerned. The main point being is I just needed really cleaned up headers to avoid a fight with bindgen to test out bindgen. Should we chose to go to bindgen, we'll probably need some good header cleanup/review for the parts we expose - the big part being not exposing any headers that also depend on headers generated from Rust I think - circular dependencies, thats where things seem to choke.

Extract a simple function function to a simple header with no circular
dependencies.

Next we'll use bindgen to generate Rust bindings for this function.

Ticket: OISF#7341
Add a build.rs to generate Rust bindings to specific C functions at
build time using the bindgen crate. As can be seen in build.rs, we
currently only pull in the test header, "app-layer-ext.h" and only
output items starting with "SC".

Bindgen generates the bindings in a file named "bindings.rs" in the
target/ direction, which "sys.rs" will statically "include" at
compiling name, making these bindings available under package
"crate::sys".

"build.rs" had to be placed in the non-standard location of
"src/build.rs" (its usually alongside Cargo.toml) to satisfy the
out-of-tree build requirements of distcheck.

Note that bindgen is also available as a command line tool which could
be used instead of integrating this at compile time, however the tool
requires a newer version of Rust than our MSRV, and may present
additional issues with respect to autoconf and distcheck.
This function is now named SCAppLayerStateGetProgressFn, note how its
definition differs from ours:

pub type SCAppLayerStateGetProgressFn = ::std::option::Option<
    unsafe extern "C" fn(
        alstate: *mut ::std::os::raw::c_void,
        direction: u8,
    ) -> ::std::os::raw::c_int,
>;

Our previous definition:

pub type StateGetProgressFn = unsafe extern "C" fn (*mut c_void, u8) -> c_int;

The main differing being wrapped in an option which makes sense as its
a function pointer that could be NULL/None, but does require wrapping
it in an Option now.
Rust will now fail, as the discrepancy between i8 and i32 is picked up.
@jasonish
Copy link
Member Author

To see the generated bindings you can do something like:

Build from clean, so only one copy exists:

make clean && make

Find the bindings:

find rust/target -name bindings.rs
cat rust/target/debug/build/suricata-fbddfaefce7312d9/out/bindings.rs
/* automatically generated by rust-bindgen 0.69.4 */

#[repr(u32)]
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum AppLayerEventType {
    APP_LAYER_EVENT_TYPE_TRANSACTION = 1,
    APP_LAYER_EVENT_TYPE_PACKET = 2,
}
pub type SCAppLayerStateGetProgressFn = ::std::option::Option<
    unsafe extern "C" fn(
        alstate: *mut ::std::os::raw::c_void,
        direction: u8,
    ) -> ::std::os::raw::c_int,
>;
pub type SCAppLayerStateGetEventInfoFn = ::std::option::Option<
    unsafe extern "C" fn(
        event_name: *const ::std::os::raw::c_char,
        event_id: *mut ::std::os::raw::c_int,
        event_type: *mut AppLayerEventType,
    ) -> ::std::os::raw::c_int,
>;
pub type SCAppLayerStateGetEventInfoByIdFn = ::std::option::Option<
    unsafe extern "C" fn(
        event_id: ::std::os::raw::c_int,
        event_name: *mut *const ::std::os::raw::c_char,
        event_type: *mut AppLayerEventType,
    ) -> ::std::os::raw::c_int,
>;

@suricata-qa
Copy link

ERROR:

ERROR: QA failed on build_fetch.

Pipeline 23178

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants