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

Report const index out-of-bound condition earlier #3170

Closed
graydon opened this issue Aug 9, 2012 · 24 comments
Closed

Report const index out-of-bound condition earlier #3170

graydon opened this issue Aug 9, 2012 · 24 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-cleanup Category: PRs that clean code up or issues documenting cleanup. P-low Low priority T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@graydon
Copy link
Contributor

graydon commented Aug 9, 2012

Currently if you try indexing into a const vector, in a const expr, we report the bounds-overrun late in compilation -- during translation. We should notice it earlier, in the const evaluation pass.

@jld
Copy link
Contributor

jld commented Feb 8, 2013

Apparently the “error” this produces doesn't cause compilation to fail — code will be generated and rustc will return 0. LLVM will complain if the index is physically out of bounds, and this is currently always equivalent to an out-of-bounds index (I think), but that won't be the case for const slices.

This is especially unexpected during testing, which (except for check-fast, apparently?) doesn't show the output/error on success.

@catamorphism
Copy link
Contributor

Not critical for 0.6; de-milestoning

@catamorphism
Copy link
Contributor

Nominating for milestone 5, production-ready

@graydon
Copy link
Contributor Author

graydon commented Jun 13, 2013

accepted for production-ready milestone

@alexcrichton
Copy link
Member

As an example of what I believe that this is talking about:

static a: &'static [int] = &[];
static b: int = a[1];

fn main() {}

yields

$ rustc foo.rs
foo.rs:2:16: 2:19 error: const index-expr is out of bounds
foo.rs:2 static b: int = a[1];
                         ^~~
Assertion failed: (ReqTy && "extractvalue indices invalid!"), function getExtractValue, file ../../../../src/llvm/lib/IR/Constants.cpp, line 1982.
zsh: abort      rustc foo.rs

Seems bad that we're hitting an LLVM assertion at all.

@pnkfelix
Copy link
Member

Accepted for P-low.

@huonw
Copy link
Member

huonw commented Jun 16, 2014

Triage: @alexcrichton's (9 month old) example is still syntactically valid (yay!) and still fails with that assertion (boo!).

@vks
Copy link
Contributor

vks commented Aug 29, 2014

I believe this is fixed.

@JustAPerson
Copy link
Contributor

If you update @alexcrichton's example:

#![allow(dead_code)]
const A: &'static [usize] = &[];
const B: usize = A[1];

fn main() {}

It now compiles successfully without any complaints.

Only once you attempt to use the invalid value B will rustc encounter a problem.

#![allow(dead_code)]
const A: &'static [usize] = &[];
const B: usize = A[1];

fn main() {
    println!("B={}", B);
}
<anon>:3:18: 3:22 error: const index-expr is out of bounds
<anon>:3 const B: usize = A[1];
                          ^~~~
rustc: /home/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-linux/build/src/llvm/lib/IR/Constants.cpp:2174: static llvm::Constant* llvm::ConstantExpr::getExtractValue(llvm::Constant*, llvm::ArrayRef<unsigned int>, llvm::Type*): Assertion `ReqTy && "extractvalue indices invalid!"' failed.
Aborted (core dumped)
playpen: application terminated with error code 134

@steveklabnik
Copy link
Member

error: cannot refer to other statics by value, use the address-of operator or a constant instead

Yup, seems good.

@pnkfelix
Copy link
Member

pnkfelix commented Mar 9, 2015

wait, @JustAPerson 's example does not seem okay to me. Reopening.

@pnkfelix pnkfelix reopened this Mar 9, 2015
@tamird
Copy link
Contributor

tamird commented Apr 17, 2015

I think this is now fixed for real:

$ cat foo.rs
#![allow(dead_code)]
const A: &'static [usize] = &[];
const B: usize = A[1];

fn main() {
    println!("B={}", B);
}
$ rustc foo.rs
foo.rs:3:18: 3:22 error: const index-expr is out of bounds
foo.rs:3 const B: usize = A[1];
                          ^~~~
error: aborting due to previous error
$ rustc --version
rustc 1.0.0-dev (a691f1eef 2015-04-15) (built 2015-04-15)

@steveklabnik
Copy link
Member

So, sometime in the last 11 days:

hello.rs:3:18: 3:22 error: const index-expr is out of bounds
hello.rs:3 const B: usize = A[1];
                            ^~~~
rustc: /home/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-linux/build/src/llvm/include/llvm/Support/Casting.h:237: typename llvm::cast_retty<X, Y*>::ret_type llvm::cast(Y*) [with X = llvm::SequentialType; Y = llvm::Type; typename llvm::cast_retty<X, Y*>::ret_type = llvm::SequentialType*]: Assertion `isa<X>(Val) && "cast<Ty>() argument of incompatible type!"' failed.

soooo seems like it's already regressed?

@tamird
Copy link
Contributor

tamird commented Apr 28, 2015

Guh, this was my mistake. I made the above report using a toolchain compiled with LLVM assertions disabled (which I didn't know was the default).

@carols10cents
Copy link
Member

(Hi, I'm trying to help make E-easy issues more accessible to newcomers 😸)

I made the above report using a toolchain compiled with LLVM assertions disabled (which I didn't know was the default).

It sounds like in order to reproduce this issue, you have to be using a toolchain compiled with a non-default setting? If so, how does one go about doing that?

It's kind of confusing what's supposed to happen here, with all the closing-reopening stuff going on. Could someone clarify what the expected behavior is and how it differs from the current behavior?

@jonas-schievink
Copy link
Contributor

./configure --enable-llvm-assertions

However, you can just use a Rust nightly, since LLVM assertions are enabled there. http://is.gd/X2RztV still fails the assertion on nightly:

<anon>:2:17: 2:21 error: const index-expr is out of bounds
<anon>:2 static b: i32 = a[1];
                         ^~~~
rustc: /home/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-linux/build/src/llvm/include/llvm/Support/Casting.h:237: typename llvm::cast_retty<X, Y*>::ret_type llvm::cast(Y*) [with X = llvm::SequentialType; Y = llvm::Type; typename llvm::cast_retty<X, Y*>::ret_type = llvm::SequentialType*]: Assertion `isa<X>(Val) && "cast<Ty>() argument of incompatible type!"' failed.
Aborted (core dumped)
playpen: application terminated with error code 134

@jld
Copy link
Contributor

jld commented Oct 4, 2015

It looks like the thing I was distressed by in 2013 is fixed: if rustc gives the const index-expr is out of bounds error, even if LLVM assertions are disabled, it exits with a failure status (and does not write an output file). I think translation used to not have access to the session/error stuff that checking does, because it wasn't supposed to be able to find errors that checking missed? But that looks like it's not the case now.

The other thing my past self mentioned… it sounds as if we used to just pass the index to LLVM even if we knew it was out-of-range, but now we construct an undef instead. But that part is taken care of in any case, because the error is handled properly now.

As for the LLVM assertion we're seeing today, I have a guess. After reporting the error, we're doing this:

C_undef(type_of::type_of(cx, bt).element_type())

and I think we want something like this (untested):

C_undef(val_ty(arr).element_type())

Because if the value being indexed is a slice or pointer, then bt (its type) won't be represented by an array type, so element_type will fail.

But, the thing @graydon opened this issue for, and what the comment in the code referencing this issue suggests doing, is to move that check to an earlier stage of compilation. And it looks like #25370/#25570 might wind up more or less accomplishing that?

jld added a commit to jld/rust that referenced this issue Oct 5, 2015
This turned up as part of rust-lang#3170.  When constructing an `undef` value to
return in the error case, we were trying to get the element type of the
Rust-level value being indexed instead of the underlying array; when
indexing a slice, that's not an array and the LLVM assertion failure
reflects this.

The regression test is a lightly altered copy of `const-array-oob.rs`.
Manishearth added a commit to Manishearth/rust that referenced this issue Oct 7, 2015
This turned up as part of rust-lang#3170.  When constructing an `undef` value to
return in the error case, we were trying to get the element type of the
Rust-level value being indexed instead of the underlying array; when
indexing a slice, that's not an array and the LLVM assertion failure
reflects this.

The regression test is a lightly altered copy of `const-array-oob.rs`.
bors added a commit that referenced this issue Oct 7, 2015
This turned up as part of #3170.  When constructing an `undef` value to
return in the error case, we were trying to get the element type of the
Rust-level value being indexed instead of the underlying array; when
indexing a slice, that's not an array and the LLVM assertion failure
reflects this.

The regression test is a lightly altered copy of `const-array-oob.rs`.
@Manishearth Manishearth removed the E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. label Nov 20, 2015
@Manishearth
Copy link
Member

I think this is fixed completely now. @oli-obk ?

@oli-obk
Copy link
Contributor

oli-obk commented Nov 20, 2015

nope, it needs to be solved in check_const and the current report location needs to be changed into a bug location

@Manishearth
Copy link
Member

@oli-obk Is this an easy fix, and if so, do you want to mentor it and leave some hints so that newcomers can try a crack at it?

@oli-obk
Copy link
Contributor

oli-obk commented Nov 20, 2015

While it's an easy fix (you can basically steal https://github.com/rust-lang/rust/blob/master/src/librustc/middle/check_const.rs#L470-L490 and do it for ExprIndex and then turn https://github.com/rust-lang/rust/blob/master/src/librustc_trans/trans/consts.rs#L708-L712 into a bug/unimplemented!()).

But it'd also be a breaking change, because unused const ARR: [u32; 0] = []; const X: u32 = ARR[5]; currently does not cause a compilation error. And check_const also checks unused constants.

Also it would end up doing all const evaluation twice. Which could be remedied once it becomes a problem by caching constants.

Of course the breaking change can be remedied by simply emitting the const_err lint.

bors added a commit that referenced this issue Apr 4, 2016
check constants even if they are not used in the current crate

For now this is just a `warn`-by-default lint. I suggest to make it a `deny`-by-default lint in the next release cycle (so no dependencies break), and then in another release cycle move to an error.

cc #19265
cc #3170
@steveklabnik steveklabnik added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Mar 9, 2017
@fbstj
Copy link
Contributor

fbstj commented Apr 24, 2018

this seems to have been 'solved' (possibly due to MIRI) as it now throws E0080 when used, rather than an LLVM assertion. though it still passes through if the access is unused.

@oli-obk
Copy link
Contributor

oli-obk commented Apr 24, 2018

The missing lint when the const is unused will be fixed by #50110

@oli-obk
Copy link
Contributor

oli-obk commented Aug 2, 2018

Yea I think we're done with this issue after 6 years 😆

@oli-obk oli-obk closed this as completed Aug 2, 2018
saethlin pushed a commit to saethlin/rust that referenced this issue Nov 17, 2023
celinval pushed a commit to celinval/rust-dev that referenced this issue Jun 4, 2024
This PR modifies the pattern used to exclude files from the copyright
check for `expected` files. This ensures we check the copyright in files
under `tests/expected/` while it skips the check for `expected` and
`*.expected` files. It also adds/modifies copyright headers for some
files that weren't being checked until now.

Resolves rust-lang#3141
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-cleanup Category: PRs that clean code up or issues documenting cleanup. P-low Low priority T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.