This commit is contained in:
Jonathan Schwender 2025-06-03 23:48:35 +02:00 committed by GitHub
commit 074f492191
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 71 additions and 13 deletions

View file

@ -40,6 +40,7 @@ from servo.platform.build_target import BuildTarget
SUPPORTED_ASAN_TARGETS = [
"aarch64-apple-darwin",
"aarch64-unknown-linux-gnu",
"aarch64-unknown-linux-ohos",
"x86_64-apple-darwin",
"x86_64-unknown-linux-gnu",
]
@ -109,6 +110,8 @@ class MachCommands(CommandBase):
opts += ["-v"]
if very_verbose:
opts += ["-vv"]
if with_asan:
self.config["build"]["with_asan"] = True
env = self.build_env()
self.ensure_bootstrapped()
@ -136,6 +139,10 @@ class MachCommands(CommandBase):
opts += ["-Zbuild-std"]
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.
rustc_llvm_version = get_rustc_llvm_version()
if rustc_llvm_version is None:
@ -144,11 +151,14 @@ class MachCommands(CommandBase):
target_clang = f"clang-{llvm_major}"
target_cxx = f"clang++-{llvm_major}"
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_CXX", target_cxx)
# TODO: We should also parse the LLVM version from the clang compiler we chose.
# It's unclear if the major version being the same is sufficient.
env.setdefault("TARGET_CC", target_clang)
env.setdefault("TARGET_CXX", target_cxx)
else:
# libasan can be compatible across multiple compiler versions and has a
# 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,
# since that causes issues when building build-scripts / proc macros.
@ -156,7 +166,6 @@ class MachCommands(CommandBase):
env.setdefault("TARGET_CXXFLAGS", "")
env["TARGET_CFLAGS"] += " -fsanitize=address"
env["TARGET_CXXFLAGS"] += " -fsanitize=address"
env["TARGET_LDFLAGS"] = "-static-libasan"
# By default build mozjs from source to enable ASAN with mozjs.
env.setdefault("MOZJS_FROM_SOURCE", "1")
@ -190,7 +199,9 @@ class MachCommands(CommandBase):
built_binary = self.get_binary_path(build_type, asan=with_asan)
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:
return rv

View file

@ -305,6 +305,7 @@ class CommandBase(object):
self.config["build"].setdefault("incremental", None)
self.config["build"].setdefault("webgl-backtrace", False)
self.config["build"].setdefault("dom-backtrace", False)
self.config["build"].setdefault("with_asan", False)
self.config.setdefault("android", {})
self.config["android"].setdefault("sdk", "")
@ -803,15 +804,16 @@ class CommandBase(object):
"--manifest-path",
path.join(self.context.topdir, "ports", "servoshell", "Cargo.toml"),
]
if target_override:
args += ["--target", target_override]
elif self.target.is_cross_build():
if self.target.is_cross_build():
args += ["--target", self.target.triple()]
if type(self.target) in [AndroidTarget, OpenHarmonyTarget]:
# Note: in practice `cargo rustc` should just be used unconditionally.
assert command != "build", "For Android / OpenHarmony `cargo rustc` must be used instead of cargo build"
if command == "rustc":
args += ["--lib", "--crate-type=cdylib"]
elif target_override:
args += ["--target", target_override]
features = []

View file

@ -184,6 +184,9 @@ class PackageCommands(CommandBase):
"-p",
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
# provided via HVIGOR_PATH
if "HVIGOR_PATH" not in env:

View file

@ -350,9 +350,8 @@ class OpenHarmonyTarget(CrossBuildTarget):
env[f"CXX_{clang_target_triple_underscore}"] = ndk_clangxx
# rustc linker
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}"
env["RUSTFLAGS"] += f" -Clink-arg=--sysroot={ohos_sysroot_posix}"
link_args = ["-fuse-ld=lld", f"--target={clang_target_triple}", f"--sysroot={ohos_sysroot_posix}"]
env["HOST_CFLAGS"] = ""
env["HOST_CXXFLAGS"] = ""
@ -398,6 +397,49 @@ class OpenHarmonyTarget(CrossBuildTarget):
bindgen_extra_clangs_args = bindgen_extra_clangs_args + " " + ohos_cflags_str
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:
return "libservoshell.so"