2 use crate::ty
::layout
::{self, HasDataLayout, Size}
;
5 AllocId
, EvalResult
, InboundsCheck
,
8 ////////////////////////////////////////////////////////////////////////////////
10 ////////////////////////////////////////////////////////////////////////////////
12 pub trait PointerArithmetic
: layout
::HasDataLayout
{
13 // These are not supposed to be overridden.
16 fn pointer_size(&self) -> Size
{
17 self.data_layout().pointer_size
20 //// Trunace the given value to the pointer size; also return whether there was an overflow
22 fn truncate_to_ptr(&self, val
: u128
) -> (u64, bool
) {
23 let max_ptr_plus_1
= 1u128 << self.pointer_size().bits();
24 ((val
% max_ptr_plus_1
) as u64, val
>= max_ptr_plus_1
)
28 fn offset
<'tcx
>(&self, val
: u64, i
: u64) -> EvalResult
<'tcx
, u64> {
29 let (res
, over
) = self.overflowing_offset(val
, i
);
30 if over { err!(Overflow(mir::BinOp::Add)) }
else { Ok(res) }
34 fn overflowing_offset(&self, val
: u64, i
: u64) -> (u64, bool
) {
35 let (res
, over1
) = val
.overflowing_add(i
);
36 let (res
, over2
) = self.truncate_to_ptr(u128
::from(res
));
41 fn signed_offset
<'tcx
>(&self, val
: u64, i
: i64) -> EvalResult
<'tcx
, u64> {
42 let (res
, over
) = self.overflowing_signed_offset(val
, i128
::from(i
));
43 if over { err!(Overflow(mir::BinOp::Add)) }
else { Ok(res) }
46 // Overflow checking only works properly on the range from -u64 to +u64.
48 fn overflowing_signed_offset(&self, val
: u64, i
: i128
) -> (u64, bool
) {
49 // FIXME: is it possible to over/underflow here?
51 // trickery to ensure that i64::min_value() works fine
52 // this formula only works for true negative values, it panics for zero!
53 let n
= u64::max_value() - (i
as u64) + 1;
54 val
.overflowing_sub(n
)
56 self.overflowing_offset(val
, i
as u64)
61 impl<T
: layout
::HasDataLayout
> PointerArithmetic
for T {}
64 /// Pointer is generic over the type that represents a reference to Allocations,
65 /// thus making it possible for the most convenient representation to be used in
68 /// Defaults to the index based and loosely coupled AllocId.
70 /// Pointer is also generic over the `Tag` associated with each pointer,
71 /// which is used to do provenance tracking during execution.
72 #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
73 pub struct Pointer
<Tag
=(),Id
=AllocId
> {
79 static_assert
!(POINTER_SIZE
: ::std
::mem
::size_of
::<Pointer
>() == 16);
81 /// Produces a `Pointer` which points to the beginning of the Allocation
82 impl From
<AllocId
> for Pointer
{
84 fn from(alloc_id
: AllocId
) -> Self {
85 Pointer
::new(alloc_id
, Size
::ZERO
)
89 impl<'tcx
> Pointer
<()> {
91 pub fn new(alloc_id
: AllocId
, offset
: Size
) -> Self {
92 Pointer { alloc_id, offset, tag: () }
96 pub fn with_default_tag
<Tag
>(self) -> Pointer
<Tag
>
99 Pointer
::new_with_tag(self.alloc_id
, self.offset
, Default
::default())
103 impl<'tcx
, Tag
> Pointer
<Tag
> {
105 pub fn new_with_tag(alloc_id
: AllocId
, offset
: Size
, tag
: Tag
) -> Self {
106 Pointer { alloc_id, offset, tag }
110 pub fn offset(self, i
: Size
, cx
: &impl HasDataLayout
) -> EvalResult
<'tcx
, Self> {
111 Ok(Pointer
::new_with_tag(
113 Size
::from_bytes(cx
.data_layout().offset(self.offset
.bytes(), i
.bytes())?
),
119 pub fn overflowing_offset(self, i
: Size
, cx
: &impl HasDataLayout
) -> (Self, bool
) {
120 let (res
, over
) = cx
.data_layout().overflowing_offset(self.offset
.bytes(), i
.bytes());
121 (Pointer
::new_with_tag(self.alloc_id
, Size
::from_bytes(res
), self.tag
), over
)
125 pub fn wrapping_offset(self, i
: Size
, cx
: &impl HasDataLayout
) -> Self {
126 self.overflowing_offset(i
, cx
).0
130 pub fn signed_offset(self, i
: i64, cx
: &impl HasDataLayout
) -> EvalResult
<'tcx
, Self> {
131 Ok(Pointer
::new_with_tag(
133 Size
::from_bytes(cx
.data_layout().signed_offset(self.offset
.bytes(), i
)?
),
139 pub fn overflowing_signed_offset(self, i
: i128
, cx
: &impl HasDataLayout
) -> (Self, bool
) {
140 let (res
, over
) = cx
.data_layout().overflowing_signed_offset(self.offset
.bytes(), i
);
141 (Pointer
::new_with_tag(self.alloc_id
, Size
::from_bytes(res
), self.tag
), over
)
145 pub fn wrapping_signed_offset(self, i
: i64, cx
: &impl HasDataLayout
) -> Self {
146 self.overflowing_signed_offset(i128
::from(i
), cx
).0
150 pub fn erase_tag(self) -> Pointer
{
151 Pointer { alloc_id: self.alloc_id, offset: self.offset, tag: () }
155 pub fn check_in_alloc(
157 allocation_size
: Size
,
158 check
: InboundsCheck
,
159 ) -> EvalResult
<'tcx
, ()> {
160 if self.offset
> allocation_size
{
161 err
!(PointerOutOfBounds
{
162 ptr
: self.erase_tag(),