Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document that slices cannot be larger than isize::MAX bytes #53784

Merged
merged 7 commits into from
Oct 1, 2018

Conversation

tbu-
Copy link
Contributor

@tbu- tbu- commented Aug 29, 2018

Fixes #53676.

@rust-highfive
Copy link
Collaborator

r? @dtolnay

(rust_highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Aug 29, 2018
Copy link
Member

@dtolnay dtolnay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@dtolnay
Copy link
Member

dtolnay commented Aug 29, 2018

@bors r+ rollup

@bors
Copy link
Contributor

bors commented Aug 29, 2018

📌 Commit f2cd6accf2cf85f5129641800d4fb5796a0b85ca has been approved by dtolnay

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Aug 29, 2018
@rust-highfive
Copy link
Collaborator

The job x86_64-gnu-llvm-5.0 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
[00:49:32] ....................................................................................................
[00:49:35] ....................................................................................................
[00:49:38] ..........i.........................................................................................
[00:49:41] ....................................................................................................
[00:49:44] ...........................................................iiiiiiiii................................
[00:49:50] ....................................................................................................
[00:49:54] ....................................................................................................
[00:49:57] .......................................i............................................................
[00:50:00] .........................................................................................i.i..ii....
---
[01:18:00] travis_fold:end:stage0-linkchecker

[01:18:00] travis_time:end:stage0-linkchecker:start=1535553810887647882,finish=1535553813369346737,duration=2481698855

[01:18:08] std/slice/fn.from_raw_parts.html:13: broken link - primitive/primitive.pointer.html
[01:18:11] core/slice/fn.from_raw_parts.html:13: broken link - primitive/primitive.pointer.html
-9]*\.!checkout!\(.*\)|\1|;y|!|/|'); if [ -f "$EXE" ]; then printf travis_fold":start:crashlog\n\033[31;1m%s\033[0m\n" "$CORE"; gdb -q -c "$CORE" "$EXE" -iex 'set auto-load off' -iex 'dir src/' -iex 'set sysroot .' -ex bt -ex q; echo travis_fold":"end:crashlog; fi; done || true
travis_fold:end:after_failure.4
travis_fold:start:after_failure.5
travis_time:start:369b7d26
travis_time:start:369b7d26
$ cat ./obj/build/x86_64-unknown-linux-gnu/native/asan/build/lib/asan/clang_rt.asan-dynamic-i386.vers || true
cat: ./obj/build/x86_64-unknown-linux-gnu/native/asan/build/lib/asan/clang_rt.asan-dynamic-i386.vers: No such file or directory
travis_fold:end:after_failure.5
travis_fold:start:after_failure.6
travis_time:start:03635120
$ dmesg | grep -i kill

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@frewsxcv
Copy link
Member

@bors r-

Documentation link seems to be broken

@bors bors added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Aug 29, 2018
@hanna-kruppe
Copy link
Contributor

cc @rust-lang/wg-unsafe-code-guidelines

@rust-highfive
Copy link
Collaborator

The job x86_64-gnu-llvm-5.0 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
[00:47:03] ....................................................................................................
[00:47:06] ....................................................................................................
[00:47:08] ..........i.........................................................................................
[00:47:11] ....................................................................................................
[00:47:14] ...........................................................iiiiiiiii................................
[00:47:19] ....................................................................................................
[00:47:23] ....................................................................................................
[00:47:25] .......................................i............................................................
[00:47:28] .........................................................................................i.i..ii....
---
[01:13:12] travis_fold:end:stage0-linkchecker

[01:13:12] travis_time:end:stage0-linkchecker:start=1535560532150584350,finish=1535560534543569111,duration=2392984761

[01:13:21] std/slice/fn.from_raw_parts.html:13: broken link - primitive.pointer.html
[01:13:23] core/slice/fn.from_raw_parts.html:13: broken link - primitive.pointer.html
[01:13:27] alloc/slice/fn.from_raw_parts.html:13: broken link - primitive.pointer.html
[01:13:27] thread 'main' panicked at 'found some broken links', tools/linkchecker/main.rs:49:9
[01:13:27] 
[01:13:27] 
[01:13:27] command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-tools-bin/linkchecker" "/checkout/obj/build/x86_64-unknown-linux-gnu/doc"
[01:13:27] expected success, got: exit code: 101
[01:13:27] expected success, got: exit code: 101
[01:13:27] 
[01:13:27] 
[01:13:27] failed to run: /checkout/obj/build/bootstrap/debug/bootstrap test
[01:13:27] Build completed unsuccessfully in 0:30:13
[01:13:27] make: *** [check] Error 1
[01:13:27] Makefile:58: recipe for target 'check' failed

The command "stamp sh -x -c "$RUN_SCRIPT"" exited with 2.
travis_time:start:02373339
$ date && (curl -fs --head https://google.com | grep ^Date: | sed 's/Date: //g' || true)
---
travis_time:end:06da3084:start=1535560551490692305,finish=1535560551501613226,duration=10920921
travis_fold:end:after_failure.3
travis_fold:start:after_failure.4
travis_time:start:22ac34c0
$ ln -s . checkout && for CORE in obj/cores/core.*; do EXE=$(echo $CORE | sed 's|obj/cores/core\.[0-9]*\.!checkout!\(.*\)|\1|;y|!|/|'); if [ -f "$EXE" ]; then printf travis_fold":start:crashlog\n\033[31;1m%s\033[0m\n" "$CORE"; gdb -q -c "$CORE" "$EXE" -iex 'set auto-load off' -iex 'dir src/' -iex 'set sysroot .' -ex bt -ex q; echo travis_fold":"end:crashlog; fi; done || true
travis_fold:end:after_failure.4
travis_fold:start:after_failure.5
travis_time:start:23616c00
travis_time:start:23616c00
$ cat ./obj/build/x86_64-unknown-linux-gnu/native/asan/build/lib/asan/clang_rt.asan-dynamic-i386.vers || true
cat: ./obj/build/x86_64-unknown-linux-gnu/native/asan/build/lib/asan/clang_rt.asan-dynamic-i386.vers: No such file or directory
travis_fold:end:after_failure.5
travis_fold:start:after_failure.6
travis_time:start:170ac800
$ dmesg | grep -i kill

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@RalfJung
Copy link
Member

RalfJung commented Aug 30, 2018

@rkruppe thanks, I had no idea that we have this extra restriction!

@tbu- Please also fix the documentation in from_raw_parts_mut, and please extend the debug_assert! to test for the maximal size.

@rust-highfive
Copy link
Collaborator

The job x86_64-gnu-llvm-5.0 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.

[00:04:50] travis_fold:start:tidy
travis_time:start:tidy
tidy check
[00:04:50] tidy error: /checkout/src/libcore/slice/mod.rs:3883: line longer than 100 chars
[00:04:50] tidy error: /checkout/src/libcore/slice/mod.rs:3902: line longer than 100 chars
[00:04:52] some tidy checks failed
[00:04:52] 
[00:04:52] 
[00:04:52] command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-tools-bin/tidy" "/checkout/src" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "--no-vendor" "--quiet"
[00:04:52] 
[00:04:52] 
[00:04:52] failed to run: /checkout/obj/build/bootstrap/debug/bootstrap test src/tools/tidy
[00:04:52] Build completed unsuccessfully in 0:00:54
[00:04:52] Build completed unsuccessfully in 0:00:54
[00:04:52] Makefile:79: recipe for target 'tidy' failed
[00:04:52] make: *** [tidy] Error 1

The command "stamp sh -x -c "$RUN_SCRIPT"" exited with 2.
travis_time:start:0ab94ed4
$ date && (curl -fs --head https://google.com | grep ^Date: | sed 's/Date: //g' || true)
---
travis_time:end:03924ab0:start=1536047819682215665,finish=1536047819691596104,duration=9380439
travis_fold:end:after_failure.3
travis_fold:start:after_failure.4
travis_time:start:1277be8a
$ ln -s . checkout && for CORE in obj/cores/core.*; do EXE=$(echo $CORE | sed 's|obj/cores/core\.[0-9]*\.!checkout!\(.*\)|\1|;y|!|/|'); if [ -f "$EXE" ]; then printf travis_fold":start:crashlog\n\033[31;1m%s\033[0m\n" "$CORE"; gdb -q -c "$CORE" "$EXE" -iex 'set auto-load off' -iex 'dir src/' -iex 'set sysroot .' -ex bt -ex q; echo travis_fold":"end:crashlog; fi; done || true
travis_fold:end:after_failure.4
travis_fold:start:after_failure.5
travis_time:start:07a8d890
travis_time:start:07a8d890
$ cat ./obj/build/x86_64-unknown-linux-gnu/native/asan/build/lib/asan/clang_rt.asan-dynamic-i386.vers || true
cat: ./obj/build/x86_64-unknown-linux-gnu/native/asan/build/lib/asan/clang_rt.asan-dynamic-i386.vers: No such file or directory
travis_fold:end:after_failure.5
travis_fold:start:after_failure.6
travis_time:start:38ab21eb
$ dmesg | grep -i kill

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@rust-highfive
Copy link
Collaborator

The job x86_64-gnu-llvm-5.0 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
[00:05:12]    Compiling rustc_msan v0.0.0 (file:///checkout/src/librustc_msan)
[00:05:13]    Compiling rustc_lsan v0.0.0 (file:///checkout/src/librustc_lsan)
[00:05:14]    Compiling rustc_asan v0.0.0 (file:///checkout/src/librustc_asan)
[00:05:14]    Compiling rustc_tsan v0.0.0 (file:///checkout/src/librustc_tsan)
[00:05:15] error[E0599]: no associated item named `MAX` found for type `isize` in the current scope
[00:05:15]      |
[00:05:15]      |
[00:05:15] 3883 |     debug_assert!(len * mem::size_of::<T>() <= isize::MAX as usize,
[00:05:15]      |                                                ^^^^^^^^^^ associated item not found in `isize`
[00:05:15] 
[00:05:15] error[E0599]: no associated item named `MAX` found for type `isize` in the current scope
[00:05:15]      |
[00:05:15]      |
[00:05:15] 3903 |     debug_assert!(len * mem::size_of::<T>() <= isize::MAX as usize,
[00:05:15]      |                                                ^^^^^^^^^^ associated item not found in `isize`
[00:05:16] error: aborting due to 2 previous errors
[00:05:16] 
[00:05:16] For more information about this error, try `rustc --explain E0599`.
[00:05:16] error: Could not compile `core`.
[00:05:16] error: Could not compile `core`.
[00:05:16] 
[00:05:16] Caused by:
[00:05:16]   process didn't exit successfully: `/checkout/obj/build/bootstrap/debug/rustc --crate-name core libcore/lib.rs --color always --error-format json --crate-type lib --emit=dep-info,link -C opt-level=2 -C metadata=bd44783aadae9ca1 -C extra-filename=-bd44783aadae9ca1 --out-dir /checkout/obj/build/x86_64-unknown-linux-gnu/stage0-std/x86_64-unknown-linux-gnu/release/deps --target x86_64-unknown-linux-gnu -L dependency=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-std/x86_64-unknown-linux-gnu/release/deps -L dependency=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-std/release/deps` (exit code: 1)
[00:05:16] warning: build failed, waiting for other jobs to finish...
[00:05:25] error: build failed
[00:05:25] command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "build" "--target" "x86_64-unknown-linux-gnu" "-j" "4" "--release" "--locked" "--color" "always" "--features" "panic-unwind jemalloc backtrace" "--manifest-path" "/checkout/src/libstd/Cargo.toml" "--message-format" "json"
[00:05:25] expected success, got: exit code: 101
[00:05:25] thread 'main' panicked at 'cargo must succeed', bootstrap/compile.rs:1155:9
[00:05:25] travis_fold:end:stage0-std

[00:05:25] travis_time:end:stage0-std:start=1536053410934339668,finish=1536053437064310554,duration=26129970886


[00:05:25] failed to run: /checkout/obj/build/bootstrap/debug/bootstrap build
[00:05:25] Build completed unsuccessfully in 0:00:27
[00:05:25] make: *** [all] Error 1
[00:05:25] Makefile:28: recipe for target 'all' failed

The command "stamp sh -x -c "$RUN_SCRIPT"" exited with 2.
travis_time:start:2d0b1c05
$ date && (curl -fs --head https://google.com | grep ^Date: | sed 's/Date: //g' || true)
---
travis_time:end:075fc52c:start=1536053437777130179,finish=1536053437784670745,duration=7540566
travis_fold:end:after_failure.3
travis_fold:start:after_failure.4
travis_time:start:05a27a83
$ ln -s . checkout && for CORE in obj/cores/core.*; do EXE=$(echo $CORE | sed 's|obj/cores/core\.[0-9]*\.!checkout!\(.*\)|\1|;y|!|/|'); if [ -f "$EXE" ]; then printf travis_fold":start:crashlog\n\033[31;1m%s\033[0m\n" "$CORE"; gdb -q -c "$CORE" "$EXE" -iex 'set auto-load off' -iex 'dir src/' -iex 'set sysroot .' -ex bt -ex q; echo travis_fold":"end:crashlog; fi; done || true
travis_fold:end:after_failure.4
travis_fold:start:after_failure.5
travis_time:start:01f196fc
travis_time:start:01f196fc
$ cat ./obj/build/x86_64-unknown-linux-gnu/native/asan/build/lib/asan/clang_rt.asan-dynamic-i386.vers || true
cat: ./obj/build/x86_64-unknown-linux-gnu/native/asan/build/lib/asan/clang_rt.asan-dynamic-i386.vers: No such file or directory
travis_fold:end:after_failure.5
travis_fold:start:after_failure.6
travis_time:start:05b64580
$ dmesg | grep -i kill

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@bors
Copy link
Contributor

bors commented Sep 4, 2018

☔ The latest upstream changes (presumably #53928) made this pull request unmergeable. Please resolve the merge conflicts.

Copy the documentation over to `slice::from_raw_parts_mut`.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
debug_assert!(data as usize % mem::align_of::<T>() == 0, "attempt to create unaligned slice");
debug_assert!(len * mem::size_of::<T>() <= isize::MAX as usize,
"attempt to create slice covering half the address space");
Copy link
Member

@RalfJung RalfJung Sep 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure that "exactly as large as half the address space" works correctly? That length (in bytes) does already not fit into a signed integer, so computing the address one-past-the-end (e.g. for iteration) would overflow.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like it'd be best written as len < isize::MAX as usize / mem::size_of::<T>()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RalfJung True.

@ubsan I don't think this is clearer.

Copy link
Contributor

@strega-nil strega-nil Sep 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tbu- not clearer, but it fixes overflow (and also happens at compile-time, as opposed to run-time)

@tbu-
Copy link
Contributor Author

tbu- commented Sep 10, 2018

Fixed the edge case isize::MAX.

@tbu-
Copy link
Contributor Author

tbu- commented Sep 11, 2018

@ubsan I think I fixed it now, can you take a look again? The ZST case is checked independently because division by 0 panics, and the + size - 1 is supposed to make the division round up (because e.g. when isize::MAX is 7 and mem::size_of::<T>() is 2, then we're allowed to have a 3-element slice, but isize::MAX / mem::size_of::<T>() is only 2, thus we need to round up instead of down).

@RalfJung
Copy link
Member

RalfJung commented Sep 17, 2018

... except, should it be < or <=?

So, I think <= is okay, but the docs should be changed from "must be lower than" to "must be no larger than" to match the code. But I'd prefer someone who actually knows what LLVM's limits are to confirm... @rkruppe? @ubsan?

@hanna-kruppe
Copy link
Contributor

I would vastly prefer < just to be on the safe side.

/// [`from_raw_parts`] for more details.
/// slices as with [`from_raw_parts`]. The total size of the slice must be no
/// larger than `isize::MAX` **bytes** in memory. See the safety documentation
/// of [`pointer::offset`].
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks a bit strange, with two "See ..." sentences right after one another. Also you made this new remark a new paragraph in the other method. Maybe remove the last sentence of this paragraph? Or else restore this paragraph to its original form, and add a new paragraph for the size limit.

@RalfJung
Copy link
Member

RalfJung commented Sep 17, 2018

@rkruppe So the max size would be "2 less than half the address space"? I somehow don't feel good about that, this just looks like we don't know what we are doing...

@hanna-kruppe
Copy link
Contributor

this just looks like we don't know what we are doing...

More so than if it was one less than half? But it's true, I for one don't really know what we're doing here 😅 or rather, I could probably (re-)learn it but I do not sufficiently trust myself to put the results in the docs of an unsafe function.

@hanna-kruppe
Copy link
Contributor

cc @gankro

@RalfJung
Copy link
Member

RalfJung commented Sep 17, 2018

More so than if it was one less than half?

Well, yes. Because half the address space is the smallest offset not representable in an isize. IOW "half minus 1" aka isize::MAX is the largest representable offset. And we want the size of everything to be representable to be able to compute the one-past-the-end address.

@RalfJung
Copy link
Member

RalfJung commented Sep 17, 2018

Curiously, the "does the type fit the architecture" check rejects even isize::MAX - 1000... not sure what the actual limit is there.

EDIT: The largest possible one seems to be isize::MAX as usize / 16 / 16 / 16 / 16. Which is a power of two. I'd have expected one less than a power of two as the largest possible...

@Gankra
Copy link
Contributor

Gankra commented Sep 17, 2018

There's a bit of fuzziness at the upper boundaries of sizes as different compiler components can make incredibly reasonable but technically limiting assumptions to pack sizes into bitfields. I expect it'd be pretty hard to accurately find the exact upper bound of type size that isn't miscompiled/ICEd.

But yeah isize::MAX bytes should be possible for a heap allocated slice.

@RalfJung
Copy link
Member

RalfJung commented Sep 18, 2018

So the limit I found originates from

/// Return exclusive upper bound on object size.
///
/// The theoretical maximum object size is defined as the maximum positive `isize` value.
/// This ensures that the `offset` semantics remain well-defined by allowing it to correctly
/// index every address within an object along with one byte past the end, along with allowing
/// `isize` to store the difference between any two pointers into an object.
///
/// The upper bound on 64-bit currently needs to be lower because LLVM uses a 64-bit integer
/// to represent object size in bits. It would need to be 1 << 61 to account for this, but is
/// currently conservatively bounded to 1 << 47 as that is enough to cover the current usable
/// address space on 64-bit ARMv8 and x86_64.
pub fn obj_size_bound(&self) -> u64 {
match self.pointer_size.bits() {
16 => 1 << 15,
32 => 1 << 31,
64 => 1 << 47,
bits => panic!("obj_size_bound: unknown pointer bit size {}", bits)
}
}
. And I think there is an off-by-one error there for 32bit and 16bit platforms -- it accepts 1 << 15 as size which it should not...

EDIT: Ah no, everyone compares with <. But then I do not understand the behavior I see.

EDIT2: Oh, my local calculate just rounds differently. D'oh. isize::MAX as usize / 16 / 16 / 16 / 16 is the same as (1usize << 47) - 1.

@RalfJung
Copy link
Member

So based on this indeed I think the max value should be 2^N - 1 for some N, just like what rust layout computation checks.

@RalfJung
Copy link
Member

I am inclined to accept once my last doc nit is resolved.

@TimNN
Copy link
Contributor

TimNN commented Sep 25, 2018

Ping from triage @tbu-: It looks like some small changes have been requested to your PR.

@kennytm kennytm added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Sep 29, 2018
@RalfJung
Copy link
Member

LGTM!

@bors r+

@bors
Copy link
Contributor

bors commented Sep 29, 2018

📌 Commit e370b1c has been approved by RalfJung

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 29, 2018
kennytm added a commit to kennytm/rust that referenced this pull request Oct 1, 2018
…Jung

Document that slices cannot be larger than `isize::MAX` bytes

Fixes rust-lang#53676.
bors added a commit that referenced this pull request Oct 1, 2018
Rollup of 13 pull requests

Successful merges:

 - #53784 (Document that slices cannot be larger than `isize::MAX` bytes)
 - #54308 (Better user experience when attempting to call associated functions with dot notation)
 - #54488 (in which we include attributes in unused `extern crate` suggestion spans)
 - #54544 (Indicate how to move value out of Box in docs.)
 - #54623 (Added help message for `impl_trait_in_bindings` feature gate)
 - #54641 (A few cleanups and minor improvements to rustc/infer)
 - #54656 (Correct doc for WorkQueue<T>::pop().)
 - #54674 (update miri)
 - #54676 (Remove `-Z disable_ast_check_for_mutation_in_guard`)
 - #54679 (Improve bug! message for impossible case in Relate)
 - #54681 (Rename sanitizer runtime libraries on OSX)
 - #54708 (Make ./x.py help <cmd> invoke ./x.py <cmd> -h on its own)
 - #54713 (Add nightly check for tool_lints warning)
@bors bors merged commit e370b1c into rust-lang:master Oct 1, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.