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

error handeling in libafl/src/corpus #2990

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion libafl/src/corpus/cached.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,13 @@ where
self.load_input_into(&mut testcase.borrow_mut())?;
let mut borrowed_num = 0;
while self.cached_indexes.borrow().len() >= self.cache_max_len {
let removed = self.cached_indexes.borrow_mut().pop_front().unwrap();
let removed = self
.cached_indexes
.borrow_mut()
.pop_front()
.ok_or_else(|| {
Error::illegal_state("Cached indexes queue was unexpectedly empty")
})?;

if let Ok(mut borrowed) = self.inner.get_from_all(removed)?.try_borrow_mut() {
*borrowed.input_mut() = None;
Expand Down
22 changes: 14 additions & 8 deletions libafl/src/corpus/inmemory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,30 +75,36 @@ impl<I> TestcaseStorageMap<I> {

/// Remove a testcase given a [`CorpusId`]
#[cfg(not(feature = "corpus_btreemap"))]
pub fn remove(&mut self, id: CorpusId) -> Option<RefCell<Testcase<I>>> {
pub fn remove(&mut self, id: CorpusId) -> Result<RefCell<Testcase<I>>, Error> {
if let Some(item) = self.map.remove(&id) {
self.remove_key(id);
if let Some(prev) = item.prev {
self.map.get_mut(&prev).unwrap().next = item.next;
self.map
.get_mut(&prev)
.ok_or_else(|| Error::illegal_state("Unable to fetch next CorpusId"))?
.next = item.next;
} else {
// first elem
self.first_id = item.next;
}
if let Some(next) = item.next {
self.map.get_mut(&next).unwrap().prev = item.prev;
self.map
.get_mut(&next)
.ok_or_else(|| Error::illegal_state("Unable to fetch previous CorpusId"))?
.prev = item.prev;
} else {
// last elem
self.last_id = item.prev;
}
Some(item.testcase)
Ok(item.testcase)
} else {
None
Err(Error::illegal_argument("Testcase not found in storage"))
}
}

/// Remove a testcase given a [`CorpusId`]
#[cfg(feature = "corpus_btreemap")]
pub fn remove(&mut self, id: CorpusId) -> Option<RefCell<Testcase<I>>> {
pub fn remove(&mut self, id: CorpusId) -> Result<RefCell<Testcase<I>>, Error> {
self.remove_key(id);
self.map.remove(&id)
}
Expand Down Expand Up @@ -359,9 +365,9 @@ impl<I> Corpus<I> for InMemoryCorpus<I> {
/// Removes an entry from the corpus, returning it if it was present; considers both enabled and disabled testcases
#[inline]
fn remove(&mut self, id: CorpusId) -> Result<Testcase<I>, Error> {
let mut testcase = self.storage.enabled.remove(id);
let mut testcase = self.storage.enabled.remove(id).ok();
if testcase.is_none() {
testcase = self.storage.disabled.remove(id);
testcase = self.storage.disabled.remove(id).ok();
}
testcase
.map(|x| x.take())
Expand Down
52 changes: 32 additions & 20 deletions libafl/src/corpus/inmemory_ondisk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ where
#[inline]
fn add(&mut self, testcase: Testcase<I>) -> Result<CorpusId, Error> {
let id = self.inner.add(testcase)?;
let testcase = &mut self.get(id).unwrap().borrow_mut();
let testcase = &mut self.get(id)?.borrow_mut();
self.save_testcase(testcase, Some(id))?;
*testcase.input_mut() = None;
Ok(id)
Expand All @@ -99,7 +99,7 @@ where
#[inline]
fn add_disabled(&mut self, testcase: Testcase<I>) -> Result<CorpusId, Error> {
let id = self.inner.add_disabled(testcase)?;
let testcase = &mut self.get_from_all(id).unwrap().borrow_mut();
let testcase = &mut self.get_from_all(id)?.borrow_mut();
self.save_testcase(testcase, Some(id))?;
*testcase.input_mut() = None;
Ok(id)
Expand All @@ -110,7 +110,7 @@ where
fn replace(&mut self, id: CorpusId, testcase: Testcase<I>) -> Result<Testcase<I>, Error> {
let entry = self.inner.replace(id, testcase)?;
self.remove_testcase(&entry)?;
let testcase = &mut self.get(id).unwrap().borrow_mut();
let testcase = &mut self.get(id)?.borrow_mut();
self.save_testcase(testcase, Some(id))?;
*testcase.input_mut() = None;
Ok(entry)
Expand Down Expand Up @@ -330,7 +330,10 @@ impl<I> InMemoryOnDiskCorpus<I> {
if testcase.filename().is_some() {
// We are renaming!

let old_filename = testcase.filename_mut().take().unwrap();
let old_filename = testcase
.filename_mut()
.take()
.ok_or_else(|| Error::illegal_argument("Testcase missing filename for renaming"))?;
let new_filename = filename;

// Do operations below when new filename is specified
Expand All @@ -357,22 +360,31 @@ impl<I> InMemoryOnDiskCorpus<I> {
where
I: Input,
{
let file_name = testcase.filename_mut().take().unwrap_or_else(|| {
// TODO walk entry metadata to ask for pieces of filename (e.g. :havoc in AFL)
testcase.input().as_ref().unwrap().generate_name(id)
});
let file_name = if let Some(name) = testcase.filename_mut().take() {
name
} else {
let input = testcase.input().as_ref().ok_or_else(|| {
Error::illegal_argument("Testcase missing input; cannot generate filename")
})?;
input.generate_name(id)
};

let mut ctr = 1;
if self.locking {
let lockfile_name = format!(".{file_name}");
let lockfile_path = self.dir_path.join(lockfile_name);

let mut lockfile = try_create_new(&lockfile_path)?.unwrap_or(
OpenOptions::new()
.write(true)
.read(true)
.open(&lockfile_path)?,
);
let mut lockfile = try_create_new(&lockfile_path)?
.or_else(|| {
OpenOptions::new()
.write(true)
.read(true)
.open(&lockfile_path)
.ok()
})
.ok_or_else(|| {
Error::illegal_state("Failed to open or create lockfile for testcase")
})?;
lockfile.lock_exclusive()?;

let mut old_ctr = String::new();
Expand All @@ -391,14 +403,14 @@ impl<I> InMemoryOnDiskCorpus<I> {
*testcase.filename_mut() = Some(file_name);

if self.meta_format.is_some() {
let filename_ref = testcase
.filename()
.as_ref()
.ok_or_else(|| Error::illegal_argument("Testcase missing filename for metadata"))?;
let metafile_name = if self.locking {
format!(
".{}_{}.metadata",
testcase.filename().as_ref().unwrap(),
ctr
)
format!(".{filename_ref}_{ctr}.metadata")
} else {
format!(".{}.metadata", testcase.filename().as_ref().unwrap())
format!(".{filename_ref}.metadata")
};
let metafile_path = self.dir_path.join(&metafile_name);
let mut tmpfile_path = metafile_path.clone();
Expand Down
7 changes: 6 additions & 1 deletion libafl/src/corpus/minimizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,12 @@ where
let mut removed = Vec::with_capacity(state.corpus().count());
for (seed, (id, _)) in seed_exprs {
// if the model says the seed isn't there, mark it for deletion
if !model.eval(&seed, true).unwrap().as_bool().unwrap() {
if !model
.eval(&seed, true)
.ok_or_else(|| Error::illegal_state("Error evaluating model"))?
.as_bool()
.ok_or_else(|| Error::illegal_state("Error converting condition to bool"))?
{
removed.push(id);
}
}
Expand Down
12 changes: 10 additions & 2 deletions libafl/src/corpus/testcase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ impl<I> Testcase<I> {
/// Returns this [`Testcase`] with a loaded `Input`]
pub fn load_input<C: Corpus<I>>(&mut self, corpus: &C) -> Result<&I, Error> {
corpus.load_input_into(self)?;
Ok(self.input.as_ref().unwrap())
self.input
.as_ref()
.ok_or_else(|| Error::illegal_argument("Error converting reference"))
}

/// Get the input, if available any
Expand Down Expand Up @@ -497,7 +499,13 @@ impl<I> Drop for Testcase<I> {
fn drop(&mut self) {
if let Some(filename) = &self.filename {
let mut path = PathBuf::from(filename);
let lockname = format!(".{}.lafl_lock", path.file_name().unwrap().to_str().unwrap());
let lockname = if let Some(name) = path.file_name().and_then(|os_str| os_str.to_str()) {
format!(".{name}.lafl_lock")
} else {
// Log an error or silently return if conversion fails.
eprintln!("Failed to convert filename to string for lock file.");
return;
};
path.set_file_name(lockname);
let _ = std::fs::remove_file(path);
}
Expand Down
Loading