Stream: git-wasmtime

Topic: wasmtime / issue #10169 Wasmtime behaves differently comp...


view this post on Zulip Wasmtime GitHub notifications bot (Feb 03 2025 at 06:43):

teyahb8 added the bug label to Issue #10169.

view this post on Zulip Wasmtime GitHub notifications bot (Feb 03 2025 at 06:43):

teyahb8 opened issue #10169:

Test Case

The wat code and the corresponding wasm module are compressed here: files.zip

Steps to Reproduce

Expected Results

Based on the differential behavior of wasmer, wamr (aot mode), and wasmedge runtimes, the expected behavior is an out of bounds error.

Actual Results

The actual result from the wasmtime runtime is a stack overflow.

Versions and Environment

Wasmtime version or commit: wasmtime 28.0.0 (3e0b7e501 2024-11-19)

Operating system: Linux

Architecture: x86_64

Can you please confirm if this behavior is expected from wasmtime or is this a bug? Thanks in advance.

view this post on Zulip Wasmtime GitHub notifications bot (Feb 03 2025 at 06:51):

teyahb8 edited issue #10169:

Test Case

The wat code and the corresponding wasm module are compressed here: files.zip

Steps to Reproduce

Expected Results

Based on the differential behavior of wasmer, wamr (aot mode), and wasmedge runtimes, the expected behavior is an out of bounds error.

Actual Results

The actual result from the wasmtime runtime is a stack overflow.

Versions and Environment

Wasmtime version or commit: wasmtime 30.0.0 (a0338af84 2025-01-31)

Operating system: Linux

Architecture: x86_64

Can you please confirm if this behavior is expected from wasmtime or is this a bug? Thanks in advance.

view this post on Zulip Wasmtime GitHub notifications bot (Feb 03 2025 at 07:23):

cfallin commented on issue #10169:

@teyahb8 in the future, would you mind posting the example directly? Posting a link to a .zip file that must be downloaded and extracted to view, especially when that .zip file is 506 bytes and the resulting WAT is 13 lines, is fairly wasteful of maintainers' time. Thanks!

The test-case is:

(module
  (memory (;0;) 25)
  (export "main" (func 0))
  (func (;0;) (result)
    i32.const 2
    memory.grow
    v128.load offset=2 align=2
    block (result) ;; label = @1
      call 0
    end
    drop
  )
)

This program recurses, and on each recursion grows the memory by 2 Wasm pages (128 KiB). The memory does not have a limit (the 25 is its initial size in Wasm pages), so it will grow up to 4GiB, or about 32K recursions (4Gi / 128 Ki, minus initial 25 pages).

It seems unsurprising to me that a program that recurses 32K times runs out of stack. Perhaps the other Wasm engines have different default stack sizes, or allocate a different (smaller) frame per function. Stack exhaustion is one of several sources of engine-specific nondeterminism in Wasm, so if you're running tests of engines against each other, you will need to account for that.

Given all that, I think this is not a bug, just nondeterminism allowed by the spec. Do you agree? Or is there something I'm missing?

view this post on Zulip Wasmtime GitHub notifications bot (Feb 03 2025 at 07:27):

cfallin commented on issue #10169:

(And lest the v128.load raise suspicions, it is performing a load from an address based on the returned new memory size in pages, but treating that as a byte-addressed location; so it is always in-bounds.)

view this post on Zulip Wasmtime GitHub notifications bot (Feb 03 2025 at 11:17):

primoly commented on issue #10169:

If the memory.grow fails due to the host not having enough memory, it returns -1 (=2<sup>32</sup>-1) leading to an out of bounds memory access.

I tested it in Firefox and it seems to run out of stack as well. I can’t test the other runtimes right now, but could it be that they do some sort of tail-call optimisation? I think that would go against the WebAssembly spec.

view this post on Zulip Wasmtime GitHub notifications bot (Feb 03 2025 at 11:52):

alexcrichton closed issue #10169:

Test Case

The wat code and the corresponding wasm module are compressed here: files.zip

Steps to Reproduce

Expected Results

Based on the differential behavior of wasmer, wamr (aot mode), and wasmedge runtimes, the expected behavior is an out of bounds error.

Actual Results

The actual result from the wasmtime runtime is a stack overflow.

Versions and Environment

Wasmtime version or commit: wasmtime 30.0.0 (a0338af84 2025-01-31)

Operating system: Linux

Architecture: x86_64

Can you please confirm if this behavior is expected from wasmtime or is this a bug? Thanks in advance.

view this post on Zulip Wasmtime GitHub notifications bot (Feb 03 2025 at 11:52):

alexcrichton commented on issue #10169:

I agree with @cfallin and @primoly in that there doesn't look to be a bug here. At best other runtimes have different defaults for when stack overflow occurs and at worst other runtimes are going against the spec as @primoly mentions. In either case resource exhaustion is not specified to be the exact same across all runtimes so I don't think there's anything for Wasmtime to do here, so closing.

I would also echo what @cfallin said, avoiding the indirection of a zip is much appreciated.

view this post on Zulip Wasmtime GitHub notifications bot (Feb 03 2025 at 12:57):

primoly edited a comment on issue #10169:

If the memory.grow fails due to the host not having enough memory, it returns -1 (=2<sup>32</sup>-1) leading to an out of bounds memory access.

I tested it in Edge and it seems to run out of stack as well. I can’t test the other runtimes right now, but could it be that they do some sort of tail-call optimisation? I think that would go against the WebAssembly spec.

view this post on Zulip Wasmtime GitHub notifications bot (Feb 03 2025 at 13:59):

teyahb8 commented on issue #10169:

Thanks for the clarification. I agree that the default stack exhaustion behavior can vary. Also, I appreciate the advice on the test case file format. I will make sure to keep this in mind for future issues.


Last updated: Feb 28 2025 at 02:27 UTC