1
1
//! Helper module for some internals, most users don't need to interact with it.
2
2
3
+ use core:: marker:: PhantomData ;
4
+ use core:: ptr:: NonNull ;
3
5
use std:: {
4
6
cell:: UnsafeCell ,
5
7
error:: Error ,
@@ -42,7 +44,7 @@ impl Error for InvalidBorrow {
42
44
#[ derive( Debug ) ]
43
45
pub struct Ref < ' a , T : ?Sized + ' a > {
44
46
flag : & ' a AtomicUsize ,
45
- value : & ' a T ,
47
+ value : NonNull < T > ,
46
48
}
47
49
48
50
impl < ' a , T : ?Sized > Ref < ' a , T > {
@@ -95,7 +97,7 @@ impl<'a, T: ?Sized> Ref<'a, T> {
95
97
{
96
98
let val = Ref {
97
99
flag : self . flag ,
98
- value : f ( self . value ) ,
100
+ value : NonNull :: from ( f ( & * self ) ) ,
99
101
} ;
100
102
101
103
std:: mem:: forget ( self ) ;
@@ -108,7 +110,8 @@ impl<'a, T: ?Sized> Deref for Ref<'a, T> {
108
110
type Target = T ;
109
111
110
112
fn deref ( & self ) -> & T {
111
- self . value
113
+ // SAFETY: `Ref` holds a shared borrow of the value.
114
+ unsafe { self . value . as_ref ( ) }
112
115
}
113
116
}
114
117
@@ -134,7 +137,10 @@ impl<'a, T: ?Sized> Clone for Ref<'a, T> {
134
137
#[ derive( Debug ) ]
135
138
pub struct RefMut < ' a , T : ?Sized + ' a > {
136
139
flag : & ' a AtomicUsize ,
137
- value : & ' a mut T ,
140
+ value : NonNull < T > ,
141
+ // `NonNull<T>` is covariant over `T` but we use it in the place of a mutable reference so we need to be
142
+ // invariant over `T`.
143
+ marker : PhantomData < & ' a mut T > ,
138
144
}
139
145
140
146
impl < ' a , T : ?Sized > RefMut < ' a , T > {
@@ -182,7 +188,7 @@ impl<'a, T: ?Sized> RefMut<'a, T> {
182
188
/// let b2: RefMut<'_, u32> = RefMut::map(b1, |t| &mut t.0);
183
189
/// assert_eq!(*b2, 5);
184
190
/// ```
185
- pub fn map < U , F > ( self , f : F ) -> RefMut < ' a , U >
191
+ pub fn map < U , F > ( mut self , f : F ) -> RefMut < ' a , U >
186
192
where
187
193
F : FnOnce ( & mut T ) -> & mut U ,
188
194
U : ?Sized ,
@@ -192,7 +198,7 @@ impl<'a, T: ?Sized> RefMut<'a, T> {
192
198
// the given `RefMut`, the lifetime we created through turning the
193
199
// pointer into a ref is valid.
194
200
let flag = self . flag ;
195
- let value = unsafe { & mut * ( self . value as * mut _ ) } ;
201
+ let value = NonNull :: from ( f ( & mut * self ) ) ;
196
202
197
203
// We have to forget self so that we do not run `Drop`. Further it's safe
198
204
// because we are creating a new `RefMut`, with the same flag, which
@@ -201,7 +207,8 @@ impl<'a, T: ?Sized> RefMut<'a, T> {
201
207
202
208
RefMut {
203
209
flag,
204
- value : f ( value) ,
210
+ value,
211
+ marker : PhantomData ,
205
212
}
206
213
}
207
214
}
@@ -210,13 +217,17 @@ impl<'a, T: ?Sized> Deref for RefMut<'a, T> {
210
217
type Target = T ;
211
218
212
219
fn deref ( & self ) -> & T {
213
- self . value
220
+ // SAFETY: `RefMut` holds an exclusive borrow of the value and we have a shared borrow of
221
+ // `RefMut` here.
222
+ unsafe { self . value . as_ref ( ) }
214
223
}
215
224
}
216
225
217
226
impl < ' a , T : ?Sized > DerefMut for RefMut < ' a , T > {
218
227
fn deref_mut ( & mut self ) -> & mut T {
219
- self . value
228
+ // SAFETY: `RefMut` holds an exclusive borrow of the value and we have an exclusive borrow
229
+ // of `RefMut` here.
230
+ unsafe { self . value . as_mut ( ) }
220
231
}
221
232
}
222
233
@@ -261,7 +272,7 @@ impl<T> TrustCell<T> {
261
272
262
273
Ref {
263
274
flag : & self . flag ,
264
- value : unsafe { & * self . inner . get ( ) } ,
275
+ value : unsafe { NonNull :: new_unchecked ( self . inner . get ( ) ) } ,
265
276
}
266
277
}
267
278
@@ -274,7 +285,7 @@ impl<T> TrustCell<T> {
274
285
275
286
Ok ( Ref {
276
287
flag : & self . flag ,
277
- value : unsafe { & * self . inner . get ( ) } ,
288
+ value : unsafe { NonNull :: new_unchecked ( self . inner . get ( ) ) } ,
278
289
} )
279
290
}
280
291
@@ -292,7 +303,8 @@ impl<T> TrustCell<T> {
292
303
293
304
RefMut {
294
305
flag : & self . flag ,
295
- value : unsafe { & mut * self . inner . get ( ) } ,
306
+ value : unsafe { NonNull :: new_unchecked ( self . inner . get ( ) ) } ,
307
+ marker : PhantomData ,
296
308
}
297
309
}
298
310
@@ -305,7 +317,8 @@ impl<T> TrustCell<T> {
305
317
306
318
Ok ( RefMut {
307
319
flag : & self . flag ,
308
- value : unsafe { & mut * self . inner . get ( ) } ,
320
+ value : unsafe { NonNull :: new_unchecked ( self . inner . get ( ) ) } ,
321
+ marker : PhantomData ,
309
322
} )
310
323
}
311
324
@@ -471,22 +484,27 @@ mod tests {
471
484
assert ! ( cell. try_borrow_mut( ) . is_err( ) ) ;
472
485
}
473
486
487
+ fn make_ref < ' a , T : ?Sized > ( flag : & ' a AtomicUsize , value : & ' a T ) -> Ref < ' a , T > {
488
+ Ref {
489
+ flag,
490
+ value : NonNull :: from ( value) ,
491
+ }
492
+ }
493
+
474
494
#[ test]
475
495
fn ref_with_non_sized ( ) {
476
- let r: Ref < ' _ , [ i32 ] > = Ref {
477
- flag : & AtomicUsize :: new ( 1 ) ,
478
- value : & [ 2 , 3 , 4 , 5 ] [ ..] ,
479
- } ;
496
+ let value = & [ 2 , 3 , 4 , 5 ] [ ..] ;
497
+ let flag = AtomicUsize :: new ( 1 ) ;
498
+ let r: Ref < ' _ , [ i32 ] > = make_ref ( & flag, value) ;
480
499
481
500
assert_eq ! ( & * r, & [ 2 , 3 , 4 , 5 ] [ ..] ) ;
482
501
}
483
502
484
503
#[ test]
485
504
fn ref_with_non_sized_clone ( ) {
486
- let r: Ref < ' _ , [ i32 ] > = Ref {
487
- flag : & AtomicUsize :: new ( 1 ) ,
488
- value : & [ 2 , 3 , 4 , 5 ] [ ..] ,
489
- } ;
505
+ let value = & [ 2 , 3 , 4 , 5 ] [ ..] ;
506
+ let flag = AtomicUsize :: new ( 1 ) ;
507
+ let r: Ref < ' _ , [ i32 ] > = make_ref ( & flag, value) ;
490
508
let rr = r. clone ( ) ;
491
509
492
510
assert_eq ! ( & * r, & [ 2 , 3 , 4 , 5 ] [ ..] ) ;
@@ -498,30 +516,35 @@ mod tests {
498
516
499
517
#[ test]
500
518
fn ref_with_trait_obj ( ) {
501
- let ra: Ref < ' _ , dyn std:: any:: Any > = Ref {
502
- flag : & AtomicUsize :: new ( 1 ) ,
503
- value : & 2i32 ,
504
- } ;
519
+ let value = & 2i32 ;
520
+ let flag = AtomicUsize :: new ( 1 ) ;
521
+ let ra: Ref < ' _ , dyn std:: any:: Any > = make_ref ( & flag, value) ;
505
522
506
523
assert_eq ! ( ra. downcast_ref:: <i32 >( ) . unwrap( ) , & 2i32 ) ;
507
524
}
508
525
526
+ fn make_ref_mut < ' a , T : ?Sized > ( flag : & ' a AtomicUsize , value : & ' a mut T ) -> RefMut < ' a , T > {
527
+ RefMut {
528
+ flag,
529
+ value : NonNull :: from ( value) ,
530
+ marker : PhantomData ,
531
+ }
532
+ }
533
+
509
534
#[ test]
510
535
fn ref_mut_with_non_sized ( ) {
511
- let mut r: RefMut < ' _ , [ i32 ] > = RefMut {
512
- flag : & AtomicUsize :: new ( 1 ) ,
513
- value : & mut [ 2 , 3 , 4 , 5 ] [ ..] ,
514
- } ;
536
+ let value: & mut [ i32 ] = & mut [ 2 , 3 , 4 , 5 ] [ ..] ;
537
+ let flag = AtomicUsize :: new ( 1 ) ;
538
+ let mut r: RefMut < ' _ , [ i32 ] > = make_ref_mut ( & flag, value) ;
515
539
516
540
assert_eq ! ( & mut * r, & mut [ 2 , 3 , 4 , 5 ] [ ..] ) ;
517
541
}
518
542
519
543
#[ test]
520
544
fn ref_mut_with_trait_obj ( ) {
521
- let mut ra: RefMut < ' _ , dyn std:: any:: Any > = RefMut {
522
- flag : & AtomicUsize :: new ( 1 ) ,
523
- value : & mut 2i32 ,
524
- } ;
545
+ let value = & mut 2i32 ;
546
+ let flag = AtomicUsize :: new ( 1 ) ;
547
+ let mut ra: RefMut < ' _ , dyn std:: any:: Any > = make_ref_mut ( & flag, value) ;
525
548
526
549
assert_eq ! ( ra. downcast_mut:: <i32 >( ) . unwrap( ) , & mut 2i32 ) ;
527
550
}
@@ -613,4 +636,18 @@ mod tests {
613
636
drop ( r) ;
614
637
assert_eq ! ( cell. flag. load( Ordering :: SeqCst ) , 0 ) ;
615
638
}
639
+
640
+ // Test intended to allow Miri to catch bugs like this scenario:
641
+ // https://github.com/rust-lang/rust/issues/63787
642
+ #[ test]
643
+ fn drop_and_borrow_in_fn_call ( ) {
644
+ fn drop_and_borrow ( cell : & TrustCell < u8 > , borrow : Ref < ' _ , u8 > ) {
645
+ drop ( borrow) ;
646
+ * cell. borrow_mut ( ) = 7u8 ;
647
+ }
648
+
649
+ let a = TrustCell :: new ( 4u8 ) ;
650
+ let borrow = a. borrow ( ) ;
651
+ drop_and_borrow ( & a, borrow) ;
652
+ }
616
653
}
0 commit comments