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> {
|
pub fn values(&self) -> slice::Iter<V> {
|
||||||
self.dense.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.
|
/// Iterating over the elements of a set.
|
||||||
|
|||||||
@@ -40,6 +40,10 @@
|
|||||||
//! - All return instructions must have return value operands matching the current
|
//! - All return instructions must have return value operands matching the current
|
||||||
//! function signature.
|
//! function signature.
|
||||||
//!
|
//!
|
||||||
|
//! Global variables
|
||||||
|
//!
|
||||||
|
//! - Detect cycles in deref(base) declarations.
|
||||||
|
//!
|
||||||
//! TODO:
|
//! TODO:
|
||||||
//! Ad hoc checking
|
//! Ad hoc checking
|
||||||
//!
|
//!
|
||||||
@@ -52,13 +56,16 @@
|
|||||||
//! - Swizzle and shuffle instructions take a variable number of lane arguments. The number
|
//! - 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.
|
//! of arguments must match the destination type, and the lane indexes must be in range.
|
||||||
|
|
||||||
|
use dbg::DisplayList;
|
||||||
use dominator_tree::DominatorTree;
|
use dominator_tree::DominatorTree;
|
||||||
use flowgraph::ControlFlowGraph;
|
use flowgraph::ControlFlowGraph;
|
||||||
|
use ir;
|
||||||
use ir::entities::AnyEntity;
|
use ir::entities::AnyEntity;
|
||||||
use ir::instructions::{InstructionFormat, BranchInfo, ResolvedConstraint, CallInfo};
|
use ir::instructions::{InstructionFormat, BranchInfo, ResolvedConstraint, CallInfo};
|
||||||
use ir::{types, Function, ValueDef, Ebb, Inst, SigRef, FuncRef, ValueList, JumpTable, StackSlot,
|
use ir::{types, Function, ValueDef, Ebb, Inst, SigRef, FuncRef, ValueList, JumpTable, StackSlot,
|
||||||
StackSlotKind, GlobalVar, Value, Type, Opcode, ValueLoc, ArgumentLoc};
|
StackSlotKind, GlobalVar, Value, Type, Opcode, ValueLoc, ArgumentLoc};
|
||||||
use isa::TargetIsa;
|
use isa::TargetIsa;
|
||||||
|
use sparse_map::SparseSet;
|
||||||
use std::error as std_error;
|
use std::error as std_error;
|
||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
use std::result;
|
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 {
|
fn ebb_integrity(&self, ebb: Ebb, inst: Inst) -> Result {
|
||||||
|
|
||||||
let is_terminator = self.func.dfg[inst].opcode().is_terminator();
|
let is_terminator = self.func.dfg[inst].opcode().is_terminator();
|
||||||
@@ -845,6 +873,7 @@ impl<'a> Verifier<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&self) -> Result {
|
pub fn run(&self) -> Result {
|
||||||
|
self.verify_global_vars()?;
|
||||||
self.typecheck_entry_block_arguments()?;
|
self.typecheck_entry_block_arguments()?;
|
||||||
for ebb in self.func.layout.ebbs() {
|
for ebb in self.func.layout.ebbs() {
|
||||||
for inst in self.func.layout.ebb_insts(ebb) {
|
for inst in self.func.layout.ebb_insts(ebb) {
|
||||||
|
|||||||
Reference in New Issue
Block a user