-
Notifications
You must be signed in to change notification settings - Fork 49
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
Using yara-x in a Rust library and handling lifetime specifiers of Scanner #184
Comments
I believe you can achieve what you want with a bit of unsafe code: /// Wraps a yara_x::Rules, but preventing it from moving around in memory.
struct PinnedRules{
rules: yara_x::Rules,
_pin: PhantomPinned,
}
struct MyScanner<'a> {
scanner: yara_x::Scanner<'a>,
// This allows MyScanner to own the yara_x::Rules and pass a reference to the
// scanner. The use of `Pin` guarantees that the rules won't be moved.
_rules: Pin<Box<PinnedRules>>,
}
impl<'a> MyScanner<'a> {
pub fn new(rules: yara_x::Rules) -> Self {
let pinned_rules = Box::pin(PinnedRules{rules, _pin: PhantomPinned});
let rules_ptr = std::ptr::from_ref(&pinned_rules.rules);
let rules_ref = unsafe { rules_ptr.as_ref().unwrap() };
let scanner = yara_x::Scanner::new(rules_ref);
Self { scanner, _rules: pinned_rules }
}
pub fn scan(&mut self, data: String) -> Result<String> {
todo!()
}
} I haven't tested it thoroughly, so it may contain bugs. |
Thank you, I tested this change in my code, all the tests passed, and nothing panics. Even though it works, I think this solution is suboptimal - I need to test it more thoroughly, and I'll deep-dive into std::pin docs to make sure this unsafe code won't crash in the future, won't memory-leak, and there isn't any race in the destructor of May I still suggest handling this issue in the yara-x library sometime in the future - to avoid forcing the library user to write unsafe code, or to introduce advanced Rust concepts. |
@xrl1 then only thing you have to do is that you need to put pub struct MyScanner<'s> {
rules: yara_x::Rules,
scanner: Option<yara_x::Scanner<'s>>,
} |
@qjerome that doesn't work because |
My bad, I thought it would work ! That's what you get when you write code without testing it ... |
Let me add a non null contribution this time: impl<'s> Deref for MyScanner<'s> {
type Target = yara_x::Scanner<'s>;
fn deref(&self) -> &Self::Target {
&self.scanner
}
}
impl<'s> DerefMut for MyScanner<'s> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.scanner
}
} Should allow you to use your |
Hello,
Related to #139 , but maybe not the same use case:
I'm trying to create a library that uses the yara-x crate. The library should initialize the rules internally, and create a struct that holds an instance of the yara-x Scanner.
Reducted code in
scanner.rs
:Reducted code of
lib.rs
:load_rules
is compiling and loading the rules from a resource file.I tried countless variations of this code, but I always reach the obstacle of the lifetime specifier on Scanner and get an error of "rules does not live long enough".
I couldn't find a way to wrap YaraScanner in an object that outlives it and holds a
Rules
object safely.I cannot create the rules in
main.rs
because I intend to export this as a library, and I don't want the user to load the Yara rules herself.The only solution Claude Sonnet and I found where to Box::leak this memory or statically load it, so it will live until the program exits. I want to avoid it to support in the future getting string rules as arguments to
MyLib::new
, so I'm confined to the lifetime of aMyLib
instance.Please let me know how you think it can be solved, because currently, I think only changing Scanner to take ownership of the rules can solve this.
The text was updated successfully, but these errors were encountered: