1 use rustc_target::abi::Size;
5 // Locks are pointer-sized pieces of data, initialized to 0.
6 // We use them to count readers, with usize::MAX representing the write-locked state.
8 fn deref_lock<'mir, 'tcx: 'mir>(
9 ecx: &mut MiriEvalContext<'mir, 'tcx>,
10 lock_op: OpTy<'tcx, Tag>,
11 ) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> {
12 // `lock` is a pointer to `void*`; cast it to a pointer to `usize`.
13 let lock = ecx.deref_operand(lock_op)?;
14 let usize = ecx.machine.layouts.usize;
15 assert_eq!(lock.layout.size, usize.size);
16 Ok(lock.offset(Size::ZERO, MemPlaceMeta::None, usize, ecx)?)
19 impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
20 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
21 #[allow(non_snake_case)]
22 fn AcquireSRWLockExclusive(
24 lock_op: OpTy<'tcx, Tag>,
25 ) -> InterpResult<'tcx> {
26 let this = self.eval_context_mut();
27 assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported");
29 let lock = deref_lock(this, lock_op)?;
30 let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?;
32 // Currently not locked. Lock it.
33 let new_val = Scalar::from_machine_usize(this.machine_usize_max(), this);
34 this.write_scalar(new_val, lock.into())?;
36 // Lock is already held. This is a deadlock.
37 throw_machine_stop!(TerminationInfo::Deadlock);
43 #[allow(non_snake_case)]
44 fn TryAcquireSRWLockExclusive(
46 lock_op: OpTy<'tcx, Tag>,
47 ) -> InterpResult<'tcx, u8> {
48 let this = self.eval_context_mut();
49 assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported");
51 let lock = deref_lock(this, lock_op)?;
52 let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?;
54 // Currently not locked. Lock it.
55 let new_val = this.machine_usize_max();
56 this.write_scalar(Scalar::from_machine_usize(new_val, this), lock.into())?;
59 // Lock is already held.
64 #[allow(non_snake_case)]
65 fn ReleaseSRWLockExclusive(
67 lock_op: OpTy<'tcx, Tag>,
68 ) -> InterpResult<'tcx> {
69 let this = self.eval_context_mut();
70 assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported");
72 let lock = deref_lock(this, lock_op)?;
73 let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?;
74 if lock_val == this.machine_usize_max() {
75 // Currently locked. Unlock it.
77 this.write_scalar(Scalar::from_machine_usize(new_val, this), lock.into())?;
79 // Lock is not locked.
80 throw_ub_format!("calling ReleaseSRWLockExclusive on an SRWLock that is not exclusively locked");
86 #[allow(non_snake_case)]
87 fn AcquireSRWLockShared(
89 lock_op: OpTy<'tcx, Tag>,
90 ) -> InterpResult<'tcx> {
91 let this = self.eval_context_mut();
92 assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported");
94 let lock = deref_lock(this, lock_op)?;
95 let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?;
96 if lock_val == this.machine_usize_max() {
97 // Currently write locked. This is a deadlock.
98 throw_machine_stop!(TerminationInfo::Deadlock);
100 // Bump up read counter (cannot overflow as we just checkd against usize::MAX);
101 let new_val = lock_val+1;
102 // Make sure this does not reach the "write locked" flag.
103 if new_val == this.machine_usize_max() {
104 throw_unsup_format!("SRWLock read-acquired too many times");
106 this.write_scalar(Scalar::from_machine_usize(new_val, this), lock.into())?;
112 #[allow(non_snake_case)]
113 fn TryAcquireSRWLockShared(
115 lock_op: OpTy<'tcx, Tag>,
116 ) -> InterpResult<'tcx, u8> {
117 let this = self.eval_context_mut();
118 assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported");
120 let lock = deref_lock(this, lock_op)?;
121 let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?;
122 if lock_val == this.machine_usize_max() {
123 // Currently write locked.
126 // Bump up read counter (cannot overflow as we just checkd against usize::MAX);
127 let new_val = lock_val+1;
128 // Make sure this does not reach the "write locked" flag.
129 if new_val == this.machine_usize_max() {
130 throw_unsup_format!("SRWLock read-acquired too many times");
132 this.write_scalar(Scalar::from_machine_usize(new_val, this), lock.into())?;
137 #[allow(non_snake_case)]
138 fn ReleaseSRWLockShared(
140 lock_op: OpTy<'tcx, Tag>,
141 ) -> InterpResult<'tcx> {
142 let this = self.eval_context_mut();
143 assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported");
145 let lock = deref_lock(this, lock_op)?;
146 let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?;
147 if lock_val == this.machine_usize_max() {
148 // Currently write locked. This is a UB.
149 throw_ub_format!("calling ReleaseSRWLockShared on write-locked SRWLock");
150 } else if lock_val == 0 {
151 // Currently not locked at all.
152 throw_ub_format!("calling ReleaseSRWLockShared on unlocked SRWLock");
154 // Decrement read counter (cannot overflow as we just checkd against 0);
155 let new_val = lock_val-1;
156 this.write_scalar(Scalar::from_machine_usize(new_val, this), lock.into())?;