Skip to content

internal compiler error: librustc_mir/hair/pattern/_match.rs:959: impossible case reached #51655

Closed
@koutheir

Description

@koutheir

I tried this code:

use std::ffi::{OsStr, OsString};
use std::os::unix::ffi::{OsStrExt, OsStringExt};
use std::path::{Path, PathBuf};
use std::{env, fs};

fn main() {
    println!("# {}", normalize_path("etc/././a/.//..//").display());
}

const PATH_DOT_: u8 = '.' as u8;
const PATH_SEPARATOR: u8 = '/' as u8;
const PATH_DOT: &[u8] = &[PATH_DOT_];
const PATH_DOT_DOT: &[u8] = &[PATH_DOT_, PATH_DOT_];

fn normalize_path(path: impl AsRef<Path>) -> PathBuf {
    let (existent_path, existent_len) = try_canonicalize(&path);
    let buffer = if let Some(existent_path) = existent_path {
        existent_path.into_os_string().into_vec()
    } else if path.as_ref().is_absolute() {
        vec![PATH_SEPARATOR]
    } else {
        let cur_dir = env::current_dir().unwrap_or_else(|_e| PathBuf::from("./"));
        cur_dir.into_os_string().into_vec()
    };

    let bytes = &path.as_ref().as_os_str().as_bytes()[existent_len..];
    let buffer = bytes
        .split(is_path_separator)
        .fold(buffer, append_to_existing_path);

    PathBuf::from(OsString::from_vec(buffer))
}

fn is_path_separator(e: &u8) -> bool {
    *e == PATH_SEPARATOR
}

fn try_canonicalize(path: impl AsRef<Path>) -> (Option<PathBuf>, usize) {
    let mut bytes = path.as_ref().as_os_str().as_bytes();
    if bytes.is_empty() {
        return (None, 0);
    }

    loop {
        let sub_path = Path::new(OsStr::from_bytes(bytes));
        if let Ok(r) = fs::canonicalize(sub_path) {
            return (Some(r), bytes.len());
        }

        let mut iter = bytes.rsplitn(2, is_path_separator);
        if let Some(_last) = iter.next() {
            if let Some(prefix) = iter.next() {
                bytes = prefix;
            } else {
                return (None, 0);
            }
        } else {
            return (None, 0);
        }
    }
}

enum ParentPathAction {
    CurrentDirectory,
    TrimRight(usize),
    AppendElement,
}

fn append_to_existing_path(mut path: Vec<u8>, element: &[u8]) -> Vec<u8> {
    match element {
        &[] | PATH_DOT => path,

        PATH_DOT_DOT => {
            let action = {
                let mut iter = path.rsplitn(2, is_path_separator);
                if let Some(parent) = iter.next() {
                    if let Some(prefix) = iter.next() {
                        if prefix.is_empty() {
                            match parent {
                                PATH_DOT | PATH_DOT_DOT => {
                                    // "/../.." => "/"
                                    ParentPathAction::TrimRight(parent.len())
                                }

                                _ => {
                                    // "/parent/.." => "/"
                                    ParentPathAction::TrimRight(parent.len())
                                }
                            }
                        } else {
                            match parent {
                                PATH_DOT | PATH_DOT_DOT => {
                                    // "prefix/../.." => "prefix/../.."
                                    ParentPathAction::AppendElement
                                }

                                _ => {
                                    // "prefix/parent/.." => "prefix"
                                    ParentPathAction::TrimRight(parent.len() + 1)
                                }
                            }
                        }
                    } else {
                        // "parent/.." => "<current_dir>"
                        ParentPathAction::CurrentDirectory
                    }
                } else {
                    // ".." => ".."
                    ParentPathAction::AppendElement
                }
            };

            match action {
                ParentPathAction::CurrentDirectory => {
                    let cur_dir = env::current_dir().unwrap_or_else(|_e| PathBuf::from("."));
                    cur_dir.into_os_string().into_vec()
                }

                ParentPathAction::TrimRight(trim) => {
                    let new_len = path.len() - trim;
                    path.truncate(new_len);
                    path
                }

                ParentPathAction::AppendElement => {
                    let path = PathBuf::from(OsString::from_vec(path));
                    let element = Path::new(OsStr::from_bytes(element));
                    path.join(element).into_os_string().into_vec()
                }
            }
        }

        _ => {
            let path = PathBuf::from(OsString::from_vec(path));
            let element = Path::new(OsStr::from_bytes(element));
            path.join(element).into_os_string().into_vec()
        }
    }
}

I expected to see this happen: compilation error or compilation success.

Instead, this happened: compiler crashed into an impossible case.

Meta

$ rustc --version --verbose
rustc 1.26.2 (594fb253c 2018-06-01)
binary: rustc
commit-hash: 594fb253c2b02b320c728391a425d028e6dc7a09
commit-date: 2018-06-01
host: x86_64-unknown-linux-gnu
release: 1.26.2
LLVM version: 6.0

Backtrace:

librustc_mir/hair/pattern/_match.rs:959: impossible case reached

Error messages:

$ cargo build --verbose
   Compiling paths v0.1.0 (file:///media/data/openjdk/126101-infrastructure/license-analyzer/paths)
     Running `rustc --crate-name paths src/main.rs --crate-type bin --emit=dep-info,link -C debuginfo=2 -C metadata=6e46ca38d9a06af0 -C extra-filename=-6e46ca38d9a06af0 --out-dir /media/data/openjdk/126101-infrastructure/license-analyzer/paths/target/debug/deps -C incremental=/media/data/openjdk/126101-infrastructure/license-analyzer/paths/target/debug/incremental -L dependency=/media/data/openjdk/126101-infrastructure/license-analyzer/paths/target/debug/deps`
error: internal compiler error: librustc_mir/hair/pattern/_match.rs:959: impossible case reached

thread 'rustc' panicked at 'Box<Any>', librustc_errors/lib.rs:543:9
note: Run with `RUST_BACKTRACE=1` for a backtrace.
error: aborting due to previous error


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.26.2 (594fb253c 2018-06-01) running on x86_64-unknown-linux-gnu

note: compiler flags: -C debuginfo=2 -C incremental --crate-type bin

note: some of the compiler flags provided by cargo are hidden

error: Could not compile `paths`.

Caused by:
  process didn't exit successfully: `rustc --crate-name paths src/main.rs --crate-type bin --emit=dep-info,link -C debuginfo=2 -C metadata=6e46ca38d9a06af0 -C extra-filename=-6e46ca38d9a06af0 --out-dir <somewhere>/paths/target/debug/deps -C incremental=<somewhere>/paths/target/debug/incremental -L dependency=<somewhere>/paths/target/debug/deps` (exit code: 101)

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.I-ICEIssue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions