mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
mach: Allow using with_asan on ohos
This also relaxes the version requirement for the clang compiler when using asan, since asan also has runtime checks, which would fail if instrumented code relies on an incompatible libasan version. - We remove `TARGET_LDFLAGS = -static-libasan` since anyway rustc invokes the linker, so this flag has no effect. - We enable frame pointers with ASAN, since we are anyway debugging. It should probably be the default anyway. - We pass the with_asan option also to mach package, since hvigor needs to know that we are building for asan, otherwise it leads to a crash at startup. Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com>
This commit is contained in:
parent
979304e493
commit
657135445a
4 changed files with 67 additions and 10 deletions
|
@ -40,6 +40,7 @@ from servo.platform.build_target import BuildTarget
|
||||||
SUPPORTED_ASAN_TARGETS = [
|
SUPPORTED_ASAN_TARGETS = [
|
||||||
"aarch64-apple-darwin",
|
"aarch64-apple-darwin",
|
||||||
"aarch64-unknown-linux-gnu",
|
"aarch64-unknown-linux-gnu",
|
||||||
|
"aarch64-unknown-linux-ohos",
|
||||||
"x86_64-apple-darwin",
|
"x86_64-apple-darwin",
|
||||||
"x86_64-unknown-linux-gnu",
|
"x86_64-unknown-linux-gnu",
|
||||||
]
|
]
|
||||||
|
@ -109,6 +110,8 @@ class MachCommands(CommandBase):
|
||||||
opts += ["-v"]
|
opts += ["-v"]
|
||||||
if very_verbose:
|
if very_verbose:
|
||||||
opts += ["-vv"]
|
opts += ["-vv"]
|
||||||
|
if with_asan:
|
||||||
|
self.config["build"]["with_asan"] = True
|
||||||
|
|
||||||
env = self.build_env()
|
env = self.build_env()
|
||||||
self.ensure_bootstrapped()
|
self.ensure_bootstrapped()
|
||||||
|
@ -136,6 +139,10 @@ class MachCommands(CommandBase):
|
||||||
opts += ["-Zbuild-std"]
|
opts += ["-Zbuild-std"]
|
||||||
kwargs["target_override"] = target_triple
|
kwargs["target_override"] = target_triple
|
||||||
|
|
||||||
|
# With asan we also want frame pointers
|
||||||
|
if "force-frame-pointers" not in env["RUSTFLAGS"]:
|
||||||
|
env["RUSTFLAGS"] += " -C force-frame-pointers=yes"
|
||||||
|
|
||||||
# Note: We want to use the same clang/LLVM version as rustc.
|
# Note: We want to use the same clang/LLVM version as rustc.
|
||||||
rustc_llvm_version = get_rustc_llvm_version()
|
rustc_llvm_version = get_rustc_llvm_version()
|
||||||
if rustc_llvm_version is None:
|
if rustc_llvm_version is None:
|
||||||
|
@ -144,11 +151,14 @@ class MachCommands(CommandBase):
|
||||||
target_clang = f"clang-{llvm_major}"
|
target_clang = f"clang-{llvm_major}"
|
||||||
target_cxx = f"clang++-{llvm_major}"
|
target_cxx = f"clang++-{llvm_major}"
|
||||||
if shutil.which(target_clang) is None or shutil.which(target_cxx) is None:
|
if shutil.which(target_clang) is None or shutil.which(target_cxx) is None:
|
||||||
raise RuntimeError(f"--with-asan requires `{target_clang}` and `{target_cxx}` to be in PATH")
|
env.setdefault("TARGET_CC", target_clang)
|
||||||
env.setdefault("TARGET_CC", target_clang)
|
env.setdefault("TARGET_CXX", target_cxx)
|
||||||
env.setdefault("TARGET_CXX", target_cxx)
|
else:
|
||||||
# TODO: We should also parse the LLVM version from the clang compiler we chose.
|
# libasan can be compatible across multiple compiler versions and has a
|
||||||
# It's unclear if the major version being the same is sufficient.
|
# runtime check, which would fail if we used incompatible compilers, so
|
||||||
|
# we can try and fallback to the default clang.
|
||||||
|
env.setdefault("TARGET_CC", "clang")
|
||||||
|
env.setdefault("TARGET_CXX", "clang++")
|
||||||
|
|
||||||
# We need to use `TARGET_CFLAGS`, since we don't want to compile host dependencies with ASAN,
|
# We need to use `TARGET_CFLAGS`, since we don't want to compile host dependencies with ASAN,
|
||||||
# since that causes issues when building build-scripts / proc macros.
|
# since that causes issues when building build-scripts / proc macros.
|
||||||
|
@ -156,7 +166,6 @@ class MachCommands(CommandBase):
|
||||||
env.setdefault("TARGET_CXXFLAGS", "")
|
env.setdefault("TARGET_CXXFLAGS", "")
|
||||||
env["TARGET_CFLAGS"] += " -fsanitize=address"
|
env["TARGET_CFLAGS"] += " -fsanitize=address"
|
||||||
env["TARGET_CXXFLAGS"] += " -fsanitize=address"
|
env["TARGET_CXXFLAGS"] += " -fsanitize=address"
|
||||||
env["TARGET_LDFLAGS"] = "-static-libasan"
|
|
||||||
# By default build mozjs from source to enable ASAN with mozjs.
|
# By default build mozjs from source to enable ASAN with mozjs.
|
||||||
env.setdefault("MOZJS_FROM_SOURCE", "1")
|
env.setdefault("MOZJS_FROM_SOURCE", "1")
|
||||||
|
|
||||||
|
@ -190,7 +199,9 @@ class MachCommands(CommandBase):
|
||||||
built_binary = self.get_binary_path(build_type, asan=with_asan)
|
built_binary = self.get_binary_path(build_type, asan=with_asan)
|
||||||
|
|
||||||
if not no_package and self.target.needs_packaging():
|
if not no_package and self.target.needs_packaging():
|
||||||
rv = Registrar.dispatch("package", context=self.context, build_type=build_type, flavor=flavor)
|
rv = Registrar.dispatch(
|
||||||
|
"package", context=self.context, build_type=build_type, flavor=flavor, with_asan=with_asan
|
||||||
|
)
|
||||||
if rv:
|
if rv:
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
|
|
|
@ -305,6 +305,7 @@ class CommandBase(object):
|
||||||
self.config["build"].setdefault("incremental", None)
|
self.config["build"].setdefault("incremental", None)
|
||||||
self.config["build"].setdefault("webgl-backtrace", False)
|
self.config["build"].setdefault("webgl-backtrace", False)
|
||||||
self.config["build"].setdefault("dom-backtrace", False)
|
self.config["build"].setdefault("dom-backtrace", False)
|
||||||
|
self.config["build"].setdefault("with_asan", False)
|
||||||
|
|
||||||
self.config.setdefault("android", {})
|
self.config.setdefault("android", {})
|
||||||
self.config["android"].setdefault("sdk", "")
|
self.config["android"].setdefault("sdk", "")
|
||||||
|
|
|
@ -184,6 +184,9 @@ class PackageCommands(CommandBase):
|
||||||
"-p",
|
"-p",
|
||||||
f"buildMode={build_mode}",
|
f"buildMode={build_mode}",
|
||||||
]
|
]
|
||||||
|
if with_asan:
|
||||||
|
hvigor_command.extend(["-p", "ohos-debug-asan=true"])
|
||||||
|
|
||||||
# Detect if PATH already has hvigor, or else fallback to npm installation
|
# Detect if PATH already has hvigor, or else fallback to npm installation
|
||||||
# provided via HVIGOR_PATH
|
# provided via HVIGOR_PATH
|
||||||
if "HVIGOR_PATH" not in env:
|
if "HVIGOR_PATH" not in env:
|
||||||
|
|
|
@ -350,9 +350,8 @@ class OpenHarmonyTarget(CrossBuildTarget):
|
||||||
env[f"CXX_{clang_target_triple_underscore}"] = ndk_clangxx
|
env[f"CXX_{clang_target_triple_underscore}"] = ndk_clangxx
|
||||||
# rustc linker
|
# rustc linker
|
||||||
env[f"CARGO_TARGET_{rust_target_triple.upper()}_LINKER"] = ndk_clang
|
env[f"CARGO_TARGET_{rust_target_triple.upper()}_LINKER"] = ndk_clang
|
||||||
# We could also use a cross-compile wrapper
|
|
||||||
env["RUSTFLAGS"] += f" -Clink-arg=--target={clang_target_triple}"
|
link_args = ["-fuse-ld=lld", f"--target={clang_target_triple}", f"--sysroot={ohos_sysroot_posix}"]
|
||||||
env["RUSTFLAGS"] += f" -Clink-arg=--sysroot={ohos_sysroot_posix}"
|
|
||||||
|
|
||||||
env["HOST_CFLAGS"] = ""
|
env["HOST_CFLAGS"] = ""
|
||||||
env["HOST_CXXFLAGS"] = ""
|
env["HOST_CXXFLAGS"] = ""
|
||||||
|
@ -398,6 +397,49 @@ class OpenHarmonyTarget(CrossBuildTarget):
|
||||||
bindgen_extra_clangs_args = bindgen_extra_clangs_args + " " + ohos_cflags_str
|
bindgen_extra_clangs_args = bindgen_extra_clangs_args + " " + ohos_cflags_str
|
||||||
env[bindgen_extra_clangs_args_var] = bindgen_extra_clangs_args
|
env[bindgen_extra_clangs_args_var] = bindgen_extra_clangs_args
|
||||||
|
|
||||||
|
# On OpenHarmony we add some additional flags when asan is enabled
|
||||||
|
if config["build"]["with_asan"]:
|
||||||
|
# Lookup `<sdk>/native/llvm/lib/clang/15.0.4/lib/aarch64-linux-ohos/libclang_rt.asan.so`
|
||||||
|
lib_clang = llvm_toolchain.joinpath("lib", "clang")
|
||||||
|
children = [f.path for f in os.scandir(lib_clang) if f.is_dir()]
|
||||||
|
if len(children) != 1:
|
||||||
|
raise RuntimeError(f"Expected exactly 1 libclang version: `{children}`")
|
||||||
|
lib_clang_version_dir = pathlib.Path(children[0])
|
||||||
|
libclang_arch = lib_clang_version_dir.joinpath("lib", clang_target_triple).resolve()
|
||||||
|
libasan_so_path = libclang_arch.joinpath("libclang_rt.asan.so")
|
||||||
|
libasan_preinit_path = libclang_arch.joinpath("libclang_rt.asan-preinit.a")
|
||||||
|
if not libasan_so_path.exists():
|
||||||
|
raise RuntimeError(f"Couldn't find ASAN runtime library at {libasan_so_path}")
|
||||||
|
link_args.extend(
|
||||||
|
[
|
||||||
|
"-fsanitize=address",
|
||||||
|
"--rtlib=compiler-rt",
|
||||||
|
"-shared-libasan",
|
||||||
|
str(libasan_so_path),
|
||||||
|
"-Wl,--whole-archive",
|
||||||
|
"-Wl," + str(libasan_preinit_path),
|
||||||
|
"-Wl,--no-whole-archive",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Use the clangrt from the NDK to use the same library for both C++ and Rust.
|
||||||
|
env["RUSTFLAGS"] += " -Zexternal-clangrt"
|
||||||
|
|
||||||
|
asan_compile_flags = (
|
||||||
|
" -fsanitize=address -shared-libasan -fno-omit-frame-pointer -fsanitize-recover=address"
|
||||||
|
)
|
||||||
|
|
||||||
|
arch_asan_ignore_list = lib_clang_version_dir.joinpath("share", "asan_ignorelist.txt")
|
||||||
|
if arch_asan_ignore_list.exists():
|
||||||
|
asan_compile_flags += " -fsanitize-system-ignorelist=" + str(arch_asan_ignore_list)
|
||||||
|
else:
|
||||||
|
print(f"Warning: Couldn't find system ASAN ignorelist at `{arch_asan_ignore_list}`")
|
||||||
|
env["TARGET_CFLAGS"] += asan_compile_flags
|
||||||
|
env["TARGET_CXXFLAGS"] += asan_compile_flags
|
||||||
|
|
||||||
|
link_args = [f"-Clink-arg={arg}" for arg in link_args]
|
||||||
|
env["RUSTFLAGS"] += " " + " ".join(link_args)
|
||||||
|
|
||||||
def binary_name(self) -> str:
|
def binary_name(self) -> str:
|
||||||
return "libservoshell.so"
|
return "libservoshell.so"
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue