Verifies that the serialized engine in `mmap` is compatible with the `engine` provided. This function will verify that the `mmap` provided can be deserialized successfully and that the contents are all compatible with the `engine` provided here, notably compatible wasm features are enabled, compatible compiler options, etc. If a mismatch is found and the compilation metadata specified is incompat
(engine: &Engine, mmap: &[u8], expected: ObjectKind)
| 47 | /// compiler options, etc. If a mismatch is found and the compilation metadata |
| 48 | /// specified is incompatible then an error is returned. |
| 49 | pub fn check_compatible(engine: &Engine, mmap: &[u8], expected: ObjectKind) -> Result<()> { |
| 50 | // Parse the input `mmap` as an ELF file and see if the header matches the |
| 51 | // Wasmtime-generated header. This includes a Wasmtime-specific `os_abi` and |
| 52 | // the `e_flags` field should indicate whether `expected` matches or not. |
| 53 | // |
| 54 | // Note that errors generated here could mean that a precompiled module was |
| 55 | // loaded as a component, or vice versa, both of which aren't supposed to |
| 56 | // work. |
| 57 | // |
| 58 | // Ideally we'd only `File::parse` once and avoid the linear |
| 59 | // `section_by_name` search here but the general serialization code isn't |
| 60 | // structured well enough to make this easy and additionally it's not really |
| 61 | // a perf issue right now so doing that is left for another day's |
| 62 | // refactoring. |
| 63 | let header = FileHeader64::<Endianness>::parse(mmap) |
| 64 | .map_err(obj::ObjectCrateErrorWrapper) |
| 65 | .context("failed to parse precompiled artifact as an ELF")?; |
| 66 | let endian = header |
| 67 | .endian() |
| 68 | .context("failed to parse header endianness")?; |
| 69 | |
| 70 | let expected_e_flags = match expected { |
| 71 | ObjectKind::Module => obj::EF_WASMTIME_MODULE, |
| 72 | ObjectKind::Component => obj::EF_WASMTIME_COMPONENT, |
| 73 | }; |
| 74 | ensure!( |
| 75 | (header.e_flags(endian) & expected_e_flags) == expected_e_flags, |
| 76 | "incompatible object file format" |
| 77 | ); |
| 78 | |
| 79 | let section_headers = header |
| 80 | .section_headers(endian, mmap) |
| 81 | .context("failed to parse section headers")?; |
| 82 | let strings = header |
| 83 | .section_strings(endian, mmap, section_headers) |
| 84 | .context("failed to parse strings table")?; |
| 85 | let sections = header |
| 86 | .sections(endian, mmap) |
| 87 | .context("failed to parse sections table")?; |
| 88 | |
| 89 | let mut section_header = None; |
| 90 | for s in sections.iter() { |
| 91 | let name = s.name(endian, strings)?; |
| 92 | if name == obj::ELF_WASM_ENGINE.as_bytes() { |
| 93 | section_header = Some(s); |
| 94 | } |
| 95 | } |
| 96 | let Some(section_header) = section_header else { |
| 97 | bail!("failed to find section `{}`", obj::ELF_WASM_ENGINE) |
| 98 | }; |
| 99 | let data = section_header |
| 100 | .data(endian, mmap) |
| 101 | .map_err(obj::ObjectCrateErrorWrapper)?; |
| 102 | let (first, data) = data |
| 103 | .split_first() |
| 104 | .ok_or_else(|| format_err!("invalid engine section"))?; |
| 105 | if *first != VERSION { |
| 106 | bail!("mismatched version in engine section"); |
no test coverage detected