Check for global variable deref cycles in the verifier.
This commit is contained in:
16
cranelift/filetests/verifier/memory.cton
Normal file
16
cranelift/filetests/verifier/memory.cton
Normal file
@@ -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
|
||||
}
|
||||
@@ -184,6 +184,11 @@ impl<K, V> SparseMap<K, V>
|
||||
pub fn values(&self) -> slice::Iter<V> {
|
||||
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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user