Rust: ICE due to `#[track_caller]` shim with -Z unleash-the-miri-inside-of-you

Created on 3 Feb 2020  路  11Comments  路  Source: rust-lang/rust

Reproducer:

// compile-flags: -Z unleash-the-miri-inside-of-you

#![feature(core_intrinsics, const_caller_location, track_caller, const_fn)]

use std::panic::Location;
use std::intrinsics::caller_location;

type L = &'static Location<'static>;

#[track_caller]
const fn foo() -> L {
    caller_location()
}

const fn bar() -> L {
    // Why we need `-Z unleash...`:
    let x: fn() -> L = foo;
    x()
}

const CTFE: L = bar();

fn main() {
    dbg!(bar());
    dbg!(CTFE); // This is what causes the ICE.
}

reduced:

#![feature(core_intrinsics, const_caller_location, track_caller, const_fn)]

use std::panic::Location;
use std::intrinsics::caller_location;

type L = &'static Location<'static>;

#[track_caller]
const fn foo() -> L {
    caller_location()
}

const fn bar() -> L {
    let x: fn() -> L = foo;
    x()
}

const CTFE: L = bar();

fn main() {
    CTFE;
}

with backtrace:

thread 'rustc' panicked at 'index out of bounds: the len is 1 but the index is 1', /rustc/48840618382eccb8a799320c8e5d08e3b52f4c42/src/libcore/slice/mod.rs:2791:10
stack backtrace:
   0: backtrace::backtrace::libunwind::trace
             at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/libunwind.rs:88
   1: backtrace::backtrace::trace_unsynchronized
             at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/mod.rs:66 
   2: std::sys_common::backtrace::_print_fmt
             at src/libstd/sys_common/backtrace.rs:77
   3: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
             at src/libstd/sys_common/backtrace.rs:59
   4: core::fmt::write
             at src/libcore/fmt/mod.rs:1057
   5: std::io::Write::write_fmt
             at src/libstd/io/mod.rs:1426
   6: std::sys_common::backtrace::_print
             at src/libstd/sys_common/backtrace.rs:62
   7: std::sys_common::backtrace::print
             at src/libstd/sys_common/backtrace.rs:49
   8: std::panicking::default_hook::{{closure}}
             at src/libstd/panicking.rs:204
   9: std::panicking::default_hook
             at src/libstd/panicking.rs:224
  10: rustc_driver::report_ice
  11: std::panicking::rust_panic_with_hook
             at src/libstd/panicking.rs:476
  12: rust_begin_unwind
             at src/libstd/panicking.rs:380
  13: core::panicking::panic_fmt
             at src/libcore/panicking.rs:85
  14: core::panicking::panic_bounds_check
             at src/libcore/panicking.rs:63
  15: rustc_mir::interpret::eval_context::InterpCx<M>::layout_of_local
  16: rustc_mir::interpret::operand::<impl rustc_mir::interpret::eval_context::InterpCx<M>>::access_local  17: rustc_mir::interpret::operand::<impl rustc_mir::interpret::eval_context::InterpCx<M>>::eval_place_to_op
  18: rustc_mir::interpret::operand::<impl rustc_mir::interpret::eval_context::InterpCx<M>>::eval_operand  19: <core::iter::adapters::ResultShunt<I,E> as core::iter::traits::iterator::Iterator>::next
  20: <alloc::vec::Vec<T> as alloc::vec::SpecExtend<T,I>>::from_iter
  21: rustc_mir::interpret::step::<impl rustc_mir::interpret::eval_context::InterpCx<M>>::step
  22: rustc_mir::const_eval::eval_queries::const_eval_raw_provider
  23: rustc::ty::query::__query_compute::const_eval_raw
  24: rustc::ty::query::<impl rustc::ty::query::config::QueryAccessors for rustc::ty::query::queries::const_eval_raw>::compute
  25: rustc::dep_graph::graph::DepGraph::with_task_impl
  26: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt>::get_query
  27: rustc_mir::const_eval::machine::<impl rustc_mir::interpret::eval_context::InterpCx<rustc_mir::const_eval::machine::CompileTimeInterpreter>>::try_eval_const_fn_call
  28: <rustc_mir::const_eval::machine::CompileTimeInterpreter as rustc_mir::interpret::machine::Machine>::find_mir_or_eval_fn
  29: rustc_mir::interpret::terminator::<impl rustc_mir::interpret::eval_context::InterpCx<M>>::eval_fn_call
  30: rustc_mir::interpret::step::<impl rustc_mir::interpret::eval_context::InterpCx<M>>::step
  31: rustc_mir::const_eval::eval_queries::const_eval_raw_provider
  32: rustc::ty::query::__query_compute::const_eval_raw
  33: rustc::ty::query::<impl rustc::ty::query::config::QueryAccessors for rustc::ty::query::queries::const_eval_raw>::compute
  34: rustc::dep_graph::graph::DepGraph::with_task_impl
  35: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt>::get_query
 36: rustc_mir::const_eval::eval_queries::const_eval_validated_provider
  37: rustc::ty::query::__query_compute::const_eval_validated
  38: rustc::ty::query::<impl rustc::ty::query::config::QueryAccessors for rustc::ty::query::queries::const_eval_validated>::compute
  39: rustc::dep_graph::graph::DepGraph::with_task_impl
  40: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt>::get_query
  41: rustc_mir::const_eval::eval_queries::const_eval_validated_provider
  42: rustc::ty::query::__query_compute::const_eval_validated
  43: rustc::ty::query::<impl rustc::ty::query::config::QueryAccessors for rustc::ty::query::queries::const_eval_validated>::compute
  44: rustc::dep_graph::graph::DepGraph::with_task_impl
  45: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt>::get_query
  46: rustc::mir::interpret::queries::<impl rustc::ty::context::TyCtxt>::const_eval_poly
  47: <rustc_lint::builtin::UnusedBrokenConst as rustc_lint::passes::LateLintPass>::check_item
  48: <rustc_lint::BuiltinCombinedLateLintPass as rustc_lint::passes::LateLintPass>::check_item
  49: rustc_hir::intravisit::Visitor::visit_nested_item
  50: rustc_hir::intravisit::walk_crate
  51: <std::panic::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
  52: __rust_maybe_catch_panic
             at src/libpanic_unwind/lib.rs:86
  53: <std::panic::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
  54: __rust_maybe_catch_panic
             at src/libpanic_unwind/lib.rs:86
  55: rustc_session::utils::<impl rustc_session::session::Session>::time
  56: rustc_interface::passes::analysis
  57: rustc::ty::query::__query_compute::analysis
  58: rustc::dep_graph::graph::DepGraph::with_task_impl
  59: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt>::get_query
  60: rustc::ty::context::tls::enter_global
  61: rustc_interface::interface::run_compiler_in_existing_thread_pool
  62: scoped_tls::ScopedKey<T>::set
  63: syntax::with_globals
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

error: internal compiler error: unexpected panic

note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports

note: rustc 1.42.0-nightly (488406183 2020-01-16) running on x86_64-unknown-linux-gnu

note: compiler flags: -Z unleash-the-miri-inside-of-you

query stack during panic:
#0 [const_eval_raw] const-evaluating `bar`
#1 [const_eval_raw] const-evaluating `CTFE`
#2 [const_eval_validated] const-evaluating + checking `CTFE`
#3 [const_eval_validated] const-evaluating + checking `CTFE`
#4 [analysis] running analysis passes on this crate                        
end of query stack   

cc @anp @RalfJung @oli-obk

Also, from the provided description in the reference PR:

In a const context, the attribute does not affect function ABI and instead informs the const
evaluator to continue walking up the stack when probing for the topmost caller location.

...it sounds like this is violating the runtime-compiletime-same-behavior rule. In particular, it sounds like dbg!(bar()); and dbg!(CTFE); would print out different things. We would get that on stable if we allowed const fn() pointers.

Relatedly, the following:

#![feature(core_intrinsics, const_caller_location, track_caller, const_fn)]

use std::panic::Location;
use std::intrinsics::caller_location;

type L = &'static Location<'static>;

#[track_caller]
const fn foo() -> L {
    caller_location()
}

const fn bar() -> L {
    let x: fn() -> L = foo;
    x()
}

fn main() {
    bar();
}

...results in:

$ RUST_BACKTRACE=1 rustc -Z unleash-the-miri-inside-of-you foo.rs
warning: skipping const checks
  --> foo.rs:15:5
   |
15 |     x()
   |     ^^^

thread 'rustc' panicked at 'index out of bounds: the len is 1 but the index is 1', /rustc/48840618382eccb8a799320c8e5d08e3b52f4c42/src/libcore/slice/mod.rs:2791:10
stack backtrace:
Incorrect number of arguments passed to called function!
  %1 = call align 8 dereferenceable(24) %"core::panic::Location"* @_ZN3foo3foo17h9a95a22c2f60a5e2E()     
in function _ZN3foo3bar17hcb643110f71c9dddE
LLVM ERROR: Broken function found, compilation aborted!
A-codegen A-const-eval A-const-fn C-bug F-track_caller I-ICE I-crash T-compiler requires-nightly

Most helpful comment

still tired from tomorrow

I won't tell anyone about your secret if you also let me use that time machine. :D

All 11 comments

...it sounds like this is violating the runtime-compiletime-same-behavior rule

It shouldn't, reification results in a shim which should cause miri to stop walking up the stack, as it looks like a non-#[track_caller] function calling the #[track_caller] function.

A real backtrace is needed (we should really try to get nightly to be built with debuginfo-level=1 somehow), but I suspect it's a minor bug similar to the one we fixed in ReifyShim creation.

Is this reproducible in Miri? I added some tests there for track_caller and function pointers (https://github.com/rust-lang/miri/pull/1162), and everything looked fine to me.

Incorrect number of arguments passed to called function!
  %1 = call align 8 dereferenceable(24) %"core::panic::Location"* @_ZN3foo3foo17h9a95a22c2f60a5e2E()     

My first guess here would be that const-prop went wrong, Cc @wesleywiser

@Centril Do I need to pass any flags other than -Z unleash-the-miri-inside-of-you? I can't get a repro with your test case.

attempt to repro

wesley@endurance:~/code/rust/rust2> cat test.rs
#![feature(core_intrinsics, const_caller_location, track_caller, const_fn)]

use std::panic::Location;
use std::intrinsics::caller_location;

type L = &'static Location<'static>;

#[track_caller]
const fn foo() -> L {
    caller_location()
}

const fn bar() -> L {
    let x: fn() -> L = foo;
    x()
}

const CTFE: L = bar();

fn main() {
    CTFE;
}

wesley@endurance:~/code/rust/rust2> rustc +stage1-2 -Z unleash-the-miri-inside-of-you test.rs
warning: skipping const checks
  --> test.rs:15:5
   |
15 |     x()
   |     ^^^

warning: path statement with no effect
  --> test.rs:21:5
   |
21 |     CTFE;
   |     ^^^^^
   |
   = note: `#[warn(path_statements)]` on by default

wesley@endurance:~/code/rust/rust2> git log -1

commit 0d34a8772251b3f9d4dd05c81d9531d455a14fc2 (HEAD, origin/master)
Merge: a2e80300cd8 a606ffdb174
Author: bors <[email protected]>
Date:   Mon Feb 3 06:38:34 2020 +0000

    Auto merge of #68772 - matthewjasper:relate-opt, r=davidtwco

    Avoid exponential behaviour when relating types

    When equating bound types we check subtyping in both directions. Since closures are invariant in their substs, we end up comparing the two types an exponential number of times. If there are no bound variables this isn't needed.

    Closes #68061

@Centril hang on, isn't this a duplicate of #68178, which https://github.com/rust-lang/rust/pull/68302/commits/19d8527890b59ed25432fbf5a9f1bd75ac814ae2 fixed?
Sadly there's no example of the index out of bounds ICE there, but IIRC @anp hit it for zero-argument functions (like you have here).

@wesleywiser No, just using that flag (on latest master, freshly rebased):

centril@centrilnas2:~/programming/rust/rust-gamma$ git log -1
commit c58e09f138075ce6b3079f41f9c2f192a15b896c (HEAD -> master, upstream/master)     
Merge: 0d34a877225 ee601584403
Author: bors <[email protected]>
Date:   Mon Feb 3 09:54:09 2020 +0000

    Auto merge of #68778 - RalfJung:raw-addr-of, r=eddyb

    add raw-addr-of variant to mir_raw_fat_ptr

    As suggested at https://github.com/rust-lang/rust/pull/48300#discussion_r372520388

    r? @eddyb

centril@centrilnas2:~/programming/rust/rust-gamma$ cat crash.rs 
#![feature(core_intrinsics, const_caller_location, track_caller, const_fn)]

use std::panic::Location;
use std::intrinsics::caller_location;

type L = &'static Location<'static>;

#[track_caller]
const fn foo() -> L {
    caller_location()
}

const fn bar() -> L {
    let x: fn() -> L = foo;
    x()
}

fn main() {
    bar();
}

centril@centrilnas2:~/programming/rust/rust-gamma$ rustc -Z unleash-the-miri-inside-of-you crash.rs      
warning: skipping const checks
  --> crash.rs:15:5
   |
15 |     x()
   |     ^^^

Incorrect number of arguments passed to called function!
  %1 = call align 8 dereferenceable(24) %"core::panic::Location"* @_ZN5crash3foo17he37aca50257bbb93E()   
in function _ZN5crash3bar17hc3bef3cb9fdd7a54E
LLVM ERROR: Broken function found, compilation aborted!
thread 'rustc' panicked at 'index out of bounds: the len is 1 but the index is 1', /rustc/48840618382eccb8a799320c8e5d08e3b52f4c42/src/libcore/slice/mod.rs:2791:10
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

centril@centrilnas2:~/programming/rust/rust-gamma$ cat ref_const.rs 
#![feature(core_intrinsics, const_caller_location, track_caller, const_fn)]

use std::panic::Location;
use std::intrinsics::caller_location;

type L = &'static Location<'static>;

#[track_caller]
const fn foo() -> L {
    caller_location()
}

const fn bar() -> L {
    let x: fn() -> L = foo;
    x()
}

const CTFE: L = bar();

fn main() {
    CTFE;
}

centril@centrilnas2:~/programming/rust/rust-gamma$ RUST_BACKTRACE=1 rustc -Z unleash-the-miri-inside-of-you ref_const.rs
warning: skipping const checks
  --> ref_const.rs:15:5
   |
15 |     x()
   |     ^^^

thread 'rustc' panicked at 'index out of bounds: the len is 1 but the index is 1', /rustc/48840618382eccb8a799320c8e5d08e3b52f4c42/src/libcore/slice/mod.rs:2791:10
stack backtrace:
   0: backtrace::backtrace::libunwind::trace
             at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/libunwind.rs:88
   1: backtrace::backtrace::trace_unsynchronized
             at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/mod.rs:66
   2: std::sys_common::backtrace::_print_fmt
             at src/libstd/sys_common/backtrace.rs:77
   3: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
             at src/libstd/sys_common/backtrace.rs:59
   4: core::fmt::write
             at src/libcore/fmt/mod.rs:1057
   5: std::io::Write::write_fmt
             at src/libstd/io/mod.rs:1426
   6: std::sys_common::backtrace::_print
             at src/libstd/sys_common/backtrace.rs:62
   7: std::sys_common::backtrace::print
             at src/libstd/sys_common/backtrace.rs:49
   8: std::panicking::default_hook::{{closure}}
             at src/libstd/panicking.rs:204
   9: std::panicking::default_hook
             at src/libstd/panicking.rs:224
  10: rustc_driver::report_ice
  11: std::panicking::rust_panic_with_hook
             at src/libstd/panicking.rs:476
  12: rust_begin_unwind
             at src/libstd/panicking.rs:380
  13: core::panicking::panic_fmt
             at src/libcore/panicking.rs:85
  14: core::panicking::panic_bounds_check
             at src/libcore/panicking.rs:63
  15: rustc_mir::interpret::eval_context::InterpCx<M>::layout_of_local
  16: rustc_mir::interpret::operand::<impl rustc_mir::interpret::eval_context::InterpCx<M>>::access_local
  17: rustc_mir::interpret::operand::<impl rustc_mir::interpret::eval_context::InterpCx<M>>::eval_place_to_op
  18: rustc_mir::interpret::operand::<impl rustc_mir::interpret::eval_context::InterpCx<M>>::eval_operand
  19: <core::iter::adapters::ResultShunt<I,E> as core::iter::traits::iterator::Iterator>::next
  20: <alloc::vec::Vec<T> as alloc::vec::SpecExtend<T,I>>::from_iter
  21: rustc_mir::interpret::step::<impl rustc_mir::interpret::eval_context::InterpCx<M>>::step
  22: rustc_mir::const_eval::eval_queries::const_eval_raw_provider
  23: rustc::ty::query::__query_compute::const_eval_raw
  24: rustc::ty::query::<impl rustc::ty::query::config::QueryAccessors for rustc::ty::query::queries::const_eval_raw>::compute
  25: rustc::dep_graph::graph::DepGraph::with_task_impl
  26: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt>::get_query
  27: rustc_mir::const_eval::machine::<impl rustc_mir::interpret::eval_context::InterpCx<rustc_mir::const_eval::machine::CompileTimeInterpreter>>::try_eval_const_fn_call
  28: <rustc_mir::const_eval::machine::CompileTimeInterpreter as rustc_mir::interpret::machine::Machine>::find_mir_or_eval_fn
  29: rustc_mir::interpret::terminator::<impl rustc_mir::interpret::eval_context::InterpCx<M>>::eval_fn_call
  30: rustc_mir::interpret::step::<impl rustc_mir::interpret::eval_context::InterpCx<M>>::step
  31: rustc_mir::const_eval::eval_queries::const_eval_raw_provider
  32: rustc::ty::query::__query_compute::const_eval_raw
  33: rustc::ty::query::<impl rustc::ty::query::config::QueryAccessors for rustc::ty::query::queries::const_eval_raw>::compute
  34: rustc::dep_graph::graph::DepGraph::with_task_impl
  35: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt>::get_query
  36: rustc_mir::const_eval::eval_queries::const_eval_validated_provider
  37: rustc::ty::query::__query_compute::const_eval_validated
  38: rustc::ty::query::<impl rustc::ty::query::config::QueryAccessors for rustc::ty::query::queries::const_eval_validated>::compute
  39: rustc::dep_graph::graph::DepGraph::with_task_impl
  40: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt>::get_query
  41: rustc_mir::const_eval::eval_queries::const_eval_validated_provider
  42: rustc::ty::query::__query_compute::const_eval_validated
  43: rustc::ty::query::<impl rustc::ty::query::config::QueryAccessors for rustc::ty::query::queries::const_eval_validated>::compute
  44: rustc::dep_graph::graph::DepGraph::with_task_impl
  45: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt>::get_query
  46: rustc::mir::interpret::queries::<impl rustc::ty::context::TyCtxt>::const_eval_poly
  47: <rustc_lint::builtin::UnusedBrokenConst as rustc_lint::passes::LateLintPass>::check_item
  48: <rustc_lint::BuiltinCombinedLateLintPass as rustc_lint::passes::LateLintPass>::check_item
  49: rustc_hir::intravisit::Visitor::visit_nested_item
  50: rustc_hir::intravisit::walk_crate
  51: <std::panic::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
  52: __rust_maybe_catch_panic
             at src/libpanic_unwind/lib.rs:86
  53: <std::panic::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
  54: __rust_maybe_catch_panic
             at src/libpanic_unwind/lib.rs:86
  55: rustc_session::utils::<impl rustc_session::session::Session>::time
  56: rustc_interface::passes::analysis
  57: rustc::ty::query::__query_compute::analysis
  58: rustc::dep_graph::graph::DepGraph::with_task_impl
  59: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt>::get_query
  60: rustc::ty::context::tls::enter_global
  61: rustc_interface::interface::run_compiler_in_existing_thread_pool
  62: scoped_tls::ScopedKey<T>::set
  63: syntax::with_globals
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

error: internal compiler error: unexpected panic

note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports

note: rustc 1.42.0-nightly (488406183 2020-01-16) running on x86_64-unknown-linux-gnu

note: compiler flags: -Z unleash-the-miri-inside-of-you

query stack during panic:
#0 [const_eval_raw] const-evaluating `bar`
#1 [const_eval_raw] const-evaluating `CTFE`
#2 [const_eval_validated] const-evaluating + checking `CTFE`
#3 [const_eval_validated] const-evaluating + checking `CTFE`
#4 [analysis] running analysis passes on this crate
end of query stack

@Centril would you happen to have LLVM assertions enabled, which @wesleywiser might not?

The following is the only modifications made to config.toml:

# Whether or not debug assertions are enabled for the compiler and standard
# library.
debug-assertions = true

# Debuginfo level for most of Rust code, corresponds to the `-C debuginfo=N` option of `rustc`.
# `0` - no debug info
# `1` - line tables only
# `2` - full debug info with variable and type information
# Can be overriden for specific subsets of Rust code (rustc, std or tools).
# Debuginfo for tests run with compiletest is not controlled by this option
# and needs to be enabled separately with `debuginfo-level-tests`.
#debuginfo-level = if debug { 2 } else { 0 }
debuginfo-level = 2

where gamma-stage1 was built with clear && ./x.py test --stage 1 --bless --pass check src/test/ui/.

Per @eddyb's advice, I'll try to nuke build/*/stage1-std to see if it reproduces.

note: rustc 1.42.0-nightly (488406183 2020-01-16) running on x86_64-unknown-linux-gnu

The ICE message betrays the old nightly you're still using, heh.

Yeah oops; I was forgetting to add +gamma-stage1 to rustc... damn, still tired from tomorrow I guess, sorry for the noise!

still tired from tomorrow

I won't tell anyone about your secret if you also let me use that time machine. :D

Was this page helpful?
0 / 5 - 0 ratings