Skip to content

[clang] Implement address sanitizer on AIX #129925

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

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions clang/include/clang/Basic/DiagnosticDriverKinds.td
Original file line number Diff line number Diff line change
@@ -257,8 +257,10 @@ def err_drv_malformed_sanitizer_coverage_ignorelist : Error<
"malformed sanitizer coverage ignorelist: '%0'">;
def err_drv_malformed_sanitizer_metadata_ignorelist : Error<
"malformed sanitizer metadata ignorelist: '%0'">;
def err_drv_unsupported_static_sanitizer_darwin : Error<
"static %0 runtime is not supported on darwin">;
def err_drv_unsupported_sanitizer : Error<
"%0 %1 runtime is not supported on %2">;
def err_drv_missing_sanitizer_file : Error<
"cannot link '%0': %1 file missing from resource directories">;
def err_drv_duplicate_config : Error<
"no more than one option '--config' is allowed">;
def err_drv_cannot_open_config_file : Error<
2 changes: 1 addition & 1 deletion clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
@@ -1586,7 +1586,7 @@ defm xl_pragma_pack : BoolFOption<"xl-pragma-pack",
"Enable IBM XL #pragma pack handling">,
NegFlag<SetFalse>>;
def shared_libsan : Flag<["-"], "shared-libsan">,
HelpText<"Dynamically link the sanitizer runtime">;
HelpText<"Dynamically link the sanitizer runtime (Not supported for ASan on AIX)">;
def static_libsan : Flag<["-"], "static-libsan">,
HelpText<"Statically link the sanitizer runtime (Not supported for ASan, TSan or UBSan on darwin)">;
def : Flag<["-"], "shared-libasan">, Alias<shared_libsan>;
5 changes: 3 additions & 2 deletions clang/lib/CodeGen/BackendUtil.cpp
Original file line number Diff line number Diff line change
@@ -280,13 +280,14 @@ static bool asanUseGlobalsGC(const Triple &T, const CodeGenOptions &CGOpts) {
return !CGOpts.DisableIntegratedAS;
case Triple::GOFF:
llvm::report_fatal_error("ASan not implemented for GOFF");
case Triple::XCOFF:
llvm::report_fatal_error("ASan not implemented for XCOFF.");
case Triple::Wasm:
case Triple::DXContainer:
case Triple::SPIRV:
case Triple::UnknownObjectFormat:
break;
case Triple::XCOFF:
// FIXME: try to enable GC-friendly instrumentation for globals on AIX.
return false;
}
return false;
}
62 changes: 62 additions & 0 deletions clang/lib/Driver/ToolChains/AIX.cpp
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@
#include <set>

using AIX = clang::driver::toolchains::AIX;
using namespace clang;
using namespace clang::driver;
using namespace clang::driver::tools;
using namespace clang::driver::toolchains;
@@ -258,6 +259,61 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// Specify linker input file(s).
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);

// Add sanitizer libraries.
const SanitizerArgs &Sanitize = ToolChain.getSanitizerArgs(Args);
const char *sanitizer = nullptr;
bool NeedsSanitizerDeps = false;
// For now, only support address sanitizer.
if (Sanitize.needsAsanRt())
sanitizer = "AddressSanitizer";

if (sanitizer) {
if (Sanitize.needsSharedRt()) {
ToolChain.getDriver().Diag(diag::err_drv_unsupported_sanitizer)
<< "shared" << sanitizer << "AIX";
return;
}
NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
}

// Add sanitizer runtime dependencies.
// Note: having the static runtime linked into shared libraries can
// lead to multiple copies of the runtime with AIX's linkage model,
// so disallow that.
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
options::OPT_shared, options::OPT_r)) {
if (NeedsSanitizerDeps)
linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs);
}

// We won't add the static sanitizer libraries to the DSO, but we will
// introduce the undefined sanitizer symbols like __asan_init to the DSO. On
// AIX, this undefined sanitizer symbol cannot pass final link. Add the
// import file to make these undefined symbols be resolved at runtime.
if (Args.hasArg(options::OPT_shared) &&
ToolChain.getSanitizerArgs(Args).needsAsanRt()) {
SmallString<128> SanRTSymbolList;
(Twine(ToolChain.getRuntimePath().value_or(".")) +
"/asan.link_with_main_exec.txt")
.toVector(SanRTSymbolList);
if (llvm::sys::fs::exists(SanRTSymbolList))
CmdArgs.push_back(Args.MakeArgString(Twine("-bI:") + SanRTSymbolList));
else
ToolChain.getDriver().Diag(diag::err_drv_missing_sanitizer_file)
<< sanitizer << "import";
if (ToolChain.getSanitizerArgs(Args).linkCXXRuntimes()) {
SanRTSymbolList.clear();
(Twine(ToolChain.getRuntimePath().value_or(".")) +
"/asan_cxx.link_with_main_exec.txt")
.toVector(SanRTSymbolList);
if (llvm::sys::fs::exists(SanRTSymbolList))
CmdArgs.push_back(Args.MakeArgString(Twine("-bI:") + SanRTSymbolList));
else
ToolChain.getDriver().Diag(diag::err_drv_missing_sanitizer_file)
<< sanitizer << "C++ import";
}
}

if (D.isUsingLTO())
addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs,
D.getLTOMode() == LTOK_Thin);
@@ -605,6 +661,12 @@ ToolChain::RuntimeLibType AIX::GetDefaultRuntimeLibType() const {
return ToolChain::RLT_CompilerRT;
}

SanitizerMask AIX::getSupportedSanitizers() const {
SanitizerMask Res = ToolChain::getSupportedSanitizers();
Res |= SanitizerKind::Address;
return Res;
}

auto AIX::buildAssembler() const -> Tool * { return new aix::Assembler(*this); }

auto AIX::buildLinker() const -> Tool * { return new aix::Linker(*this); }
2 changes: 2 additions & 0 deletions clang/lib/Driver/ToolChains/AIX.h
Original file line number Diff line number Diff line change
@@ -98,6 +98,8 @@ class LLVM_LIBRARY_VISIBILITY AIX : public ToolChain {
return llvm::DebuggerKind::DBX;
}

SanitizerMask getSupportedSanitizers() const override;

path_list getArchSpecificLibPaths() const override { return path_list(); };

protected:
47 changes: 40 additions & 7 deletions clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
@@ -1462,6 +1462,19 @@ static bool addSanitizerDynamicList(const ToolChain &TC, const ArgList &Args,
// the option, so don't try to pass it.
if (TC.getTriple().isOSSolaris() && !LinkerIsGnuLd)
return true;

if (TC.getTriple().isOSAIX()) {
SmallString<128> SanRTSymbolList;
(Twine(TC.getRuntimePath().value_or(".")) + "/" + Sanitizer +
".link_with_main_exec.txt")
.toVector(SanRTSymbolList);
if (llvm::sys::fs::exists(SanRTSymbolList)) {
CmdArgs.push_back(Args.MakeArgString(Twine("-bE:") + SanRTSymbolList));
return true;
}
return false;
}

SmallString<128> SanRT(TC.getCompilerRT(Args, Sanitizer));
if (llvm::sys::fs::exists(SanRT + ".syms")) {
CmdArgs.push_back(Args.MakeArgString("--dynamic-list=" + SanRT + ".syms"));
@@ -1496,7 +1509,9 @@ void tools::linkSanitizerRuntimeDeps(const ToolChain &TC,
ArgStringList &CmdArgs) {
// Force linking against the system libraries sanitizers depends on
// (see PR15823 why this is necessary).
addAsNeededOption(TC, Args, CmdArgs, false);
// AIX does not support any --as-needed options.
if (!TC.getTriple().isOSAIX())
addAsNeededOption(TC, Args, CmdArgs, false);
// There's no libpthread or librt on RTEMS & Android.
if (TC.getTriple().getOS() != llvm::Triple::RTEMS &&
!TC.getTriple().isAndroid() && !TC.getTriple().isOHOSFamily()) {
@@ -1523,6 +1538,9 @@ void tools::linkSanitizerRuntimeDeps(const ToolChain &TC,
if (TC.getTriple().isOSLinux() && !TC.getTriple().isAndroid() &&
!TC.getTriple().isMusl())
CmdArgs.push_back("-lresolv");

if (TC.getTriple().isOSAIX())
CmdArgs.push_back("-latomic");
}

static void
@@ -1578,7 +1596,8 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
StaticRuntimes.push_back("stats_client");

// Always link the static runtime regardless of DSO or executable.
if (SanArgs.needsAsanRt())
// Don't see a reason that AIX needs asan_static library though.
if (SanArgs.needsAsanRt() && !TC.getTriple().isOSAIX())
HelperStaticRuntimes.push_back("asan_static");

// Collect static runtimes.
@@ -1711,18 +1730,32 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
for (auto RT : HelperStaticRuntimes)
addSanitizerRuntime(TC, Args, CmdArgs, RT, false, true);
bool AddExportDynamic = false;
StringRef RTNeedsExport;
for (auto RT : StaticRuntimes) {
addSanitizerRuntime(TC, Args, CmdArgs, RT, false, true);
AddExportDynamic |= !addSanitizerDynamicList(TC, Args, CmdArgs, RT);
// AIX does not support --whole-archive.
addSanitizerRuntime(TC, Args, CmdArgs, RT, false,
!TC.getTriple().isOSAIX());
if (!addSanitizerDynamicList(TC, Args, CmdArgs, RT)) {
AddExportDynamic = true;
RTNeedsExport = RT;
}
}
for (auto RT : NonWholeStaticRuntimes) {
addSanitizerRuntime(TC, Args, CmdArgs, RT, false, false);
AddExportDynamic |= !addSanitizerDynamicList(TC, Args, CmdArgs, RT);
if (!addSanitizerDynamicList(TC, Args, CmdArgs, RT)) {
AddExportDynamic = true;
RTNeedsExport = RT;
}
}
// If there is a static runtime with no dynamic list, force all the symbols
// to be dynamic to be sure we export sanitizer interface functions.
if (AddExportDynamic)
CmdArgs.push_back("--export-dynamic");
if (AddExportDynamic) {
if (!TC.getTriple().isOSAIX())
CmdArgs.push_back("--export-dynamic");
else
TC.getDriver().Diag(diag::err_drv_missing_sanitizer_file)
<< RTNeedsExport << "export";
}

if (SanArgs.hasCrossDsoCfi() && !AddExportDynamic)
CmdArgs.push_back("--export-dynamic-symbol=__cfi_check");
4 changes: 2 additions & 2 deletions clang/lib/Driver/ToolChains/Darwin.cpp
Original file line number Diff line number Diff line change
@@ -1569,8 +1569,8 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
sanitizer = "ThreadSanitizer";
}
if (sanitizer) {
getDriver().Diag(diag::err_drv_unsupported_static_sanitizer_darwin)
<< sanitizer;
getDriver().Diag(diag::err_drv_unsupported_sanitizer)
<< "static" << sanitizer << "darwin";
return;
}
}
125 changes: 125 additions & 0 deletions clang/test/Driver/sanitizer-ld.c
Original file line number Diff line number Diff line change
@@ -1370,6 +1370,131 @@
// CHECK-DSO-SHARED-HWASAN-AARCH64-LINUX-NOT: "--export-dynamic"
// CHECK-DSO-SHARED-HWASAN-AARCH64-LINUX-NOT: "--dynamic-list"

// RUN: %clang -fsanitize=address -### %s 2>&1 \
// RUN: --target=powerpc-ibm-aix \
// RUN: -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir \
// RUN: --sysroot=%S/Inputs/aix_ppc_tree \
// RUN: | FileCheck --check-prefixes=CHECK-ASAN-LINK-RUNTIME-AIX,CHECK-ASAN-LINK-RUNTIME-AIX32 %s
//
// RUN: %clang -fsanitize=address -### %s 2>&1 \
// RUN: --target=powerpc64-ibm-aix \
// RUN: -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir \
// RUN: --sysroot=%S/Inputs/aix_ppc_tree \
// RUN: | FileCheck --check-prefixes=CHECK-ASAN-LINK-RUNTIME-AIX,CHECK-ASAN-LINK-RUNTIME-AIX64 %s
//
// RUN: %clang --driver-mode=g++ -fsanitize=address -### %s 2>&1 \
// RUN: --target=powerpc-ibm-aix \
// RUN: -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir \
// RUN: --sysroot=%S/Inputs/aix_ppc_tree \
// RUN: | FileCheck --check-prefixes=CHECK-ASAN-LINK-RUNTIME-AIX,CHECK-ASAN-LINK-RUNTIME-AIX32,CHECK-ASAN-LINK-RUNTIME-AIXCXX32,CHECK-ASAN-LINK-RUNTIME-AIXCXX %s
//
// RUN: %clang --driver-mode=g++ -fsanitize=address -### %s 2>&1 \
// RUN: --target=powerpc64-ibm-aix \
// RUN: -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir \
// RUN: --sysroot=%S/Inputs/aix_ppc_tree \
// RUN: | FileCheck --check-prefixes=CHECK-ASAN-LINK-RUNTIME-AIX,CHECK-ASAN-LINK-RUNTIME-AIX64,CHECK-ASAN-LINK-RUNTIME-AIXCXX64,CHECK-ASAN-LINK-RUNTIME-AIXCXX %s
//
// RUN: %clang -fsanitize=address -### %s 2>&1 \
// RUN: -static-libsan --target=powerpc-ibm-aix \
// RUN: -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir \
// RUN: --sysroot=%S/Inputs/aix_ppc_tree \
// RUN: | FileCheck --check-prefixes=CHECK-ASAN-LINK-RUNTIME-AIX,CHECK-ASAN-LINK-RUNTIME-AIX32 %s
//
// RUN: %clang -fsanitize=address -### %s 2>&1 \
// RUN: -static-libsan --target=powerpc64-ibm-aix \
// RUN: -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir \
// RUN: --sysroot=%S/Inputs/aix_ppc_tree \
// RUN: | FileCheck --check-prefixes=CHECK-ASAN-LINK-RUNTIME-AIX,CHECK-ASAN-LINK-RUNTIME-AIX64 %s
//
// CHECK-ASAN-LINK-RUNTIME-AIX: "{{.*}}ld{{(.exe)?}}"
// CHECK-ASAN-LINK-RUNTIME-AIX32: "-b32"
// CHECK-ASAN-LINK-RUNTIME-AIX64: "-b64"
// CHECK-ASAN-LINK-RUNTIME-AIX: "-bcdtors:all:0:s"
// CHECK-ASAN-LINK-RUNTIME-AIX32: "{{.*}}libclang_rt.asan.a"
// CHECK-ASAN-LINK-RUNTIME-AIX64: "{{.*}}libclang_rt.asan.a"
// CHECK-ASAN-LINK-RUNTIME-AIX: "-bE:{{.*}}asan.link_with_main_exec.txt"
// CHECK-ASAN-LINK-RUNTIME-AIXCXX32: "{{.*}}libclang_rt.asan_cxx.a"
// CHECK-ASAN-LINK-RUNTIME-AIXCXX64: "{{.*}}libclang_rt.asan_cxx.a"
// CHECK-ASAN-LINK-RUNTIME-AIXCXX: "-bE:{{.*}}asan_cxx.link_with_main_exec.txt"
// CHECK-ASAN-LINK-RUNTIME-AIX: "-lpthread"
// CHECK-ASAN-LINK-RUNTIME-AIX: "-latomic"
// CHECK-ASAN-LINK-RUNTIME-AIX: "-lunwind"
// CHECK-ASAN-LINK-RUNTIME-AIX: "-lc"

// RUN: not %clang -fsanitize=address -### %s 2>&1 \
// RUN: -shared-libsan --target=powerpc-ibm-aix \
// RUN: -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir \
// RUN: --sysroot=%S/Inputs/aix_ppc_tree \
// RUN: | FileCheck --check-prefixes=CHECK-SHARED-ASAN-AIX %s
//
// RUN: not %clang -fsanitize=address -### %s 2>&1 \
// RUN: -shared-libsan --target=powerpc64-ibm-aix \
// RUN: -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir \
// RUN: --sysroot=%S/Inputs/aix_ppc_tree \
// RUN: | FileCheck --check-prefixes=CHECK-SHARED-ASAN-AIX %s
//
// CHECK-SHARED-ASAN-AIX: {{.*}}error: shared AddressSanitizer runtime is not supported on AIX

// RUN: not %clang -fsanitize=address -### %s 2>&1 \
// RUN: --target=powerpc-ibm-aix \
// RUN: -resource-dir=/missing_resource_dir \
// RUN: --sysroot=%S/Inputs/aix_ppc_tree \
// RUN: | FileCheck --check-prefixes=CHECK-MISSING-EXPORT-AIX %s
// CHECK-MISSING-EXPORT-AIX: {{.*}}error: cannot link 'asan': export file missing from resource directories

// RUN: not %clang -fsanitize=address -### %s 2>&1 \
// RUN: -shared --target=powerpc-ibm-aix \
// RUN: -resource-dir=/missing_resource_dir \
// RUN: --sysroot=%S/Inputs/aix_ppc_tree \
// RUN: | FileCheck --check-prefixes=CHECK-MISSING-IMPORT-AIX %s
// CHECK-MISSING-IMPORT-AIX: {{.*}}error: cannot link 'AddressSanitizer': import file missing from resource directories

// RUN: not %clang -fsanitize=address --driver-mode=g++ -### %s 2>&1 \
// RUN: -shared --target=powerpc-ibm-aix \
// RUN: -resource-dir=/missing_resource_dir \
// RUN: --sysroot=%S/Inputs/aix_ppc_tree \
// RUN: | FileCheck --check-prefixes=CHECK-MISSING-CXX-IMPORT-AIX %s
// CHECK-MISSING-CXX-IMPORT-AIX: {{.*}}error: cannot link 'AddressSanitizer': C++ import file
// missing from resource directories

// RUN: %clang -fsanitize=address -shared -### %s 2>&1 \
// RUN: --target=powerpc-ibm-aix \
// RUN: -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir \
// RUN: --sysroot=%S/Inputs/aix_ppc_tree \
// RUN: | FileCheck --check-prefixes=CHECK-ASAN-SHARED-LIBRARY-AIX,CHECK-ASAN-SHARED-LIBRARY-AIX32 %s
//
// RUN: %clang -fsanitize=address -shared -### %s 2>&1 \
// RUN: --target=powerpc64-ibm-aix \
// RUN: -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir \
// RUN: --sysroot=%S/Inputs/aix_ppc_tree \
// RUN: | FileCheck --check-prefixes=CHECK-ASAN-SHARED-LIBRARY-AIX,CHECK-ASAN-SHARED-LIBRARY-AIX64 %s
//
// RUN: %clang -fsanitize=address --driver-mode=g++ -shared -### %s 2>&1 \
// RUN: --target=powerpc-ibm-aix \
// RUN: -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir \
// RUN: --sysroot=%S/Inputs/aix_ppc_tree \
// RUN: | FileCheck --check-prefixes=CHECK-ASAN-SHARED-LIBRARY-AIX,CHECK-ASAN-SHARED-LIBRARY-AIX32,CHECK-ASAN-SHARED-LIBRARY-AIXCXX %s
//
// RUN: %clang -fsanitize=address --driver-mode=g++ -shared -### %s 2>&1 \
// RUN: --target=powerpc64-ibm-aix \
// RUN: -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir \
// RUN: --sysroot=%S/Inputs/aix_ppc_tree \
// RUN: | FileCheck --check-prefixes=CHECK-ASAN-SHARED-LIBRARY-AIX,CHECK-ASAN-SHARED-LIBRARY-AIX64,CHECK-ASAN-SHARED-LIBRARY-AIXCXX %s
//
// CHECK-ASAN-SHARED-LIBRARY-AIX: "{{.*}}ld{{(.exe)?}}"
// CHECK-ASAN-SHARED-LIBRARY-AIX32: "-b32"
// CHECK-ASAN-SHARED-LIBRARY-AIX64: "-b64"
// CHECK-ASAN-SHARED-LIBRARY-AIX: "-bcdtors:all:0:s"
// CHECK-ASAN-SHARED-LIBRARY-AIX: "-bI:{{.*}}asan.link_with_main_exec.txt"
// CHECK-ASAN-SHARED-LIBRARY-AIXCXX: "-bI:{{.*}}asan_cxx.link_with_main_exec.txt"
// CHECK-ASAN-SHARED-LIBRARY-AIX32-NOT: "{{.*}}libclang_rt.asan.a"
// CHECK-ASAN-SHARED-LIBRARY-AIX64-NOT: "{{.*}}libclang_rt.asan.a"
// CHECK-ASAN-SHARED-LIBRARY-AIXCXX-NOT: "{{.*}}libclang_rt.asan_cxx.a"
// CHECK-ASAN-SHARED-LIBRARY-AIX-NOT: "-lpthread"
// CHECK-ASAN-SHARED-LIBRARY-AIX-NOT: "-latomic"
// CHECK-ASAN-SHARED-LIBRARY-AIX: "-lunwind"
// CHECK-ASAN-SHARED-LIBRARY-AIX: "-lc"

// RUN: %clang -fsanitize=address,undefined -r -### %s 2>&1 \
// RUN: --target=x86_64-unknown-linux -fuse-ld=ld \
// RUN: -resource-dir=%S/Inputs/resource_dir \