Improve platform compatibility of fuzz test cases (#3824)

In #3800 I added support to consume fuzz input as selection of whether
or not target features should be enabled. This was done in a
platform-specific manner, however, which means that I can no longer
reliably take the fuzz reproducer cases from oss-fuzz and reproduce them
locally on an aarch64 machine. This commit fixes this problem by
unconditionally pulling bytes from the input for fuzz features,
irrespective of the host platform. Features are then discarded if
they're not applicable.
This commit is contained in:
Alex Crichton
2022-02-17 12:07:02 -06:00
committed by GitHub
parent e572198f85
commit 37b0fd482d

View File

@@ -671,33 +671,62 @@ impl<'a> Arbitrary<'a> for CodegenSettings {
// Helper macro to enable clif features based on what the native host // Helper macro to enable clif features based on what the native host
// supports. If the input says to enable a feature and the host doesn't // supports. If the input says to enable a feature and the host doesn't
// support it then that test case is rejected with a warning. // support it then that test case is rejected with a warning.
//
// Note that this specifically consumes bytes from the fuzz input for
// features for all targets, discarding anything which isn't applicable
// to the current target. The theory behind this is that most fuzz bugs
// won't be related to this feature selection so by consistently
// consuming input irrespective of the current platform reproducing fuzz
// bugs should be easier between different architectures.
macro_rules! target_features { macro_rules! target_features {
( (
test:$test:ident, $(
$(std: $std:tt => clif: $clif:tt $(ratio: $a:tt in $b:tt)?,)* $arch:tt => {
test:$test:ident,
$(std: $std:tt => clif: $clif:tt $(ratio: $a:tt in $b:tt)?,)*
},
)*
) => ({ ) => ({
let mut flags = Vec::new(); let mut flags = Vec::new();
$( $( // for each `$arch`
let (low, hi) = (1, 2); $( // for each `$std`/`$clif` pair
$(let (low, hi) = ($a, $b);)? // Use the input to generate whether `$clif` will be
let enable = u.ratio(low, hi)?; // enabled. By default this is a 1 in 2 chance but each
if enable && !std::$test!($std) { // feature supports a custom ratio as well which shadows
log::error!("want to enable clif `{}` but host doesn't support it", // the (low, hi)
$clif); let (low, hi) = (1, 2);
return Err(arbitrary::Error::EmptyChoose) $(let (low, hi) = ($a, $b);)?
} let enable = u.ratio(low, hi)?;
flags.push((
$clif.to_string(), // If we're actually on the relevant platform and the
enable.to_string(), // feature is enabled be sure to check that this host
)); // supports it. If the host doesn't support it then
// print a warning and return an error because this fuzz
// input must be discarded.
#[cfg(target_arch = $arch)]
if enable && !std::$test!($std) {
log::error!("want to enable clif `{}` but host doesn't support it",
$clif);
return Err(arbitrary::Error::EmptyChoose)
}
// And finally actually push the feature into the set of
// flags to enable, but only if we're on the right
// architecture.
if cfg!(target_arch = $arch) {
flags.push((
$clif.to_string(),
enable.to_string(),
));
}
)*
)* )*
flags flags
}) })
} }
#[cfg(target_arch = "x86_64")] if u.ratio(1, 10)? {
{ let flags = target_features! {
if u.ratio(1, 10)? { "x86_64" => {
let flags = target_features! {
test: is_x86_feature_detected, test: is_x86_feature_detected,
// These features are considered to be baseline required by // These features are considered to be baseline required by
@@ -724,12 +753,12 @@ impl<'a> Arbitrary<'a> for CodegenSettings {
std:"avx512f" => clif:"has_avx512f" ratio: 1 in 1000, std:"avx512f" => clif:"has_avx512f" ratio: 1 in 1000,
std:"avx512vl" => clif:"has_avx512vl" ratio: 1 in 1000, std:"avx512vl" => clif:"has_avx512vl" ratio: 1 in 1000,
std:"avx512vbmi" => clif:"has_avx512vbmi" ratio: 1 in 1000, std:"avx512vbmi" => clif:"has_avx512vbmi" ratio: 1 in 1000,
}; },
return Ok(CodegenSettings::Target { };
target: target_lexicon::Triple::host().to_string(), return Ok(CodegenSettings::Target {
flags, target: target_lexicon::Triple::host().to_string(),
}); flags,
} });
} }
Ok(CodegenSettings::Native) Ok(CodegenSettings::Native)
} }