Skip to content

Commit 9208b52

Browse files
committed
Disable "UseOdrIndicator" ASan instrumentation mode by default.
Previously Swift enabled the "UseOdrIndicator" ASan instrumentation mode and gave no option to disable this. This probably wasn't intentional but happened due to the fact the `createModuleAddressSanitizerLegacyPassPass()` function has a default value for the `UseOdrIndicator` parameter of `true` and in Swift we never specified this parameter explicitly. Clang disables the "UseOdrIndicator" mode by default but allows it to be enabled using the `-fsanitize-address-use-odr-indicator` flag. Having "UseOdrIndicator" off by default is probably the right default choice because it bloats the binary. So this patch changes the Swift compiler to match Clang's behavior. This patch disables the "UseOdrIndicator" mode by default but adds a hidden driver and frontend flag (`-sanitize-address-use-odr-indicator`) to enable it. The flag is hidden so that we can remove it in the future if needed. A side effect of disabling "UseOdrIndicator" is that by we will no longer use private aliases for poisoning globals. Private aliases were introduced to avoid crashes (google/sanitizers#398) due to ODR violations with non-instrumented binaries. On Apple platforms the use of two-level namespaces probably means that using private aliases wasn't ever really necessary to avoid crashes. On platforms with a flat linking namespace (e.g. Linux) using private aliases might matter more but should users actually run into problems they can either: * Fix their environment to remove the ODR, thus avoiding the crash. * Instrument the previously non-instrumented code to avoid the crash. * Use the new `-sanitize-address-use-odr-indicator` flag rdar://problem/69335186
1 parent 08d9680 commit 9208b52

10 files changed

+81
-2
lines changed

include/swift/AST/IRGenOptions.h

+4
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,9 @@ class IRGenOptions {
190190
/// Which sanitizer(s) have recovery instrumentation enabled.
191191
OptionSet<SanitizerKind> SanitizersWithRecoveryInstrumentation;
192192

193+
/// Whether to enable ODR indicators when building with ASan.
194+
unsigned SanitizeAddressUseODRIndicator : 1;
195+
193196
/// Path prefixes that should be rewritten in debug info.
194197
PathRemapper DebugPrefixMap;
195198

@@ -345,6 +348,7 @@ class IRGenOptions {
345348
Verify(true), OptMode(OptimizationMode::NotSet),
346349
Sanitizers(OptionSet<SanitizerKind>()),
347350
SanitizersWithRecoveryInstrumentation(OptionSet<SanitizerKind>()),
351+
SanitizeAddressUseODRIndicator(false),
348352
DebugInfoLevel(IRGenDebugInfoLevel::None),
349353
DebugInfoFormat(IRGenDebugInfoFormat::None),
350354
DisableClangModuleSkeletonCUs(false), UseJIT(false),

include/swift/Option/Options.td

+7
Original file line numberDiff line numberDiff line change
@@ -1104,6 +1104,13 @@ def sanitize_recover_EQ
11041104
"checks should be comma separated. Default behavior is to not "
11051105
"allow error recovery.">;
11061106

1107+
def sanitize_address_use_odr_indicator
1108+
: Flag<["-"], "sanitize-address-use-odr-indicator">,
1109+
Flags<[FrontendOption, NoInteractiveOption, HelpHidden]>,
1110+
HelpText<"When using AddressSanitizer enable ODR indicator globals to "
1111+
"avoid false ODR violation reports in partially sanitized "
1112+
"programs at the cost of an increase in binary size">;
1113+
11071114
def sanitize_coverage_EQ : CommaJoined<["-"], "sanitize-coverage=">,
11081115
Flags<[FrontendOption, NoInteractiveOption]>,
11091116
MetaVarName<"<type>">,

include/swift/Option/SanitizerOptions.h

+5
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ llvm::SanitizerCoverageOptions parseSanitizerCoverageArgValue(
4747
DiagnosticEngine &Diag,
4848
OptionSet<SanitizerKind> sanitizers);
4949

50+
/// Parse -sanitize-address-use-odr-indicator's value.
51+
bool parseSanitizerAddressUseODRIndicator(
52+
const llvm::opt::Arg *A, const OptionSet<SanitizerKind> &enabledSanitizers,
53+
DiagnosticEngine &Diags);
54+
5055
/// Returns the active sanitizers as a comma-separated list.
5156
std::string getSanitizerList(const OptionSet<SanitizerKind> &Set);
5257
}

lib/Driver/ToolChains.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,8 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI,
246246
options::OPT_no_warnings_as_errors);
247247
inputArgs.AddLastArg(arguments, options::OPT_sanitize_EQ);
248248
inputArgs.AddLastArg(arguments, options::OPT_sanitize_recover_EQ);
249+
inputArgs.AddLastArg(arguments,
250+
options::OPT_sanitize_address_use_odr_indicator);
249251
inputArgs.AddLastArg(arguments, options::OPT_sanitize_coverage_EQ);
250252
inputArgs.AddLastArg(arguments, options::OPT_static);
251253
inputArgs.AddLastArg(arguments, options::OPT_swift_version);

lib/Frontend/CompilerInvocation.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -1228,6 +1228,12 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
12281228
/*emitWarnings=*/true);
12291229
}
12301230

1231+
if (const Arg *A =
1232+
Args.getLastArg(options::OPT_sanitize_address_use_odr_indicator)) {
1233+
IRGenOpts.SanitizeAddressUseODRIndicator =
1234+
parseSanitizerAddressUseODRIndicator(A, Opts.Sanitizers, Diags);
1235+
}
1236+
12311237
if (auto A = Args.getLastArg(OPT_enable_verify_exclusivity,
12321238
OPT_disable_verify_exclusivity)) {
12331239
Opts.VerifyExclusivity

lib/IRGen/IRGen.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,11 @@ static void addAddressSanitizerPasses(const PassManagerBuilder &Builder,
134134
auto recover =
135135
bool(BuilderWrapper.IRGOpts.SanitizersWithRecoveryInstrumentation &
136136
SanitizerKind::Address);
137+
auto useODRIndicator = BuilderWrapper.IRGOpts.SanitizeAddressUseODRIndicator;
137138
PM.add(createAddressSanitizerFunctionPass(/*CompileKernel=*/false, recover));
138-
PM.add(createModuleAddressSanitizerLegacyPassPass(/*CompileKernel=*/false,
139-
recover));
139+
PM.add(createModuleAddressSanitizerLegacyPassPass(
140+
/*CompileKernel=*/false, recover, /*UseGlobalsGC=*/true,
141+
useODRIndicator));
140142
}
141143

142144
static void addThreadSanitizerPass(const PassManagerBuilder &Builder,

lib/Option/SanitizerOptions.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,22 @@ OptionSet<SanitizerKind> swift::parseSanitizerRecoverArgValues(
258258
return sanitizerRecoverSet;
259259
}
260260

261+
// Note this implementation cannot be inlined at its use site because it calls
262+
// `toStringRef(const SanitizerKind).`
263+
bool swift::parseSanitizerAddressUseODRIndicator(
264+
const llvm::opt::Arg *A, const OptionSet<SanitizerKind> &enabledSanitizers,
265+
DiagnosticEngine &Diags) {
266+
// Warn if ASan isn't enabled.
267+
if (!(enabledSanitizers & SanitizerKind::Address)) {
268+
Diags.diagnose(
269+
SourceLoc(), diag::warning_option_requires_specific_sanitizer,
270+
A->getOption().getPrefixedName(), toStringRef(SanitizerKind::Address));
271+
return false;
272+
}
273+
274+
return true;
275+
}
276+
261277
std::string swift::getSanitizerList(const OptionSet<SanitizerKind> &Set) {
262278
std::string list;
263279
#define SANITIZER(_, kind, name, file) \
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// REQUIRES: asan_runtime
2+
// RUN: %swiftc_driver -driver-print-jobs -sanitize=address -sanitize-address-use-odr-indicator %s 2>&1 | %FileCheck %s
3+
4+
// CHECK: swift
5+
// CHECK-DAG: -sanitize=address
6+
// CHECK-DAG: -sanitize-address-use-odr-indicator
7+
8+
// Missing `-sanitize=address` causes warning to be emitted
9+
// RUN: %swiftc_driver -sanitize-address-use-odr-indicator \
10+
// RUN: %s -o %t 2>&1 | %FileCheck -check-prefix=CHECK-MISSING-ARG %s
11+
// CHECK-MISSING-ARG: warning: option '-sanitize-address-use-odr-indicator' has no effect when 'address' sanitizer is disabled. Use -sanitize=address to enable the sanitizer
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// REQUIRES: asan_runtime
2+
3+
// Default instrumentation that does not use ODR indicators
4+
// and private aliases.
5+
// RUN: %target-swift-frontend -emit-ir -sanitize=address %s | %FileCheck %s
6+
// CHECK: @"[[MANGLED_GLOBAL:.+aGlobal.+]]" =
7+
// CHECK-NOT: __odr_asan_gen_[[MANGLED_GLOBAL]]
8+
// CHECK-NOT: @{{.+}} = private alias {{.*}}@"[[MANGLED_GLOBAL]]"
9+
10+
// Instrumentation with ODR indicators (implies private aliases)
11+
// RUN: %target-swift-frontend -emit-ir -sanitize=address \
12+
// RUN: -sanitize-address-use-odr-indicator %s | \
13+
// RUN: %FileCheck -check-prefix=CHECK-ODR %s
14+
// CHECK-ODR: @"[[MANGLED_GLOBAL:.+aGlobal.+]]" =
15+
// CHECK-ODR: __odr_asan_gen_[[MANGLED_GLOBAL]]
16+
// CHECK-ODR: @{{.+}} = private alias {{.*}}@"[[MANGLED_GLOBAL]]"
17+
18+
let aGlobal:Int = 128;

test/Sanitizers/asan.swift

+8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
// RUN: %target-swiftc_driver %s -target %sanitizers-target-triple -g -sanitize=address -o %t_asan-binary
22
// RUN: %target-codesign %t_asan-binary
33
// RUN: env %env-ASAN_OPTIONS=abort_on_error=0 not %target-run %t_asan-binary 2>&1 | %FileCheck %s
4+
5+
// ODR Indicator variant
6+
// RUN: %target-swiftc_driver %s -target %sanitizers-target-triple -g -sanitize=address \
7+
// RUN: -sanitize-address-use-odr-indicator -o %t_asan-binary-odr-indicator
8+
// RUN: %target-codesign %t_asan-binary-odr-indicator
9+
// RUN: env %env-ASAN_OPTIONS=abort_on_error=0 not %target-run \
10+
// RUN: %t_asan-binary-odr-indicator 2>&1 | %FileCheck %s
11+
412
// REQUIRES: executable_test
513
// REQUIRES: asan_runtime
614

0 commit comments

Comments
 (0)