Skip to content

Commit aad13a1

Browse files
committed
centralize Scalar size sanity checks and also do them in release builds
1 parent 3defb3f commit aad13a1

File tree

8 files changed

+54
-79
lines changed

8 files changed

+54
-79
lines changed

src/librustc/mir/interpret/allocation.rs

+3-13
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
33
use super::{
44
Pointer, EvalResult, AllocId, ScalarMaybeUndef, write_target_uint, read_target_uint, Scalar,
5-
truncate,
65
};
76

87
use crate::ty::layout::{Size, Align};
@@ -382,18 +381,9 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
382381
ScalarMaybeUndef::Undef => return self.mark_definedness(ptr, type_size, false),
383382
};
384383

385-
let bytes = match val {
386-
Scalar::Ptr(val) => {
387-
assert_eq!(type_size, cx.data_layout().pointer_size);
388-
val.offset.bytes() as u128
389-
}
390-
391-
Scalar::Raw { data, size } => {
392-
assert_eq!(size as u64, type_size.bytes());
393-
debug_assert_eq!(truncate(data, Size::from_bytes(size.into())), data,
394-
"Unexpected value of size {} when writing to memory", size);
395-
data
396-
},
384+
let bytes = match val.to_bits_or_ptr(type_size, cx) {
385+
Err(val) => val.offset.bytes() as u128,
386+
Ok(data) => data,
397387
};
398388

399389
let endian = cx.data_layout().endian;

src/librustc/mir/interpret/value.rs

+29-13
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ impl<'tcx, Tag> Scalar<Tag> {
232232
}
233233
}
234234

235-
/// Returns this pointers offset from the allocation base, or from NULL (for
235+
/// Returns this pointer's offset from the allocation base, or from NULL (for
236236
/// integer pointers).
237237
#[inline]
238238
pub fn get_ptr_offset(self, cx: &impl HasDataLayout) -> Size {
@@ -269,7 +269,7 @@ impl<'tcx, Tag> Scalar<Tag> {
269269
#[inline]
270270
pub fn from_uint(i: impl Into<u128>, size: Size) -> Self {
271271
let i = i.into();
272-
debug_assert_eq!(truncate(i, size), i,
272+
assert_eq!(truncate(i, size), i,
273273
"Unsigned value {} does not fit in {} bits", i, size.bits());
274274
Scalar::Raw { data: i, size: size.bytes() as u8 }
275275
}
@@ -279,7 +279,7 @@ impl<'tcx, Tag> Scalar<Tag> {
279279
let i = i.into();
280280
// `into` performed sign extension, we have to truncate
281281
let truncated = truncate(i as u128, size);
282-
debug_assert_eq!(sign_extend(truncated, size) as i128, i,
282+
assert_eq!(sign_extend(truncated, size) as i128, i,
283283
"Signed value {} does not fit in {} bits", i, size.bits());
284284
Scalar::Raw { data: truncated, size: size.bytes() as u8 }
285285
}
@@ -294,12 +294,35 @@ impl<'tcx, Tag> Scalar<Tag> {
294294
Scalar::Raw { data: f.to_bits() as u128, size: 8 }
295295
}
296296

297+
#[inline]
298+
pub fn to_bits_or_ptr(
299+
self,
300+
target_size: Size,
301+
cx: &impl HasDataLayout,
302+
) -> Result<u128, Pointer<Tag>> {
303+
match self {
304+
Scalar::Raw { data, size } => {
305+
assert_eq!(target_size.bytes(), size as u64);
306+
assert_ne!(size, 0, "to_bits cannot be used with zsts");
307+
assert_eq!(truncate(data, target_size), data,
308+
"Scalar value {:#x} exceeds size of {} bytes", data, size);
309+
Ok(data)
310+
}
311+
Scalar::Ptr(ptr) => {
312+
assert_eq!(target_size, cx.data_layout().pointer_size);
313+
Err(ptr)
314+
}
315+
}
316+
}
317+
297318
#[inline]
298319
pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
299320
match self {
300321
Scalar::Raw { data, size } => {
301322
assert_eq!(target_size.bytes(), size as u64);
302323
assert_ne!(size, 0, "to_bits cannot be used with zsts");
324+
assert_eq!(truncate(data, target_size), data,
325+
"Scalar value {:#x} exceeds size of {} bytes", data, size);
303326
Ok(data)
304327
}
305328
Scalar::Ptr(_) => err!(ReadPointerAsBytes),
@@ -350,58 +373,51 @@ impl<'tcx, Tag> Scalar<Tag> {
350373
pub fn to_u8(self) -> EvalResult<'static, u8> {
351374
let sz = Size::from_bits(8);
352375
let b = self.to_bits(sz)?;
353-
assert_eq!(b as u8 as u128, b);
354376
Ok(b as u8)
355377
}
356378

357379
pub fn to_u32(self) -> EvalResult<'static, u32> {
358380
let sz = Size::from_bits(32);
359381
let b = self.to_bits(sz)?;
360-
assert_eq!(b as u32 as u128, b);
361382
Ok(b as u32)
362383
}
363384

364385
pub fn to_u64(self) -> EvalResult<'static, u64> {
365386
let sz = Size::from_bits(64);
366387
let b = self.to_bits(sz)?;
367-
assert_eq!(b as u64 as u128, b);
368388
Ok(b as u64)
369389
}
370390

371391
pub fn to_usize(self, cx: &impl HasDataLayout) -> EvalResult<'static, u64> {
372392
let b = self.to_bits(cx.data_layout().pointer_size)?;
373-
assert_eq!(b as u64 as u128, b);
374393
Ok(b as u64)
375394
}
376395

377396
pub fn to_i8(self) -> EvalResult<'static, i8> {
378397
let sz = Size::from_bits(8);
379398
let b = self.to_bits(sz)?;
380399
let b = sign_extend(b, sz) as i128;
381-
assert_eq!(b as i8 as i128, b);
382400
Ok(b as i8)
383401
}
384402

385403
pub fn to_i32(self) -> EvalResult<'static, i32> {
386404
let sz = Size::from_bits(32);
387405
let b = self.to_bits(sz)?;
388406
let b = sign_extend(b, sz) as i128;
389-
assert_eq!(b as i32 as i128, b);
390407
Ok(b as i32)
391408
}
392409

393410
pub fn to_i64(self) -> EvalResult<'static, i64> {
394411
let sz = Size::from_bits(64);
395412
let b = self.to_bits(sz)?;
396413
let b = sign_extend(b, sz) as i128;
397-
assert_eq!(b as i64 as i128, b);
398414
Ok(b as i64)
399415
}
400416

401417
pub fn to_isize(self, cx: &impl HasDataLayout) -> EvalResult<'static, i64> {
402-
let b = self.to_bits(cx.data_layout().pointer_size)?;
403-
let b = sign_extend(b, cx.data_layout().pointer_size) as i128;
404-
assert_eq!(b as i64 as i128, b);
418+
let sz = cx.data_layout().pointer_size;
419+
let b = self.to_bits(sz)?;
420+
let b = sign_extend(b, sz) as i128;
405421
Ok(b as i64)
406422
}
407423

src/librustc_codegen_utils/symbol_names.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> {
443443
ct: &'tcx ty::Const<'tcx>,
444444
) -> Result<Self::Const, Self::Error> {
445445
// only print integers
446-
if let ConstValue::Scalar(Scalar::Bits { .. }) = ct.val {
446+
if let ConstValue::Scalar(Scalar::Raw { .. }) = ct.val {
447447
if ct.ty.is_integral() {
448448
return self.pretty_print_const(ct);
449449
}

src/librustc_mir/hair/constant.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,5 @@ fn parse_float<'tcx>(
101101
}
102102
};
103103

104-
// We trust that `data` is properly truncated.
105-
Ok(ConstValue::Scalar(Scalar::Raw { data, size }))
104+
Ok(ConstValue::Scalar(Scalar::from_uint(data, Size::from_bytes(size))))
106105
}

src/librustc_mir/interpret/cast.rs

+8-33
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use syntax::symbol::sym;
66

77
use rustc_apfloat::ieee::{Single, Double};
88
use rustc::mir::interpret::{
9-
Scalar, EvalResult, Pointer, PointerArithmetic, InterpError, truncate
9+
Scalar, EvalResult, Pointer, PointerArithmetic, InterpError,
1010
};
1111
use rustc::mir::CastKind;
1212
use rustc_apfloat::Float;
@@ -135,29 +135,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
135135
use rustc::ty::TyKind::*;
136136
trace!("Casting {:?}: {:?} to {:?}", val, src_layout.ty, dest_layout.ty);
137137

138-
match val {
139-
Scalar::Ptr(ptr) => self.cast_from_ptr(ptr, dest_layout.ty),
140-
Scalar::Raw { data, size } => {
141-
debug_assert_eq!(size as u64, src_layout.size.bytes());
142-
debug_assert_eq!(truncate(data, Size::from_bytes(size.into())), data,
143-
"Unexpected value of size {} before casting", size);
144-
145-
let res = match src_layout.ty.sty {
146-
Float(fty) => self.cast_from_float(data, fty, dest_layout.ty)?,
147-
_ => self.cast_from_int(data, src_layout, dest_layout)?,
148-
};
149-
150-
// Sanity check
151-
match res {
152-
Scalar::Ptr(_) => bug!("Fabricated a ptr value from an int...?"),
153-
Scalar::Raw { data, size } => {
154-
debug_assert_eq!(size as u64, dest_layout.size.bytes());
155-
debug_assert_eq!(truncate(data, Size::from_bytes(size.into())), data,
156-
"Unexpected value of size {} after casting", size);
157-
}
138+
match val.to_bits_or_ptr(src_layout.size, self) {
139+
Err(ptr) => self.cast_from_ptr(ptr, dest_layout.ty),
140+
Ok(data) => {
141+
match src_layout.ty.sty {
142+
Float(fty) => self.cast_from_float(data, fty, dest_layout.ty),
143+
_ => self.cast_from_int(data, src_layout, dest_layout),
158144
}
159-
// Done
160-
Ok(res)
161145
}
162146
}
163147
}
@@ -177,7 +161,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
177161
trace!("cast_from_int: {}, {}, {}", v, src_layout.ty, dest_layout.ty);
178162
use rustc::ty::TyKind::*;
179163
match dest_layout.ty.sty {
180-
Int(_) | Uint(_) => {
164+
Int(_) | Uint(_) | RawPtr(_) => {
181165
let v = self.truncate(v, dest_layout);
182166
Ok(Scalar::from_uint(v, dest_layout.size))
183167
}
@@ -205,15 +189,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
205189
Ok(Scalar::from_uint(v, Size::from_bytes(4)))
206190
},
207191

208-
// No alignment check needed for raw pointers.
209-
// But we have to truncate to target ptr size.
210-
RawPtr(_) => {
211-
Ok(Scalar::from_uint(
212-
self.truncate_to_ptr(v).0,
213-
self.pointer_size(),
214-
))
215-
},
216-
217192
// Casts to bool are not permitted by rustc, no need to handle them here.
218193
_ => err!(Unimplemented(format!("int to {:?} cast", dest_layout.ty))),
219194
}

src/librustc_mir/interpret/memory.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -247,16 +247,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
247247
required_align: Align
248248
) -> EvalResult<'tcx> {
249249
// Check non-NULL/Undef, extract offset
250-
let (offset, alloc_align) = match ptr {
251-
Scalar::Ptr(ptr) => {
250+
let (offset, alloc_align) = match ptr.to_bits_or_ptr(self.pointer_size(), self) {
251+
Err(ptr) => {
252252
// check this is not NULL -- which we can ensure only if this is in-bounds
253253
// of some (potentially dead) allocation.
254254
let align = self.check_bounds_ptr(ptr, InboundsCheck::MaybeDead)?;
255255
(ptr.offset.bytes(), align)
256256
}
257-
Scalar::Raw { data, size } => {
258-
assert_eq!(size as u64, self.pointer_size().bytes());
259-
assert!(data < (1u128 << self.pointer_size().bits()));
257+
Ok(data) => {
260258
// check this is not NULL
261259
if data == 0 {
262260
return err!(InvalidNullPointerUsage);

src/librustc_mir/interpret/operand.rs

+6-7
Original file line numberDiff line numberDiff line change
@@ -639,18 +639,19 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
639639
} => {
640640
let variants_start = niche_variants.start().as_u32() as u128;
641641
let variants_end = niche_variants.end().as_u32() as u128;
642-
match raw_discr {
643-
ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) => {
642+
let raw_discr = raw_discr.not_undef()
643+
.map_err(|_| InterpError::InvalidDiscriminant(ScalarMaybeUndef::Undef))?;
644+
match raw_discr.to_bits_or_ptr(discr_val.layout.size, self) {
645+
Err(ptr) => {
644646
// The niche must be just 0 (which an inbounds pointer value never is)
645647
let ptr_valid = niche_start == 0 && variants_start == variants_end &&
646648
self.memory.check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok();
647649
if !ptr_valid {
648-
return err!(InvalidDiscriminant(raw_discr.erase_tag()));
650+
return err!(InvalidDiscriminant(raw_discr.erase_tag().into()));
649651
}
650652
(dataful_variant.as_u32() as u128, dataful_variant)
651653
},
652-
ScalarMaybeUndef::Scalar(Scalar::Raw { data: raw_discr, size }) => {
653-
assert_eq!(size as u64, discr_val.layout.size.bytes());
654+
Ok(raw_discr) => {
654655
let adjusted_discr = raw_discr.wrapping_sub(niche_start)
655656
.wrapping_add(variants_start);
656657
if variants_start <= adjusted_discr && adjusted_discr <= variants_end {
@@ -665,8 +666,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
665666
(dataful_variant.as_u32() as u128, dataful_variant)
666667
}
667668
},
668-
ScalarMaybeUndef::Undef =>
669-
return err!(InvalidDiscriminant(ScalarMaybeUndef::Undef)),
670669
}
671670
}
672671
})

src/librustc_mir/interpret/validity.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -480,8 +480,8 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
480480
wrapping_range_format(&layout.valid_range, max_hi),
481481
)
482482
);
483-
let bits = match value {
484-
Scalar::Ptr(ptr) => {
483+
let bits = match value.to_bits_or_ptr(op.layout.size, self.ecx) {
484+
Err(ptr) => {
485485
if lo == 1 && hi == max_hi {
486486
// only NULL is not allowed.
487487
// We can call `check_align` to check non-NULL-ness, but have to also look
@@ -509,10 +509,8 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
509509
);
510510
}
511511
}
512-
Scalar::Raw { data, size } => {
513-
assert_eq!(size as u64, op.layout.size.bytes());
512+
Ok(data) =>
514513
data
515-
}
516514
};
517515
// Now compare. This is slightly subtle because this is a special "wrap-around" range.
518516
if wrapping_range_contains(&layout.valid_range, bits) {

0 commit comments

Comments
 (0)