Skip to content

Weird behavior of wasi::filesystem through Rust std::fs::remove_dir_all #11701

@vigoo

Description

@vigoo

I would like to report a very weird issue that I ran into while debugging this through Golem (which uses wasmtime under the hood). Through the investigation I realized that the issue can be reproduced purely with wasmtime, even with the latest published version.

However, the reproducer is a bit fragile:

  • the original issue I was debugging is that for a particular directory structure created within a Rust guest, calling std::fs::remove_dir_all on it ended up in an infinite loop where the Rust standard library seems to continuously creating a read dir iterator, and calling unlike_at and stat_at on the same files.
  • slightly modifying the code though (even when I just copy-pasted it into another example component and removed some unused functions!) it turns into failing with (the remove_dir_all call) Directory not empty (os error 55) which is also unexpected, but different

Even compiling to debug vs release seems to affect which of the above two outcome happens.

Test Case

I'm attaching a cargo-component crate that is reproducing me both of the above cases with rustc 1.89 and cargo-component 0.21.1.

Steps to Reproduce

Reproducing the "error 55" case with debug build:

  • compile to debug: cargo component build
  • create a temp directory on the host: mkdir tmp
  • run with wasmtime --invoke 'reproducer()' --dir 'tmp::/' target/wasm32-wasip1/debug/file_service.wasm

Output:

Trying to create directory /tmp/py/modules/0/mytest/__pycache__
Finished creating directory /tmp/py/modules/0/mytest/__pycache__
Ok(())
Creating files
Ok(())
Ok(())
Ok(())
Ok(())
Removing all
print_tree "/tmp/py/modules/0"
📁 mytest
print_tree "/tmp/py/modules/0/mytest"
  📄 __init__.py
  📁 __pycache__
print_tree "/tmp/py/modules/0/mytest/__pycache__"
    📄 mymodule.rustpython-01.pyc
    📄 __init__.rustpython-01.pyc
  📄 mymodule.py
Err("Directory not empty (os error 55)")
()

Reproducing the infinite loop with a release build:

  • compile to debug: cargo component build --release
  • create a temp directory on the host: mkdir tmp
  • run with wasmtime --invoke 'reproducer()' --dir 'tmp::/' target/wasm32-wasip1/release/file_service.wasm

Output:

Trying to create directory /tmp/py/modules/0/mytest/__pycache__
Finished creating directory /tmp/py/modules/0/mytest/__pycache__
Ok(())
Creating files
Ok(())
Ok(())
Ok(())
Ok(())
Removing all
print_tree "/tmp/py/modules/0"
📁 mytest
print_tree "/tmp/py/modules/0/mytest"
  📄 __init__.py
  📁 __pycache__
print_tree "/tmp/py/modules/0/mytest/__pycache__"
    📄 mymodule.rustpython-01.pyc
    📄 __init__.rustpython-01.pyc
  📄 mymodule.py

and hanging here.

Note that even removing things like prints from the code can make it rather fail than hang, so I'm not sure how stable this reproducer is on other machines.
Also the attached code contains many other functions which are used in different tests originally - I left them because removing them made the "hanging case" irreproducible for me.

I can attach the actual two WASMs if it helps.

Expected Results

The directory structure deleted and the guest returns without error.

Versions and Environment

Wasmtime version: tried with 33.0.0 (what we use internally) and the latest published (36.0.2)

Operating system: Darwin Kernel Version 24.6.0
Architecture: arm64

reproducer.zip

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugIncorrect behavior in the current implementation that needs fixingwasi:implIssues pertaining to WASI implementation in Wasmtime

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions