Skip to content
This repository was archived by the owner on Oct 21, 2022. It is now read-only.

Commit 2527571

Browse files
authored
Merge pull request #19 from rphmeier/fix-unsafety
make unsafe usages more safe
2 parents bf56cd9 + 8b14e9f commit 2527571

File tree

5 files changed

+92
-51
lines changed

5 files changed

+92
-51
lines changed

src/elements/primitives.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ impl Deserialize for VarInt7 {
190190
// expand sign
191191
if u8buf[0] & 0b0100_0000 == 0b0100_0000 { u8buf[0] |= 0b1000_0000 }
192192
// todo check range
193-
Ok(VarInt7(unsafe { ::std::mem::transmute (u8buf[0]) }))
193+
Ok(VarInt7(u8buf[0] as i8))
194194
}
195195
}
196196

src/interpreter/env.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use interpreter::module::{ModuleInstanceInterface, ModuleInstance, ExecutionPara
99
ItemIndex, CallerContext};
1010
use interpreter::memory::{MemoryInstance, LINEAR_MEMORY_PAGE_SIZE};
1111
use interpreter::table::TableInstance;
12-
use interpreter::value::{RuntimeValue, TransmuteInto};
12+
use interpreter::value::RuntimeValue;
1313
use interpreter::variable::VariableInstance;
1414

1515
/// Memory address, at which stack begins.
@@ -169,23 +169,23 @@ pub fn env_module(params: EnvParams) -> Result<EnvModuleInstance, Error> {
169169
.build()
170170
.with_export(ExportEntry::new("table".into(), Internal::Table(INDEX_TABLE)))
171171
// globals
172-
.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const(DEFAULT_STACK_BASE.transmute_into())])))
172+
.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const(DEFAULT_STACK_BASE as i32)])))
173173
.with_export(ExportEntry::new("STACK_BASE".into(), Internal::Global(INDEX_GLOBAL_STACK_BASE)))
174-
.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, true), InitExpr::new(vec![Opcode::I32Const(DEFAULT_STACK_BASE.transmute_into())])))
174+
.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, true), InitExpr::new(vec![Opcode::I32Const(DEFAULT_STACK_BASE as i32)])))
175175
.with_export(ExportEntry::new("STACKTOP".into(), Internal::Global(INDEX_GLOBAL_STACK_TOP)))
176-
.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const((DEFAULT_STACK_BASE + params.total_stack).transmute_into())])))
176+
.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const((DEFAULT_STACK_BASE + params.total_stack) as i32)])))
177177
.with_export(ExportEntry::new("STACK_MAX".into(), Internal::Global(INDEX_GLOBAL_STACK_MAX)))
178-
.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const((DEFAULT_STACK_BASE + params.total_stack).transmute_into())])))
178+
.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const((DEFAULT_STACK_BASE + params.total_stack) as i32)])))
179179
.with_export(ExportEntry::new("DYNAMIC_BASE".into(), Internal::Global(INDEX_GLOBAL_DYNAMIC_BASE)))
180-
.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, true), InitExpr::new(vec![Opcode::I32Const((DEFAULT_STACK_BASE + params.total_stack).transmute_into())])))
180+
.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, true), InitExpr::new(vec![Opcode::I32Const((DEFAULT_STACK_BASE + params.total_stack) as i32)])))
181181
.with_export(ExportEntry::new("DYNAMICTOP_PTR".into(), Internal::Global(INDEX_GLOBAL_DYNAMICTOP_PTR)))
182-
.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, params.allow_memory_growth), InitExpr::new(vec![Opcode::I32Const(params.total_memory.transmute_into())])))
182+
.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, params.allow_memory_growth), InitExpr::new(vec![Opcode::I32Const(params.total_memory as i32)])))
183183
.with_export(ExportEntry::new("TOTAL_MEMORY".into(), Internal::Global(INDEX_GLOBAL_TOTAL_MEMORY)))
184184
.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, true), InitExpr::new(vec![Opcode::I32Const(0)])))
185185
.with_export(ExportEntry::new("ABORT".into(), Internal::Global(INDEX_GLOBAL_ABORT)))
186186
.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, true), InitExpr::new(vec![Opcode::I32Const(0)])))
187187
.with_export(ExportEntry::new("EXITSTATUS".into(), Internal::Global(INDEX_GLOBAL_EXIT_STATUS)))
188-
.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const(DEFAULT_TABLE_BASE.transmute_into())]))) // TODO: what is this?
188+
.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const(DEFAULT_TABLE_BASE as i32)]))) // TODO: what is this?
189189
.with_export(ExportEntry::new("tableBase".into(), Internal::Global(INDEX_GLOBAL_TABLE_BASE)))
190190
// functions
191191
.function()

src/interpreter/module.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use interpreter::program::ProgramInstanceEssence;
99
use interpreter::runner::{Interpreter, FunctionContext};
1010
use interpreter::stack::StackWithLimit;
1111
use interpreter::table::TableInstance;
12-
use interpreter::value::{RuntimeValue, TryInto, TransmuteInto};
12+
use interpreter::value::{RuntimeValue, TryInto};
1313
use interpreter::variable::{VariableInstance, VariableType};
1414

1515
#[derive(Default, Clone)]
@@ -421,8 +421,8 @@ fn get_initializer(expr: &InitExpr, module: &Module, imports: &ModuleImports) ->
421421
},
422422
&Opcode::I32Const(val) => Ok(RuntimeValue::I32(val)),
423423
&Opcode::I64Const(val) => Ok(RuntimeValue::I64(val)),
424-
&Opcode::F32Const(val) => Ok(RuntimeValue::F32(val.transmute_into())),
425-
&Opcode::F64Const(val) => Ok(RuntimeValue::F64(val.transmute_into())),
424+
&Opcode::F32Const(val) => Ok(RuntimeValue::decode_f32(val)),
425+
&Opcode::F64Const(val) => Ok(RuntimeValue::decode_f64(val)),
426426
_ => Err(Error::Initialization(format!("not-supported {:?} instruction in instantiation-time initializer", first_opcode))),
427427
}
428428
}

src/interpreter/runner.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ use elements::{Opcode, BlockType, FunctionType};
88
use interpreter::Error;
99
use interpreter::module::{ModuleInstance, ModuleInstanceInterface, CallerContext, ItemIndex};
1010
use interpreter::stack::StackWithLimit;
11-
use interpreter::value::{RuntimeValue, TryInto, WrapInto, TryTruncateInto, ExtendInto, TransmuteInto,
12-
ArithmeticOps, Integer, Float, LittleEndianConvert};
11+
use interpreter::value::{
12+
RuntimeValue, TryInto, WrapInto, TryTruncateInto, ExtendInto,
13+
ArithmeticOps, Integer, Float, LittleEndianConvert, TransmuteInto,
14+
};
1315
use interpreter::variable::VariableInstance;
1416

1517
const DEFAULT_MEMORY_INDEX: u32 = 0;

src/interpreter/value.rs

Lines changed: 76 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use std::{i32, i64, u32, u64, f32};
22
use std::io;
3-
use std::mem;
43
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
54
use interpreter::Error;
65
use interpreter::variable::VariableType;
@@ -54,9 +53,9 @@ pub trait TransmuteInto<T> {
5453

5554
/// Convert from and to little endian.
5655
pub trait LittleEndianConvert where Self: Sized {
57-
/// Convert to little endian bufer.
56+
/// Convert to little endian buffer.
5857
fn into_little_endian(self) -> Vec<u8>;
59-
/// Convert from little endian bufer.
58+
/// Convert from little endian buffer.
6059
fn from_little_endian(buffer: Vec<u8>) -> Result<Self, Error>;
6160
}
6261

@@ -124,12 +123,12 @@ impl RuntimeValue {
124123

125124
/// Creates new value by interpreting passed u32 as f32.
126125
pub fn decode_f32(val: u32) -> Self {
127-
RuntimeValue::F32(val.transmute_into())
126+
RuntimeValue::F32(f32_from_bits(val))
128127
}
129128

130129
/// Creates new value by interpreting passed u64 as f64.
131130
pub fn decode_f64(val: u64) -> Self {
132-
RuntimeValue::F64(val.transmute_into())
131+
RuntimeValue::F64(f64_from_bits(val))
133132
}
134133

135134
/// Returns true if value is null.
@@ -224,7 +223,6 @@ impl TryInto<f32, Error> for RuntimeValue {
224223
impl TryInto<f64, Error> for RuntimeValue {
225224
fn try_into(self) -> Result<f64, Error> {
226225
match self {
227-
//RuntimeValue::F32(val) => Some(val as f64),
228226
RuntimeValue::F64(val) => Ok(val),
229227
_ => Err(Error::Value(format!("64-bit float value expected"))),
230228
}
@@ -234,9 +232,7 @@ impl TryInto<f64, Error> for RuntimeValue {
234232
impl TryInto<u32, Error> for RuntimeValue {
235233
fn try_into(self) -> Result<u32, Error> {
236234
match self {
237-
RuntimeValue::I32(val) => Ok(unsafe {
238-
mem::transmute(val)
239-
}),
235+
RuntimeValue::I32(val) => Ok(val as u32),
240236
_ => Err(Error::Value(format!("32-bit int value expected"))),
241237
}
242238
}
@@ -245,9 +241,7 @@ impl TryInto<u32, Error> for RuntimeValue {
245241
impl TryInto<u64, Error> for RuntimeValue {
246242
fn try_into(self) -> Result<u64, Error> {
247243
match self {
248-
RuntimeValue::I64(val) => Ok(unsafe {
249-
mem::transmute(val)
250-
}),
244+
RuntimeValue::I64(val) => Ok(val as u64),
251245
_ => Err(Error::Value(format!("64-bit int value expected"))),
252246
}
253247
}
@@ -347,39 +341,48 @@ impl_transmute_into_self!(i64);
347341
impl_transmute_into_self!(f32);
348342
impl_transmute_into_self!(f64);
349343

350-
macro_rules! impl_transmute_into {
344+
macro_rules! impl_transmute_into_as {
351345
($from: ident, $into: ident) => {
352346
impl TransmuteInto<$into> for $from {
353347
fn transmute_into(self) -> $into {
354-
unsafe {
355-
mem::transmute(self)
356-
}
348+
self as $into
357349
}
358350
}
359351
}
360352
}
361353

362-
impl_transmute_into!(i8, u8);
363-
impl_transmute_into!(u8, i8);
364-
impl_transmute_into!(i32, u32);
365-
impl_transmute_into!(u32, i32);
366-
impl_transmute_into!(u32, f32);
367-
impl_transmute_into!(i32, f32);
368-
impl_transmute_into!(f32, i32);
369-
impl_transmute_into!(i64, u64);
370-
impl_transmute_into!(u64, i64);
371-
impl_transmute_into!(u64, f64);
372-
impl_transmute_into!(i64, f64);
373-
impl_transmute_into!(f64, i64);
354+
impl_transmute_into_as!(i8, u8);
355+
impl_transmute_into_as!(u8, i8);
356+
impl_transmute_into_as!(i32, u32);
357+
impl_transmute_into_as!(u32, i32);
358+
impl_transmute_into_as!(i64, u64);
359+
impl_transmute_into_as!(u64, i64);
360+
361+
// TODO: rewrite these safely when `f32/f32::to_bits/from_bits` stabilized.
362+
impl TransmuteInto<i32> for f32 {
363+
fn transmute_into(self) -> i32 { unsafe { ::std::mem::transmute(self) } }
364+
}
365+
366+
impl TransmuteInto<i64> for f64 {
367+
fn transmute_into(self) -> i64 { unsafe { ::std::mem::transmute(self) } }
368+
}
369+
370+
impl TransmuteInto<f32> for i32 {
371+
fn transmute_into(self) -> f32 { f32_from_bits(self as _) }
372+
}
373+
374+
impl TransmuteInto<f64> for i64 {
375+
fn transmute_into(self) -> f64 { f64_from_bits(self as _) }
376+
}
374377

375378
impl LittleEndianConvert for i8 {
376379
fn into_little_endian(self) -> Vec<u8> {
377-
vec![self.transmute_into()]
380+
vec![self as u8]
378381
}
379382

380383
fn from_little_endian(buffer: Vec<u8>) -> Result<Self, Error> {
381384
buffer.get(0)
382-
.map(|v| v.transmute_into())
385+
.map(|v| *v as i8)
383386
.ok_or(Error::Value("invalid little endian buffer".into()))
384387
}
385388
}
@@ -469,33 +472,69 @@ impl LittleEndianConvert for i64 {
469472
impl LittleEndianConvert for f32 {
470473
fn into_little_endian(self) -> Vec<u8> {
471474
let mut vec = Vec::with_capacity(4);
472-
vec.write_i32::<LittleEndian>(self.transmute_into())
473-
.expect("i32 is written without any errors");
475+
vec.write_f32::<LittleEndian>(self)
476+
.expect("f32 is written without any errors");
474477
vec
475478
}
476479

477480
fn from_little_endian(buffer: Vec<u8>) -> Result<Self, Error> {
478-
io::Cursor::new(buffer).read_i32::<LittleEndian>()
479-
.map(TransmuteInto::transmute_into)
481+
io::Cursor::new(buffer).read_u32::<LittleEndian>()
482+
.map(f32_from_bits)
480483
.map_err(|e| Error::Value(e.to_string()))
481484
}
482485
}
483486

484487
impl LittleEndianConvert for f64 {
485488
fn into_little_endian(self) -> Vec<u8> {
486489
let mut vec = Vec::with_capacity(8);
487-
vec.write_i64::<LittleEndian>(self.transmute_into())
490+
vec.write_f64::<LittleEndian>(self)
488491
.expect("i64 is written without any errors");
489492
vec
490493
}
491494

492495
fn from_little_endian(buffer: Vec<u8>) -> Result<Self, Error> {
493-
io::Cursor::new(buffer).read_i64::<LittleEndian>()
494-
.map(TransmuteInto::transmute_into)
496+
io::Cursor::new(buffer).read_u64::<LittleEndian>()
497+
.map(f64_from_bits)
495498
.map_err(|e| Error::Value(e.to_string()))
496499
}
497500
}
498501

502+
// Convert u32 to f32 safely, masking out sNAN
503+
fn f32_from_bits(mut v: u32) -> f32 {
504+
const EXP_MASK: u32 = 0x7F800000;
505+
const QNAN_MASK: u32 = 0x00400000;
506+
const FRACT_MASK: u32 = 0x007FFFFF;
507+
508+
if v & EXP_MASK == EXP_MASK && v & FRACT_MASK != 0 {
509+
// If we have a NaN value, we
510+
// convert signaling NaN values to quiet NaN
511+
// by setting the the highest bit of the fraction
512+
// TODO: remove when https://github.com/BurntSushi/byteorder/issues/71 closed.
513+
// or `f32::from_bits` stabilized.
514+
v |= QNAN_MASK;
515+
}
516+
517+
unsafe { ::std::mem::transmute(v) }
518+
}
519+
520+
// Convert u64 to f64 safely, masking out sNAN
521+
fn f64_from_bits(mut v: u64) -> f64 {
522+
const EXP_MASK: u64 = 0x7FF0000000000000;
523+
const QNAN_MASK: u64 = 0x0001000000000000;
524+
const FRACT_MASK: u64 = 0x000FFFFFFFFFFFFF;
525+
526+
if v & EXP_MASK == EXP_MASK && v & FRACT_MASK != 0 {
527+
// If we have a NaN value, we
528+
// convert signaling NaN values to quiet NaN
529+
// by setting the the highest bit of the fraction
530+
// TODO: remove when https://github.com/BurntSushi/byteorder/issues/71 closed.
531+
// or `f64::from_bits` stabilized.
532+
v |= QNAN_MASK;
533+
}
534+
535+
unsafe { ::std::mem::transmute(v) }
536+
}
537+
499538
macro_rules! impl_integer_arithmetic_ops {
500539
($type: ident) => {
501540
impl ArithmeticOps<$type> for $type {

0 commit comments

Comments
 (0)