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

WASI: path_open regression in Rust 1.51 when using LTO #82758

Closed
PiotrSikora opened this issue Mar 4, 2021 · 10 comments
Closed

WASI: path_open regression in Rust 1.51 when using LTO #82758

PiotrSikora opened this issue Mar 4, 2021 · 10 comments
Labels
C-bug Category: This is a bug. O-wasm Target: WASM (WebAssembly), http://webassembly.org/ P-high High priority regression-from-stable-to-beta Performance or correctness regression from stable to beta. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Milestone

Comments

@PiotrSikora
Copy link

PiotrSikora commented Mar 4, 2021

Code

I tried this code:

fn main() {
    let _ = std::fs::File::open("/proxy-wasm-sandbox/regression.txt");
}
$ cargo +beta build --target wasm32-wasi --release

I expected to see this happen:

This is executed inside Envoy Proxy with preopen dir /proxy-wasm-sandbox, but hopefully the output is readable:

[host->vm] _start()
[vm->host] wasi_snapshot_preview1.fd_prestat_get(3, 1048568)
[vm<-host] wasi_snapshot_preview1.fd_prestat_get return: 0
[vm->host] wasi_snapshot_preview1.fd_prestat_dir_name(3, 1114128, 19)
[vm<-host] wasi_snapshot_preview1.fd_prestat_dir_name return: 0
[vm->host] wasi_snapshot_preview1.fd_prestat_get(4, 1048568)
[vm<-host] wasi_snapshot_preview1.fd_prestat_get return: 8
[vm->host] wasi_snapshot_preview1.path_open(3, 1, 1114320, 14, 0, 262667966, 262667966, 0, 1048520)
[vm<-host] wasi_snapshot_preview1.path_open return: 0
[vm->host] wasi_snapshot_preview1.fd_close(4)
[vm<-host] wasi_snapshot_preview1.fd_close return: 0
[host<-vm] _start return: void

The memory address and size passed in the call (path_open(.., 1114320, 14, ..)) correctly point to a regression.txt.

Instead, this happened:

[host->vm] _start()
[vm->host] wasi_snapshot_preview1.fd_prestat_get(3, 1048568)
[vm<-host] wasi_snapshot_preview1.fd_prestat_get return: 0
[vm->host] wasi_snapshot_preview1.fd_prestat_dir_name(3, 1058576, 19)
[vm<-host] wasi_snapshot_preview1.fd_prestat_dir_name return: 0
[vm->host] wasi_snapshot_preview1.fd_prestat_get(4, 1048568)
[vm<-host] wasi_snapshot_preview1.fd_prestat_get return: 8
[vm->host] wasi_snapshot_preview1.path_open(3, 1, 1, 0, 0, 262667966, 262667966, 0, 1048520)
[vm<-host] wasi_snapshot_preview1.path_open return: 44
[host<-vm] _start return: void

The memory address and size passed in the call (path_open(.., 1, 0, ..)) are wrong.

Version it worked on

It most recently worked on: Rust 1.50

rustc --version --verbose:

rustc 1.50.0 (cb75ad5db 2021-02-10)
binary: rustc
commit-hash: cb75ad5db02783e8b0222fee363c5f63f7e2cf5b
commit-date: 2021-02-10
host: x86_64-unknown-linux-gnu
release: 1.50.0

Version with regression

rustc --version --verbose:

rustc 1.51.0-beta.3 (b631c914c 2021-02-24)
binary: rustc
commit-hash: b631c914cdb5b74dac8f182ca96fdfd3e03ab319
commit-date: 2021-02-24
host: x86_64-unknown-linux-gnu
release: 1.51.0-beta.3
LLVM version: 11.0.1

@rustbot modify labels: +regression-from-stable-to-beta -regression-untriaged

@rustbot rustbot added regression-from-stable-to-beta Performance or correctness regression from stable to beta. I-prioritize Issue: Indicates that prioritization has been requested for this issue. labels Mar 4, 2021
@PiotrSikora
Copy link
Author

PiotrSikora commented Mar 4, 2021

Those PRs look like a possible candidates: #79578, WebAssembly/wasi-libc#214.

Perhaps there is a bug in my code, but it works with Rust 1.50, and the preopens are populated correctly even in Rust 1.51 (otherwise it wouldn't reach path_open), so there aren't too many places left to make a mistake.

cc @alexcrichton

@PiotrSikora
Copy link
Author

I think I found the culprit.

This happens only in the release builds with LTO enabled, where __wasilibc_find_relpath_alloc gets optimized out:

  (func $undefined:__wasilibc_find_relpath_alloc (type $9)
    (param $0 i32)
    (param $1 i32)
    (param $2 i32)
    (param $3 i32)
    (param $4 i32)
    (result i32)
    unreachable
    )

@PiotrSikora
Copy link
Author

Confirmed: if I "use" __wasilibc_find_relpath_alloc, so that it doesn't get optimized out, then everything works fine:

use libc;

extern "C" {
    fn __wasilibc_find_relpath_alloc(
        path: *const libc::c_char,
        abs_prefix: *mut *const libc::c_char,
        relative_path: *mut *const libc::c_char,
        relative_path_len: libc::size_t,
        can_realloc: libc::c_int,
    ) -> libc::c_int;
}

fn main() {
    unsafe {
        let _ = __wasilibc_find_relpath_alloc(
            0 as *const libc::c_char,
            0 as *mut *const libc::c_char,
            0 as *mut *const libc::c_char,
            0,
            0,
        );
    }
    let _ = std::fs::File::open("/proxy-wasm-sandbox/regression.txt");
}

@PiotrSikora PiotrSikora changed the title WASI: path_open regression in Rust 1.51 WASI: path_open regression in Rust 1.51 when using LTO Mar 4, 2021
@JohnTitor JohnTitor added C-bug Category: This is a bug. O-wasm Target: WASM (WebAssembly), http://webassembly.org/ T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Mar 4, 2021
@alexcrichton
Copy link
Member

@PiotrSikora can you clarify how you're building your project? Are you using an external libc or the one shipped with libstd?

@PiotrSikora
Copy link
Author

PiotrSikora commented Mar 4, 2021

$ find . -type f
./src/main.rs
./Cargo.toml
$ cat Cargo.toml
[package]
name = "regress"
version = "0.1.0"
authors = ["Piotr Sikora <piotrsikora@google.com>"]
edition = "2018"

[profile.release]
lto = true
opt-level = 3
panic = "abort"
$ cat src/main.rs
fn main() {
    let _ = std::fs::File::open("/proxy-wasm-sandbox/regression.txt");
}
$ cargo +beta --version && rustc +beta --version && cargo +beta build --target wasm32-wasi --release
cargo 1.51.0-beta (929458982 2021-02-22)
rustc 1.51.0-beta.3 (b631c914c 2021-02-24)
   Compiling regress v0.1.0 (/tmp/regress)
    Finished release [optimized] target(s) in 1.85s
$ wasm-dis target/wasm32-wasi/release/regress.wasm | grep -A2 __wasilibc_find_relpath_alloc | head -3
 (func $undefined:__wasilibc_find_relpath_alloc (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (param $4 i32) (result i32)
  (unreachable)
 )

@LeSeulArtichaut
Copy link
Contributor

Just to clarify, this does not happen with LTO disabled?

@alexcrichton
Copy link
Member

Ok I believe that this is fixed in #82804. The undefined bit you see there is normal, that's what's happening with weak function references during LTO because that function isn't actually used.

@PiotrSikora
Copy link
Author

Just to clarify, this does not happen with LTO disabled?

Correct.

Ok I believe that this is fixed in #82804. The undefined bit you see there is normal, that's what's happening with weak function references during LTO because that function isn't actually used.

Thanks! I verified that #82804 fixes the issue for me.

@apiraino
Copy link
Contributor

Assigning P-high as discussed as part of the Prioritization Working Group procedure and removing I-prioritize.

@rustbot label -I-prioritize +P-high

@rustbot rustbot added P-high High priority and removed I-prioritize Issue: Indicates that prioritization has been requested for this issue. labels Mar 10, 2021
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this issue Mar 11, 2021
This commit fixes an issue pointed out in rust-lang#82758 where LTO changed the
behavior of a program. It turns out that LTO was not at fault here, it
simply uncovered an existing bug. The bindings to
`__wasilibc_find_relpath` assumed that the relative portion of the path
returned was always contained within thee input `buf` we passed in. This
isn't actually the case, however, and sometimes the relative portion of
the path may reference a sub-portion of the input string itself.

The fix here is to use the relative path pointer coming out of
`__wasilibc_find_relpath` as the source of truth. The `buf` used for
local storage is discarded in this function and the relative path is
copied out unconditionally. We might be able to get away with some
`Cow`-like business or such to avoid the extra allocation, but for now
this is probably the easiest patch to fix the original issue.
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this issue Mar 11, 2021
std: Fix a bug on the wasm32-wasi target opening files

This commit fixes an issue pointed out in rust-lang#82758 where LTO changed the
behavior of a program. It turns out that LTO was not at fault here, it
simply uncovered an existing bug. The bindings to
`__wasilibc_find_relpath` assumed that the relative portion of the path
returned was always contained within thee input `buf` we passed in. This
isn't actually the case, however, and sometimes the relative portion of
the path may reference a sub-portion of the input string itself.

The fix here is to use the relative path pointer coming out of
`__wasilibc_find_relpath` as the source of truth. The `buf` used for
local storage is discarded in this function and the relative path is
copied out unconditionally. We might be able to get away with some
`Cow`-like business or such to avoid the extra allocation, but for now
this is probably the easiest patch to fix the original issue.
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this issue Mar 13, 2021
std: Fix a bug on the wasm32-wasi target opening files

This commit fixes an issue pointed out in rust-lang#82758 where LTO changed the
behavior of a program. It turns out that LTO was not at fault here, it
simply uncovered an existing bug. The bindings to
`__wasilibc_find_relpath` assumed that the relative portion of the path
returned was always contained within thee input `buf` we passed in. This
isn't actually the case, however, and sometimes the relative portion of
the path may reference a sub-portion of the input string itself.

The fix here is to use the relative path pointer coming out of
`__wasilibc_find_relpath` as the source of truth. The `buf` used for
local storage is discarded in this function and the relative path is
copied out unconditionally. We might be able to get away with some
`Cow`-like business or such to avoid the extra allocation, but for now
this is probably the easiest patch to fix the original issue.
JohnTitor added a commit to JohnTitor/rust that referenced this issue Mar 14, 2021
std: Fix a bug on the wasm32-wasi target opening files

This commit fixes an issue pointed out in rust-lang#82758 where LTO changed the
behavior of a program. It turns out that LTO was not at fault here, it
simply uncovered an existing bug. The bindings to
`__wasilibc_find_relpath` assumed that the relative portion of the path
returned was always contained within thee input `buf` we passed in. This
isn't actually the case, however, and sometimes the relative portion of
the path may reference a sub-portion of the input string itself.

The fix here is to use the relative path pointer coming out of
`__wasilibc_find_relpath` as the source of truth. The `buf` used for
local storage is discarded in this function and the relative path is
copied out unconditionally. We might be able to get away with some
`Cow`-like business or such to avoid the extra allocation, but for now
this is probably the easiest patch to fix the original issue.
Mark-Simulacrum pushed a commit to Mark-Simulacrum/rust that referenced this issue Mar 22, 2021
This commit fixes an issue pointed out in rust-lang#82758 where LTO changed the
behavior of a program. It turns out that LTO was not at fault here, it
simply uncovered an existing bug. The bindings to
`__wasilibc_find_relpath` assumed that the relative portion of the path
returned was always contained within thee input `buf` we passed in. This
isn't actually the case, however, and sometimes the relative portion of
the path may reference a sub-portion of the input string itself.

The fix here is to use the relative path pointer coming out of
`__wasilibc_find_relpath` as the source of truth. The `buf` used for
local storage is discarded in this function and the relative path is
copied out unconditionally. We might be able to get away with some
`Cow`-like business or such to avoid the extra allocation, but for now
this is probably the easiest patch to fix the original issue.
@Mark-Simulacrum Mark-Simulacrum added this to the 1.51.0 milestone Mar 25, 2021
@pnkfelix
Copy link
Member

pnkfelix commented Apr 1, 2021

Discussed in weekly rustc triage meeting. We believe this was fixed by #82804. Closing as fixed.

@pnkfelix pnkfelix closed this as completed Apr 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug. O-wasm Target: WASM (WebAssembly), http://webassembly.org/ P-high High priority regression-from-stable-to-beta Performance or correctness regression from stable to beta. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

8 participants