@@ -7,7 +7,7 @@ use std::convert::TryFrom;
7
7
use rustc_hir:: def_id:: DefId ;
8
8
use rustc_middle:: mir:: {
9
9
self ,
10
- interpret:: { ConstValue , GlobalId , InterpResult , Scalar } ,
10
+ interpret:: { ConstValue , GlobalId , InterpResult , PointerArithmetic , Scalar } ,
11
11
BinOp ,
12
12
} ;
13
13
use rustc_middle:: ty;
@@ -328,15 +328,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
328
328
// We managed to find a valid allocation for one pointer, but not the other.
329
329
// That means they are definitely not pointing to the same allocation.
330
330
throw_ub_format ! (
331
- "{} called on pointers into different allocations" ,
331
+ "`{}` called on pointers into different allocations" ,
332
332
intrinsic_name
333
333
) ;
334
334
}
335
335
( Ok ( ( a_alloc_id, a_offset, _) ) , Ok ( ( b_alloc_id, b_offset, _) ) ) => {
336
336
// Found allocation for both. They must be into the same allocation.
337
337
if a_alloc_id != b_alloc_id {
338
338
throw_ub_format ! (
339
- "{} called on pointers into different allocations" ,
339
+ "`{}` called on pointers into different allocations" ,
340
340
intrinsic_name
341
341
) ;
342
342
}
@@ -346,47 +346,71 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
346
346
} ;
347
347
348
348
// Compute distance.
349
- let distance = {
350
- // The subtraction is always done in `isize` to enforce
351
- // the "no more than `isize::MAX` apart" requirement.
352
- let a_offset = ImmTy :: from_uint ( a_offset, isize_layout) ;
353
- let b_offset = ImmTy :: from_uint ( b_offset, isize_layout) ;
354
- let ( val, overflowed, _ty) =
355
- self . overflowing_binary_op ( BinOp :: Sub , & a_offset, & b_offset) ?;
349
+ let dist = {
350
+ // Addresses are unsigned, so this is a `usize` computation. We have to do the
351
+ // overflow check separately anyway.
352
+ let ( val, overflowed, _ty) = {
353
+ let a_offset = ImmTy :: from_uint ( a_offset, usize_layout) ;
354
+ let b_offset = ImmTy :: from_uint ( b_offset, usize_layout) ;
355
+ self . overflowing_binary_op ( BinOp :: Sub , & a_offset, & b_offset) ?
356
+ } ;
356
357
if overflowed {
357
- throw_ub_format ! ( "pointers were too far apart for {}" , intrinsic_name) ;
358
+ // a < b
359
+ if intrinsic_name == sym:: ptr_offset_from_unsigned {
360
+ throw_ub_format ! (
361
+ "`{}` called when first pointer has smaller offset than second: {} < {}" ,
362
+ intrinsic_name,
363
+ a_offset,
364
+ b_offset,
365
+ ) ;
366
+ }
367
+ // The signed form of the intrinsic allows this. If we interpret the
368
+ // difference as isize, we'll get the proper signed difference. If that
369
+ // seems *positive*, they were more than isize::MAX apart.
370
+ let dist = val. to_machine_isize ( self ) ?;
371
+ if dist >= 0 {
372
+ throw_ub_format ! (
373
+ "`{}` called when first pointer is too far before second" ,
374
+ intrinsic_name
375
+ ) ;
376
+ }
377
+ dist
378
+ } else {
379
+ // b >= a
380
+ let dist = val. to_machine_isize ( self ) ?;
381
+ // If converting to isize produced a *negative* result, we had an overflow
382
+ // because they were more than isize::MAX apart.
383
+ if dist < 0 {
384
+ throw_ub_format ! (
385
+ "`{}` called when first pointer is too far ahead of second" ,
386
+ intrinsic_name
387
+ ) ;
388
+ }
389
+ dist
358
390
}
359
- val. to_machine_isize ( self ) ?
360
391
} ;
361
392
362
393
// Check that the range between them is dereferenceable ("in-bounds or one past the
363
394
// end of the same allocation"). This is like the check in ptr_offset_inbounds.
364
- let min_ptr = if distance >= 0 { b } else { a } ;
395
+ let min_ptr = if dist >= 0 { b } else { a } ;
365
396
self . check_ptr_access_align (
366
397
min_ptr,
367
- Size :: from_bytes ( distance . unsigned_abs ( ) ) ,
398
+ Size :: from_bytes ( dist . unsigned_abs ( ) ) ,
368
399
Align :: ONE ,
369
400
CheckInAllocMsg :: OffsetFromTest ,
370
401
) ?;
371
402
372
- if intrinsic_name == sym:: ptr_offset_from_unsigned && distance < 0 {
373
- throw_ub_format ! (
374
- "{} called when first pointer has smaller offset than second: {} < {}" ,
375
- intrinsic_name,
376
- a_offset,
377
- b_offset,
378
- ) ;
379
- }
380
-
381
403
// Perform division by size to compute return value.
382
404
let ret_layout = if intrinsic_name == sym:: ptr_offset_from_unsigned {
405
+ assert ! ( 0 <= dist && dist <= self . machine_isize_max( ) ) ;
383
406
usize_layout
384
407
} else {
408
+ assert ! ( self . machine_isize_min( ) <= dist && dist <= self . machine_isize_max( ) ) ;
385
409
isize_layout
386
410
} ;
387
411
let pointee_layout = self . layout_of ( substs. type_at ( 0 ) ) ?;
388
412
// If ret_layout is unsigned, we checked that so is the distance, so we are good.
389
- let val = ImmTy :: from_int ( distance , ret_layout) ;
413
+ let val = ImmTy :: from_int ( dist , ret_layout) ;
390
414
let size = ImmTy :: from_int ( pointee_layout. size . bytes ( ) , ret_layout) ;
391
415
self . exact_div ( & val, & size, dest) ?;
392
416
}
0 commit comments