Fix segfault when using --object-format serialized and compile errors

This commit is contained in:
Felix Schütt
2022-12-28 10:04:28 +01:00
parent 8a97f4458f
commit 032cb2cbcd
2 changed files with 92 additions and 47 deletions

View File

@@ -450,15 +450,15 @@ build-capi-llvm-universal: capi-setup
build-capi-headless: capi-setup build-capi-headless: capi-setup
ifeq ($(CARGO_TARGET),) ifeq ($(CARGO_TARGET),)
RUSTFLAGS="${RUSTFLAGS} -C panic=abort -C link-dead-code -C lto -O -C embed-bitcode=yes" $(CARGO_BINARY) build --target $(HOST_TARGET) --manifest-path lib/c-api/Cargo.toml --release \ RUSTFLAGS="${RUSTFLAGS} -C panic=abort -C link-dead-code -C lto -O -C embed-bitcode=yes" $(CARGO_BINARY) build --target $(HOST_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features compiler-headless,wasi --target-dir target/$(CARGO_TARGET)/headless --no-default-features --features compiler-headless,wasi,webc_runner --target-dir target/$(CARGO_TARGET)/headless
else else
RUSTFLAGS="${RUSTFLAGS} -C panic=abort -C link-dead-code -C lto -O -C embed-bitcode=yes" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \ RUSTFLAGS="${RUSTFLAGS} -C panic=abort -C link-dead-code -C lto -O -C embed-bitcode=yes" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features compiler-headless,wasi --target-dir target/$(CARGO_TARGET)/headless --no-default-features --features compiler-headless,wasi,webc_runner --target-dir target/$(CARGO_TARGET)/headless
endif endif
build-capi-headless-ios: capi-setup build-capi-headless-ios: capi-setup
RUSTFLAGS="${RUSTFLAGS} -C panic=abort" cargo lipo --manifest-path lib/c-api/Cargo.toml --release \ RUSTFLAGS="${RUSTFLAGS} -C panic=abort" cargo lipo --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features compiler-headless,wasi --target-dir target/$(CARGO_TARGET)/headless --no-default-features --features compiler-headless,wasi,webc_runner --target-dir target/$(CARGO_TARGET)/headless
##### #####
# #

View File

@@ -161,8 +161,9 @@ impl CreateExe {
let starting_cd = env::current_dir()?; let starting_cd = env::current_dir()?;
let input_path = starting_cd.join(&self.path); let input_path = starting_cd.join(&self.path);
let output_path = starting_cd.join(&self.output); let output_path = starting_cd.join(&self.output);
let object_format = self.object_format.unwrap_or_default();
let cross_compilation = let cross_compilation =
utils::get_cross_compile_setup(&mut cc, &target_triple, &starting_cd)?; utils::get_cross_compile_setup(&mut cc, &target_triple, &starting_cd, &object_format)?;
if input_path.is_dir() { if input_path.is_dir() {
return Err(anyhow::anyhow!("input path cannot be a directory")); return Err(anyhow::anyhow!("input path cannot be a directory"));
@@ -180,7 +181,7 @@ impl CreateExe {
&self.compiler, &self.compiler,
&self.cpu_features, &self.cpu_features,
&cross_compilation.target, &cross_compilation.target,
self.object_format.unwrap_or_default(), object_format,
&self.precompiled_atom, &self.precompiled_atom,
AllowMultiWasm::Allow, AllowMultiWasm::Allow,
)?; )?;
@@ -210,7 +211,7 @@ impl CreateExe {
&self.compiler, &self.compiler,
&cross_compilation.target, &cross_compilation.target,
&self.cpu_features, &self.cpu_features,
self.object_format.unwrap_or_default(), object_format,
&self.precompiled_atom, &self.precompiled_atom,
)?; )?;
get_module_infos(&tempdir, &atoms)?; get_module_infos(&tempdir, &atoms)?;
@@ -641,7 +642,12 @@ fn conpile_atoms(
} }
/// Compile the C code. /// Compile the C code.
fn run_c_compile(path_to_c_src: &Path, output_name: &Path, target: &Triple) -> anyhow::Result<()> { fn run_c_compile(
path_to_c_src: &Path,
output_name: &Path,
target: &Triple,
debug: bool,
) -> anyhow::Result<()> {
#[cfg(not(windows))] #[cfg(not(windows))]
let c_compiler = "cc"; let c_compiler = "cc";
// We must use a C++ compiler on Windows because wasm.h uses `static_assert` // We must use a C++ compiler on Windows because wasm.h uses `static_assert`
@@ -658,9 +664,16 @@ fn run_c_compile(path_to_c_src: &Path, output_name: &Path, target: &Triple) -> a
.arg("-I") .arg("-I")
.arg(utils::get_wasmer_include_directory()?) .arg(utils::get_wasmer_include_directory()?)
.arg("-target") .arg("-target")
.arg(format!("{}", target)); .arg(format!("{}", target))
.arg("-o")
.arg(output_name);
let output = command.arg("-o").arg(output_name).output()?; if debug {
println!("{command:#?}");
}
let output = command.output()?;
if debug {
eprintln!( eprintln!(
"run_c_compile: stdout: {}\n\nstderr: {}", "run_c_compile: stdout: {}\n\nstderr: {}",
std::str::from_utf8(&output.stdout) std::str::from_utf8(&output.stdout)
@@ -668,6 +681,7 @@ fn run_c_compile(path_to_c_src: &Path, output_name: &Path, target: &Triple) -> a
std::str::from_utf8(&output.stderr) std::str::from_utf8(&output.stderr)
.expect("stderr is not utf8! need to handle arbitrary bytes") .expect("stderr is not utf8! need to handle arbitrary bytes")
); );
}
if !output.status.success() { if !output.status.success() {
bail!( bail!(
@@ -963,6 +977,7 @@ fn link_exe_from_dir(
&directory.join("wasmer_main.c"), &directory.join("wasmer_main.c"),
&directory.join("wasmer_main.o"), &directory.join("wasmer_main.o"),
&cross_compilation.target, &cross_compilation.target,
debug,
) )
.map_err(|e| { .map_err(|e| {
anyhow::anyhow!( anyhow::anyhow!(
@@ -1210,8 +1225,6 @@ fn generate_wasmer_main_c(
}} }}
")?; ")?;
} else { } else {
extra_headers.push(format!("const extern unsigned char {module_name}[];\r\n"));
write!( write!(
c_code_to_add, c_code_to_add,
" "
@@ -1319,7 +1332,7 @@ fn generate_wasmer_main_c(
#[allow(dead_code)] #[allow(dead_code)]
pub(super) mod utils { pub(super) mod utils {
use super::{CrossCompile, CrossCompileSetup}; use super::{CrossCompile, CrossCompileSetup, ObjectFormat};
use anyhow::Context; use anyhow::Context;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use target_lexicon::{Architecture, OperatingSystem, Triple}; use target_lexicon::{Architecture, OperatingSystem, Triple};
@@ -1342,9 +1355,14 @@ pub(super) mod utils {
cross_subc: &mut CrossCompile, cross_subc: &mut CrossCompile,
target_triple: &Triple, target_triple: &Triple,
starting_cd: &Path, starting_cd: &Path,
object_format: &ObjectFormat,
) -> Result<CrossCompileSetup, anyhow::Error> { ) -> Result<CrossCompileSetup, anyhow::Error> {
let target = target_triple; let target = target_triple;
if *object_format == ObjectFormat::Serialized && *target_triple != Triple::host() {
return Err(anyhow::anyhow!("cannot cross-compile: --object-format serialized + cross-compilation is not supported"));
}
if let Some(tarball_path) = cross_subc.tarball.as_mut() { if let Some(tarball_path) = cross_subc.tarball.as_mut() {
if tarball_path.is_relative() { if tarball_path.is_relative() {
*tarball_path = starting_cd.join(&tarball_path); *tarball_path = starting_cd.join(&tarball_path);
@@ -1381,8 +1399,31 @@ pub(super) mod utils {
if let Some(local_tarball) = cross_subc.tarball.as_ref() { if let Some(local_tarball) = cross_subc.tarball.as_ref() {
find_filename(local_tarball, target) find_filename(local_tarball, target)
} else { } else {
// check WASMER_DIR if Target = native
let mut local = None;
if *target_triple == Triple::host() && std::env::var("WASMER_DIR").is_ok() {
let wasmer_dir = wasmer_registry::WasmerConfig::get_wasmer_dir().ok();
if let Some(library) = wasmer_dir.as_ref().and_then(|wasmer_dir| {
find_libwasmer_in_files(&target, &super::http_fetch::list_dir(wasmer_dir))
.ok()
}) {
if Path::new(&library).exists() {
local = Some((
format!(
"{}",
Path::new(&library).canonicalize().unwrap().display()
),
wasmer_dir.unwrap(),
));
}
}
}
// check if the tarball for the target already exists locally // check if the tarball for the target already exists locally
let local_tarball = std::fs::read_dir(get_libwasmer_cache_path()?)? let local_tarball = if local.is_some() {
None
} else {
std::fs::read_dir(get_libwasmer_cache_path()?)?
.filter_map(|e| e.ok()) .filter_map(|e| e.ok())
.filter_map(|e| { .filter_map(|e| {
let path = format!("{}", e.path().display()); let path = format!("{}", e.path().display());
@@ -1393,9 +1434,12 @@ pub(super) mod utils {
} }
}) })
.filter_map(|p| filter_tarballs(&p, target)) .filter_map(|p| filter_tarballs(&p, target))
.next(); .next()
};
if let Some(local_tarball) = local_tarball.as_ref() { if let Some(local) = local {
Ok(local)
} else if let Some(local_tarball) = local_tarball.as_ref() {
find_filename(local_tarball, target) find_filename(local_tarball, target)
} else { } else {
let release = super::http_fetch::get_latest_release()?; let release = super::http_fetch::get_latest_release()?;
@@ -1431,11 +1475,14 @@ pub(super) mod utils {
std::fs::create_dir_all(&target_file_path) std::fs::create_dir_all(&target_file_path)
.map_err(|e| anyhow::anyhow!("{e}")) .map_err(|e| anyhow::anyhow!("{e}"))
.with_context(|| anyhow::anyhow!("{}", target_file_path.display()))?; .with_context(|| anyhow::anyhow!("{}", target_file_path.display()))?;
let files = let files = super::http_fetch::untar(local_tarball, &target_file_path)?;
super::http_fetch::untar(local_tarball.to_path_buf(), target_file_path.clone())?;
let tarball_dir = target_file_path.canonicalize().unwrap_or(target_file_path); let tarball_dir = target_file_path.canonicalize().unwrap_or(target_file_path);
let file = find_libwasmer_in_files(&target, &files)?;
Ok((file, tarball_dir))
}
let file = files fn find_libwasmer_in_files(target: &Triple, files: &[String]) -> Result<String, anyhow::Error> {
files
.iter() .iter()
.find(|f| f.ends_with("libwasmer-headless.a") || f.ends_with("wasmer-headless.lib")) .find(|f| f.ends_with("libwasmer-headless.a") || f.ends_with("wasmer-headless.lib"))
.or_else(|| { .or_else(|| {
@@ -1446,9 +1493,7 @@ pub(super) mod utils {
.cloned() .cloned()
.ok_or_else(|| { .ok_or_else(|| {
anyhow!("Could not find libwasmer.a for {} target in the provided tarball path (files = {files:#?})", target) anyhow!("Could not find libwasmer.a for {} target in the provided tarball path (files = {files:#?})", target)
})?; })
Ok((file, tarball_dir))
} }
pub(super) fn filter_tarballs(p: &Path, target: &Triple) -> Option<PathBuf> { pub(super) fn filter_tarballs(p: &Path, target: &Triple) -> Option<PathBuf> {
@@ -1661,6 +1706,7 @@ mod http_fetch {
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use http_req::{request::Request, response::StatusCode, uri::Uri}; use http_req::{request::Request, response::StatusCode, uri::Uri};
use std::convert::TryFrom; use std::convert::TryFrom;
use std::path::Path;
use target_lexicon::OperatingSystem; use target_lexicon::OperatingSystem;
pub(super) fn get_latest_release() -> Result<serde_json::Value> { pub(super) fn get_latest_release() -> Result<serde_json::Value> {
@@ -1917,18 +1963,17 @@ mod http_fetch {
} }
} }
pub(super) fn untar( pub(crate) fn list_dir(target: &Path) -> Vec<String> {
tarball: std::path::PathBuf,
target: std::path::PathBuf,
) -> Result<Vec<String>> {
use walkdir::WalkDir; use walkdir::WalkDir;
WalkDir::new(&target)
wasmer_registry::try_unpack_targz(&tarball, &target, false)?;
Ok(WalkDir::new(&target)
.into_iter() .into_iter()
.filter_map(|e| e.ok()) .filter_map(|e| e.ok())
.map(|entry| format!("{}", entry.path().display())) .map(|entry| format!("{}", entry.path().display()))
.collect()) .collect()
}
pub(super) fn untar(tarball: &Path, target: &Path) -> Result<Vec<String>> {
wasmer_registry::try_unpack_targz(tarball, target, false)?;
Ok(list_dir(target))
} }
} }