Check for global variable deref cycles in the verifier.

This commit is contained in:
Jakob Stoklund Olesen
2017-08-17 15:11:35 -07:00
parent bf4ae3bb2e
commit 5566c99dba
3 changed files with 50 additions and 0 deletions

View 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
}

View File

@@ -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.

View File

@@ -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) {