diff --git a/cranelift/filetests/verifier/memory.cton b/cranelift/filetests/verifier/memory.cton new file mode 100644 index 0000000000..46bf18d636 --- /dev/null +++ b/cranelift/filetests/verifier/memory.cton @@ -0,0 +1,16 @@ +test verifier + +function %deref_cycle() { + gv1 = deref(gv2)-32 ; error: deref cycle: [gv0, gv1] + gv2 = deref(gv1) + +ebb1: + return +} + +function %self_cycle() { + gv0 = deref(gv0)-32 ; error: deref cycle: [gv0] + +ebb1: + return +} diff --git a/lib/cretonne/src/sparse_map.rs b/lib/cretonne/src/sparse_map.rs index b1e844b618..c1a8bf5480 100644 --- a/lib/cretonne/src/sparse_map.rs +++ b/lib/cretonne/src/sparse_map.rs @@ -184,6 +184,11 @@ impl SparseMap pub fn values(&self) -> slice::Iter { self.dense.iter() } + + /// Get the values as a slice. + pub fn as_slice(&self) -> &[V] { + self.dense.as_slice() + } } /// Iterating over the elements of a set. diff --git a/lib/cretonne/src/verifier/mod.rs b/lib/cretonne/src/verifier/mod.rs index af8bcd0c7e..0995449362 100644 --- a/lib/cretonne/src/verifier/mod.rs +++ b/lib/cretonne/src/verifier/mod.rs @@ -40,6 +40,10 @@ //! - All return instructions must have return value operands matching the current //! function signature. //! +//! Global variables +//! +//! - Detect cycles in deref(base) declarations. +//! //! TODO: //! Ad hoc checking //! @@ -52,13 +56,16 @@ //! - Swizzle and shuffle instructions take a variable number of lane arguments. The number //! of arguments must match the destination type, and the lane indexes must be in range. +use dbg::DisplayList; use dominator_tree::DominatorTree; use flowgraph::ControlFlowGraph; +use ir; use ir::entities::AnyEntity; use ir::instructions::{InstructionFormat, BranchInfo, ResolvedConstraint, CallInfo}; use ir::{types, Function, ValueDef, Ebb, Inst, SigRef, FuncRef, ValueList, JumpTable, StackSlot, StackSlotKind, GlobalVar, Value, Type, Opcode, ValueLoc, ArgumentLoc}; use isa::TargetIsa; +use sparse_map::SparseSet; use std::error as std_error; use std::fmt::{self, Display, Formatter}; use std::result; @@ -150,6 +157,27 @@ impl<'a> Verifier<'a> { } } + // Check for cycles in the global variable declarations. + fn verify_global_vars(&self) -> Result { + let mut seen = SparseSet::new(); + + for gv in self.func.global_vars.keys() { + seen.clear(); + seen.insert(gv); + + let mut cur = gv; + while let &ir::GlobalVarData::Deref { base, .. } = &self.func.global_vars[cur] { + if seen.insert(base).is_some() { + return err!(gv, "deref cycle: {}", DisplayList(seen.as_slice())); + } + + cur = base; + } + } + + Ok(()) + } + fn ebb_integrity(&self, ebb: Ebb, inst: Inst) -> Result { let is_terminator = self.func.dfg[inst].opcode().is_terminator(); @@ -845,6 +873,7 @@ impl<'a> Verifier<'a> { } pub fn run(&self) -> Result { + self.verify_global_vars()?; self.typecheck_entry_block_arguments()?; for ebb in self.func.layout.ebbs() { for inst in self.func.layout.ebb_insts(ebb) {