Fixed stackifier fuzzbug
This commit is contained in:
parent
b84509c938
commit
ca0570c0d0
|
@ -13,6 +13,7 @@ cargo-fuzz = true
|
||||||
libfuzzer-sys = "0.4"
|
libfuzzer-sys = "0.4"
|
||||||
wasm-smith = "0.8"
|
wasm-smith = "0.8"
|
||||||
env_logger = "0.9"
|
env_logger = "0.9"
|
||||||
|
log = "0.4"
|
||||||
|
|
||||||
[dependencies.waffle]
|
[dependencies.waffle]
|
||||||
path = ".."
|
path = ".."
|
||||||
|
|
|
@ -5,6 +5,7 @@ use waffle::Module;
|
||||||
|
|
||||||
fuzz_target!(|module: wasm_smith::Module| {
|
fuzz_target!(|module: wasm_smith::Module| {
|
||||||
let _ = env_logger::try_init();
|
let _ = env_logger::try_init();
|
||||||
|
log::debug!("original module: {:?}", module);
|
||||||
let orig_bytes = module.to_bytes();
|
let orig_bytes = module.to_bytes();
|
||||||
let parsed_module = Module::from_wasm_bytes(&orig_bytes[..]).unwrap();
|
let parsed_module = Module::from_wasm_bytes(&orig_bytes[..]).unwrap();
|
||||||
let _ = parsed_module.to_wasm_bytes();
|
let _ = parsed_module.to_wasm_bytes();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
//! IR-to-Wasm transform.
|
//! IR-to-Wasm transform.
|
||||||
|
|
||||||
use crate::{cfg::CFGInfo, ir::*};
|
use crate::{cfg::CFGInfo, ir::*};
|
||||||
|
use log::debug;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Shape {
|
pub enum Shape {
|
||||||
|
@ -13,7 +14,7 @@ pub enum Shape {
|
||||||
/// Index in RPO.
|
/// Index in RPO.
|
||||||
type OrderedBlockId = usize;
|
type OrderedBlockId = usize;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
enum Region {
|
enum Region {
|
||||||
/// Forward-branch region. Extends from end (just prior to
|
/// Forward-branch region. Extends from end (just prior to
|
||||||
/// terminator) of first block to just before second block. Can be
|
/// terminator) of first block to just before second block. Can be
|
||||||
|
@ -78,10 +79,14 @@ impl Region {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Shape {
|
impl Shape {
|
||||||
pub fn compute(_f: &FunctionBody, cfg: &CFGInfo) -> Self {
|
pub fn compute(f: &FunctionBody, cfg: &CFGInfo) -> Self {
|
||||||
// Process all non-contiguous edges in RPO block order. For
|
// Process all non-contiguous edges in RPO block order. For
|
||||||
// forward and backward edges, emit Regions.
|
// forward and backward edges, emit Regions.
|
||||||
|
debug!("f = {:?}", f);
|
||||||
|
debug!("cfg = {:?}", cfg);
|
||||||
let order = cfg.rpo();
|
let order = cfg.rpo();
|
||||||
|
debug!("rpo = {:?}", order);
|
||||||
|
|
||||||
assert_eq!(order[0], 0); // Entry block should come first.
|
assert_eq!(order[0], 0); // Entry block should come first.
|
||||||
let mut regions = vec![];
|
let mut regions = vec![];
|
||||||
for (block_pos, &block) in order.iter().enumerate() {
|
for (block_pos, &block) in order.iter().enumerate() {
|
||||||
|
@ -102,6 +107,7 @@ impl Shape {
|
||||||
// regions where necessary and duplicating where we find
|
// regions where necessary and duplicating where we find
|
||||||
// irreducible control flow.
|
// irreducible control flow.
|
||||||
regions.sort_by_key(|r| r.start());
|
regions.sort_by_key(|r| r.start());
|
||||||
|
debug!("regions = {:?}", regions);
|
||||||
|
|
||||||
// Examine each region in the sequence, determining whether it
|
// Examine each region in the sequence, determining whether it
|
||||||
// is properly nested with respect to all overlapping regions.
|
// is properly nested with respect to all overlapping regions.
|
||||||
|
@ -110,16 +116,23 @@ impl Shape {
|
||||||
i += 1;
|
i += 1;
|
||||||
let prev = regions[i - 1];
|
let prev = regions[i - 1];
|
||||||
let this = regions[i];
|
let this = regions[i];
|
||||||
|
debug!("examining: {:?} -> {:?}", prev, this);
|
||||||
|
|
||||||
if !prev.overlaps(&this) {
|
if !prev.overlaps(&this) {
|
||||||
|
debug!(" -> no overlap");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
match (prev, this) {
|
match (prev, this) {
|
||||||
|
(a, b) if a == b => {
|
||||||
|
regions.remove(i);
|
||||||
|
i -= 1;
|
||||||
|
}
|
||||||
(Region::Backward(a, b), Region::Backward(c, d)) if a == c => {
|
(Region::Backward(a, b), Region::Backward(c, d)) if a == c => {
|
||||||
// Merge by extending end.
|
// Merge by extending end.
|
||||||
regions[i - 1] = Region::Backward(a, std::cmp::max(b, d));
|
regions[i - 1] = Region::Backward(a, std::cmp::max(b, d));
|
||||||
regions.remove(i);
|
regions.remove(i);
|
||||||
|
i -= 1;
|
||||||
}
|
}
|
||||||
(Region::Backward(a, b), Region::Backward(c, _d)) if a < c && c <= b => {
|
(Region::Backward(a, b), Region::Backward(c, _d)) if a < c && c <= b => {
|
||||||
panic!("Irreducible CFG");
|
panic!("Irreducible CFG");
|
||||||
|
@ -137,6 +150,7 @@ impl Shape {
|
||||||
// Merge.
|
// Merge.
|
||||||
regions[i - 1] = Region::Forward(std::cmp::min(a, c), b);
|
regions[i - 1] = Region::Forward(std::cmp::min(a, c), b);
|
||||||
regions.remove(i);
|
regions.remove(i);
|
||||||
|
i -= 1;
|
||||||
}
|
}
|
||||||
(Region::Forward(a, b), Region::Forward(c, d)) if a <= c && b < d => {
|
(Region::Forward(a, b), Region::Forward(c, d)) if a <= c && b < d => {
|
||||||
regions[i - 1] = Region::Forward(a, d);
|
regions[i - 1] = Region::Forward(a, d);
|
||||||
|
@ -146,6 +160,8 @@ impl Shape {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug!("after stackifying: {:?}", regions);
|
||||||
|
|
||||||
// Ensure the regions properly nest.
|
// Ensure the regions properly nest.
|
||||||
let mut stack: Vec<Region> = vec![];
|
let mut stack: Vec<Region> = vec![];
|
||||||
for region in ®ions {
|
for region in ®ions {
|
||||||
|
@ -167,6 +183,10 @@ impl Shape {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: make regions properly nest by doing replication right
|
||||||
|
// as we compute the RPO. Track the current nesting, and
|
||||||
|
// traverse more than once if needed.
|
||||||
|
|
||||||
Shape::None
|
Shape::None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue