Skip to content

Wasmtime: fix stack walking across frames from different stores#4779

Merged
fitzgen merged 1 commit into
bytecodealliance:mainfrom
fitzgen:stack-trace-panic
Aug 30, 2022
Merged

Wasmtime: fix stack walking across frames from different stores#4779
fitzgen merged 1 commit into
bytecodealliance:mainfrom
fitzgen:stack-trace-panic

Conversation

@fitzgen
Copy link
Copy Markdown
Member

@fitzgen fitzgen commented Aug 24, 2022

We were previously implicitly assuming that all Wasm frames in a stack used the same VMRuntimeLimits as the previous frame's CallThreadState, but this is not true when Wasm in store A calls into the host which then calls into Wasm in store B:

| ...             |
| Host            |  |
+-----------------+  | stack
| Wasm in store A |  | grows
+-----------------+  | down
| Host            |  |
+-----------------+  |
| Wasm in store B |  V
+-----------------+

Trying to walk this stack would previously result in a runtime panic.

The solution is to push the maintenance of our list of saved Wasm FP/SP/PC registers that allow us to identify contiguous regions of Wasm frames on the stack deeper into CallThreadState. The saved registers list is now maintained whenever updating the CallThreadState linked list by making the CallThreadState::prev field private and only accessible via a getter and setter, where the setter always maintains our invariants.

Thanks to @bnjbvr for reporting this bug!

@cfallin do you feel familiar enough with this stuff that you'd be comfortable reviewing it? If not, I can totally wait for Alex to come back from PTO.

@github-actions github-actions Bot added the wasmtime:api Related to the API of the `wasmtime` crate itself label Aug 25, 2022
@github-actions
Copy link
Copy Markdown

Subscribe to Label Action

cc @peterhuene

Details This issue or pull request has been labeled: "wasmtime:api"

Thus the following users have been cc'd because of the following labels:

  • peterhuene: wasmtime:api

To subscribe or unsubscribe from this label, edit the .github/subscribe-to-label.json configuration file.

Learn more.

Copy link
Copy Markdown
Member

@alexcrichton alexcrichton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch on this one! All makes sense and the fix here looks good to me.

I am a bit worried about how much code is being grown over time though to manage all these lists of registers going in/out of wasm. I suspect that this is becoming a growing portion of the time spent calling into wasm since there's so many branches and memory reads/writes. For now I think it's fine but I also don't know how we would improve the situation unfortunately.

Comment thread crates/runtime/src/traphandlers.rs Outdated
We were previously implicitly assuming that all Wasm frames in a stack used the
same `VMRuntimeLimits` as the previous frame we walked, but this is not true
when Wasm in store A calls into the host which then calls into Wasm in store B:

    | ...             |
    | Host            |  |
    +-----------------+  | stack
    | Wasm in store A |  | grows
    +-----------------+  | down
    | Host            |  |
    +-----------------+  |
    | Wasm in store B |  V
    +-----------------+

Trying to walk this stack would previously result in a runtime panic.

The solution is to push the maintenance of our list of saved Wasm FP/SP/PC
registers that allow us to identify contiguous regions of Wasm frames on the
stack deeper into `CallThreadState`. The saved registers list is now maintained
whenever updating the `CallThreadState` linked list by making the
`CallThreadState::prev` field private and only accessible via a getter and
setter, where the setter always maintains our invariants.
@fitzgen fitzgen force-pushed the stack-trace-panic branch from efebd1d to bde52b9 Compare August 30, 2022 17:02
@fitzgen fitzgen enabled auto-merge (squash) August 30, 2022 17:03
@fitzgen fitzgen merged commit ff0e84e into bytecodealliance:main Aug 30, 2022
@fitzgen fitzgen deleted the stack-trace-panic branch August 30, 2022 22:23
fitzgen added a commit to fitzgen/wasmtime that referenced this pull request Aug 31, 2022
…codealliance#4779)

We were previously implicitly assuming that all Wasm frames in a stack used the
same `VMRuntimeLimits` as the previous frame we walked, but this is not true
when Wasm in store A calls into the host which then calls into Wasm in store B:

    | ...             |
    | Host            |  |
    +-----------------+  | stack
    | Wasm in store A |  | grows
    +-----------------+  | down
    | Host            |  |
    +-----------------+  |
    | Wasm in store B |  V
    +-----------------+

Trying to walk this stack would previously result in a runtime panic.

The solution is to push the maintenance of our list of saved Wasm FP/SP/PC
registers that allow us to identify contiguous regions of Wasm frames on the
stack deeper into `CallThreadState`. The saved registers list is now maintained
whenever updating the `CallThreadState` linked list by making the
`CallThreadState::prev` field private and only accessible via a getter and
setter, where the setter always maintains our invariants.
@fitzgen
Copy link
Copy Markdown
Member Author

fitzgen commented Aug 31, 2022

FYI this is being backported to the 0.40.X release branch in #4834

fitzgen added a commit that referenced this pull request Aug 31, 2022
* Wasmtime: fix stack walking across frames from different stores (#4779)

We were previously implicitly assuming that all Wasm frames in a stack used the
same `VMRuntimeLimits` as the previous frame we walked, but this is not true
when Wasm in store A calls into the host which then calls into Wasm in store B:

    | ...             |
    | Host            |  |
    +-----------------+  | stack
    | Wasm in store A |  | grows
    +-----------------+  | down
    | Host            |  |
    +-----------------+  |
    | Wasm in store B |  V
    +-----------------+

Trying to walk this stack would previously result in a runtime panic.

The solution is to push the maintenance of our list of saved Wasm FP/SP/PC
registers that allow us to identify contiguous regions of Wasm frames on the
stack deeper into `CallThreadState`. The saved registers list is now maintained
whenever updating the `CallThreadState` linked list by making the
`CallThreadState::prev` field private and only accessible via a getter and
setter, where the setter always maintains our invariants.

* Remove unnecessary parens that cause a warning

* Update release notes for 0.40.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

wasmtime:api Related to the API of the `wasmtime` crate itself

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants