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

Wasmtime: disable unwind_info unless needed #4351

Merged
merged 3 commits into from
Jun 30, 2022

Conversation

Stebalien
Copy link
Contributor

Disable the "unwind_info" cranelift feature unless backtraces (or reference types) are enabled. Maintaining unwind info in deeply recursive modules can get expensive.

fixes #4350

fixes bytecodealliance#4350

Otherwise wasm modules will be built with unwind info, even if
backtraces are disabled. This can get expensive in deeply recursive
modules.
@@ -381,6 +380,7 @@ impl Engine {
| "enable_verifier"
| "regalloc_checker"
| "is_pic"
| "unwind_info"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note: this is inconsistent with "enable_safepoints", which checks that we don't ahve the reference_types feature enabled. But so is "enable_simd", so I'm not sure which way to go.

@github-actions github-actions bot added wasmtime:api Related to the API of the `wasmtime` crate itself wasmtime:config Issues related to the configuration of Wasmtime labels Jun 29, 2022
@github-actions
Copy link

Subscribe to Label Action

cc @peterhuene

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

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.

@github-actions
Copy link

Label Messager: wasmtime:config

It looks like you are changing Wasmtime's configuration options. Make sure to
complete this check list:

  • If you added a new Config method, you wrote extensive documentation for
    it.

    Our documentation should be of the following form:

    Short, simple summary sentence.
    
    More details. These details can be multiple paragraphs. There should be
    information about not just the method, but its parameters and results as
    well.
    
    Is this method fallible? If so, when can it return an error?
    
    Can this method panic? If so, when does it panic?
    
    # Example
    
    Optional example here.
    
  • If you added a new Config method, or modified an existing one, you
    ensured that this configuration is exercised by the fuzz targets.

    For example, if you expose a new strategy for allocating the next instance
    slot inside the pooling allocator, you should ensure that at least one of our
    fuzz targets exercises that new strategy.

    Often, all that is required of you is to ensure that there is a knob for this
    configuration option in wasmtime_fuzzing::Config (or one
    of its nested structs).

    Rarely, this may require authoring a new fuzz target to specifically test this
    configuration. See our docs on fuzzing for more details.

  • If you are enabling a configuration option by default, make sure that it
    has been fuzzed for at least two weeks before turning it on by default.


To modify this label's message, edit the .github/label-messager/wasmtime-config.md file.

To add new label messages or remove existing label messages, edit the
.github/label-messager.json configuration file.

Learn more.

@alexcrichton
Copy link
Member

Would you be up for adding a test which disables backtraces? I thought we had something along those lines but it sounds like your configuration is different which our current test suite isn't covering.

@alexcrichton
Copy link
Member

Also, I'm a bit confused how this is coming up, this example program works for me:

use anyhow::Result;
use wasmtime::*;

fn main() -> Result<()> {
    let mut config = Config::new();
    config.wasm_backtrace(false);
    let engine = Engine::new(&config).unwrap();
    let m1 = Module::new(&engine, "(module (func unreachable))")?;

    let bytes = m1.serialize()?;
    let m2 = unsafe { Module::deserialize(&engine, &bytes)? };

    let mut store = Store::new(&engine, ());
    Instance::new(&mut store, &m1, &[])?;
    Instance::new(&mut store, &m2, &[])?;
    Ok(())
}

so I'm also curious what configuration you're using to trigger the error coming out.

@Stebalien
Copy link
Contributor Author

Would you be up for adding a test which disables backtraces? I thought we had something along those lines but it sounds like your configuration is different which our current test suite isn't covering.

There's a test:

#[test]
fn test_trap_backtrace_disabled() -> Result<()> {
let mut config = Config::default();
config.wasm_backtrace(false);
let engine = Engine::new(&config).unwrap();
let mut store = Store::<()>::new(&engine, ());
let wat = r#"
(module $hello_mod
(func (export "run") (call $hello))
(func $hello (unreachable))
)
"#;
let module = Module::new(store.engine(), wat)?;
let instance = Instance::new(&mut store, &module, &[])?;
let run_func = instance.get_typed_func::<(), (), _>(&mut store, "run")?;
let e = run_func
.call(&mut store, ())
.err()
.expect("error calling function");
assert!(e.trace().is_none(), "backtraces should be disabled");
Ok(())
}

But it doesn't test that unwind info isn't generated. I've just added a targeted one to make sure it's disabled at the compiler level, but there may be a better way.

@Stebalien
Copy link
Contributor Author

Also, I'm a bit confused how this is coming up, this example program works for me:

It does work, however:

  1. In 0.38, unwind info won't be disabled unless you also disable reference types. If you disable reference types as well, that won't work.
  2. In 0.39 (dev), that will "work" simply because unwind info won't be disabled no matter what you do.

The test I added should catch this.

@Stebalien Stebalien closed this Jun 29, 2022
@Stebalien Stebalien reopened this Jun 29, 2022
@alexcrichton
Copy link
Member

Ah ok that makes sense, thanks for clarifying. I had forgotten that the changes to Config and idempotency which would affect this were only on 0.39.0 and not 0.38.0.

Otherwise though I think that the unwind_info flag still needs verification as you mentioned along the lines of safepoints. If wasm_backtrace or wasm_reference_types are enabled then unwind_info must be true, but otherwise the value of the flag does not matter.

@Stebalien
Copy link
Contributor Author

Otherwise though I think that the unwind_info flag still needs verification as you mentioned along the lines of safepoints.

I was pointing out an inconsistency. It looks like that function is primarily for validating that the config matches the current system, not for validating that the config matches the flags. That function isn't currently checking, e.g., enable_simd, enable_float, enable_verifier, etc. either. The enable_safepoints check is actually the exception.

The config is checked against the compiler flags in

pub(crate) fn build_compiler(&mut self) -> Result<Box<dyn wasmtime_environ::Compiler>> {

@alexcrichton
Copy link
Member

This is needed for memory safety I believe. Without a check it's possible to load a wasm module which doesn't have .eh_frame and we're then unable to produce backtraces or backtraces crash at runtime if backtraces are required. The specific problem is compiling a module without .eh_frame as a precompiled artifact and then loading it into an engine that tries to do backtraces.

@Stebalien
Copy link
Contributor Author

Ah, because this is checking the compiled module. Got it, thanks. That also explains why we don't care about enable_simd, enable_float, etc. (although the fact that the engine will happily deserialize a module that doesn't quite match the engine's config is non-obvious).

I've pushed a fix, but I think there's still technically a bug. We're checking that we have unwind_info if the flag is present, but we're not making sure the flag is actually present. I'm not sure if we really care, but I figured I'd mention it.


Meta: would you like me to squash?

Copy link
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.

Currently we're guaranteed that every module will have all the options listed, but yeah as you've noticed this isn't the best system and we'd like to improve it. For now this should be good enough but it's definitely not great that each individual option tries to have an ad-hoc level of compatibility when we'd probably get the same mileage with just asserting everything is the same.

@alexcrichton alexcrichton merged commit b4830ef into bytecodealliance:main Jun 30, 2022
@Stebalien
Copy link
Contributor Author

@alexcrichton and @pchickey, thanks for guiding me through this!

@Stebalien Stebalien deleted the fix/disable-unwind-info branch June 30, 2022 15:27
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 wasmtime:config Issues related to the configuration of Wasmtime
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Can't fully disable wasm backtraces
3 participants