cranelift-wasm: Better track reachability after translating loads (#5511)
We can sometimes statically determine that a given load will unconditionally trap. When this happens, we emit an unconditional trap, and we need to stop adding new instructions to the block. This commit introduces a `Reachability<T>` type that is like `Option<T>` but specifically for communicating reachability and is marked `must_use` to receivers to handle transitions from reachable to unreachable states. Additionally, adds handling of reachable -> unreachable state transitions to some SIMD op translations that weren't checking for it. Fixes #5455 Fixes #5456
This commit is contained in:
@@ -97,8 +97,8 @@ use std::convert::TryFrom;
|
|||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
use wasmparser::{FuncValidator, MemArg, Operator, WasmModuleResources};
|
use wasmparser::{FuncValidator, MemArg, Operator, WasmModuleResources};
|
||||||
|
|
||||||
/// Given an `Option<T>`, unwrap the inner `T` or, if the option is `None`, set
|
/// Given a `Reachability<T>`, unwrap the inner `T` or, when unreachable, set
|
||||||
/// the state to unreachable and return.
|
/// `state.reachable = false` and return.
|
||||||
///
|
///
|
||||||
/// Used in combination with calling `prepare_addr` and `prepare_atomic_addr`
|
/// Used in combination with calling `prepare_addr` and `prepare_atomic_addr`
|
||||||
/// when we can statically determine that a Wasm access will unconditionally
|
/// when we can statically determine that a Wasm access will unconditionally
|
||||||
@@ -106,8 +106,8 @@ use wasmparser::{FuncValidator, MemArg, Operator, WasmModuleResources};
|
|||||||
macro_rules! unwrap_or_return_unreachable_state {
|
macro_rules! unwrap_or_return_unreachable_state {
|
||||||
($state:ident, $value:expr) => {
|
($state:ident, $value:expr) => {
|
||||||
match $value {
|
match $value {
|
||||||
Some(x) => x,
|
Reachability::Reachable(x) => x,
|
||||||
None => {
|
Reachability::Unreachable => {
|
||||||
$state.reachable = false;
|
$state.reachable = false;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@@ -670,49 +670,94 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
* The memory base address is provided by the environment.
|
* The memory base address is provided by the environment.
|
||||||
************************************************************************************/
|
************************************************************************************/
|
||||||
Operator::I32Load8U { memarg } => {
|
Operator::I32Load8U { memarg } => {
|
||||||
translate_load(memarg, ir::Opcode::Uload8, I32, builder, state, environ)?;
|
unwrap_or_return_unreachable_state!(
|
||||||
|
state,
|
||||||
|
translate_load(memarg, ir::Opcode::Uload8, I32, builder, state, environ)?
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Operator::I32Load16U { memarg } => {
|
Operator::I32Load16U { memarg } => {
|
||||||
translate_load(memarg, ir::Opcode::Uload16, I32, builder, state, environ)?;
|
unwrap_or_return_unreachable_state!(
|
||||||
|
state,
|
||||||
|
translate_load(memarg, ir::Opcode::Uload16, I32, builder, state, environ)?
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Operator::I32Load8S { memarg } => {
|
Operator::I32Load8S { memarg } => {
|
||||||
translate_load(memarg, ir::Opcode::Sload8, I32, builder, state, environ)?;
|
unwrap_or_return_unreachable_state!(
|
||||||
|
state,
|
||||||
|
translate_load(memarg, ir::Opcode::Sload8, I32, builder, state, environ)?
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Operator::I32Load16S { memarg } => {
|
Operator::I32Load16S { memarg } => {
|
||||||
translate_load(memarg, ir::Opcode::Sload16, I32, builder, state, environ)?;
|
unwrap_or_return_unreachable_state!(
|
||||||
|
state,
|
||||||
|
translate_load(memarg, ir::Opcode::Sload16, I32, builder, state, environ)?
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Operator::I64Load8U { memarg } => {
|
Operator::I64Load8U { memarg } => {
|
||||||
translate_load(memarg, ir::Opcode::Uload8, I64, builder, state, environ)?;
|
unwrap_or_return_unreachable_state!(
|
||||||
|
state,
|
||||||
|
translate_load(memarg, ir::Opcode::Uload8, I64, builder, state, environ)?
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Operator::I64Load16U { memarg } => {
|
Operator::I64Load16U { memarg } => {
|
||||||
translate_load(memarg, ir::Opcode::Uload16, I64, builder, state, environ)?;
|
unwrap_or_return_unreachable_state!(
|
||||||
|
state,
|
||||||
|
translate_load(memarg, ir::Opcode::Uload16, I64, builder, state, environ)?
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Operator::I64Load8S { memarg } => {
|
Operator::I64Load8S { memarg } => {
|
||||||
translate_load(memarg, ir::Opcode::Sload8, I64, builder, state, environ)?;
|
unwrap_or_return_unreachable_state!(
|
||||||
|
state,
|
||||||
|
translate_load(memarg, ir::Opcode::Sload8, I64, builder, state, environ)?
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Operator::I64Load16S { memarg } => {
|
Operator::I64Load16S { memarg } => {
|
||||||
translate_load(memarg, ir::Opcode::Sload16, I64, builder, state, environ)?;
|
unwrap_or_return_unreachable_state!(
|
||||||
|
state,
|
||||||
|
translate_load(memarg, ir::Opcode::Sload16, I64, builder, state, environ)?
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Operator::I64Load32S { memarg } => {
|
Operator::I64Load32S { memarg } => {
|
||||||
translate_load(memarg, ir::Opcode::Sload32, I64, builder, state, environ)?;
|
unwrap_or_return_unreachable_state!(
|
||||||
|
state,
|
||||||
|
translate_load(memarg, ir::Opcode::Sload32, I64, builder, state, environ)?
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Operator::I64Load32U { memarg } => {
|
Operator::I64Load32U { memarg } => {
|
||||||
translate_load(memarg, ir::Opcode::Uload32, I64, builder, state, environ)?;
|
unwrap_or_return_unreachable_state!(
|
||||||
|
state,
|
||||||
|
translate_load(memarg, ir::Opcode::Uload32, I64, builder, state, environ)?
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Operator::I32Load { memarg } => {
|
Operator::I32Load { memarg } => {
|
||||||
translate_load(memarg, ir::Opcode::Load, I32, builder, state, environ)?;
|
unwrap_or_return_unreachable_state!(
|
||||||
|
state,
|
||||||
|
translate_load(memarg, ir::Opcode::Load, I32, builder, state, environ)?
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Operator::F32Load { memarg } => {
|
Operator::F32Load { memarg } => {
|
||||||
translate_load(memarg, ir::Opcode::Load, F32, builder, state, environ)?;
|
unwrap_or_return_unreachable_state!(
|
||||||
|
state,
|
||||||
|
translate_load(memarg, ir::Opcode::Load, F32, builder, state, environ)?
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Operator::I64Load { memarg } => {
|
Operator::I64Load { memarg } => {
|
||||||
translate_load(memarg, ir::Opcode::Load, I64, builder, state, environ)?;
|
unwrap_or_return_unreachable_state!(
|
||||||
|
state,
|
||||||
|
translate_load(memarg, ir::Opcode::Load, I64, builder, state, environ)?
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Operator::F64Load { memarg } => {
|
Operator::F64Load { memarg } => {
|
||||||
translate_load(memarg, ir::Opcode::Load, F64, builder, state, environ)?;
|
unwrap_or_return_unreachable_state!(
|
||||||
|
state,
|
||||||
|
translate_load(memarg, ir::Opcode::Load, F64, builder, state, environ)?
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Operator::V128Load { memarg } => {
|
Operator::V128Load { memarg } => {
|
||||||
translate_load(memarg, ir::Opcode::Load, I8X16, builder, state, environ)?;
|
unwrap_or_return_unreachable_state!(
|
||||||
|
state,
|
||||||
|
translate_load(memarg, ir::Opcode::Load, I8X16, builder, state, environ)?
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Operator::V128Load8x8S { memarg } => {
|
Operator::V128Load8x8S { memarg } => {
|
||||||
let (flags, base) = unwrap_or_return_unreachable_state!(
|
let (flags, base) = unwrap_or_return_unreachable_state!(
|
||||||
@@ -1502,6 +1547,8 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
| Operator::V128Load16Splat { memarg }
|
| Operator::V128Load16Splat { memarg }
|
||||||
| Operator::V128Load32Splat { memarg }
|
| Operator::V128Load32Splat { memarg }
|
||||||
| Operator::V128Load64Splat { memarg } => {
|
| Operator::V128Load64Splat { memarg } => {
|
||||||
|
unwrap_or_return_unreachable_state!(
|
||||||
|
state,
|
||||||
translate_load(
|
translate_load(
|
||||||
memarg,
|
memarg,
|
||||||
ir::Opcode::Load,
|
ir::Opcode::Load,
|
||||||
@@ -1509,11 +1556,14 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
builder,
|
builder,
|
||||||
state,
|
state,
|
||||||
environ,
|
environ,
|
||||||
)?;
|
)?
|
||||||
|
);
|
||||||
let splatted = builder.ins().splat(type_of(op), state.pop1());
|
let splatted = builder.ins().splat(type_of(op), state.pop1());
|
||||||
state.push1(splatted)
|
state.push1(splatted)
|
||||||
}
|
}
|
||||||
Operator::V128Load32Zero { memarg } | Operator::V128Load64Zero { memarg } => {
|
Operator::V128Load32Zero { memarg } | Operator::V128Load64Zero { memarg } => {
|
||||||
|
unwrap_or_return_unreachable_state!(
|
||||||
|
state,
|
||||||
translate_load(
|
translate_load(
|
||||||
memarg,
|
memarg,
|
||||||
ir::Opcode::Load,
|
ir::Opcode::Load,
|
||||||
@@ -1521,7 +1571,8 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
builder,
|
builder,
|
||||||
state,
|
state,
|
||||||
environ,
|
environ,
|
||||||
)?;
|
)?
|
||||||
|
);
|
||||||
let as_vector = builder.ins().scalar_to_vector(type_of(op), state.pop1());
|
let as_vector = builder.ins().scalar_to_vector(type_of(op), state.pop1());
|
||||||
state.push1(as_vector)
|
state.push1(as_vector)
|
||||||
}
|
}
|
||||||
@@ -1530,6 +1581,8 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
| Operator::V128Load32Lane { memarg, lane }
|
| Operator::V128Load32Lane { memarg, lane }
|
||||||
| Operator::V128Load64Lane { memarg, lane } => {
|
| Operator::V128Load64Lane { memarg, lane } => {
|
||||||
let vector = pop1_with_bitcast(state, type_of(op), builder);
|
let vector = pop1_with_bitcast(state, type_of(op), builder);
|
||||||
|
unwrap_or_return_unreachable_state!(
|
||||||
|
state,
|
||||||
translate_load(
|
translate_load(
|
||||||
memarg,
|
memarg,
|
||||||
ir::Opcode::Load,
|
ir::Opcode::Load,
|
||||||
@@ -1537,7 +1590,8 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
builder,
|
builder,
|
||||||
state,
|
state,
|
||||||
environ,
|
environ,
|
||||||
)?;
|
)?
|
||||||
|
);
|
||||||
let replacement = state.pop1();
|
let replacement = state.pop1();
|
||||||
state.push1(builder.ins().insertlane(vector, replacement, *lane))
|
state.push1(builder.ins().insertlane(vector, replacement, *lane))
|
||||||
}
|
}
|
||||||
@@ -2239,7 +2293,7 @@ fn prepare_addr<FE>(
|
|||||||
builder: &mut FunctionBuilder,
|
builder: &mut FunctionBuilder,
|
||||||
state: &mut FuncTranslationState,
|
state: &mut FuncTranslationState,
|
||||||
environ: &mut FE,
|
environ: &mut FE,
|
||||||
) -> WasmResult<Option<(MemFlags, Value)>>
|
) -> WasmResult<Reachability<(MemFlags, Value)>>
|
||||||
where
|
where
|
||||||
FE: FuncEnvironment + ?Sized,
|
FE: FuncEnvironment + ?Sized,
|
||||||
{
|
{
|
||||||
@@ -2372,8 +2426,8 @@ where
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
let addr = match addr {
|
let addr = match addr {
|
||||||
None => return Ok(None),
|
Reachability::Unreachable => return Ok(Reachability::Unreachable),
|
||||||
Some(a) => a,
|
Reachability::Reachable(a) => a,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Note that we don't set `is_aligned` here, even if the load instruction's
|
// Note that we don't set `is_aligned` here, even if the load instruction's
|
||||||
@@ -2389,7 +2443,7 @@ where
|
|||||||
// vmctx, stack) accesses.
|
// vmctx, stack) accesses.
|
||||||
flags.set_heap();
|
flags.set_heap();
|
||||||
|
|
||||||
Ok(Some((flags, addr)))
|
Ok(Reachability::Reachable((flags, addr)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn align_atomic_addr(
|
fn align_atomic_addr(
|
||||||
@@ -2436,12 +2490,30 @@ fn prepare_atomic_addr<FE: FuncEnvironment + ?Sized>(
|
|||||||
builder: &mut FunctionBuilder,
|
builder: &mut FunctionBuilder,
|
||||||
state: &mut FuncTranslationState,
|
state: &mut FuncTranslationState,
|
||||||
environ: &mut FE,
|
environ: &mut FE,
|
||||||
) -> WasmResult<Option<(MemFlags, Value)>> {
|
) -> WasmResult<Reachability<(MemFlags, Value)>> {
|
||||||
align_atomic_addr(memarg, loaded_bytes, builder, state);
|
align_atomic_addr(memarg, loaded_bytes, builder, state);
|
||||||
prepare_addr(memarg, loaded_bytes, builder, state, environ)
|
prepare_addr(memarg, loaded_bytes, builder, state, environ)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Like `Option<T>` but specifically for passing information about transitions
|
||||||
|
/// from reachable to unreachable state and the like from callees to callers.
|
||||||
|
///
|
||||||
|
/// Marked `must_use` to force callers to update
|
||||||
|
/// `FuncTranslationState::reachable` as necessary.
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
#[must_use]
|
||||||
|
pub enum Reachability<T> {
|
||||||
|
/// The Wasm execution state is reachable, here is a `T`.
|
||||||
|
Reachable(T),
|
||||||
|
/// The Wasm execution state has been determined to be statically
|
||||||
|
/// unreachable. It is the receiver of this value's responsibility to update
|
||||||
|
/// `FuncTranslationState::reachable` as necessary.
|
||||||
|
Unreachable,
|
||||||
|
}
|
||||||
|
|
||||||
/// Translate a load instruction.
|
/// Translate a load instruction.
|
||||||
|
///
|
||||||
|
/// Returns the execution state's reachability after the load is translated.
|
||||||
fn translate_load<FE: FuncEnvironment + ?Sized>(
|
fn translate_load<FE: FuncEnvironment + ?Sized>(
|
||||||
memarg: &MemArg,
|
memarg: &MemArg,
|
||||||
opcode: ir::Opcode,
|
opcode: ir::Opcode,
|
||||||
@@ -2449,22 +2521,22 @@ fn translate_load<FE: FuncEnvironment + ?Sized>(
|
|||||||
builder: &mut FunctionBuilder,
|
builder: &mut FunctionBuilder,
|
||||||
state: &mut FuncTranslationState,
|
state: &mut FuncTranslationState,
|
||||||
environ: &mut FE,
|
environ: &mut FE,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<Reachability<()>> {
|
||||||
let (flags, base) = unwrap_or_return_unreachable_state!(
|
let (flags, base) = match prepare_addr(
|
||||||
state,
|
|
||||||
prepare_addr(
|
|
||||||
memarg,
|
memarg,
|
||||||
mem_op_size(opcode, result_ty),
|
mem_op_size(opcode, result_ty),
|
||||||
builder,
|
builder,
|
||||||
state,
|
state,
|
||||||
environ,
|
environ,
|
||||||
)?
|
)? {
|
||||||
);
|
Reachability::Unreachable => return Ok(Reachability::Unreachable),
|
||||||
|
Reachability::Reachable((f, b)) => (f, b),
|
||||||
|
};
|
||||||
let (load, dfg) = builder
|
let (load, dfg) = builder
|
||||||
.ins()
|
.ins()
|
||||||
.Load(opcode, result_ty, flags, Offset32::new(0), base);
|
.Load(opcode, result_ty, flags, Offset32::new(0), base);
|
||||||
state.push1(dfg.first_result(load));
|
state.push1(dfg.first_result(load));
|
||||||
Ok(())
|
Ok(Reachability::Reachable(()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Translate a store instruction.
|
/// Translate a store instruction.
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
//!
|
//!
|
||||||
//! bounds check the memory access and translate it into a native memory access.
|
//! bounds check the memory access and translate it into a native memory access.
|
||||||
|
|
||||||
|
use super::Reachability;
|
||||||
use crate::{FuncEnvironment, HeapData, HeapStyle};
|
use crate::{FuncEnvironment, HeapData, HeapStyle};
|
||||||
use cranelift_codegen::{
|
use cranelift_codegen::{
|
||||||
cursor::{Cursor, FuncCursor},
|
cursor::{Cursor, FuncCursor},
|
||||||
@@ -15,6 +16,7 @@ use cranelift_codegen::{
|
|||||||
};
|
};
|
||||||
use cranelift_frontend::FunctionBuilder;
|
use cranelift_frontend::FunctionBuilder;
|
||||||
use wasmtime_types::WasmResult;
|
use wasmtime_types::WasmResult;
|
||||||
|
use Reachability::*;
|
||||||
|
|
||||||
/// Helper used to emit bounds checks (as necessary) and compute the native
|
/// Helper used to emit bounds checks (as necessary) and compute the native
|
||||||
/// address of a heap access.
|
/// address of a heap access.
|
||||||
@@ -31,7 +33,7 @@ pub fn bounds_check_and_compute_addr<Env>(
|
|||||||
offset: u32,
|
offset: u32,
|
||||||
// Static size of the heap access.
|
// Static size of the heap access.
|
||||||
access_size: u8,
|
access_size: u8,
|
||||||
) -> WasmResult<Option<ir::Value>>
|
) -> WasmResult<Reachability<ir::Value>>
|
||||||
where
|
where
|
||||||
Env: FuncEnvironment + ?Sized,
|
Env: FuncEnvironment + ?Sized,
|
||||||
{
|
{
|
||||||
@@ -76,7 +78,7 @@ where
|
|||||||
// checks.
|
// checks.
|
||||||
HeapStyle::Dynamic { bound_gv } if offset_and_size == 1 && spectre_mitigations_enabled => {
|
HeapStyle::Dynamic { bound_gv } if offset_and_size == 1 && spectre_mitigations_enabled => {
|
||||||
let bound = builder.ins().global_value(env.pointer_type(), bound_gv);
|
let bound = builder.ins().global_value(env.pointer_type(), bound_gv);
|
||||||
Some(compute_addr(
|
Reachable(compute_addr(
|
||||||
&mut builder.cursor(),
|
&mut builder.cursor(),
|
||||||
heap,
|
heap,
|
||||||
env.pointer_type(),
|
env.pointer_type(),
|
||||||
@@ -96,7 +98,7 @@ where
|
|||||||
.ins()
|
.ins()
|
||||||
.icmp(IntCC::UnsignedGreaterThanOrEqual, index, bound);
|
.icmp(IntCC::UnsignedGreaterThanOrEqual, index, bound);
|
||||||
builder.ins().trapnz(oob, ir::TrapCode::HeapOutOfBounds);
|
builder.ins().trapnz(oob, ir::TrapCode::HeapOutOfBounds);
|
||||||
Some(compute_addr(
|
Reachable(compute_addr(
|
||||||
&mut builder.cursor(),
|
&mut builder.cursor(),
|
||||||
heap,
|
heap,
|
||||||
env.pointer_type(),
|
env.pointer_type(),
|
||||||
@@ -120,7 +122,7 @@ where
|
|||||||
{
|
{
|
||||||
let bound = builder.ins().global_value(env.pointer_type(), bound_gv);
|
let bound = builder.ins().global_value(env.pointer_type(), bound_gv);
|
||||||
let adjusted_bound = builder.ins().iadd_imm(bound, -(offset_and_size as i64));
|
let adjusted_bound = builder.ins().iadd_imm(bound, -(offset_and_size as i64));
|
||||||
Some(compute_addr(
|
Reachable(compute_addr(
|
||||||
&mut builder.cursor(),
|
&mut builder.cursor(),
|
||||||
heap,
|
heap,
|
||||||
env.pointer_type(),
|
env.pointer_type(),
|
||||||
@@ -142,7 +144,7 @@ where
|
|||||||
.ins()
|
.ins()
|
||||||
.icmp(IntCC::UnsignedGreaterThan, index, adjusted_bound);
|
.icmp(IntCC::UnsignedGreaterThan, index, adjusted_bound);
|
||||||
builder.ins().trapnz(oob, ir::TrapCode::HeapOutOfBounds);
|
builder.ins().trapnz(oob, ir::TrapCode::HeapOutOfBounds);
|
||||||
Some(compute_addr(
|
Reachable(compute_addr(
|
||||||
&mut builder.cursor(),
|
&mut builder.cursor(),
|
||||||
heap,
|
heap,
|
||||||
env.pointer_type(),
|
env.pointer_type(),
|
||||||
@@ -169,7 +171,7 @@ where
|
|||||||
ir::TrapCode::HeapOutOfBounds,
|
ir::TrapCode::HeapOutOfBounds,
|
||||||
);
|
);
|
||||||
let bound = builder.ins().global_value(env.pointer_type(), bound_gv);
|
let bound = builder.ins().global_value(env.pointer_type(), bound_gv);
|
||||||
Some(compute_addr(
|
Reachable(compute_addr(
|
||||||
&mut builder.cursor(),
|
&mut builder.cursor(),
|
||||||
heap,
|
heap,
|
||||||
env.pointer_type(),
|
env.pointer_type(),
|
||||||
@@ -198,7 +200,7 @@ where
|
|||||||
.ins()
|
.ins()
|
||||||
.icmp(IntCC::UnsignedGreaterThan, adjusted_index, bound);
|
.icmp(IntCC::UnsignedGreaterThan, adjusted_index, bound);
|
||||||
builder.ins().trapnz(oob, ir::TrapCode::HeapOutOfBounds);
|
builder.ins().trapnz(oob, ir::TrapCode::HeapOutOfBounds);
|
||||||
Some(compute_addr(
|
Reachable(compute_addr(
|
||||||
&mut builder.cursor(),
|
&mut builder.cursor(),
|
||||||
heap,
|
heap,
|
||||||
env.pointer_type(),
|
env.pointer_type(),
|
||||||
@@ -219,7 +221,7 @@ where
|
|||||||
HeapStyle::Static { bound } if offset_and_size > bound.into() => {
|
HeapStyle::Static { bound } if offset_and_size > bound.into() => {
|
||||||
env.before_unconditionally_trapping_memory_access(builder)?;
|
env.before_unconditionally_trapping_memory_access(builder)?;
|
||||||
builder.ins().trap(ir::TrapCode::HeapOutOfBounds);
|
builder.ins().trap(ir::TrapCode::HeapOutOfBounds);
|
||||||
None
|
Unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Second special case for when we can completely omit explicit
|
// 2. Second special case for when we can completely omit explicit
|
||||||
@@ -265,7 +267,7 @@ where
|
|||||||
&& u64::from(u32::MAX)
|
&& u64::from(u32::MAX)
|
||||||
<= u64::from(bound) + u64::from(heap.offset_guard_size) - offset_and_size =>
|
<= u64::from(bound) + u64::from(heap.offset_guard_size) - offset_and_size =>
|
||||||
{
|
{
|
||||||
Some(compute_addr(
|
Reachable(compute_addr(
|
||||||
&mut builder.cursor(),
|
&mut builder.cursor(),
|
||||||
heap,
|
heap,
|
||||||
env.pointer_type(),
|
env.pointer_type(),
|
||||||
@@ -295,7 +297,7 @@ where
|
|||||||
let adjusted_bound = builder
|
let adjusted_bound = builder
|
||||||
.ins()
|
.ins()
|
||||||
.iconst(env.pointer_type(), adjusted_bound as i64);
|
.iconst(env.pointer_type(), adjusted_bound as i64);
|
||||||
Some(compute_addr(
|
Reachable(compute_addr(
|
||||||
&mut builder.cursor(),
|
&mut builder.cursor(),
|
||||||
heap,
|
heap,
|
||||||
env.pointer_type(),
|
env.pointer_type(),
|
||||||
@@ -318,7 +320,7 @@ where
|
|||||||
.ins()
|
.ins()
|
||||||
.icmp_imm(IntCC::UnsignedGreaterThan, index, adjusted_bound as i64);
|
.icmp_imm(IntCC::UnsignedGreaterThan, index, adjusted_bound as i64);
|
||||||
builder.ins().trapnz(oob, ir::TrapCode::HeapOutOfBounds);
|
builder.ins().trapnz(oob, ir::TrapCode::HeapOutOfBounds);
|
||||||
Some(compute_addr(
|
Reachable(compute_addr(
|
||||||
&mut builder.cursor(),
|
&mut builder.cursor(),
|
||||||
heap,
|
heap,
|
||||||
env.pointer_type(),
|
env.pointer_type(),
|
||||||
|
|||||||
Reference in New Issue
Block a user