1 // Copyright (C) 2019 Alibaba Cloud Computing. All rights reserved.
2 //
3 // Portions Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 //
5 // Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
6 // Use of this source code is governed by a BSD-style license that can be
7 // found in the LICENSE-BSD-3-Clause file.
8 //
9 // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
10 
11 //! Traits to represent an address within an address space.
12 //!
13 //! Two traits are defined to represent an address within an address space:
14 //! - [`AddressValue`](trait.AddressValue.html): stores the raw value of an address. Typically
15 //! `u32`,`u64` or `usize` is used to store the raw value. But pointers, such as `*u8`, can't be used
16 //! because they don't implement the [`Add`](https://doc.rust-lang.org/std/ops/trait.Add.html) and
17 //! [`Sub`](https://doc.rust-lang.org/std/ops/trait.Sub.html) traits.
18 //! - [Address](trait.Address.html): encapsulates an [`AddressValue`](trait.AddressValue.html)
19 //! object and defines methods to access and manipulate it.
20 
21 use std::cmp::{Eq, Ord, PartialEq, PartialOrd};
22 use std::fmt::Debug;
23 use std::ops::{Add, BitAnd, BitOr, Not, Sub};
24 
25 /// Simple helper trait used to store a raw address value.
26 pub trait AddressValue {
27     /// Type of the raw address value.
28     type V: Copy
29         + PartialEq
30         + Eq
31         + PartialOrd
32         + Ord
33         + Not<Output = Self::V>
34         + Add<Output = Self::V>
35         + Sub<Output = Self::V>
36         + BitAnd<Output = Self::V>
37         + BitOr<Output = Self::V>
38         + Debug
39         + From<u8>;
40 
41     /// Return the value zero, coerced into the value type `Self::V`
zero() -> Self::V42     fn zero() -> Self::V {
43         0u8.into()
44     }
45 
46     /// Return the value zero, coerced into the value type `Self::V`
one() -> Self::V47     fn one() -> Self::V {
48         1u8.into()
49     }
50 }
51 
52 /// Trait to represent an address within an address space.
53 ///
54 /// To simplify the design and implementation, assume the same raw data type `(AddressValue::V)`
55 /// could be used to store address, size and offset for the address space. Thus the `Address` trait
56 /// could be used to manage address, size and offset. On the other hand, type aliases may be
57 /// defined to improve code readability.
58 ///
59 /// One design rule is applied to the `Address` trait, namely that operators (+, -, &, | etc) are
60 /// not supported and it forces clients to explicitly invoke corresponding methods. But there are
61 /// always exceptions:
62 ///     `Address` (BitAnd|BitOr) `AddressValue` are supported.
63 pub trait Address:
64     AddressValue
65     + Sized
66     + Default
67     + Copy
68     + Eq
69     + PartialEq
70     + Ord
71     + PartialOrd
72     + BitAnd<<Self as AddressValue>::V, Output = Self>
73     + BitOr<<Self as AddressValue>::V, Output = Self>
74 {
75     /// Creates an address from a raw address value.
76     fn new(addr: Self::V) -> Self;
77 
78     /// Returns the raw value of the address.
79     fn raw_value(&self) -> Self::V;
80 
81     /// Returns the bitwise and of the address with the given mask.
82     fn mask(&self, mask: Self::V) -> Self::V {
83         self.raw_value() & mask
84     }
85 
86     /// Computes the offset from this address to the given base address.
87     ///
88     /// Returns `None` if there is underflow.
89     fn checked_offset_from(&self, base: Self) -> Option<Self::V>;
90 
91     /// Computes the offset from this address to the given base address.
92     ///
93     /// In the event of overflow, follows standard Rust behavior, i.e. panic in debug builds,
94     /// silently wrap in release builds.
95     ///
96     /// Note that, unlike the `unchecked_*` methods in std, this method never invokes undefined
97     /// behavior.
98     /// # Examples
99     ///
100     /// ```
101     /// # use vm_memory::{Address, GuestAddress};
102     /// #
103     /// let base = GuestAddress(0x100);
104     /// let addr = GuestAddress(0x150);
105     /// assert_eq!(addr.unchecked_offset_from(base), 0x50);
106     /// ```
107     fn unchecked_offset_from(&self, base: Self) -> Self::V {
108         self.raw_value() - base.raw_value()
109     }
110 
111     /// Returns self, aligned to the given power of two.
112     fn checked_align_up(&self, power_of_two: Self::V) -> Option<Self> {
113         let mask = power_of_two - Self::one();
114         assert_ne!(power_of_two, Self::zero());
115         assert_eq!(power_of_two & mask, Self::zero());
116         self.checked_add(mask).map(|x| x & !mask)
117     }
118 
119     /// Returns self, aligned to the given power of two.
120     /// Only use this when the result is guaranteed not to overflow.
121     fn unchecked_align_up(&self, power_of_two: Self::V) -> Self {
122         let mask = power_of_two - Self::one();
123         self.unchecked_add(mask) & !mask
124     }
125 
126     /// Computes `self + other`, returning `None` if overflow occurred.
127     fn checked_add(&self, other: Self::V) -> Option<Self>;
128 
129     /// Computes `self + other`.
130     ///
131     /// Returns a tuple of the addition result along with a boolean indicating whether an arithmetic
132     /// overflow would occur. If an overflow would have occurred then the wrapped address
133     /// is returned.
134     fn overflowing_add(&self, other: Self::V) -> (Self, bool);
135 
136     /// Computes `self + offset`.
137     ///
138     /// In the event of overflow, follows standard Rust behavior, i.e. panic in debug builds,
139     /// silently wrap in release builds.
140     ///
141     /// Note that, unlike the `unchecked_*` methods in std, this method never invokes undefined
142     /// behavior..
143     fn unchecked_add(&self, offset: Self::V) -> Self;
144 
145     /// Subtracts two addresses, checking for underflow. If underflow happens, `None` is returned.
146     fn checked_sub(&self, other: Self::V) -> Option<Self>;
147 
148     /// Computes `self - other`.
149     ///
150     /// Returns a tuple of the subtraction result along with a boolean indicating whether an
151     /// arithmetic overflow would occur. If an overflow would have occurred then the wrapped
152     /// address is returned.
153     fn overflowing_sub(&self, other: Self::V) -> (Self, bool);
154 
155     /// Computes `self - other`.
156     ///
157     /// In the event of underflow, follows standard Rust behavior, i.e. panic in debug builds,
158     /// silently wrap in release builds.
159     ///
160     /// Note that, unlike the `unchecked_*` methods in std, this method never invokes undefined
161     /// behavior.
162     fn unchecked_sub(&self, other: Self::V) -> Self;
163 }
164 
165 macro_rules! impl_address_ops {
166     ($T:ident, $V:ty) => {
167         impl AddressValue for $T {
168             type V = $V;
169         }
170 
171         impl Address for $T {
172             fn new(value: $V) -> $T {
173                 $T(value)
174             }
175 
176             fn raw_value(&self) -> $V {
177                 self.0
178             }
179 
180             fn checked_offset_from(&self, base: $T) -> Option<$V> {
181                 self.0.checked_sub(base.0)
182             }
183 
184             fn checked_add(&self, other: $V) -> Option<$T> {
185                 self.0.checked_add(other).map($T)
186             }
187 
188             fn overflowing_add(&self, other: $V) -> ($T, bool) {
189                 let (t, ovf) = self.0.overflowing_add(other);
190                 ($T(t), ovf)
191             }
192 
193             fn unchecked_add(&self, offset: $V) -> $T {
194                 $T(self.0 + offset)
195             }
196 
197             fn checked_sub(&self, other: $V) -> Option<$T> {
198                 self.0.checked_sub(other).map($T)
199             }
200 
201             fn overflowing_sub(&self, other: $V) -> ($T, bool) {
202                 let (t, ovf) = self.0.overflowing_sub(other);
203                 ($T(t), ovf)
204             }
205 
206             fn unchecked_sub(&self, other: $V) -> $T {
207                 $T(self.0 - other)
208             }
209         }
210 
211         impl Default for $T {
212             fn default() -> $T {
213                 Self::new(0 as $V)
214             }
215         }
216 
217         impl BitAnd<$V> for $T {
218             type Output = $T;
219 
220             fn bitand(self, other: $V) -> $T {
221                 $T(self.0 & other)
222             }
223         }
224 
225         impl BitOr<$V> for $T {
226             type Output = $T;
227 
228             fn bitor(self, other: $V) -> $T {
229                 $T(self.0 | other)
230             }
231         }
232     };
233 }
234 
235 #[cfg(test)]
236 mod tests {
237     use super::*;
238 
239     #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
240     struct MockAddress(pub u64);
241     impl_address_ops!(MockAddress, u64);
242 
243     #[test]
244     fn test_new() {
245         assert_eq!(MockAddress::new(0), MockAddress(0));
246         assert_eq!(MockAddress::new(std::u64::MAX), MockAddress(std::u64::MAX));
247     }
248 
249     #[test]
250     fn test_offset_from() {
251         let base = MockAddress(0x100);
252         let addr = MockAddress(0x150);
253         assert_eq!(addr.unchecked_offset_from(base), 0x50u64);
254         assert_eq!(addr.checked_offset_from(base), Some(0x50u64));
255         assert_eq!(base.checked_offset_from(addr), None);
256     }
257 
258     #[test]
259     fn test_equals() {
260         let a = MockAddress(0x300);
261         let b = MockAddress(0x300);
262         let c = MockAddress(0x301);
263         assert_eq!(a, MockAddress(a.raw_value()));
264         assert_eq!(a, b);
265         assert_eq!(b, a);
266         assert_ne!(a, c);
267         assert_ne!(c, a);
268     }
269 
270     #[test]
271     fn test_cmp() {
272         let a = MockAddress(0x300);
273         let b = MockAddress(0x301);
274         assert!(a < b);
275     }
276 
277     #[test]
278     fn test_checked_align_up() {
279         assert_eq!(
280             MockAddress::new(0x128).checked_align_up(8),
281             Some(MockAddress(0x128))
282         );
283         assert_eq!(
284             MockAddress::new(0x128).checked_align_up(16),
285             Some(MockAddress(0x130))
286         );
287         assert_eq!(
288             MockAddress::new(std::u64::MAX - 0x3fff).checked_align_up(0x10000),
289             None
290         );
291     }
292 
293     #[test]
294     #[should_panic]
295     fn test_checked_align_up_invalid() {
296         let _ = MockAddress::new(0x128).checked_align_up(12);
297     }
298 
299     #[test]
300     fn test_unchecked_align_up() {
301         assert_eq!(
302             MockAddress::new(0x128).unchecked_align_up(8),
303             MockAddress(0x128)
304         );
305         assert_eq!(
306             MockAddress::new(0x128).unchecked_align_up(16),
307             MockAddress(0x130)
308         );
309     }
310 
311     #[test]
312     fn test_mask() {
313         let a = MockAddress(0x5050);
314         assert_eq!(MockAddress(0x5000), a & 0xff00u64);
315         assert_eq!(0x5000, a.mask(0xff00u64));
316         assert_eq!(MockAddress(0x5055), a | 0x0005u64);
317     }
318 
319     fn check_add(a: u64, b: u64, expected_overflow: bool, expected_result: u64) {
320         assert_eq!(
321             (MockAddress(expected_result), expected_overflow),
322             MockAddress(a).overflowing_add(b)
323         );
324         if expected_overflow {
325             assert!(MockAddress(a).checked_add(b).is_none());
326             #[cfg(debug_assertions)]
327             assert!(std::panic::catch_unwind(|| MockAddress(a).unchecked_add(b)).is_err());
328         } else {
329             assert_eq!(
330                 Some(MockAddress(expected_result)),
331                 MockAddress(a).checked_add(b)
332             );
333             assert_eq!(
334                 MockAddress(expected_result),
335                 MockAddress(a).unchecked_add(b)
336             );
337         }
338     }
339 
340     #[test]
341     fn test_add() {
342         // without overflow
343         // normal case
344         check_add(10, 10, false, 20);
345         // edge case
346         check_add(std::u64::MAX - 1, 1, false, std::u64::MAX);
347 
348         // with overflow
349         check_add(std::u64::MAX, 1, true, 0);
350     }
351 
352     fn check_sub(a: u64, b: u64, expected_overflow: bool, expected_result: u64) {
353         assert_eq!(
354             (MockAddress(expected_result), expected_overflow),
355             MockAddress(a).overflowing_sub(b)
356         );
357         if expected_overflow {
358             assert!(MockAddress(a).checked_sub(b).is_none());
359             assert!(MockAddress(a).checked_offset_from(MockAddress(b)).is_none());
360             #[cfg(debug_assertions)]
361             assert!(std::panic::catch_unwind(|| MockAddress(a).unchecked_sub(b)).is_err());
362         } else {
363             assert_eq!(
364                 Some(MockAddress(expected_result)),
365                 MockAddress(a).checked_sub(b)
366             );
367             assert_eq!(
368                 Some(expected_result),
369                 MockAddress(a).checked_offset_from(MockAddress(b))
370             );
371             assert_eq!(
372                 MockAddress(expected_result),
373                 MockAddress(a).unchecked_sub(b)
374             );
375         }
376     }
377 
378     #[test]
379     fn test_sub() {
380         // without overflow
381         // normal case
382         check_sub(20, 10, false, 10);
383         // edge case
384         check_sub(1, 1, false, 0);
385 
386         // with underflow
387         check_sub(0, 1, true, std::u64::MAX);
388     }
389 
390     #[test]
391     fn test_default() {
392         assert_eq!(MockAddress::default(), MockAddress(0));
393     }
394 
395     #[test]
396     fn test_bit_and() {
397         let a = MockAddress(0x0ff0);
398         assert_eq!(a & 0xf00f, MockAddress(0));
399     }
400 
401     #[test]
402     fn test_bit_or() {
403         let a = MockAddress(0x0ff0);
404         assert_eq!(a | 0xf00f, MockAddress(0xffff));
405     }
406 }
407