Skip to content

Commit 210e059

Browse files
committed
clearly define int and uint to fix unsoundness
This fixes the gap in the language definition causing #18726 by defining a clear bound on the maximum size for libraries to enforce. Closes #18069
1 parent e09d986 commit 210e059

File tree

6 files changed

+59
-20
lines changed

6 files changed

+59
-20
lines changed

src/doc/reference.md

+8-11
Original file line numberDiff line numberDiff line change
@@ -3557,17 +3557,14 @@ The machine types are the following:
35573557

35583558
#### Machine-dependent integer types
35593559

3560-
The Rust type `uint` [^rustuint] is an
3561-
unsigned integer type with target-machine-dependent size. Its size, in
3562-
bits, is equal to the number of bits required to hold any memory address on
3563-
the target machine.
3564-
3565-
The Rust type `int` [^rustint] is a two's complement signed integer type with
3566-
target-machine-dependent size. Its size, in bits, is equal to the size of the
3567-
rust type `uint` on the same target machine.
3568-
3569-
[^rustuint]: A Rust `uint` is analogous to a C99 `uintptr_t`.
3570-
[^rustint]: A Rust `int` is analogous to a C99 `intptr_t`.
3560+
The `uint` type is an unsigned integer type with the same number of bits as the
3561+
platform's pointer type. It can represent every memory address in the process.
3562+
3563+
The `int` type is a signed integer type with the same number of bits as the
3564+
platform's pointer type. The theoretical upper bound on object and array size
3565+
is the maximum `int` value. This ensures that `int` can be used to calculate
3566+
differences between pointers into an object or array and can address every byte
3567+
within an object along with one byte past the end.
35713568

35723569
### Textual types
35733570

src/librustc_trans/trans/adt.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -464,17 +464,17 @@ fn ensure_struct_fits_in_address_space(ccx: &CrateContext,
464464
scapegoat: ty::t) {
465465
let mut offset = 0;
466466
for &llty in fields.iter() {
467-
// Invariant: offset < ccx.max_obj_size() <= 1<<61
467+
// Invariant: offset < ccx.obj_size_bound() <= 1<<61
468468
if !packed {
469469
let type_align = machine::llalign_of_min(ccx, llty);
470470
offset = roundup(offset, type_align);
471471
}
472-
// type_align is a power-of-2, so still offset < ccx.max_obj_size()
473-
// llsize_of_alloc(ccx, llty) is also less than ccx.max_obj_size()
472+
// type_align is a power-of-2, so still offset < ccx.obj_size_bound()
473+
// llsize_of_alloc(ccx, llty) is also less than ccx.obj_size_bound()
474474
// so the sum is less than 1<<62 (and therefore can't overflow).
475475
offset += machine::llsize_of_alloc(ccx, llty);
476476

477-
if offset >= ccx.max_obj_size() {
477+
if offset >= ccx.obj_size_bound() {
478478
ccx.report_overbig_object(scapegoat);
479479
}
480480
}
@@ -493,11 +493,11 @@ fn ensure_enum_fits_in_address_space(ccx: &CrateContext,
493493
let discr_size = machine::llsize_of_alloc(ccx, ll_inttype(ccx, discr));
494494
let (field_size, field_align) = union_size_and_align(fields);
495495

496-
// field_align < 1<<32, discr_size <= 8, field_size < MAX_OBJ_SIZE <= 1<<61
496+
// field_align < 1<<32, discr_size <= 8, field_size < OBJ_SIZE_BOUND <= 1<<61
497497
// so the sum is less than 1<<62 (and can't overflow).
498498
let total_size = roundup(discr_size, field_align) + field_size;
499499

500-
if total_size >= ccx.max_obj_size() {
500+
if total_size >= ccx.obj_size_bound() {
501501
ccx.report_overbig_object(scapegoat);
502502
}
503503
}

src/librustc_trans/trans/context.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -703,8 +703,23 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
703703
&self.local.trait_cache
704704
}
705705

706-
pub fn max_obj_size(&self) -> u64 {
707-
1<<31 /* FIXME #18069: select based on architecture */
706+
/// Return exclusive upper bound on object size.
707+
///
708+
/// The theoretical maximum object size is defined as the maximum positive `int` value. This
709+
/// ensures that the `offset` semantics remain well-defined by allowing it to correctly index
710+
/// every address within an object along with one byte past the end, along with allowing `int`
711+
/// to store the difference between any two pointers into an object.
712+
///
713+
/// The upper bound on 64-bit currently needs to be lower because LLVM uses a 64-bit integer to
714+
/// represent object size in bits. It would need to be 1 << 61 to account for this, but is
715+
/// currently conservatively bounded to 1 << 47 as that is enough to cover the current usable
716+
/// address space on 64-bit ARMv8 and x86_64.
717+
pub fn obj_size_bound(&self) -> u64 {
718+
match self.sess().target.target.target_word_size[] {
719+
"32" => 1 << 31,
720+
"64" => 1 << 47,
721+
_ => unreachable!() // error handled by config::build_target_config
722+
}
708723
}
709724

710725
pub fn report_overbig_object(&self, obj: ty::t) -> ! {

src/librustc_trans/trans/type_of.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ fn ensure_array_fits_in_address_space(ccx: &CrateContext,
3434
scapegoat: ty::t) {
3535
let esz = machine::llsize_of_alloc(ccx, llet);
3636
match esz.checked_mul(size) {
37-
Some(n) if n < ccx.max_obj_size() => {}
37+
Some(n) if n < ccx.obj_size_bound() => {}
3838
_ => { ccx.report_overbig_object(scapegoat) }
3939
}
4040
}

src/test/compile-fail/huge-enum.rs

+6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@
1212

1313
// FIXME: work properly with higher limits
1414

15+
#[cfg(target_word_size = "32")]
1516
fn main() {
1617
let big: Option<[u32, ..(1<<29)-1]> = None;
1718
}
19+
20+
#[cfg(target_word_size = "64")]
21+
fn main() {
22+
let big: Option<[u32, ..(1<<45)-1]> = None;
23+
}
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::mem::size_of;
12+
13+
#[cfg(target_word_size = "32")]
14+
pub fn main() {
15+
assert_eq!(size_of::<[u8, ..(1 << 31) - 1]>(), (1 << 31) - 1);
16+
}
17+
18+
#[cfg(target_word_size = "64")]
19+
pub fn main() {
20+
assert_eq!(size_of::<[u8, ..(1 << 47) - 1]>(), (1 << 47) - 1);
21+
}

0 commit comments

Comments
 (0)