Skip to content

Commit ba022bb

Browse files
author
George Karpenkov
committed
Determine whether a given sanitizer is available based on the presence of the library.
rdar://37192887
1 parent 9cc534a commit ba022bb

17 files changed

+53
-44
lines changed

include/swift/Driver/ToolChain.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,10 @@ class ToolChain {
199199
///
200200
/// \param args Invocation arguments.
201201
/// \param sanitizer Sanitizer name.
202+
/// \param shared Whether the library is shared
202203
virtual bool sanitizerRuntimeLibExists(const llvm::opt::ArgList &args,
203-
StringRef sanitizer) const;
204+
StringRef sanitizer,
205+
bool shared=true) const;
204206

205207
};
206208
} // end namespace driver

include/swift/Option/SanitizerOptions.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,9 @@ class DiagnosticEngine;
3232
// sanitizer dylib with a given name.
3333
/// \return Returns a SanitizerKind.
3434
OptionSet<SanitizerKind> parseSanitizerArgValues(
35-
const llvm::opt::ArgList &Args,
36-
const llvm::opt::Arg *A,
37-
const llvm::Triple &Triple,
38-
DiagnosticEngine &Diag,
39-
llvm::function_ref<bool(llvm::StringRef)> sanitizerRuntimeLibExists);
35+
const llvm::opt::ArgList &Args, const llvm::opt::Arg *A,
36+
const llvm::Triple &Triple, DiagnosticEngine &Diag,
37+
llvm::function_ref<bool(llvm::StringRef, bool)> sanitizerRuntimeLibExists);
4038

4139
/// \brief Parses a -sanitize-coverage= argument's value.
4240
llvm::SanitizerCoverageOptions parseSanitizerCoverageArgValue(

lib/Driver/Driver.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,8 +1356,8 @@ void Driver::buildOutputInfo(const ToolChain &TC, const DerivedArgList &Args,
13561356
if (const Arg *A = Args.getLastArg(options::OPT_sanitize_EQ))
13571357
OI.SelectedSanitizers = parseSanitizerArgValues(
13581358
Args, A, TC.getTriple(), Diags,
1359-
[&](StringRef sanitizerName) {
1360-
return TC.sanitizerRuntimeLibExists(Args, sanitizerName);
1359+
[&](StringRef sanitizerName, bool shared) {
1360+
return TC.sanitizerRuntimeLibExists(Args, sanitizerName, shared);
13611361
});
13621362

13631363
if (const Arg *A = Args.getLastArg(options::OPT_sanitize_coverage_EQ)) {

lib/Driver/ToolChain.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,8 @@ ToolChain::constructBatchJob(ArrayRef<const Job *> jobs,
317317

318318
bool
319319
ToolChain::sanitizerRuntimeLibExists(const ArgList &args,
320-
StringRef sanitizerName) const {
320+
StringRef sanitizerName,
321+
bool shared) const {
321322
// Assume no sanitizers are supported by default.
322323
// This method should be overriden by a platform-specific subclass.
323324
return false;

lib/Driver/ToolChains.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,18 +1148,21 @@ getSanitizerRuntimeLibNameForLinux(StringRef Sanitizer, const llvm::Triple &Trip
11481148
}
11491149

11501150
bool toolchains::Darwin::sanitizerRuntimeLibExists(
1151-
const ArgList &args, StringRef sanitizer) const {
1151+
const ArgList &args, StringRef sanitizer, bool shared) const {
11521152
SmallString<128> sanitizerLibPath;
11531153
getClangLibraryPath(*this, args, sanitizerLibPath);
11541154
llvm::sys::path::append(sanitizerLibPath,
1155-
getSanitizerRuntimeLibNameForDarwin(sanitizer, this->getTriple()));
1155+
getSanitizerRuntimeLibNameForDarwin(
1156+
sanitizer, this->getTriple(), shared));
11561157
return llvm::sys::fs::exists(sanitizerLibPath.str());
11571158
}
11581159

11591160
bool toolchains::GenericUnix::sanitizerRuntimeLibExists(
1160-
const ArgList &args, StringRef sanitizer) const {
1161+
const ArgList &args, StringRef sanitizer, bool shared) const {
11611162
SmallString<128> sanitizerLibPath;
11621163
getClangLibraryPath(*this, args, sanitizerLibPath);
1164+
1165+
// All libraries are static for linux.
11631166
llvm::sys::path::append(sanitizerLibPath,
11641167
getSanitizerRuntimeLibNameForLinux(sanitizer, this->getTriple()));
11651168
return llvm::sys::fs::exists(sanitizerLibPath.str());
@@ -1800,4 +1803,3 @@ std::string toolchains::Cygwin::getDefaultLinker() const {
18001803
std::string toolchains::Cygwin::getTargetForLinker() const {
18011804
return "";
18021805
}
1803-

lib/Driver/ToolChains.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ class LLVM_LIBRARY_VISIBILITY Darwin : public ToolChain {
3434
Darwin(const Driver &D, const llvm::Triple &Triple) : ToolChain(D, Triple) {}
3535
~Darwin() = default;
3636
bool sanitizerRuntimeLibExists(const llvm::opt::ArgList &args,
37-
StringRef sanitizerLibName)
37+
StringRef sanitizerLibName,
38+
bool shared)
3839
const override;
3940
};
4041

@@ -73,7 +74,8 @@ class LLVM_LIBRARY_VISIBILITY GenericUnix : public ToolChain {
7374
GenericUnix(const Driver &D, const llvm::Triple &Triple) : ToolChain(D, Triple) {}
7475
~GenericUnix() = default;
7576
bool sanitizerRuntimeLibExists(const llvm::opt::ArgList &args,
76-
StringRef sanitizerLibName)
77+
StringRef sanitizerLibName,
78+
bool shared)
7779
const override;
7880
};
7981

lib/Frontend/CompilerInvocation.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,7 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
686686
if (const Arg *A = Args.getLastArg(options::OPT_sanitize_EQ)) {
687687
Opts.Sanitizers = parseSanitizerArgValues(
688688
Args, A, Triple, Diags,
689-
/* sanitizerRuntimeLibExists= */[](StringRef libName) {
689+
/* sanitizerRuntimeLibExists= */[](StringRef libName, bool shared) {
690690

691691
// The driver has checked the existence of the library
692692
// already.

lib/Option/SanitizerOptions.cpp

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,18 @@ static StringRef toStringRef(const SanitizerKind kind) {
4141
llvm_unreachable("Unsupported sanitizer");
4242
}
4343

44+
static const char* toFileName(const SanitizerKind kind) {
45+
switch (kind) {
46+
case SanitizerKind::Address:
47+
return "asan";
48+
case SanitizerKind::Thread:
49+
return "tsan";
50+
case SanitizerKind::Fuzzer:
51+
return "fuzzer";
52+
}
53+
llvm_unreachable("Unsupported sanitizer");
54+
}
55+
4456
llvm::SanitizerCoverageOptions swift::parseSanitizerCoverageArgValue(
4557
const llvm::opt::Arg *A, const llvm::Triple &Triple,
4658
DiagnosticEngine &Diags, OptionSet<SanitizerKind> sanitizers) {
@@ -108,33 +120,34 @@ llvm::SanitizerCoverageOptions swift::parseSanitizerCoverageArgValue(
108120
return opts;
109121
}
110122

111-
static bool isTSanSupported(
112-
const llvm::Triple &Triple,
113-
llvm::function_ref<bool(llvm::StringRef)> sanitizerRuntimeLibExists) {
114-
115-
return Triple.isArch64Bit() && sanitizerRuntimeLibExists("tsan");
116-
}
117-
118123
OptionSet<SanitizerKind> swift::parseSanitizerArgValues(
119124
const llvm::opt::ArgList &Args,
120125
const llvm::opt::Arg *A,
121126
const llvm::Triple &Triple,
122127
DiagnosticEngine &Diags,
123-
llvm::function_ref<bool(llvm::StringRef)> sanitizerRuntimeLibExists) {
128+
llvm::function_ref<bool(llvm::StringRef, bool)> sanitizerRuntimeLibExists) {
124129
OptionSet<SanitizerKind> sanitizerSet;
125130

126131
// Find the sanitizer kind.
127132
for (int i = 0, n = A->getNumValues(); i != n; ++i) {
128-
StringRef opt = A->getValue(i);
129-
if (opt == "address") {
130-
sanitizerSet |= SanitizerKind::Address;
131-
} else if (opt == "thread") {
132-
sanitizerSet |= SanitizerKind::Thread;
133-
} else if (opt == "fuzzer") {
134-
sanitizerSet |= SanitizerKind::Fuzzer;
135-
} else {
133+
auto kind = llvm::StringSwitch<Optional<SanitizerKind>>(A->getValue(i))
134+
.Case("address", SanitizerKind::Address)
135+
.Case("thread", SanitizerKind::Thread)
136+
.Case("fuzzer", SanitizerKind::Fuzzer)
137+
.Default(None);
138+
bool isShared = kind && *kind != SanitizerKind::Fuzzer;
139+
if (!kind) {
136140
Diags.diagnose(SourceLoc(), diag::error_unsupported_option_argument,
137141
A->getOption().getPrefixedName(), A->getValue(i));
142+
} else if (sanitizerRuntimeLibExists(toFileName(*kind), isShared)
143+
&& (*kind != SanitizerKind::Thread || Triple.isArch64Bit())) {
144+
sanitizerSet |= *kind;
145+
} else {
146+
SmallString<128> b;
147+
Diags.diagnose(SourceLoc(), diag::error_unsupported_opt_for_target,
148+
(A->getOption().getPrefixedName() + toStringRef(*kind))
149+
.toStringRef(b),
150+
Triple.getTriple());
138151
}
139152
}
140153

@@ -159,16 +172,5 @@ OptionSet<SanitizerKind> swift::parseSanitizerArgValues(
159172
+ toStringRef(SanitizerKind::Thread)).toStringRef(b2));
160173
}
161174

162-
// Thread Sanitizer only works on OS X and the simulators. It's only supported
163-
// on 64 bit architectures.
164-
if ((sanitizerSet & SanitizerKind::Thread) &&
165-
!isTSanSupported(Triple, sanitizerRuntimeLibExists)) {
166-
SmallString<128> b;
167-
Diags.diagnose(SourceLoc(), diag::error_unsupported_opt_for_target,
168-
(A->getOption().getPrefixedName()
169-
+ toStringRef(SanitizerKind::Thread)).toStringRef(b),
170-
Triple.getTriple());
171-
}
172-
173175
return sanitizerSet;
174176
}

test/Driver/Inputs/fake-resource-dir/lib/swift/clang/lib/darwin/libclang_rt.asan_ios_dynamic.dylib

Whitespace-only changes.

test/Driver/Inputs/fake-resource-dir/lib/swift/clang/lib/darwin/libclang_rt.asan_iossim_dynamic.dylib

Whitespace-only changes.

test/Driver/Inputs/fake-resource-dir/lib/swift/clang/lib/darwin/libclang_rt.asan_tvos_dynamic.dylib

Whitespace-only changes.

test/Driver/Inputs/fake-resource-dir/lib/swift/clang/lib/darwin/libclang_rt.asan_tvossim_dynamic.dylib

Whitespace-only changes.

test/Driver/Inputs/fake-resource-dir/lib/swift/clang/lib/darwin/libclang_rt.asan_watchos_dynamic.dylib

Whitespace-only changes.

test/Driver/Inputs/fake-resource-dir/lib/swift/clang/lib/darwin/libclang_rt.asan_watchossim_dynamic.dylib

Whitespace-only changes.

test/Driver/Inputs/fake-resource-dir/lib/swift/clang/lib/darwin/libclang_rt.fuzzer_osx.a

Whitespace-only changes.

test/Driver/fuzzer.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %swiftc_driver -driver-print-jobs -sanitize=fuzzer,address %s | %FileCheck -check-prefix=LIBFUZZER %s
1+
// RUN: %swiftc_driver -driver-print-jobs -sanitize=fuzzer,address -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ %s | %FileCheck -check-prefix=LIBFUZZER %s
22

33
// LIBFUZZER: libclang_rt.fuzzer
44
@_cdecl("LLVMFuzzerTestOneInput") public func fuzzOneInput(Data: UnsafePointer<CChar>, Size: CLong) -> CInt {

test/Driver/sanitizers.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=address -target x86_64-apple-macosx10.9 %s | %FileCheck -check-prefix=ASAN -check-prefix=ASAN_OSX %s
2+
// RUN: not %swiftc_driver -driver-print-jobs -sanitize=fuzzer -target x86_64-apple-macosx10.9 -resource-dir %S/Inputs/nonexistent-resource-dir %s 2>&1 | %FileCheck -check-prefix=FUZZER_NONEXISTENT %s
23
// RUN: %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=address -target x86_64-apple-ios7.1 %s | %FileCheck -check-prefix=ASAN -check-prefix=ASAN_IOSSIM %s
34
// RUN: %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=address -target arm64-apple-ios7.1 %s | %FileCheck -check-prefix=ASAN -check-prefix=ASAN_IOS %s
45
// RUN: %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=address -target x86_64-apple-tvos9.0 %s | %FileCheck -check-prefix=ASAN -check-prefix=ASAN_tvOS_SIM %s
@@ -54,6 +55,7 @@
5455
// TSAN_tvOS: unsupported option '-sanitize=thread' for target 'arm64-apple-tvos9.0'
5556
// TSAN_watchOS_SIM: unsupported option '-sanitize=thread' for target 'i386-apple-watchos2.0'
5657
// TSAN_watchOS: unsupported option '-sanitize=thread' for target 'armv7k-apple-watchos2.0'
58+
// FUZZER_NONEXISTENT: unsupported option '-sanitize=fuzzer' for target 'x86_64-apple-macosx10.9'
5759
// TSAN_LINUX: lib/swift/clang/lib/linux/libclang_rt.tsan-x86_64.a
5860

5961
// TSAN: -rpath @executable_path

0 commit comments

Comments
 (0)