-
Notifications
You must be signed in to change notification settings - Fork 407
Store Feature
flags in line rather than on the heap by default (without increasing their size)
#3730
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
Store Feature
flags in line rather than on the heap by default (without increasing their size)
#3730
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
// This file is Copyright its original authors, visible in version control | ||
// history. | ||
// | ||
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE | ||
// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. | ||
// You may not use this file except in accordance with one or both of these | ||
// licenses. | ||
|
||
// This file is auto-generated by gen_target.sh based on target_template.txt | ||
// To modify it, modify target_template.txt and run gen_target.sh instead. | ||
|
||
#![cfg_attr(feature = "libfuzzer_fuzz", no_main)] | ||
#![cfg_attr(rustfmt, rustfmt_skip)] | ||
|
||
#[cfg(not(fuzzing))] | ||
compile_error!("Fuzz targets need cfg=fuzzing"); | ||
|
||
#[cfg(not(hashes_fuzz))] | ||
compile_error!("Fuzz targets need cfg=hashes_fuzz"); | ||
|
||
#[cfg(not(secp256k1_fuzz))] | ||
compile_error!("Fuzz targets need cfg=secp256k1_fuzz"); | ||
|
||
extern crate lightning_fuzz; | ||
use lightning_fuzz::feature_flags::*; | ||
|
||
#[cfg(feature = "afl")] | ||
#[macro_use] extern crate afl; | ||
#[cfg(feature = "afl")] | ||
fn main() { | ||
fuzz!(|data| { | ||
feature_flags_run(data.as_ptr(), data.len()); | ||
}); | ||
} | ||
|
||
#[cfg(feature = "honggfuzz")] | ||
#[macro_use] extern crate honggfuzz; | ||
#[cfg(feature = "honggfuzz")] | ||
fn main() { | ||
loop { | ||
fuzz!(|data| { | ||
feature_flags_run(data.as_ptr(), data.len()); | ||
}); | ||
} | ||
} | ||
|
||
#[cfg(feature = "libfuzzer_fuzz")] | ||
#[macro_use] extern crate libfuzzer_sys; | ||
#[cfg(feature = "libfuzzer_fuzz")] | ||
fuzz_target!(|data: &[u8]| { | ||
feature_flags_run(data.as_ptr(), data.len()); | ||
}); | ||
|
||
#[cfg(feature = "stdin_fuzz")] | ||
fn main() { | ||
use std::io::Read; | ||
|
||
let mut data = Vec::with_capacity(8192); | ||
std::io::stdin().read_to_end(&mut data).unwrap(); | ||
feature_flags_run(data.as_ptr(), data.len()); | ||
} | ||
|
||
#[test] | ||
fn run_test_cases() { | ||
use std::fs; | ||
use std::io::Read; | ||
use lightning_fuzz::utils::test_logger::StringBuffer; | ||
|
||
use std::sync::{atomic, Arc}; | ||
{ | ||
let data: Vec<u8> = vec![0]; | ||
feature_flags_run(data.as_ptr(), data.len()); | ||
} | ||
let mut threads = Vec::new(); | ||
let threads_running = Arc::new(atomic::AtomicUsize::new(0)); | ||
if let Ok(tests) = fs::read_dir("test_cases/feature_flags") { | ||
for test in tests { | ||
let mut data: Vec<u8> = Vec::new(); | ||
let path = test.unwrap().path(); | ||
fs::File::open(&path).unwrap().read_to_end(&mut data).unwrap(); | ||
threads_running.fetch_add(1, atomic::Ordering::AcqRel); | ||
|
||
let thread_count_ref = Arc::clone(&threads_running); | ||
let main_thread_ref = std::thread::current(); | ||
threads.push((path.file_name().unwrap().to_str().unwrap().to_string(), | ||
std::thread::spawn(move || { | ||
let string_logger = StringBuffer::new(); | ||
|
||
let panic_logger = string_logger.clone(); | ||
let res = if ::std::panic::catch_unwind(move || { | ||
feature_flags_test(&data, panic_logger); | ||
}).is_err() { | ||
Some(string_logger.into_string()) | ||
} else { None }; | ||
thread_count_ref.fetch_sub(1, atomic::Ordering::AcqRel); | ||
main_thread_ref.unpark(); | ||
res | ||
}) | ||
)); | ||
while threads_running.load(atomic::Ordering::Acquire) > 32 { | ||
std::thread::park(); | ||
} | ||
} | ||
} | ||
let mut failed_outputs = Vec::new(); | ||
for (test, thread) in threads.drain(..) { | ||
if let Some(output) = thread.join().unwrap() { | ||
println!("\nOutput of {}:\n{}\n", test, output); | ||
failed_outputs.push(test); | ||
} | ||
} | ||
if !failed_outputs.is_empty() { | ||
println!("Test cases which failed: "); | ||
for case in failed_outputs { | ||
println!("{}", case); | ||
} | ||
panic!(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
// This file is Copyright its original authors, visible in version control | ||
// history. | ||
// | ||
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE | ||
// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. | ||
// You may not use this file except in accordance with one or both of these | ||
// licenses. | ||
|
||
use lightning::types::features::FeatureFlags; | ||
|
||
use crate::utils::test_logger; | ||
|
||
use std::ops::{Deref, DerefMut}; | ||
|
||
/// Check various methods on [`FeatureFlags`] given `v` which should be equal to `feat` and an | ||
/// `old_v` which should be equal to `old_feat`. | ||
fn check_eq(v: &Vec<u8>, feat: &FeatureFlags, old_v: &mut Vec<u8>, old_feat: &mut FeatureFlags) { | ||
assert_eq!(v.len(), feat.len()); | ||
assert_eq!(v.deref(), feat.deref()); | ||
assert_eq!(old_v.deref_mut(), old_feat.deref_mut()); | ||
Comment on lines
+19
to
+21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not have the same checks for the new and old sets of features? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We call this method once for each updated set of features. The old features here were already passed to this method as the new features in the previous loop iteration. |
||
|
||
let mut feat_clone = feat.clone(); | ||
assert!(feat_clone == *feat); | ||
|
||
// Test iteration over the `FeatureFlags` with the base iterator | ||
let mut feat_iter = feat.iter(); | ||
let mut vec_iter = v.iter(); | ||
assert_eq!(feat_iter.len(), vec_iter.len()); | ||
while let Some(feat) = feat_iter.next() { | ||
let v = vec_iter.next().unwrap(); | ||
assert_eq!(*feat, *v); | ||
} | ||
assert!(vec_iter.next().is_none()); | ||
|
||
// Do the same test of iteration over the `FeatureFlags` with the mutable iterator | ||
let mut feat_iter = feat_clone.iter_mut(); | ||
let mut vec_iter = v.iter(); | ||
assert_eq!(feat_iter.len(), vec_iter.len()); | ||
while let Some(feat) = feat_iter.next() { | ||
let v = vec_iter.next().unwrap(); | ||
assert_eq!(*feat, *v); | ||
} | ||
assert!(vec_iter.next().is_none()); | ||
|
||
assert_eq!(v < old_v, feat < old_feat); | ||
assert_eq!(v.partial_cmp(old_v), feat.partial_cmp(old_feat)); | ||
} | ||
|
||
#[inline] | ||
pub fn do_test(data: &[u8]) { | ||
if data.len() % 3 != 0 { | ||
return; | ||
} | ||
Comment on lines
+52
to
+54
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess you could just redefine There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yea, the fuzzer can deal :) |
||
let mut vec = Vec::new(); | ||
let mut features = FeatureFlags::empty(); | ||
|
||
// For each 3-tuple in the input, interpret the first byte as a "command", the second byte as | ||
// an index within `vec`/`features` to mutate, and the third byte as a value. | ||
for step in data.windows(3) { | ||
TheBlueMatt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let mut old_vec = vec.clone(); | ||
let mut old_features = features.clone(); | ||
match step[0] { | ||
0 => { | ||
vec.resize(step[1] as usize, step[2]); | ||
features.resize(step[1] as usize, step[2]); | ||
}, | ||
1 => { | ||
if vec.len() > step[1] as usize { | ||
vec[step[1] as usize] = step[2]; | ||
features[step[1] as usize] = step[2]; | ||
} | ||
}, | ||
2 => { | ||
if vec.len() > step[1] as usize { | ||
*vec.iter_mut().skip(step[1] as usize).next().unwrap() = step[2]; | ||
*features.iter_mut().skip(step[1] as usize).next().unwrap() = step[2]; | ||
} | ||
}, | ||
_ => {}, | ||
} | ||
// After each mutation, check that `vec` and `features` remain the same, and pass the | ||
// previous state for testing comparisons. | ||
check_eq(&vec, &features, &mut old_vec, &mut old_features); | ||
} | ||
|
||
check_eq(&vec, &features, &mut vec.clone(), &mut features.clone()); | ||
} | ||
|
||
pub fn feature_flags_test<Out: test_logger::Output>(data: &[u8], _out: Out) { | ||
do_test(data); | ||
} | ||
|
||
#[no_mangle] | ||
pub extern "C" fn feature_flags_run(data: *const u8, datalen: usize) { | ||
do_test(unsafe { std::slice::from_raw_parts(data, datalen) }); | ||
} |
Uh oh!
There was an error while loading. Please reload this page.