-
Notifications
You must be signed in to change notification settings - Fork 136
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
fix: improve ffi safety #247
Conversation
I think we're also missing some null checks inside fil_verify_aggregate_seal_proof. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few more comments, but otherwise this looks good to go.
rust/src/util/api.rs
Outdated
let devices: Vec<fil_Bytes> = devices.iter().map(|d| d.name().into()).collect(); | ||
let devices: fil_Array<fil_Bytes> = devices.into(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could implement FromIterator
for fil_Array
.
rust/src/proofs/api.rs
Outdated
#[no_mangle] | ||
pub unsafe extern "C" fn fil_generate_fallback_sector_challenges( | ||
registered_proof: fil_RegisteredPoStProof, | ||
randomness: fil_32ByteArray, | ||
sector_ids_ptr: *const u64, | ||
sector_ids_len: libc::size_t, | ||
sector_ids: &fil_Array<u64>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
future note: with a repr(transparent)
, we may be able to use a fil_Array<SectorId>
here. But that's a future change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not seeing anything very wrong here, but I feel like this probably deserves at least one more look from someone who in more into rust.
rust/src/bls/api.rs
Outdated
/// * `messages_sizes_ptr` - pointer to an array containing the lengths of the messages | ||
/// * `messages_len` - length of the two messages arrays | ||
/// * `flattened_public_keys_ptr` - pointer to a byte array containing public keys | ||
/// * `flattened_public_keys_len` - length of the array |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// * `messages_sizes_ptr` - pointer to an array containing the lengths of the messages | |
/// * `messages_len` - length of the two messages arrays | |
/// * `flattened_public_keys_ptr` - pointer to a byte array containing public keys | |
/// * `flattened_public_keys_len` - length of the array | |
/// * `messages_sizes` - pointer to an array containing the lengths of the messages | |
/// * `flattened_public_keys` - pointer to a byte array containing public keys |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// * `messages_sizes_ptr` - pointer to an array containing the lengths of the messages | |
/// * `messages_len` - length of the two messages arrays | |
/// * `flattened_public_keys_ptr` - pointer to a byte array containing public keys | |
/// * `flattened_public_keys_len` - length of the array | |
/// * `signature` - byte array containing the signature | |
/// * `messages` - array containing the pointers to the messages | |
/// * `messages_sizes` - array containing the lengths of the messages | |
/// * `flattened_public_keys` - byte array containing public keys |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some ideas/comments. Honestly, the unsafety of things like ptr.Slice()
is probably fine given the context.
cgo/types.go
Outdated
func (ptr SliceBoxedUint8) Slice() []byte { | ||
return unsafe.Slice((*byte)(ptr.ptr), int(ptr.len)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe call this something like UnsafeSlice
(and do we actually need it?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just want to make it super clear that the underlying slice may be freed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only small things and some of them that could/should be done on subsequent PRs.
@@ -12,32 +10,36 @@ use rand::rngs::OsRng; | |||
use rand::SeedableRng; | |||
use rand_chacha::ChaChaRng; | |||
use rayon::prelude::*; | |||
use safer_ffi::prelude::*; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a fan of star imports. When you're not familiar with safer-ffi
, I'd wonder "where does that derive_ReprC
come from? Is that a new builtin I haven't heard of?" when reading the source. As this PR is already huge, I'd be happy to change it myself in a later PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is especially confusing because we have an str
module in here.
rust/src/bls/api.rs
Outdated
/// * `messages_sizes_ptr` - pointer to an array containing the lengths of the messages | ||
/// * `messages_len` - length of the two messages arrays | ||
/// * `flattened_public_keys_ptr` - pointer to a byte array containing public keys | ||
/// * `flattened_public_keys_len` - length of the array |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// * `messages_sizes_ptr` - pointer to an array containing the lengths of the messages | |
/// * `messages_len` - length of the two messages arrays | |
/// * `flattened_public_keys_ptr` - pointer to a byte array containing public keys | |
/// * `flattened_public_keys_len` - length of the array | |
/// * `signature` - byte array containing the signature | |
/// * `messages` - array containing the pointers to the messages | |
/// * `messages_sizes` - array containing the lengths of the messages | |
/// * `flattened_public_keys` - byte array containing public keys |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still not a fan of glob imports, but other than that it looks good. I've only reviewed the Rust part of it btw.
89f57b6
to
55b02e4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only two minor, non blocking things.
I've only reviewed the Rust side of things. Great work! This is really a massive improvement and also a huge amount of tiresome work. Wow.
I will restate the question regarding changes to function signatures. filecoin-ffi is used by multiple downstream projects, and changes to function signatures will have painful side-effects. |
cgo/helpers.go
Outdated
if len == 0 { | ||
// can't take element 0 of an empty slice | ||
return SliceRefUint8{ | ||
ptr: (*C.uint8_t)(unsafe.Pointer(&goBytes)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would feel better if we had a global uint8
variable and were taking pointer to it instead of the slice.
Reinterpreting the slice pointer to C.uint8_t
feels wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But it would make the code more verbose (all different types).
Alternative would be the pointer to be nil
which AFAIK is acceptable from Go's perspective.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand the concern/solution I am afraid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Kubuxu can you re-explain this if it's still a concern?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
explained in person, fix just pushed
Same comment as previously on Slack: as the bindings are written for specific headers, I would would prefer if header file itself was checked in. I can be convinced otherwise but from my perspective, it makes changes more auditable as most Go types not are aliases to C types. |
Can you clarify which part of the api. The C-API or the go-api? |
I don't mind either way, happy to do as others think makes the most sense |
I know of few projects using the Go side of filecoin-ffi. I'm not aware of any using the C/rust side. |
Unfortunately this requires a merge from master again following the merge of execution traces. @dignifiedquire do you have a few minutes to look at this? |
@@ -12,32 +10,36 @@ use rand::rngs::OsRng; | |||
use rand::SeedableRng; | |||
use rand_chacha::ChaChaRng; | |||
use rayon::prelude::*; | |||
use safer_ffi::prelude::*; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is especially confusing because we have an str
module in here.
pub(crate) machine: Option<Mutex<CgoExecutor>>, | ||
} | ||
|
||
pub type FvmMachine = Option<repr_c::Box<InnerFvmMachine>>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a very confusing type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not a great type, but necessary, I'll add a comment
if err := CheckErr(resp); err != nil { | ||
faults := resp.value.faulty_sectors.copy() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is invalid memory otherwise? Maybe we should fix it in rust?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it wasn’t an issue, just wanted to make the code more defensive on both sides
@@ -64,6 +64,10 @@ main() { | |||
find . -type f -name "lib$1.a" | |||
fi | |||
|
|||
# generate filcrypto.h | |||
RUSTFLAGS="${__rust_flags}" HEADER_DIR="." \ | |||
cargo test build_headers --features c-headers |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dignifiedquire why build with a test?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically, it means we need to rebuild everything (and we should just be using cargo run
with a bin target).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly because that is how the safer-ffi
docs do it, and it didn't quite work when doing it differently due to how that project currently works.
Ok. I've now synced the chain with the address sanitizer enabled (both in rust and go) with both the FVM and the lotus VM. Now I'm running the lotus tests with the address sanitizer enabled. |
I'm getting:
Why can this not be empty? |
They're fine. We can't represent them as null, but rust will internally represent them as 0x1. We could just _assume_ that, but it's safer to call into rust and let it handle this case.
Wow! |
C -> go bindings
: remove c-for-go in favor of manual bindingsrust -> C bindings
: use safer_ffi instead of bindgenCloses filecoin-project/rust-fil-ffi-toolkit#9, #231
TODOs
Depends on filecoin-project/rust-fil-ffi-toolkit#11