Show More
@@ -1,105 +1,142 b'' | |||||
1 | use super::dirstate_map::DirstateMap; |
|
1 | use super::dirstate_map::DirstateMap; | |
2 | use stable_deref_trait::StableDeref; |
|
2 | use stable_deref_trait::StableDeref; | |
3 | use std::ops::Deref; |
|
3 | use std::ops::Deref; | |
4 |
|
4 | |||
|
5 | /* | |||
|
6 | // /!\ This is unsound and can cause use after free. It will be fixed in the | |||
|
7 | // next patch | |||
|
8 | ||||
|
9 | // If we change `value` from its current use of `HgPathBuf` to `&HgPath`, | |||
|
10 | // nothing here tells that `value` will outlive `OwningDirstateMap` | |||
|
11 | pub fn copy_map_insert<'a,'owned>( | |||
|
12 | &'owned mut self, | |||
|
13 | key: &HgPath, | |||
|
14 | value: &'a HgPath, | |||
|
15 | ) -> Result<Option<HgPathBuf>, DirstateV2ParseError> { | |||
|
16 | // `'local` is smaller than `'a` here | |||
|
17 | let map: &'local mut DirstateMap<'local> = self.get_map_mut(); | |||
|
18 | let node: &'local mut Node<'local> = DirstateMap::get_or_insert_node( | |||
|
19 | map.on_disk, | |||
|
20 | &mut map.unreachable_bytes, | |||
|
21 | &mut map.root, | |||
|
22 | &key, | |||
|
23 | WithBasename::to_cow_owned, | |||
|
24 | |_ancestor| {}, | |||
|
25 | )?; | |||
|
26 | if node.copy_source.is_none() { | |||
|
27 | map.nodes_with_copy_source_count += 1 | |||
|
28 | } | |||
|
29 | Ok(node.copy_source.replace(value.into()).map(Cow::into_owned)) | |||
|
30 | // and right here ----------^^^^^^^^^^^^ | |||
|
31 | // we are storing `&'a HgPath` in `Node<'local>` which is possible | |||
|
32 | // because to the compiler, `'a` is longer than ``local`. | |||
|
33 | // It is wrong because nothing proves that `&'a HgPath` will outlive `self`. | |||
|
34 | } | |||
|
35 | ||||
|
36 | // All of this is caused by the wrong cast of the DirstateMap pointer that | |||
|
37 | // fakes the lifetime of `DirstateMap` and ensures the compiler that it lives | |||
|
38 | // as long as `on_disk`, which is only true for its immutable data. | |||
|
39 | // This will be fixed in the next commit. | |||
|
40 | */ | |||
|
41 | ||||
5 | /// Keep a `DirstateMap<'on_disk>` next to the `on_disk` buffer that it |
|
42 | /// Keep a `DirstateMap<'on_disk>` next to the `on_disk` buffer that it | |
6 | /// borrows. |
|
43 | /// borrows. | |
7 | /// |
|
44 | /// | |
8 | /// This is similar to [`OwningRef`] which is more limited because it |
|
45 | /// This is similar to [`OwningRef`] which is more limited because it | |
9 | /// represents exactly one `&T` reference next to the value it borrows, as |
|
46 | /// represents exactly one `&T` reference next to the value it borrows, as | |
10 | /// opposed to a struct that may contain an arbitrary number of references in |
|
47 | /// opposed to a struct that may contain an arbitrary number of references in | |
11 | /// arbitrarily-nested data structures. |
|
48 | /// arbitrarily-nested data structures. | |
12 | /// |
|
49 | /// | |
13 | /// [`OwningRef`]: https://docs.rs/owning_ref/0.4.1/owning_ref/struct.OwningRef.html |
|
50 | /// [`OwningRef`]: https://docs.rs/owning_ref/0.4.1/owning_ref/struct.OwningRef.html | |
14 | pub struct OwningDirstateMap { |
|
51 | pub struct OwningDirstateMap { | |
15 | /// Owned handle to a bytes buffer with a stable address. |
|
52 | /// Owned handle to a bytes buffer with a stable address. | |
16 | /// |
|
53 | /// | |
17 | /// See <https://docs.rs/owning_ref/0.4.1/owning_ref/trait.StableAddress.html>. |
|
54 | /// See <https://docs.rs/owning_ref/0.4.1/owning_ref/trait.StableAddress.html>. | |
18 | on_disk: Box<dyn Deref<Target = [u8]> + Send>, |
|
55 | on_disk: Box<dyn Deref<Target = [u8]> + Send>, | |
19 |
|
56 | |||
20 | /// Pointer for `Box<DirstateMap<'on_disk>>`, typed-erased because the |
|
57 | /// Pointer for `Box<DirstateMap<'on_disk>>`, typed-erased because the | |
21 | /// language cannot represent a lifetime referencing a sibling field. |
|
58 | /// language cannot represent a lifetime referencing a sibling field. | |
22 | /// This is not quite a self-referencial struct (moving this struct is not |
|
59 | /// This is not quite a self-referencial struct (moving this struct is not | |
23 | /// a problem as it doesn’t change the address of the bytes buffer owned |
|
60 | /// a problem as it doesn’t change the address of the bytes buffer owned | |
24 | /// by `on_disk`) but touches similar borrow-checker limitations. |
|
61 | /// by `on_disk`) but touches similar borrow-checker limitations. | |
25 | ptr: *mut (), |
|
62 | ptr: *mut (), | |
26 | } |
|
63 | } | |
27 |
|
64 | |||
28 | impl OwningDirstateMap { |
|
65 | impl OwningDirstateMap { | |
29 | pub fn new_empty<OnDisk>(on_disk: OnDisk) -> Self |
|
66 | pub fn new_empty<OnDisk>(on_disk: OnDisk) -> Self | |
30 | where |
|
67 | where | |
31 | OnDisk: Deref<Target = [u8]> + StableDeref + Send + 'static, |
|
68 | OnDisk: Deref<Target = [u8]> + StableDeref + Send + 'static, | |
32 | { |
|
69 | { | |
33 | let on_disk = Box::new(on_disk); |
|
70 | let on_disk = Box::new(on_disk); | |
34 | let bytes: &'_ [u8] = &on_disk; |
|
71 | let bytes: &'_ [u8] = &on_disk; | |
35 | let map = DirstateMap::empty(bytes); |
|
72 | let map = DirstateMap::empty(bytes); | |
36 |
|
73 | |||
37 | // Like in `bytes` above, this `'_` lifetime parameter borrows from |
|
74 | // Like in `bytes` above, this `'_` lifetime parameter borrows from | |
38 | // the bytes buffer owned by `on_disk`. |
|
75 | // the bytes buffer owned by `on_disk`. | |
39 | let ptr: *mut DirstateMap<'_> = Box::into_raw(Box::new(map)); |
|
76 | let ptr: *mut DirstateMap<'_> = Box::into_raw(Box::new(map)); | |
40 |
|
77 | |||
41 | // Erase the pointed type entirely in order to erase the lifetime. |
|
78 | // Erase the pointed type entirely in order to erase the lifetime. | |
42 | let ptr: *mut () = ptr.cast(); |
|
79 | let ptr: *mut () = ptr.cast(); | |
43 |
|
80 | |||
44 | Self { on_disk, ptr } |
|
81 | Self { on_disk, ptr } | |
45 | } |
|
82 | } | |
46 |
|
83 | |||
47 | pub fn get_pair_mut<'a>( |
|
84 | pub fn get_pair_mut<'a>( | |
48 | &'a mut self, |
|
85 | &'a mut self, | |
49 | ) -> (&'a [u8], &'a mut DirstateMap<'a>) { |
|
86 | ) -> (&'a [u8], &'a mut DirstateMap<'a>) { | |
50 | // SAFETY: We cast the type-erased pointer back to the same type it had |
|
87 | // SAFETY: We cast the type-erased pointer back to the same type it had | |
51 | // in `new`, except with a different lifetime parameter. This time we |
|
88 | // in `new`, except with a different lifetime parameter. This time we | |
52 | // connect the lifetime to that of `self`. This cast is valid because |
|
89 | // connect the lifetime to that of `self`. This cast is valid because | |
53 | // `self` owns the same `on_disk` whose buffer `DirstateMap` |
|
90 | // `self` owns the same `on_disk` whose buffer `DirstateMap` | |
54 | // references. That buffer has a stable memory address because our |
|
91 | // references. That buffer has a stable memory address because our | |
55 | // `Self::new_empty` counstructor requires `StableDeref`. |
|
92 | // `Self::new_empty` counstructor requires `StableDeref`. | |
56 | let ptr: *mut DirstateMap<'a> = self.ptr.cast(); |
|
93 | let ptr: *mut DirstateMap<'a> = self.ptr.cast(); | |
57 | // SAFETY: we dereference that pointer, connecting the lifetime of the |
|
94 | // SAFETY: we dereference that pointer, connecting the lifetime of the | |
58 | // new `&mut` to that of `self`. This is valid because the |
|
95 | // new `&mut` to that of `self`. This is valid because the | |
59 | // raw pointer is to a boxed value, and `self` owns that box. |
|
96 | // raw pointer is to a boxed value, and `self` owns that box. | |
60 | (&self.on_disk, unsafe { &mut *ptr }) |
|
97 | (&self.on_disk, unsafe { &mut *ptr }) | |
61 | } |
|
98 | } | |
62 |
|
99 | |||
63 | pub fn get_map_mut<'a>(&'a mut self) -> &'a mut DirstateMap<'a> { |
|
100 | pub fn get_map_mut<'a>(&'a mut self) -> &'a mut DirstateMap<'a> { | |
64 | self.get_pair_mut().1 |
|
101 | self.get_pair_mut().1 | |
65 | } |
|
102 | } | |
66 |
|
103 | |||
67 | pub fn get_map<'a>(&'a self) -> &'a DirstateMap<'a> { |
|
104 | pub fn get_map<'a>(&'a self) -> &'a DirstateMap<'a> { | |
68 | // SAFETY: same reasoning as in `get_pair_mut` above. |
|
105 | // SAFETY: same reasoning as in `get_pair_mut` above. | |
69 | let ptr: *mut DirstateMap<'a> = self.ptr.cast(); |
|
106 | let ptr: *mut DirstateMap<'a> = self.ptr.cast(); | |
70 | unsafe { &*ptr } |
|
107 | unsafe { &*ptr } | |
71 | } |
|
108 | } | |
72 |
|
109 | |||
73 | pub fn on_disk<'a>(&'a self) -> &'a [u8] { |
|
110 | pub fn on_disk<'a>(&'a self) -> &'a [u8] { | |
74 | &self.on_disk |
|
111 | &self.on_disk | |
75 | } |
|
112 | } | |
76 | } |
|
113 | } | |
77 |
|
114 | |||
78 | impl Drop for OwningDirstateMap { |
|
115 | impl Drop for OwningDirstateMap { | |
79 | fn drop(&mut self) { |
|
116 | fn drop(&mut self) { | |
80 | // Silence a "field is never read" warning, and demonstrate that this |
|
117 | // Silence a "field is never read" warning, and demonstrate that this | |
81 | // value is still alive. |
|
118 | // value is still alive. | |
82 | let _: &Box<dyn Deref<Target = [u8]> + Send> = &self.on_disk; |
|
119 | let _: &Box<dyn Deref<Target = [u8]> + Send> = &self.on_disk; | |
83 | // SAFETY: this cast is the same as in `get_mut`, and is valid for the |
|
120 | // SAFETY: this cast is the same as in `get_mut`, and is valid for the | |
84 | // same reason. `self.on_disk` still exists at this point, drop glue |
|
121 | // same reason. `self.on_disk` still exists at this point, drop glue | |
85 | // will drop it implicitly after this `drop` method returns. |
|
122 | // will drop it implicitly after this `drop` method returns. | |
86 | let ptr: *mut DirstateMap<'_> = self.ptr.cast(); |
|
123 | let ptr: *mut DirstateMap<'_> = self.ptr.cast(); | |
87 | // SAFETY: `Box::from_raw` takes ownership of the box away from `self`. |
|
124 | // SAFETY: `Box::from_raw` takes ownership of the box away from `self`. | |
88 | // This is fine because drop glue does nothing for `*mut ()` and we’re |
|
125 | // This is fine because drop glue does nothing for `*mut ()` and we’re | |
89 | // in `drop`, so `get` and `get_mut` cannot be called again. |
|
126 | // in `drop`, so `get` and `get_mut` cannot be called again. | |
90 | unsafe { drop(Box::from_raw(ptr)) } |
|
127 | unsafe { drop(Box::from_raw(ptr)) } | |
91 | } |
|
128 | } | |
92 | } |
|
129 | } | |
93 |
|
130 | |||
94 | fn _static_assert_is_send<T: Send>() {} |
|
131 | fn _static_assert_is_send<T: Send>() {} | |
95 |
|
132 | |||
96 | fn _static_assert_fields_are_send() { |
|
133 | fn _static_assert_fields_are_send() { | |
97 | _static_assert_is_send::<Box<DirstateMap<'_>>>(); |
|
134 | _static_assert_is_send::<Box<DirstateMap<'_>>>(); | |
98 | } |
|
135 | } | |
99 |
|
136 | |||
100 | // SAFETY: we don’t get this impl implicitly because `*mut (): !Send` because |
|
137 | // SAFETY: we don’t get this impl implicitly because `*mut (): !Send` because | |
101 | // thread-safety of raw pointers is unknown in the general case. However this |
|
138 | // thread-safety of raw pointers is unknown in the general case. However this | |
102 | // particular raw pointer represents a `Box<DirstateMap<'on_disk>>` that we |
|
139 | // particular raw pointer represents a `Box<DirstateMap<'on_disk>>` that we | |
103 | // own. Since that `Box` is `Send` as shown in above, it is sound to mark |
|
140 | // own. Since that `Box` is `Send` as shown in above, it is sound to mark | |
104 | // this struct as `Send` too. |
|
141 | // this struct as `Send` too. | |
105 | unsafe impl Send for OwningDirstateMap {} |
|
142 | unsafe impl Send for OwningDirstateMap {} |
General Comments 0
You need to be logged in to leave comments.
Login now