-
Notifications
You must be signed in to change notification settings - Fork 824
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix soundness issue in vm::Global #1590
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ use std::cell::UnsafeCell; | |
use std::ptr::NonNull; | ||
use std::sync::Mutex; | ||
use thiserror::Error; | ||
use wasmer_types::{GlobalType, Type}; | ||
use wasmer_types::{GlobalType, Mutability, Type, Value}; | ||
|
||
#[derive(Debug)] | ||
/// TODO: figure out a decent name for this thing | ||
|
@@ -63,13 +63,57 @@ impl Global { | |
unsafe { NonNull::new_unchecked(ptr) } | ||
} | ||
|
||
/// Get a reference to the definition | ||
pub fn get(&self) -> &VMGlobalDefinition { | ||
unsafe { &*self.vm_global_definition.get() } | ||
/// Get a value from the global. | ||
pub fn get<T>(&self) -> Value<T> { | ||
let _global_guard = self.lock.lock().unwrap(); | ||
unsafe { | ||
let definition = &*self.vm_global_definition.get(); | ||
match self.ty().ty { | ||
Type::I32 => Value::from(*definition.as_i32()), | ||
Type::I64 => Value::from(*definition.as_i64()), | ||
Type::F32 => Value::F32(*definition.as_f32()), | ||
Type::F64 => Value::F64(*definition.as_f64()), | ||
Type::V128 => Value::V128(*definition.as_u128()), | ||
MarkMcCaskey marked this conversation as resolved.
Show resolved
Hide resolved
|
||
_ => unimplemented!("Global::get for {:?}", self.ty), | ||
} | ||
} | ||
} | ||
|
||
/// Set a value for the global. | ||
/// | ||
/// # Safety | ||
/// The caller should check that the `val` comes from the same store as this global. | ||
pub unsafe fn set<T>(&self, val: Value<T>) -> Result<(), GlobalError> { | ||
MarkMcCaskey marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let _global_guard = self.lock.lock().unwrap(); | ||
if self.ty().mutability != Mutability::Var { | ||
return Err(GlobalError::ImmutableGlobalCannotBeSet); | ||
} | ||
if val.ty() != self.ty().ty { | ||
return Err(GlobalError::IncorrectType { | ||
expected: self.ty.ty, | ||
found: val.ty(), | ||
}); | ||
} | ||
self.set_unchecked(val) | ||
} | ||
|
||
/// Get a mutable reference to the definition | ||
pub fn get_mut(&self) -> &mut VMGlobalDefinition { | ||
unsafe { &mut *self.vm_global_definition.get() } | ||
/// Set a value from the global (unchecked) | ||
/// | ||
/// # Safety | ||
/// The caller should check that the `val` comes from the same store as this global. | ||
/// The caller should also ensure that this global is synchronized. Otherwise, use | ||
/// `set` instead. | ||
pub unsafe fn set_unchecked<T>(&self, val: Value<T>) -> Result<(), GlobalError> { | ||
// ideally we'd use atomics here | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this a TODO? Do you mean that you wish the assignment into There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, the idea is that we'd use atomics instead of a mutex on platforms with atomics that go up to 16 bytes... if there are any platforms that have that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think it's particularly actionable, but I also don't think leaving that comment there is hurting anything, it might inspire a future person to try something! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just think the comment is terse, it doesn't describe why an atomic is better than not atomic. Like, generally we don't use atomics and using atomics is slower on CPU, and is less clean code. So why the suggestion to use one here? What would it help? I'm trying to improve the comment "// TODO: if we used atomics here, we could ..." but I don't know enough to write that comment myself. |
||
let definition = &mut *self.vm_global_definition.get(); | ||
match val { | ||
Value::I32(i) => *definition.as_i32_mut() = i, | ||
Value::I64(i) => *definition.as_i64_mut() = i, | ||
Value::F32(f) => *definition.as_f32_mut() = f, | ||
Value::F64(f) => *definition.as_f64_mut() = f, | ||
Value::V128(x) => *definition.as_u128_bits_mut() = x.to_ne_bytes(), | ||
_ => unimplemented!("Global::set for {:?}", val.ty()), | ||
} | ||
Ok(()) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.