Skip to content

ICE: std::os::getcwd fails too eagerly #16946

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

Closed
mahkoh opened this issue Sep 2, 2014 · 6 comments
Closed

ICE: std::os::getcwd fails too eagerly #16946

mahkoh opened this issue Sep 2, 2014 · 6 comments
Labels
I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️

Comments

@mahkoh
Copy link
Contributor

mahkoh commented Sep 2, 2014

2014-09-02-212638_449x195_scrot
This means that getcwd is unusable outside of toy programs. There is no way to see if this function might fail before calling it or to get the path in a safe way.

rustc uses getcwd and will ICE under the conditions described in this issue.

@thehydroimpulse
Copy link
Contributor

It would probably be better to return a result instead of failing.

@mahkoh
Copy link
Contributor Author

mahkoh commented Sep 2, 2014

Naturally an IoResult would be best. For now I've fixed this locally:

static BUF_BYTES: uint = 4096;

#[cfg(unix)]
pub fn getcwd() -> Option<Path> {
    use std::c_str::CString;
    use libc::{c_char, size_t};

    let mut buf = [0 as c_char, ..BUF_BYTES];
    unsafe {
        if libc::getcwd(buf.as_mut_ptr(), buf.len() as size_t).is_null() {
            None
        } else {
            Some(Path::new(CString::new(buf.as_ptr(), false)))
        }
    }
}

#[cfg(windows)]
pub fn getcwd() -> Option<Path> {
    use libc::DWORD;
    use libc::GetCurrentDirectoryW;

    let mut buf = [0 as u16, ..BUF_BYTES];
    unsafe {
        if libc::GetCurrentDirectoryW(buf.len() as DWORD, buf.as_mut_ptr()) == 0 {
            return None;
        }
    }
    match String::from_utf16(std::str::truncate_utf16_at_nul(buf)) {
        Some(s) => Some(Path::new(s)),
        _ => None,
    }
}

And while we're at it: BUF_BYTES is 2048 in the stdlib which is way too small.

@mahkoh
Copy link
Contributor Author

mahkoh commented Sep 2, 2014

Apparently there is no path length limit on linux. glibc has the following extension that could be used to handle this:

       As  an  extension  to the POSIX.1-2001 standard, glibc's getcwd() allocates
       the buffer dynamically using malloc(3) if buf is NULL.  In this  case,  the
       allocated buffer has the length size unless size is zero, when buf is allo‐
       cated as big as necessary.  The caller should free(3) the returned buffer.

Not sure about jemalloc <-> malloc here. FreeBSD has the same extension.

@huonw huonw changed the title std::os::getcwd is useless std::os::getcwd fails too eagerly Sep 2, 2014
@huonw huonw added the A-libs label Sep 2, 2014
@mahkoh
Copy link
Contributor Author

mahkoh commented Sep 2, 2014

@huonw Not sure why you changed the title. You cannot use getcwd in its current form in a safe way if you don't want your program to crash. Even if the user just deleted the directory your program was started from, your program will crash. If your program was started with a very long cwd path? Crash. getcwd is literally useless in its current form. No need to sugarcoat the issue.

Furthermore your title is misleading since this is not the only issue. getcwd also fails if the buffer is too small. That means that the documentation is incorrect.

@huonw
Copy link
Member

huonw commented Sep 2, 2014

The original title was unnecessarily inflammatory and nonspecific; I changed it to accurately reflect the problem: it fail!s instead of handling errors properly.

Furthermore your title is misleading since this is not the only issue. getcwd also fails if the buffer is too small.

That is included in "failing too eagerly": it doesn't handle this 'error' properly.

That means that the documentation is incorrect.

Your title didn't address this either.

@mahkoh mahkoh changed the title std::os::getcwd fails too eagerly ICE: std::os::getcwd fails too eagerly Sep 3, 2014
@brson
Copy link
Contributor

brson commented Sep 5, 2014

cc @aturon

@steveklabnik steveklabnik added the I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ label Sep 22, 2014
bors added a commit that referenced this issue Nov 18, 2014
Make old-fashioned functions in the `std::os` module utilize `IoResult`.

I'm still investigating the possibility to include more functions in this pull request. Currently, it covers `getcwd()`, `make_absolute()`, and `change_dir()`. The issues covered by this PR are #16946 and #16315.

A few concerns:

- Should we provide `OsError` in distinction from `IoError`? I'm saying this because in Python, those two are distinguished. One advantage that we keep using `IoError` is that we can make the error cascade down other functions whose return type also includes `IoError`. An example of such functions is `std::io::TempDir::new_in()`, which uses `os::make_absolute()` as well as returns `IoResult<TempDir>`.
- `os::getcwd()` uses an internal buffer whose size is 2048 bytes, which is passed to `getcwd(3)`. There is no upper limitation of file paths in the POSIX standard, but typically it is set to 4096 bytes such as in Linux. Should we increase the buffer size? One thing that makes me nervous is that the size of 2048 bytes already seems a bit excessive, thinking that in normal cases, there would be no filenames that even exceeds 512 bytes.

Fixes #16946.
Fixes #16315.

Any ideas are welcomed. Thanks!
@bors bors closed this as completed in 6f422c4 Nov 18, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants