Refactor sync shims with setters and getters
This commit is contained in:
parent
fd94255b9d
commit
141319a412
@ -6,26 +6,16 @@ use crate::*;
|
|||||||
|
|
||||||
impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
|
impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
|
||||||
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
|
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
|
||||||
// pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform
|
|
||||||
// memory layout: store an i32 in the first four bytes equal to the
|
|
||||||
// corresponding libc mutex kind constant (i.e. PTHREAD_MUTEX_NORMAL)
|
|
||||||
|
|
||||||
fn pthread_mutexattr_init(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
fn pthread_mutexattr_init(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
// Ensure that the following write at an offset to the attr pointer is within bounds
|
|
||||||
assert_ptr_target_min_size(this, attr_op, 4)?;
|
|
||||||
|
|
||||||
let attr = this.read_scalar(attr_op)?.not_undef()?;
|
let attr = this.read_scalar(attr_op)?.not_undef()?;
|
||||||
if this.is_null(attr)? {
|
if this.is_null(attr)? {
|
||||||
return this.eval_libc_i32("EINVAL");
|
return this.eval_libc_i32("EINVAL");
|
||||||
}
|
}
|
||||||
|
|
||||||
let attr_place = this.deref_operand(attr_op)?;
|
|
||||||
let i32_layout = this.layout_of(this.tcx.types.i32)?;
|
|
||||||
let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, this)?;
|
|
||||||
let default_kind = this.eval_libc("PTHREAD_MUTEX_DEFAULT")?;
|
let default_kind = this.eval_libc("PTHREAD_MUTEX_DEFAULT")?;
|
||||||
this.write_scalar(default_kind, kind_place.into())?;
|
mutexattr_set_kind(this, attr_op, default_kind)?;
|
||||||
|
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
@ -37,22 +27,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
) -> InterpResult<'tcx, i32> {
|
) -> InterpResult<'tcx, i32> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
// Ensure that the following write at an offset to the attr pointer is within bounds
|
|
||||||
assert_ptr_target_min_size(this, attr_op, 4)?;
|
|
||||||
|
|
||||||
let attr = this.read_scalar(attr_op)?.not_undef()?;
|
let attr = this.read_scalar(attr_op)?.not_undef()?;
|
||||||
if this.is_null(attr)? {
|
if this.is_null(attr)? {
|
||||||
return this.eval_libc_i32("EINVAL");
|
return this.eval_libc_i32("EINVAL");
|
||||||
}
|
}
|
||||||
|
|
||||||
let kind = this.read_scalar(kind_op)?.not_undef()?;
|
let kind = this.read_scalar(kind_op)?.not_undef()?;
|
||||||
if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? ||
|
if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")?
|
||||||
kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? ||
|
|| kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")?
|
||||||
kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? {
|
|| kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")?
|
||||||
let attr_place = this.deref_operand(attr_op)?;
|
{
|
||||||
let i32_layout = this.layout_of(this.tcx.types.i32)?;
|
mutexattr_set_kind(this, attr_op, kind)?;
|
||||||
let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, this)?;
|
|
||||||
this.write_scalar(kind, kind_place.into())?;
|
|
||||||
} else {
|
} else {
|
||||||
let einval = this.eval_libc_i32("EINVAL")?;
|
let einval = this.eval_libc_i32("EINVAL")?;
|
||||||
return Ok(einval);
|
return Ok(einval);
|
||||||
@ -64,30 +49,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
fn pthread_mutexattr_destroy(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
fn pthread_mutexattr_destroy(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
// Ensure that the following write at an offset to the attr pointer is within bounds
|
|
||||||
assert_ptr_target_min_size(this, attr_op, 4)?;
|
|
||||||
|
|
||||||
let attr = this.read_scalar(attr_op)?.not_undef()?;
|
let attr = this.read_scalar(attr_op)?.not_undef()?;
|
||||||
if this.is_null(attr)? {
|
if this.is_null(attr)? {
|
||||||
return this.eval_libc_i32("EINVAL");
|
return this.eval_libc_i32("EINVAL");
|
||||||
}
|
}
|
||||||
|
|
||||||
let attr_place = this.deref_operand(attr_op)?;
|
mutexattr_set_kind(this, attr_op, ScalarMaybeUndef::Undef)?;
|
||||||
let i32_layout = this.layout_of(this.tcx.types.i32)?;
|
|
||||||
let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, this)?;
|
|
||||||
this.write_scalar(ScalarMaybeUndef::Undef, kind_place.into())?;
|
|
||||||
|
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// pthread_mutex_t is between 24 and 48 bytes, depending on the platform
|
|
||||||
// memory layout:
|
|
||||||
// bytes 0-3: reserved for signature on macOS
|
|
||||||
// bytes 4-7: count of how many times this mutex has been locked, as a u32
|
|
||||||
// bytes 12-15: mutex kind, as an i32
|
|
||||||
// (the kind should be at this offset for compatibility with the static
|
|
||||||
// initializer macro)
|
|
||||||
|
|
||||||
fn pthread_mutex_init(
|
fn pthread_mutex_init(
|
||||||
&mut self,
|
&mut self,
|
||||||
mutex_op: OpTy<'tcx, Tag>,
|
mutex_op: OpTy<'tcx, Tag>,
|
||||||
@ -95,34 +66,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
) -> InterpResult<'tcx, i32> {
|
) -> InterpResult<'tcx, i32> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
// Ensure that the following writes at offsets to the mutex pointer are within bounds
|
|
||||||
assert_ptr_target_min_size(this, mutex_op, 16)?;
|
|
||||||
// Ensure that the following read at an offset to the attr pointer is within bounds
|
|
||||||
assert_ptr_target_min_size(this, attr_op, 4)?;
|
|
||||||
|
|
||||||
let mutex = this.read_scalar(mutex_op)?.not_undef()?;
|
let mutex = this.read_scalar(mutex_op)?.not_undef()?;
|
||||||
if this.is_null(mutex)? {
|
if this.is_null(mutex)? {
|
||||||
return this.eval_libc_i32("EINVAL");
|
return this.eval_libc_i32("EINVAL");
|
||||||
}
|
}
|
||||||
let mutex_place = this.deref_operand(mutex_op)?;
|
|
||||||
|
|
||||||
let i32_layout = this.layout_of(this.tcx.types.i32)?;
|
|
||||||
|
|
||||||
let attr = this.read_scalar(attr_op)?.not_undef()?;
|
let attr = this.read_scalar(attr_op)?.not_undef()?;
|
||||||
let kind = if this.is_null(attr)? {
|
let kind = if this.is_null(attr)? {
|
||||||
this.eval_libc("PTHREAD_MUTEX_DEFAULT")?
|
this.eval_libc("PTHREAD_MUTEX_DEFAULT")?
|
||||||
} else {
|
} else {
|
||||||
let attr_place = this.deref_operand(attr_op)?;
|
mutexattr_get_kind(this, attr_op)?.not_undef()?
|
||||||
let attr_kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, this)?;
|
|
||||||
this.read_scalar(attr_kind_place.into())?.not_undef()?
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let u32_layout = this.layout_of(this.tcx.types.u32)?;
|
mutex_set_locked_count(this, mutex_op, Scalar::from_u32(0))?;
|
||||||
let locked_count_place = mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?;
|
mutex_set_kind(this, mutex_op, kind)?;
|
||||||
this.write_scalar(Scalar::from_u32(0), locked_count_place.into())?;
|
|
||||||
|
|
||||||
let mutex_kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, &*this.tcx)?;
|
|
||||||
this.write_scalar(kind, mutex_kind_place.into())?;
|
|
||||||
|
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
@ -130,39 +87,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
fn pthread_mutex_lock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
fn pthread_mutex_lock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
// Ensure that the following reads and writes at offsets to the mutex pointer are within bounds
|
|
||||||
assert_ptr_target_min_size(this, mutex_op, 16)?;
|
|
||||||
|
|
||||||
let mutex = this.read_scalar(mutex_op)?.not_undef()?;
|
let mutex = this.read_scalar(mutex_op)?.not_undef()?;
|
||||||
if this.is_null(mutex)? {
|
if this.is_null(mutex)? {
|
||||||
return this.eval_libc_i32("EINVAL");
|
return this.eval_libc_i32("EINVAL");
|
||||||
}
|
}
|
||||||
let mutex_place = this.deref_operand(mutex_op)?;
|
|
||||||
|
|
||||||
let i32_layout = this.layout_of(this.tcx.types.i32)?;
|
let kind = mutex_get_kind(this, mutex_op)?.not_undef()?;
|
||||||
let kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, this)?;
|
let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?;
|
||||||
let kind = this.read_scalar(kind_place.into())?.not_undef()?;
|
|
||||||
|
|
||||||
let u32_layout = this.layout_of(this.tcx.types.u32)?;
|
|
||||||
let locked_count_place = mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?;
|
|
||||||
let locked_count = this.read_scalar(locked_count_place.into())?.to_u32()?;
|
|
||||||
|
|
||||||
if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? {
|
if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? {
|
||||||
if locked_count == 0 {
|
if locked_count == 0 {
|
||||||
this.write_scalar(Scalar::from_u32(1), locked_count_place.into())?;
|
mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?;
|
||||||
Ok(0)
|
Ok(0)
|
||||||
} else {
|
} else {
|
||||||
throw_unsup_format!("Deadlock due to locking a PTHREAD_MUTEX_NORMAL mutex twice");
|
throw_unsup_format!("Deadlock due to locking a PTHREAD_MUTEX_NORMAL mutex twice");
|
||||||
}
|
}
|
||||||
} else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? {
|
} else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? {
|
||||||
if locked_count == 0 {
|
if locked_count == 0 {
|
||||||
this.write_scalar(Scalar::from_u32(1), locked_count_place.into())?;
|
mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?;
|
||||||
Ok(0)
|
Ok(0)
|
||||||
} else {
|
} else {
|
||||||
this.eval_libc_i32("EDEADLK")
|
this.eval_libc_i32("EDEADLK")
|
||||||
}
|
}
|
||||||
} else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? {
|
} else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? {
|
||||||
this.write_scalar(Scalar::from_u32(locked_count + 1), locked_count_place.into())?;
|
mutex_set_locked_count(this, mutex_op, Scalar::from_u32(locked_count + 1))?;
|
||||||
Ok(0)
|
Ok(0)
|
||||||
} else {
|
} else {
|
||||||
this.eval_libc_i32("EINVAL")
|
this.eval_libc_i32("EINVAL")
|
||||||
@ -172,33 +120,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
fn pthread_mutex_trylock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
fn pthread_mutex_trylock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
// Ensure that the following reads and writes at offsets to the mutex pointer are within bounds
|
|
||||||
assert_ptr_target_min_size(this, mutex_op, 16)?;
|
|
||||||
|
|
||||||
let mutex = this.read_scalar(mutex_op)?.not_undef()?;
|
let mutex = this.read_scalar(mutex_op)?.not_undef()?;
|
||||||
if this.is_null(mutex)? {
|
if this.is_null(mutex)? {
|
||||||
return this.eval_libc_i32("EINVAL");
|
return this.eval_libc_i32("EINVAL");
|
||||||
}
|
}
|
||||||
let mutex_place = this.deref_operand(mutex_op)?;
|
|
||||||
|
|
||||||
let i32_layout = this.layout_of(this.tcx.types.i32)?;
|
let kind = mutex_get_kind(this, mutex_op)?.not_undef()?;
|
||||||
let kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, this)?;
|
let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?;
|
||||||
let kind = this.read_scalar(kind_place.into())?.not_undef()?;
|
|
||||||
|
|
||||||
let u32_layout = this.layout_of(this.tcx.types.u32)?;
|
if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")?
|
||||||
let locked_count_place = mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?;
|
|| kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")?
|
||||||
let locked_count = this.read_scalar(locked_count_place.into())?.to_u32()?;
|
{
|
||||||
|
|
||||||
if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? ||
|
|
||||||
kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? {
|
|
||||||
if locked_count == 0 {
|
if locked_count == 0 {
|
||||||
this.write_scalar(Scalar::from_u32(1), locked_count_place.into())?;
|
mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?;
|
||||||
Ok(0)
|
Ok(0)
|
||||||
} else {
|
} else {
|
||||||
this.eval_libc_i32("EBUSY")
|
this.eval_libc_i32("EBUSY")
|
||||||
}
|
}
|
||||||
} else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? {
|
} else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? {
|
||||||
this.write_scalar(Scalar::from_u32(locked_count + 1), locked_count_place.into())?;
|
mutex_set_locked_count(this, mutex_op, Scalar::from_u32(locked_count + 1))?;
|
||||||
Ok(0)
|
Ok(0)
|
||||||
} else {
|
} else {
|
||||||
this.eval_libc_i32("EINVAL")
|
this.eval_libc_i32("EINVAL")
|
||||||
@ -208,40 +148,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
fn pthread_mutex_unlock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
fn pthread_mutex_unlock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
// Ensure that the following reads and writes at offsets to the mutex pointer are within bounds
|
|
||||||
assert_ptr_target_min_size(this, mutex_op, 16)?;
|
|
||||||
|
|
||||||
let mutex = this.read_scalar(mutex_op)?.not_undef()?;
|
let mutex = this.read_scalar(mutex_op)?.not_undef()?;
|
||||||
if this.is_null(mutex)? {
|
if this.is_null(mutex)? {
|
||||||
return this.eval_libc_i32("EINVAL");
|
return this.eval_libc_i32("EINVAL");
|
||||||
}
|
}
|
||||||
let mutex_place = this.deref_operand(mutex_op)?;
|
|
||||||
|
|
||||||
let i32_layout = this.layout_of(this.tcx.types.i32)?;
|
let kind = mutex_get_kind(this, mutex_op)?.not_undef()?;
|
||||||
let kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, this)?;
|
let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?;
|
||||||
let kind = this.read_scalar(kind_place.into())?.not_undef()?;
|
|
||||||
|
|
||||||
let u32_layout = this.layout_of(this.tcx.types.u32)?;
|
|
||||||
let locked_count_place = mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?;
|
|
||||||
let locked_count = this.read_scalar(locked_count_place.into())?.to_u32()?;
|
|
||||||
|
|
||||||
if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? {
|
if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? {
|
||||||
if locked_count == 1 {
|
if locked_count == 1 {
|
||||||
this.write_scalar(Scalar::from_u32(0), locked_count_place.into())?;
|
mutex_set_locked_count(this, mutex_op, Scalar::from_u32(0))?;
|
||||||
Ok(0)
|
Ok(0)
|
||||||
} else {
|
} else {
|
||||||
throw_ub_format!("Attempted to unlock a PTHREAD_MUTEX_NORMAL mutex that was not locked");
|
throw_ub_format!(
|
||||||
|
"Attempted to unlock a PTHREAD_MUTEX_NORMAL mutex that was not locked"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? {
|
} else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? {
|
||||||
if locked_count == 1 {
|
if locked_count == 1 {
|
||||||
this.write_scalar(Scalar::from_u32(0), locked_count_place.into())?;
|
mutex_set_locked_count(this, mutex_op, Scalar::from_u32(0))?;
|
||||||
Ok(0)
|
Ok(0)
|
||||||
} else {
|
} else {
|
||||||
this.eval_libc_i32("EPERM")
|
this.eval_libc_i32("EPERM")
|
||||||
}
|
}
|
||||||
} else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? {
|
} else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? {
|
||||||
if locked_count > 0 {
|
if locked_count > 0 {
|
||||||
this.write_scalar(Scalar::from_u32(locked_count - 1), locked_count_place.into())?;
|
mutex_set_locked_count(this, mutex_op, Scalar::from_u32(locked_count - 1))?;
|
||||||
Ok(0)
|
Ok(0)
|
||||||
} else {
|
} else {
|
||||||
this.eval_libc_i32("EPERM")
|
this.eval_libc_i32("EPERM")
|
||||||
@ -254,56 +187,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
fn pthread_mutex_destroy(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
fn pthread_mutex_destroy(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
// Ensure that the following read and writes at offsets to the mutex pointer are within bounds
|
|
||||||
assert_ptr_target_min_size(this, mutex_op, 16)?;
|
|
||||||
|
|
||||||
let mutex = this.read_scalar(mutex_op)?.not_undef()?;
|
let mutex = this.read_scalar(mutex_op)?.not_undef()?;
|
||||||
if this.is_null(mutex)? {
|
if this.is_null(mutex)? {
|
||||||
return this.eval_libc_i32("EINVAL");
|
return this.eval_libc_i32("EINVAL");
|
||||||
}
|
}
|
||||||
let mutex_place = this.deref_operand(mutex_op)?;
|
|
||||||
|
|
||||||
let u32_layout = this.layout_of(this.tcx.types.u32)?;
|
if mutex_get_locked_count(this, mutex_op)?.to_u32()? != 0 {
|
||||||
let locked_count_place = mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?;
|
|
||||||
if this.read_scalar(locked_count_place.into())?.to_u32()? != 0 {
|
|
||||||
return this.eval_libc_i32("EBUSY");
|
return this.eval_libc_i32("EBUSY");
|
||||||
}
|
}
|
||||||
|
|
||||||
let i32_layout = this.layout_of(this.tcx.types.i32)?;
|
mutex_set_kind(this, mutex_op, ScalarMaybeUndef::Undef)?;
|
||||||
let kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, this)?;
|
mutex_set_locked_count(this, mutex_op, ScalarMaybeUndef::Undef)?;
|
||||||
this.write_scalar(ScalarMaybeUndef::Undef, kind_place.into())?;
|
|
||||||
this.write_scalar(ScalarMaybeUndef::Undef, locked_count_place.into())?;
|
|
||||||
|
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// pthread_rwlock_t is between 32 and 56 bytes, depending on the platform
|
|
||||||
// memory layout:
|
|
||||||
// bytes 0-3: reserved for signature on macOS
|
|
||||||
// bytes 4-7: reader count, as a u32
|
|
||||||
// bytes 8-11: writer count, as a u32
|
|
||||||
|
|
||||||
fn pthread_rwlock_rdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
fn pthread_rwlock_rdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
// Ensure that the following reads and write at offsets to the rwlock pointer are within bounds
|
|
||||||
assert_ptr_target_min_size(this, rwlock_op, 12)?;
|
|
||||||
|
|
||||||
let rwlock = this.read_scalar(rwlock_op)?.not_undef()?;
|
let rwlock = this.read_scalar(rwlock_op)?.not_undef()?;
|
||||||
if this.is_null(rwlock)? {
|
if this.is_null(rwlock)? {
|
||||||
return this.eval_libc_i32("EINVAL");
|
return this.eval_libc_i32("EINVAL");
|
||||||
}
|
}
|
||||||
let rwlock_place = this.deref_operand(rwlock_op)?;
|
|
||||||
|
|
||||||
let u32_layout = this.layout_of(this.tcx.types.u32)?;
|
let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?;
|
||||||
let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?;
|
let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?;
|
||||||
let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?;
|
|
||||||
let readers = this.read_scalar(readers_place.into())?.to_u32()?;
|
|
||||||
let writers = this.read_scalar(writers_place.into())?.to_u32()?;
|
|
||||||
if writers != 0 {
|
if writers != 0 {
|
||||||
throw_unsup_format!("Deadlock due to read-locking a pthreads read-write lock while it is already write-locked");
|
throw_unsup_format!(
|
||||||
|
"Deadlock due to read-locking a pthreads read-write lock while it is already write-locked"
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
this.write_scalar(Scalar::from_u32(readers + 1), readers_place.into())?;
|
rwlock_set_readers(this, rwlock_op, Scalar::from_u32(readers + 1))?;
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -311,24 +225,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
// Ensure that the following reads and write at offsets to the rwlock pointer are within bounds
|
|
||||||
assert_ptr_target_min_size(this, rwlock_op, 12)?;
|
|
||||||
|
|
||||||
let rwlock = this.read_scalar(rwlock_op)?.not_undef()?;
|
let rwlock = this.read_scalar(rwlock_op)?.not_undef()?;
|
||||||
if this.is_null(rwlock)? {
|
if this.is_null(rwlock)? {
|
||||||
return this.eval_libc_i32("EINVAL");
|
return this.eval_libc_i32("EINVAL");
|
||||||
}
|
}
|
||||||
let rwlock_place = this.deref_operand(rwlock_op)?;
|
|
||||||
|
|
||||||
let u32_layout = this.layout_of(this.tcx.types.u32)?;
|
let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?;
|
||||||
let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?;
|
let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?;
|
||||||
let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?;
|
|
||||||
let readers = this.read_scalar(readers_place.into())?.to_u32()?;
|
|
||||||
let writers = this.read_scalar(writers_place.into())?.to_u32()?;
|
|
||||||
if writers != 0 {
|
if writers != 0 {
|
||||||
this.eval_libc_i32("EBUSY")
|
this.eval_libc_i32("EBUSY")
|
||||||
} else {
|
} else {
|
||||||
this.write_scalar(Scalar::from_u32(readers + 1), readers_place.into())?;
|
rwlock_set_readers(this, rwlock_op, Scalar::from_u32(readers + 1))?;
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -336,26 +243,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
fn pthread_rwlock_wrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
fn pthread_rwlock_wrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
// Ensure that the following reads and write at offsets to the rwlock pointer are within bounds
|
|
||||||
assert_ptr_target_min_size(this, rwlock_op, 12)?;
|
|
||||||
|
|
||||||
let rwlock = this.read_scalar(rwlock_op)?.not_undef()?;
|
let rwlock = this.read_scalar(rwlock_op)?.not_undef()?;
|
||||||
if this.is_null(rwlock)? {
|
if this.is_null(rwlock)? {
|
||||||
return this.eval_libc_i32("EINVAL");
|
return this.eval_libc_i32("EINVAL");
|
||||||
}
|
}
|
||||||
let rwlock_place = this.deref_operand(rwlock_op)?;
|
|
||||||
|
|
||||||
let u32_layout = this.layout_of(this.tcx.types.u32)?;
|
let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?;
|
||||||
let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?;
|
let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?;
|
||||||
let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?;
|
|
||||||
let readers = this.read_scalar(readers_place.into())?.to_u32()?;
|
|
||||||
let writers = this.read_scalar(writers_place.into())?.to_u32()?;
|
|
||||||
if readers != 0 {
|
if readers != 0 {
|
||||||
throw_unsup_format!("Deadlock due to write-locking a pthreads read-write lock while it is already read-locked");
|
throw_unsup_format!(
|
||||||
|
"Deadlock due to write-locking a pthreads read-write lock while it is already read-locked"
|
||||||
|
);
|
||||||
} else if writers != 0 {
|
} else if writers != 0 {
|
||||||
throw_unsup_format!("Deadlock due to write-locking a pthreads read-write lock while it is already write-locked");
|
throw_unsup_format!(
|
||||||
|
"Deadlock due to write-locking a pthreads read-write lock while it is already write-locked"
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
this.write_scalar(Scalar::from_u32(1), writers_place.into())?;
|
rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?;
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -363,24 +267,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
fn pthread_rwlock_trywrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
fn pthread_rwlock_trywrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
// Ensure that the following reads and write at offsets to the rwlock pointer are within bounds
|
|
||||||
assert_ptr_target_min_size(this, rwlock_op, 12)?;
|
|
||||||
|
|
||||||
let rwlock = this.read_scalar(rwlock_op)?.not_undef()?;
|
let rwlock = this.read_scalar(rwlock_op)?.not_undef()?;
|
||||||
if this.is_null(rwlock)? {
|
if this.is_null(rwlock)? {
|
||||||
return this.eval_libc_i32("EINVAL");
|
return this.eval_libc_i32("EINVAL");
|
||||||
}
|
}
|
||||||
let rwlock_place = this.deref_operand(rwlock_op)?;
|
|
||||||
|
|
||||||
let u32_layout = this.layout_of(this.tcx.types.u32)?;
|
let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?;
|
||||||
let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?;
|
let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?;
|
||||||
let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?;
|
|
||||||
let readers = this.read_scalar(readers_place.into())?.to_u32()?;
|
|
||||||
let writers = this.read_scalar(writers_place.into())?.to_u32()?;
|
|
||||||
if readers != 0 || writers != 0 {
|
if readers != 0 || writers != 0 {
|
||||||
this.eval_libc_i32("EBUSY")
|
this.eval_libc_i32("EBUSY")
|
||||||
} else {
|
} else {
|
||||||
this.write_scalar(Scalar::from_u32(1), writers_place.into())?;
|
rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?;
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -388,25 +285,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
fn pthread_rwlock_unlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
fn pthread_rwlock_unlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
// Ensure that the following reads and writes at offsets to the rwlock pointer are within bounds
|
|
||||||
assert_ptr_target_min_size(this, rwlock_op, 12)?;
|
|
||||||
|
|
||||||
let rwlock = this.read_scalar(rwlock_op)?.not_undef()?;
|
let rwlock = this.read_scalar(rwlock_op)?.not_undef()?;
|
||||||
if this.is_null(rwlock)? {
|
if this.is_null(rwlock)? {
|
||||||
return this.eval_libc_i32("EINVAL");
|
return this.eval_libc_i32("EINVAL");
|
||||||
}
|
}
|
||||||
let rwlock_place = this.deref_operand(rwlock_op)?;
|
|
||||||
|
|
||||||
let u32_layout = this.layout_of(this.tcx.types.u32)?;
|
let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?;
|
||||||
let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?;
|
let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?;
|
||||||
let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?;
|
|
||||||
let readers = this.read_scalar(readers_place.into())?.to_u32()?;
|
|
||||||
let writers = this.read_scalar(writers_place.into())?.to_u32()?;
|
|
||||||
if readers != 0 {
|
if readers != 0 {
|
||||||
this.write_scalar(Scalar::from_u32(readers - 1), readers_place.into())?;
|
rwlock_set_readers(this, rwlock_op, Scalar::from_u32(readers - 1))?;
|
||||||
Ok(0)
|
Ok(0)
|
||||||
} else if writers != 0 {
|
} else if writers != 0 {
|
||||||
this.write_scalar(Scalar::from_u32(0), writers_place.into())?;
|
rwlock_set_writers(this, rwlock_op, Scalar::from_u32(0))?;
|
||||||
Ok(0)
|
Ok(0)
|
||||||
} else {
|
} else {
|
||||||
this.eval_libc_i32("EPERM")
|
this.eval_libc_i32("EPERM")
|
||||||
@ -416,38 +306,186 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
fn pthread_rwlock_destroy(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
fn pthread_rwlock_destroy(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
// Ensure that the following reads and writes at offsets to the rwlock pointer are within bounds
|
|
||||||
assert_ptr_target_min_size(this, rwlock_op, 12)?;
|
|
||||||
|
|
||||||
let rwlock = this.read_scalar(rwlock_op)?.not_undef()?;
|
let rwlock = this.read_scalar(rwlock_op)?.not_undef()?;
|
||||||
if this.is_null(rwlock)? {
|
if this.is_null(rwlock)? {
|
||||||
return this.eval_libc_i32("EINVAL");
|
return this.eval_libc_i32("EINVAL");
|
||||||
}
|
}
|
||||||
let rwlock_place = this.deref_operand(rwlock_op)?;
|
|
||||||
|
|
||||||
let u32_layout = this.layout_of(this.tcx.types.u32)?;
|
if rwlock_get_readers(this, rwlock_op)?.to_u32()? != 0 {
|
||||||
let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?;
|
|
||||||
if this.read_scalar(readers_place.into())?.to_u32()? != 0 {
|
|
||||||
return this.eval_libc_i32("EBUSY");
|
return this.eval_libc_i32("EBUSY");
|
||||||
}
|
}
|
||||||
let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?;
|
if rwlock_get_writers(this, rwlock_op)?.to_u32()? != 0 {
|
||||||
if this.read_scalar(writers_place.into())?.to_u32()? != 0 {
|
|
||||||
return this.eval_libc_i32("EBUSY");
|
return this.eval_libc_i32("EBUSY");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.write_scalar(ScalarMaybeUndef::Undef, readers_place.into())?;
|
rwlock_set_readers(this, rwlock_op, ScalarMaybeUndef::Undef)?;
|
||||||
this.write_scalar(ScalarMaybeUndef::Undef, writers_place.into())?;
|
rwlock_set_writers(this, rwlock_op, ScalarMaybeUndef::Undef)?;
|
||||||
|
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>(ecx: &MiriEvalContext<'mir, 'tcx>, operand: OpTy<'tcx, Tag>, min_size: u64) -> InterpResult<'tcx, ()> {
|
fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>(
|
||||||
|
ecx: &MiriEvalContext<'mir, 'tcx>,
|
||||||
|
operand: OpTy<'tcx, Tag>,
|
||||||
|
min_size: u64,
|
||||||
|
) -> InterpResult<'tcx, ()> {
|
||||||
let target_ty = match operand.layout.ty.kind {
|
let target_ty = match operand.layout.ty.kind {
|
||||||
TyKind::RawPtr(TypeAndMut{ ty, mutbl: _ }) => ty,
|
TyKind::RawPtr(TypeAndMut { ty, mutbl: _ }) => ty,
|
||||||
_ => panic!("Argument to pthread function was not a raw pointer"),
|
_ => panic!("Argument to pthread function was not a raw pointer"),
|
||||||
};
|
};
|
||||||
let target_layout = ecx.layout_of(target_ty)?;
|
let target_layout = ecx.layout_of(target_ty)?;
|
||||||
assert!(target_layout.size.bytes() >= min_size);
|
assert!(target_layout.size.bytes() >= min_size);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform
|
||||||
|
// memory layout: store an i32 in the first four bytes equal to the
|
||||||
|
// corresponding libc mutex kind constant (i.e. PTHREAD_MUTEX_NORMAL)
|
||||||
|
|
||||||
|
fn mutexattr_get_kind<'mir, 'tcx: 'mir>(
|
||||||
|
ecx: &MiriEvalContext<'mir, 'tcx>,
|
||||||
|
attr_op: OpTy<'tcx, Tag>,
|
||||||
|
) -> InterpResult<'tcx, ScalarMaybeUndef<Tag>> {
|
||||||
|
// Ensure that the following read at an offset to the attr pointer is within bounds
|
||||||
|
assert_ptr_target_min_size(ecx, attr_op, 4)?;
|
||||||
|
let attr_place = ecx.deref_operand(attr_op)?;
|
||||||
|
let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?;
|
||||||
|
let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, ecx)?;
|
||||||
|
ecx.read_scalar(kind_place.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mutexattr_set_kind<'mir, 'tcx: 'mir>(
|
||||||
|
ecx: &mut MiriEvalContext<'mir, 'tcx>,
|
||||||
|
attr_op: OpTy<'tcx, Tag>,
|
||||||
|
kind: impl Into<ScalarMaybeUndef<Tag>>,
|
||||||
|
) -> InterpResult<'tcx, ()> {
|
||||||
|
// Ensure that the following write at an offset to the attr pointer is within bounds
|
||||||
|
assert_ptr_target_min_size(ecx, attr_op, 4)?;
|
||||||
|
let attr_place = ecx.deref_operand(attr_op)?;
|
||||||
|
let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?;
|
||||||
|
let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, ecx)?;
|
||||||
|
ecx.write_scalar(kind.into(), kind_place.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
// pthread_mutex_t is between 24 and 48 bytes, depending on the platform
|
||||||
|
// memory layout:
|
||||||
|
// bytes 0-3: reserved for signature on macOS
|
||||||
|
// bytes 4-7: count of how many times this mutex has been locked, as a u32
|
||||||
|
// bytes 12-15: mutex kind, as an i32
|
||||||
|
// (the kind should be at this offset for compatibility with the static
|
||||||
|
// initializer macro)
|
||||||
|
|
||||||
|
fn mutex_get_locked_count<'mir, 'tcx: 'mir>(
|
||||||
|
ecx: &MiriEvalContext<'mir, 'tcx>,
|
||||||
|
mutex_op: OpTy<'tcx, Tag>,
|
||||||
|
) -> InterpResult<'tcx, ScalarMaybeUndef<Tag>> {
|
||||||
|
// Ensure that the following read at an offset to the mutex pointer is within bounds
|
||||||
|
assert_ptr_target_min_size(ecx, mutex_op, 16)?;
|
||||||
|
let mutex_place = ecx.deref_operand(mutex_op)?;
|
||||||
|
let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?;
|
||||||
|
let locked_count_place =
|
||||||
|
mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?;
|
||||||
|
ecx.read_scalar(locked_count_place.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mutex_set_locked_count<'mir, 'tcx: 'mir>(
|
||||||
|
ecx: &mut MiriEvalContext<'mir, 'tcx>,
|
||||||
|
mutex_op: OpTy<'tcx, Tag>,
|
||||||
|
locked_count: impl Into<ScalarMaybeUndef<Tag>>,
|
||||||
|
) -> InterpResult<'tcx, ()> {
|
||||||
|
// Ensure that the following write at an offset to the mutex pointer is within bounds
|
||||||
|
assert_ptr_target_min_size(ecx, mutex_op, 16)?;
|
||||||
|
let mutex_place = ecx.deref_operand(mutex_op)?;
|
||||||
|
let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?;
|
||||||
|
let locked_count_place =
|
||||||
|
mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?;
|
||||||
|
ecx.write_scalar(locked_count.into(), locked_count_place.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mutex_get_kind<'mir, 'tcx: 'mir>(
|
||||||
|
ecx: &MiriEvalContext<'mir, 'tcx>,
|
||||||
|
mutex_op: OpTy<'tcx, Tag>,
|
||||||
|
) -> InterpResult<'tcx, ScalarMaybeUndef<Tag>> {
|
||||||
|
// Ensure that the following read at an offset to the mutex pointer is within bounds
|
||||||
|
assert_ptr_target_min_size(ecx, mutex_op, 16)?;
|
||||||
|
let mutex_place = ecx.deref_operand(mutex_op)?;
|
||||||
|
let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?;
|
||||||
|
let kind_place =
|
||||||
|
mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, ecx)?;
|
||||||
|
ecx.read_scalar(kind_place.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mutex_set_kind<'mir, 'tcx: 'mir>(
|
||||||
|
ecx: &mut MiriEvalContext<'mir, 'tcx>,
|
||||||
|
mutex_op: OpTy<'tcx, Tag>,
|
||||||
|
kind: impl Into<ScalarMaybeUndef<Tag>>,
|
||||||
|
) -> InterpResult<'tcx, ()> {
|
||||||
|
// Ensure that the following write at an offset to the mutex pointer is within bounds
|
||||||
|
assert_ptr_target_min_size(ecx, mutex_op, 16)?;
|
||||||
|
let mutex_place = ecx.deref_operand(mutex_op)?;
|
||||||
|
let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?;
|
||||||
|
let kind_place =
|
||||||
|
mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, ecx)?;
|
||||||
|
ecx.write_scalar(kind.into(), kind_place.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
// pthread_rwlock_t is between 32 and 56 bytes, depending on the platform
|
||||||
|
// memory layout:
|
||||||
|
// bytes 0-3: reserved for signature on macOS
|
||||||
|
// bytes 4-7: reader count, as a u32
|
||||||
|
// bytes 8-11: writer count, as a u32
|
||||||
|
|
||||||
|
fn rwlock_get_readers<'mir, 'tcx: 'mir>(
|
||||||
|
ecx: &MiriEvalContext<'mir, 'tcx>,
|
||||||
|
rwlock_op: OpTy<'tcx, Tag>,
|
||||||
|
) -> InterpResult<'tcx, ScalarMaybeUndef<Tag>> {
|
||||||
|
// Ensure that the following read at an offset to the rwlock pointer is within bounds
|
||||||
|
assert_ptr_target_min_size(ecx, rwlock_op, 12)?;
|
||||||
|
let rwlock_place = ecx.deref_operand(rwlock_op)?;
|
||||||
|
let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?;
|
||||||
|
let readers_place =
|
||||||
|
rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?;
|
||||||
|
ecx.read_scalar(readers_place.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rwlock_set_readers<'mir, 'tcx: 'mir>(
|
||||||
|
ecx: &mut MiriEvalContext<'mir, 'tcx>,
|
||||||
|
rwlock_op: OpTy<'tcx, Tag>,
|
||||||
|
readers: impl Into<ScalarMaybeUndef<Tag>>,
|
||||||
|
) -> InterpResult<'tcx, ()> {
|
||||||
|
// Ensure that the following write at an offset to the rwlock pointer is within bounds
|
||||||
|
assert_ptr_target_min_size(ecx, rwlock_op, 12)?;
|
||||||
|
let rwlock_place = ecx.deref_operand(rwlock_op)?;
|
||||||
|
let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?;
|
||||||
|
let readers_place =
|
||||||
|
rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?;
|
||||||
|
ecx.write_scalar(readers.into(), readers_place.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rwlock_get_writers<'mir, 'tcx: 'mir>(
|
||||||
|
ecx: &MiriEvalContext<'mir, 'tcx>,
|
||||||
|
rwlock_op: OpTy<'tcx, Tag>,
|
||||||
|
) -> InterpResult<'tcx, ScalarMaybeUndef<Tag>> {
|
||||||
|
// Ensure that the following read at an offset to the rwlock pointer is within bounds
|
||||||
|
assert_ptr_target_min_size(ecx, rwlock_op, 12)?;
|
||||||
|
let rwlock_place = ecx.deref_operand(rwlock_op)?;
|
||||||
|
let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?;
|
||||||
|
let writers_place =
|
||||||
|
rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, ecx)?;
|
||||||
|
ecx.read_scalar(writers_place.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rwlock_set_writers<'mir, 'tcx: 'mir>(
|
||||||
|
ecx: &mut MiriEvalContext<'mir, 'tcx>,
|
||||||
|
rwlock_op: OpTy<'tcx, Tag>,
|
||||||
|
writers: impl Into<ScalarMaybeUndef<Tag>>,
|
||||||
|
) -> InterpResult<'tcx, ()> {
|
||||||
|
// Ensure that the following write at an offset to the rwlock pointer is within bounds
|
||||||
|
assert_ptr_target_min_size(ecx, rwlock_op, 12)?;
|
||||||
|
let rwlock_place = ecx.deref_operand(rwlock_op)?;
|
||||||
|
let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?;
|
||||||
|
let writers_place =
|
||||||
|
rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, ecx)?;
|
||||||
|
ecx.write_scalar(writers.into(), writers_place.into())
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user