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 14 commits into
base: main
Choose a base branch
from
4 changes: 2 additions & 2 deletions clang/include/clang/Basic/DiagnosticDriverKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,8 @@ 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_duplicate_config : Error<
"no more than one option '--config' is allowed">;
def err_drv_cannot_open_config_file : Error<
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -1571,7 +1571,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>;
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/CodeGen/BackendUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,13 +285,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;
}
Expand Down
60 changes: 60 additions & 0 deletions clang/lib/Driver/ToolChains/AIX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,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;
Expand Down Expand Up @@ -259,6 +260,59 @@ 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
llvm::report_fatal_error("Missing address sanitizer import list.");
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
llvm::report_fatal_error("Missing address sanitizer c++ import list.");
}
}

if (D.isUsingLTO())
addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs,
D.getLTOMode() == LTOK_Thin);
Expand Down Expand Up @@ -606,6 +660,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
Expand Up @@ -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:
Expand Down
36 changes: 31 additions & 5 deletions clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1376,6 +1376,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()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a review comment, but a question for my own understanding. Why are these exports needed? (I see we are forcing the same on ELF platforms)

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));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto comment about missing lists.

I guess we can't use exactly the same list as --dynamic-list= because format is slightly different, but I'm guessing we can generate it in a similar fashion.

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"));
Expand Down Expand Up @@ -1410,7 +1423,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()) {
Expand All @@ -1437,6 +1452,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
Expand Down Expand Up @@ -1492,7 +1510,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.
Expand Down Expand Up @@ -1626,7 +1645,9 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
addSanitizerRuntime(TC, Args, CmdArgs, RT, false, true);
bool AddExportDynamic = false;
for (auto RT : StaticRuntimes) {
addSanitizerRuntime(TC, Args, CmdArgs, RT, false, true);
// AIX does not support --whole-archive.
addSanitizerRuntime(TC, Args, CmdArgs, RT, false,
!TC.getTriple().isOSAIX());
AddExportDynamic |= !addSanitizerDynamicList(TC, Args, CmdArgs, RT);
}
for (auto RT : NonWholeStaticRuntimes) {
Expand All @@ -1635,8 +1656,13 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
}
// 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
llvm::report_fatal_error("Sanitizer interface functions must be exported "
"by export files on AIX.");
}

if (SanArgs.hasCrossDsoCfi() && !AddExportDynamic)
CmdArgs.push_back("--export-dynamic-symbol=__cfi_check");
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Driver/ToolChains/Darwin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1572,8 +1572,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;
}
}
Expand Down
104 changes: 104 additions & 0 deletions clang/test/Driver/sanitizer-ld.c
Original file line number Diff line number Diff line change
Expand Up @@ -1369,3 +1369,107 @@
// CHECK-DSO-SHARED-HWASAN-AARCH64-LINUX-NOT: "-lresolv"
// 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: %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"

Loading