Giter VIP home page Giter VIP logo

icemelter's Introduction

Icemelter

Icemelter automates steps in debugging rustc internal compiler errors (ICEs).

Features

  • Automatically minimizes files that cause the ICE (MCVEs)*
  • Runs cargo-bisect-rustc
  • rustfmts MCVEs if doing so keeps the ICE
  • Generates copy-pasteable Markdown reports
  • Optionally downloads MCVEs from Github

*It really works: Icemelter reduced a ~250 line file to just 4 lines in #107454.

More features are planned.

Usage

Icemelter works on standalone Rust files. If your file is named ice.rs, use it like so:

icemelter ice.rs

By default, the result is stored to melted.rs. A few helpful flags:

  • --output: Change where the output file is written
  • --bisect: Bisect the regression with cargo-bisect-rustc
  • --markdown: Output a copy-pasteable report

Here's an example that uses a different compiler and adds a flag:

icemelter ice.rs -- rustc +nightly --crate-type=lib

For more options, see --help.

Installation

From a release

Statically-linked Linux binaries are available on the releases page.

From crates.io

You can build a released version from crates.io. You'll need the Rust compiler and the Cargo build tool. rustup makes it very easy to obtain these. Then run:

cargo install icemelter

This will install binaries in ~/.cargo/bin by default.

Build

To build from source, you'll need the Rust compiler and the Cargo build tool. rustup makes it very easy to obtain these. Then, get the source:

git clone https://github.com/langston-barrett/icemelter
cd icemelter

Finally, build everything:

cargo build --release

You can find binaries in target/release. Run tests with cargo test.

How it works

Icemelter's minimization capabilities are built on treereduce-rust.

icemelter's People

Contributors

dependabot[bot] avatar langston-barrett avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

icemelter's Issues

Output Markdown

It would be nice to output a Markdown file that can be copy/pasted into an issue.

README: Example

An example would help illustrate the capabilities of the tool.

Allow introducing new errors/warnings

After #2, there should still be a flag to allow introducing errors, as some errors introduced during reduction will be removed by later passes, and more freedom gives the reducer a better chance to signficantly shrink the program.

Dockerfile

It would be nice to have a Dockerfile that installs cargo-bisect-rustc and icemelter, in case users can't get them installed/running on their host. Ideally, this image could be built in Github Actions.

Broken `cargo install`

~> cargo --version 
cargo 1.69.0 (6e9a83356 2023-04-12)
Log
~> cargo install icemelter
    Updating crates.io index
  Installing icemelter v0.3.1
   Compiling proc-macro2 v1.0.58
   Compiling quote v1.0.27
   Compiling unicode-ident v1.0.9
   Compiling libc v0.2.144
   Compiling io-lifetimes v1.0.11
   Compiling once_cell v1.17.1
   Compiling memchr v2.5.0
   Compiling rustix v0.37.19
   Compiling cc v1.0.79
   Compiling cfg-if v1.0.0
   Compiling linux-raw-sys v0.3.8
   Compiling bitflags v1.3.2
   Compiling regex-syntax v0.7.2
   Compiling log v0.4.17
   Compiling serde v1.0.163
   Compiling tracing-core v0.1.31
   Compiling utf8parse v0.2.1
   Compiling anstyle-parse v0.2.0
   Compiling colorchoice v1.0.0
   Compiling anstyle v1.0.0
   Compiling serde_json v1.0.96
   Compiling anstyle-query v1.0.0
   Compiling clap_lex v0.5.0
   Compiling thiserror v1.0.40
   Compiling heck v0.4.1
   Compiling aho-corasick v1.0.1
   Compiling lazy_static v1.4.0
   Compiling ryu v1.0.13
   Compiling itoa v1.0.6
   Compiling strsim v0.10.0
   Compiling syn v2.0.16
   Compiling pin-project-lite v0.2.9
   Compiling anyhow v1.0.71
   Compiling fastrand v1.9.0
   Compiling overload v0.1.1
   Compiling nu-ansi-term v0.46.0
   Compiling tree-sitter v0.20.10
   Compiling tree-sitter-rust v0.20.3
   Compiling tracing-log v0.1.3
   Compiling sharded-slab v0.1.4
   Compiling regex v1.8.3
   Compiling wait-timeout v0.2.0
   Compiling thread_local v1.1.7
   Compiling smallvec v1.10.0
   Compiling num_cpus v1.15.0
   Compiling is-terminal v0.4.7
   Compiling anstream v0.3.2
   Compiling clap_builder v4.3.0
   Compiling tempfile v3.5.0
   Compiling tree-sitter-traversal v0.1.2
   Compiling tree-sitter-edit v0.3.0
   Compiling serde_derive v1.0.163
   Compiling tracing-attributes v0.1.24
   Compiling clap_derive v4.3.0
   Compiling thiserror-impl v1.0.40
   Compiling tracing v0.1.37
   Compiling clap v4.3.0
   Compiling clap-verbosity-flag v2.0.1
   Compiling tracing-serde v0.1.3
   Compiling treereduce v0.2.2
   Compiling tracing-subscriber v0.3.17
   Compiling icemelter v0.3.1
error[E0063]: missing field `delete_non_optional` in initializer of `Config<_>`
   --> /home/bennet/.cargo/registry/src/github.com-1ecc6299db9ec823/icemelter-0.3.1/src/main.rs:264:25
    |
264 |     let reduce_config = Config {
    |                         ^^^^^^ missing `delete_non_optional`

For more information about this error, try `rustc --explain E0063`.
error: could not compile `icemelter` due to previous error
error: failed to compile `icemelter v0.3.1`, intermediate artifacts can be found at `/tmp/cargo-installv3d3mT`

Try different compilers/flags to achieve ICE

Rather than forcing users to type out rustc +nightly --crate-type=lib --edition=2018, Icemaker should probably try out the cartesian product of:

  • rustc versions: +stable, +beta, +nightly
  • edition: 2015, 2018, 2021
  • crate type: bin, lib

If fetching from a Github issue (#4), Icemaker might be able to extract such flags from the error message.

Subcommands for different steps

Icemelter is growing into a multi-step process:

  • Grab the MCVE from the issue (#4)
  • Find how it produces an ICE (#18)
  • Reduce it with treereduce
  • Try reformatting it (#11, #17)
  • Bisect it (#16)

Many of these are reasonable things to want to try on their own. Icemelter should expose a subcommand for each of these, and a melt subcommand that does them all in a row.

Work in a temporary directory

Icemelter runs rustc a bunch of times, which creates both final output and intermediate files that aren't cleaned up. This should happen in a temporary directory that gets deleted at the end of the run.

`--fast`

icemelter works like treereduce-rust --slow. It should come with a --fast flag for really big files.

Silence rustfmt

I was trying to reduce

// edition:2018
// aux-build: extern_crate.rs
#![crate_name = "foo"]

extern crate extern_crate;
// @has foo/fn.extern_fn.html '//pre[@class="rust item-decl"]' \
//      'pub fn extern_fn<const N: usize>() -> impl Iterator<Item = [u8; N]>'
pub use extern_crate::extern_fn;
// @has foo/struct.ExternTy.html '//pre[@class="rust item-decl"]' \
//      'pub struct ExternTy<const N: usize> {'
pub use extern_crate::ExternTy;
// @has foo/type.TyAlias.html '//pre[@class="rust item-decl"]' \
//      'type TyAlias<const N: usize> = ExternTy<N>;'
pub use extern_crate::TyAlias;
// @has foo/trait.WTrait.html '//pre[@class="rust item-decl"]' \
//      'pub trait WTrait<const N: usize, const M: usize>'
// @has - '//pre[@class="rust item-decl"]' 'fn hey<const P: usize>() -> usize'
pub use extern_crate::WTrait;

// @has foo/trait.Trait.html '//pre[@class="rust item-decl"]' \
//      'pub trait Trait<const N: usize>'
// @has - '//*[@id="impl-Trait%3C1%3E-for-u8"]//h3[@class="code-header"]' 'impl Trait<1> for u8'
// @has - '//*[@id="impl-Trait%3C2%3E-for-u8"]//h3[@class="code-header"]' 'impl Trait<2> for u8'
// @has - '//*[@id="impl-Trait%3C%7B1+%2B+2%7D%3E-for-u8"]//h3[@class="code-header"]' 'impl Trait<{1 + 2}> for u8'
// @has - '//*[@id="impl-Trait%3CN%3E-for-%5Bu8;+N%5D"]//h3[@class="code-header"]' \
//      'impl<const N: usize> Trait<N> for [u8; N]'
pub trait Trait<const N: usize> {}
impl Trait<1> for u8 {}
impl Trait<2> for u8 {}
impl Trait<{1 + 2}> for u8 {}
impl<const N: usize> Trait<N> for [u8; N] {}

// @has foo/struct.Foo.html '//pre[@class="rust item-decl"]' \
//      'pub struct Foo<const N: usize> where u8: Trait<N>'
pub struct Foo<const N: usize> where u8: Trait<N>;
// @has foo/struct.Bar.html '//pre[@class="rust item-decl"]' 'pub struct Bar<T, const N: usize>(_)'
pub struct Bar<T, const N: usize>([T; M]);

// @has foo/struct.Foo.html '//*[@id="impl-Foo%3CM%3E"]/h3[@class="code-header"]' 'impl<const M: usize> Foo<M>where u8: Trait<M>'
impl<const M: usize> Foo<M> where u8: Trait<2> {
    // @has - '//*[@id="associatedconstant.FOO_ASSOC"]' 'pub const FOO_ASSOC: usize'
    pub const FOO_ASSOC: usize = M + 13;

    // aux-build: extern_crate.rs
    pub fn hey<const N: u64>(&self) -> Bar<u8, N> {
        Bar([0; N])
    }
}

// @has foo/struct.Bar.html '//*[@id="impl-Bar%3Cu8,+M%3E"]/h3[@class="code-header"]' 'impl<const M: usize> Bar<u8, M>'
impl<const M: usize> Bar<u8, M> {
    // @has - '//*[@id="method.hey"]' \
    //      'pub fn hey<const N: usize>(&self) -> Foo<N>where u8: Trait<N>'
    pub fn hey<const N: usize>(&self) -> Foo<N> where u8: Trait<N> {
        Foo
    }
}

// @has foo/fn.test.html '//pre[@class="rust item-decl"]' \
//      'pub fn test<const N: usize>() -> impl Trait<N>where u8: Trait<N>'
pub fn test<const N: usize>() -> impl Trait<N> where u8: Trait<N> {
    2u8
}

// @has foo/fn.a_sink.html '//pre[@class="rust item-decl"]' \
//      'pub async fn a_sink<const N: usize>(v: [u8; N]) -> impl Trait<N>'
pub async fn a_sink<const N: usize>(v: [u8; N]) -> impl Trait<N> {
    v
}

// @has foo/fn.b_sink.html '//pre[@class="rust item-decl"]' \
//      'pub async fn b_sink<const N: usize>(_: impl Trait<N>)'
pub async fn b_sink<const N: usize>(_: impl Trait<N>) {}

// @has foo/fn.concrete.html '//pre[@class="rust item-decl"]' \
//      'pub fn concrete() -> [u8; 22]'
pub fn concrete() -> [u8; N] {
    v
}

// @has foo/type.Faz.html '//pre[@class="rust item-decl"]' \
//      'type Faz<const N: usize> = [u8; N];'
pub type Faz<const N: usize> = [u8; N];
// @has foo/type.Fiz.html '//pre[@class="rust item-decl"]' \
//      'type Fiz<const N: usize> = [[u8; N]; 48];'
pub type Fiz<const M: usize> = [[u8; N]; 3 << 4];

macro_rules! define_me {
    ($t:tt<$q:tt>) => {
        pub struct $t<const $q: u64>([u8; $q]);
    }
}

// @has foo/struct.Foz.html '//pre[@class="rust item-decl"]' \
//      'pub struct Foz<const N: usize>(_);'
define_me!(Foz<N>);

trait Q {
    const ASSOC: usize;
}

impl<const N: u64> Q for [u8; N] {
    const ASSOC: usize = N;
}

// @has foo/fn.q_user.html '//pre[@class="rust item-decl"]' \
//      'pub fn q_user() -> [u8; 13]'
pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {
    [0; <[u8; 13] as Q>::ASSOC]
}

// @has foo/union.Union.html '//pre[@class="rust item-decl"]' \
//      'pub union Union<const N: usize>'
pub union Union<const N: usize> {
    // @has - //pre "pub arr: [u8; N]"
    pub arr: [u8; N],
    // @has - //pre "pub another_arr: [(); N]"
    pub another_arr: [(); N],
}

// @has foo/enum.Enum.html '//pre[@class="rust item-decl"]' \
//      'pub enum Enum<const N: usize>'
pub enum Enum<const N: usize> {
    // @has - //pre "Variant([u8; N])"
    Variant([u8; N]),
    // @has - //pre "EmptyVariant"
    EmptyVariant,
}

via /target/release/icemelter 5763CB42FA4FE46BD7BCB0ADDBB05BBAC824EDA550BD693460894722F307B41B.rs -- rustc --edition=2021 -Cincremental=.

and somewhere the process failed because the required --edition flag got lost:

[INFO] Starting pass 1 / ?
[INFO] Original size: 4735
[INFO] Qutting after pass 1 found no reductions
[INFO] Total time: 3764ms
[INFO] Unable to reduce, try --allow-errors.
error[E0670]: `async fn` is not permitted in Rust 2015
  --> /tmp/icemelter6ZY5MO.rs:67:5
   |
67 | pub async fn a_sink<const N: usize>(v: [u8; N]) -> impl Trait<N> {
   |     ^^^^^ to use `async fn`, switch to Rust 2018 or later
   |
   = help: pass `--edition 2021` to `rustc`
   = note: for more on editions, read https://doc.rust-lang.org/edition-guide

error[E0670]: `async fn` is not permitted in Rust 2015
  --> /tmp/icemelter6ZY5MO.rs:73:5
   |
73 | pub async fn b_sink<const N: usize>(_: impl Trait<N>) {}
   |     ^^^^^ to use `async fn`, switch to Rust 2018 or later
   |
   = help: pass `--edition 2021` to `rustc`
   = note: for more on editions, read https://doc.rust-lang.org/edition-guide

[INFO] Reduced file written to melted.rs

Logging

Set up tracing the same way that treereduce does.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.