Remove lifetime of Capstone, and adjust self mutablity for disasm#49
Conversation
… immutable reference to self
…present the fact that this is a eager iterator
Codecov Report
@@ Coverage Diff @@
## master #49 +/- ##
==========================================
+ Coverage 93.85% 94.07% +0.21%
==========================================
Files 15 15
Lines 2019 2094 +75
==========================================
+ Hits 1895 1970 +75
Misses 124 124
Continue to review full report at Codecov.
|
|
|
||
| /// Disassemble all instructions in buffer | ||
| pub fn disasm_all<'a>( | ||
| &mut self, |
There was a problem hiding this comment.
I'm worried about removing the mut requirement for self on the disasm() methods since the cs_disasm() function mutates the underlying handle:
https://github.com/capstone-rust/capstone-sys/blob/master/capstone/cs.c#L646-L650
However, maybe this is safe to do since:
- Capstone is not
SendorSync - Capstone is not
Clone(so the handle should be unique to a givenCapstoneinstance)
There was a problem hiding this comment.
I think this is like a UnsafeCell hidden behind FFI... So if we can prove that it is not possible to have two disasm call in progress simultaneously, we should be safe.
There was a problem hiding this comment.
On the other hand, if this turn out not safe, then the csh method will need to accept &mut self, as the semantic requires csh works like a *mut c_void.
There was a problem hiding this comment.
To ensure safety, we need to prove that is is not possible to perform two operation that mutate the underlying handle simultaneously.
If it is not safe, we need to change csh method to accept &mut self, because it returns something that semantically equal to *mut c_void.
There was a problem hiding this comment.
As Send or Sync is not an issue, unwinding is become the main focus as this is another way to run code simutaneously (i.e. mutation in one piece of code panic, and unwind calls another piece of mutating code).
So your unsafe advanture will arrive the next stop: unwind safety. The following is from Nomicon:
Rust's unwinding strategy is not specified to be fundamentally compatible with any other language's unwinding. As such, unwinding into Rust from another language, or unwinding into another language from Rust is Undefined Behavior. You must absolutely catch any panics at the FFI boundary! What you do at that point is up to you, but something must be done. If you fail to do this, at best, your application will crash and burn. At worst, your application won't crash and burn, and will proceed with completely clobbered state.
There was a problem hiding this comment.
So, unfortunately there is no easy solutions, you need to be ready to create a wrapper in C and making sure all exceptions are handled in the wrapper. Or, if you are sure the C function is already exception free, you can just trust it.
There was a problem hiding this comment.
In this library, the Rust code calls into the C code; the C code never calls into the Rust (or any other language).
From that point of view, we should also be safe (since C has no exceptions or stack unwinding).
earthengine
left a comment
There was a problem hiding this comment.
It looks like that Capstone is also not UnwindSafe, because it contains *mut _, this is a good thing as this only prevents you to return a Capstone from catch_unwind, and this is the safety garantee that the underline handle can never being called simultaneously.
|
|
||
| /// Disassemble all instructions in buffer | ||
| pub fn disasm_all<'a>( | ||
| &mut self, |
There was a problem hiding this comment.
To ensure safety, we need to prove that is is not possible to perform two operation that mutate the underlying handle simultaneously.
If it is not safe, we need to change csh method to accept &mut self, because it returns something that semantically equal to *mut c_void.
|
|
||
| /// Disassemble all instructions in buffer | ||
| pub fn disasm_all<'a>( | ||
| &mut self, |
There was a problem hiding this comment.
As Send or Sync is not an issue, unwinding is become the main focus as this is another way to run code simutaneously (i.e. mutation in one piece of code panic, and unwind calls another piece of mutating code).
So your unsafe advanture will arrive the next stop: unwind safety. The following is from Nomicon:
Rust's unwinding strategy is not specified to be fundamentally compatible with any other language's unwinding. As such, unwinding into Rust from another language, or unwinding into another language from Rust is Undefined Behavior. You must absolutely catch any panics at the FFI boundary! What you do at that point is up to you, but something must be done. If you fail to do this, at best, your application will crash and burn. At worst, your application won't crash and burn, and will proceed with completely clobbered state.
|
|
||
| /// Disassemble all instructions in buffer | ||
| pub fn disasm_all<'a>( | ||
| &mut self, |
There was a problem hiding this comment.
So, unfortunately there is no easy solutions, you need to be ready to create a wrapper in C and making sure all exceptions are handled in the wrapper. Or, if you are sure the C function is already exception free, you can just trust it.
|
I think that remove the @earthengine thanks for your help! |
Discussed in the following post:
https://www.reddit.com/r/rust/comments/9hwr5r/a_rust_ffi_adventure_in_unsafety/
Conclusion:
Capstoneto ensureInstructions's lifetime constrainted.disasmmethods might not actually needselfto be mutable, as it only access immutable methods.disasmmethods uses unbound lifetime, which is not desired here. Bound toselfinstead. However, as the semantic is eager evaluation, there is no need to also bound the code slice.disasmis no longer mutatingCapstone.This change compiles all tests, but I didn't run the tests, please confirm with your own test before merge.