Skip to content

Commit 777d4fa

Browse files
committed
Add scudo sanitizer support
Add support for Scudo sanitizer. Fixes #866
1 parent c8d474c commit 777d4fa

File tree

6 files changed

+213
-8
lines changed

6 files changed

+213
-8
lines changed

Sources/SWBCore/Settings/BuiltinMacros.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,7 @@ public final class BuiltinMacros {
408408
public static let ENABLE_THREAD_SANITIZER = BuiltinMacros.declareBooleanMacro("ENABLE_THREAD_SANITIZER")
409409
public static let ENABLE_UNDEFINED_BEHAVIOR_SANITIZER = BuiltinMacros.declareBooleanMacro("ENABLE_UNDEFINED_BEHAVIOR_SANITIZER")
410410
public static let ENABLE_MEMORY_TAGGING_ADDRESS_SANITIZER = BuiltinMacros.declareBooleanMacro("ENABLE_MEMORY_TAGGING_ADDRESS_SANITIZER")
411+
public static let ENABLE_SCUDO_SANITIZER = BuiltinMacros.declareBooleanMacro("ENABLE_SCUDO_SANITIZER")
411412
public static let ENABLE_SYSTEM_SANITIZERS = BuiltinMacros.declareBooleanMacro("ENABLE_SYSTEM_SANITIZERS")
412413

413414
// MARK: Unit testing macros
@@ -1789,6 +1790,7 @@ public final class BuiltinMacros {
17891790
ENABLE_PRIVATE_TESTING_SEARCH_PATHS,
17901791
ENABLE_THREAD_SANITIZER,
17911792
ENABLE_UNDEFINED_BEHAVIOR_SANITIZER,
1793+
ENABLE_SCUDO_SANITIZER,
17921794
ENABLE_MEMORY_TAGGING_ADDRESS_SANITIZER,
17931795
DISABLE_TASK_SANDBOXING,
17941796
ENABLE_USER_SCRIPT_SANDBOXING,

Sources/SWBCore/Settings/Settings.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4703,7 +4703,11 @@ private class SettingsBuilder: ProjectMatchLookup {
47034703
}
47044704

47054705
// If any sanitizer is enabled, and this product type has a runpath to its Frameworks directory defined, then we want to add that path to the runpath search path if it's not already present.
4706-
if scope.evaluate(BuiltinMacros.ENABLE_ADDRESS_SANITIZER) || scope.evaluate(BuiltinMacros.ENABLE_THREAD_SANITIZER) || scope.evaluate(BuiltinMacros.ENABLE_UNDEFINED_BEHAVIOR_SANITIZER) || scope.evaluate(BuiltinMacros.ENABLE_MEMORY_TAGGING_ADDRESS_SANITIZER)
4706+
if scope.evaluate(BuiltinMacros.ENABLE_ADDRESS_SANITIZER)
4707+
|| scope.evaluate(BuiltinMacros.ENABLE_THREAD_SANITIZER)
4708+
|| scope.evaluate(BuiltinMacros.ENABLE_UNDEFINED_BEHAVIOR_SANITIZER)
4709+
|| scope.evaluate(BuiltinMacros.ENABLE_MEMORY_TAGGING_ADDRESS_SANITIZER)
4710+
|| scope.evaluate(BuiltinMacros.ENABLE_SCUDO_SANITIZER)
47074711
{
47084712
if let frameworksRunpath = productType?.frameworksRunpathSearchPath(in: scope)?.str {
47094713
if !scope.evaluate(BuiltinMacros.LD_RUNPATH_SEARCH_PATHS).contains(frameworksRunpath) {

Sources/SWBUniversalPlatform/Specs/Clang.xcspec

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2925,6 +2925,26 @@
29252925
};
29262926
},
29272927

2928+
// Scudo sanitizer option
2929+
{
2930+
Name = "CLANG_SCUDO_SANITIZER";
2931+
Type = Boolean;
2932+
DefaultValue = "$(ENABLE_SCUDO_SANITIZER)";
2933+
CommandLineArgs = {
2934+
YES = (
2935+
"-fsanitize=scudo",
2936+
);
2937+
NO = ();
2938+
};
2939+
AdditionalLinkerArgs = {
2940+
YES = (
2941+
"$($(LINKER_DRIVER)_LD_SCUDO_SANITIZER)",
2942+
);
2943+
NO = ();
2944+
};
2945+
// Not visible in the build settings editor
2946+
},
2947+
29282948
// Address Sanitizer options.
29292949
{
29302950
Name = "CLANG_ADDRESS_SANITIZER";

Sources/SWBUniversalPlatform/Specs/Ld.xcspec

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -695,11 +695,58 @@
695695
// Not visible in the build settings editor
696696
},
697697

698+
// Scudo Sanitizer options
699+
{
700+
Name = "LD_SCUDO_SANITIZER";
701+
Type = Boolean;
702+
DefaultValue = "$(ENABLE_SCUDO_SANITIZER)";
703+
},
704+
{
705+
Name = "CLANG_LD_SCUDO_SANITIZER";
706+
Type = Boolean;
707+
DefaultValue = "$(LD_SCUDO_SANITIZER)";
708+
Architectures = (
709+
x86_64,
710+
x86_64h,
711+
aarch64,
712+
arm64,
713+
arm64e,
714+
);
715+
Condition = "$(LINKER_DRIVER) == clang";
716+
CommandLineArgs = {
717+
YES = (
718+
"-fsanitize=scudo",
719+
);
720+
NO = ();
721+
};
722+
// Not visible in the build settings editor
723+
},
724+
{
725+
Name = "SWIFTC_LD_SCUDO_SANITIZER";
726+
Type = Boolean;
727+
DefaultValue = "$(LD_SCUDO_SANITIZER)";
728+
Architectures = (
729+
x86_64,
730+
x86_64h,
731+
aarch64,
732+
arm64,
733+
arm64e,
734+
);
735+
Condition = "$(LINKER_DRIVER) == swiftc";
736+
CommandLineArgs = {
737+
YES = (
738+
"-sanitize=scudo",
739+
);
740+
NO = ();
741+
};
742+
// Not visible in the build settings editor
743+
},
744+
698745
{
699746
Name = "LD_DEBUG_VARIANT";
700747
Type = Boolean;
701748
DefaultValue = YES;
702-
Condition = "$(ENABLE_ADDRESS_SANITIZER) || $(ENABLE_THREAD_SANITIZER) || $(ENABLE_SANITIZER_COVERAGE) || $(ENABLE_UNDEFINED_BEHAVIOR_SANITIZER) || $(ENABLE_MEMORY_TAGGING_ADDRESS_SANITIZER) || $(CLANG_COVERAGE_MAPPING)";
749+
Condition = "$(ENABLE_ADDRESS_SANITIZER) || $(ENABLE_THREAD_SANITIZER) || $(ENABLE_SANITIZER_COVERAGE) || $(ENABLE_UNDEFINED_BEHAVIOR_SANITIZER) || $(ENABLE_SCUDO_SANITIZER) || $(ENABLE_MEMORY_TAGGING_ADDRESS_SANITIZER) || $(CLANG_COVERAGE_MAPPING)";
703750
CommandLineArgs = {
704751
YES = (
705752
"-Xlinker",

Sources/SWBUniversalPlatform/Specs/Swift.xcspec

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,6 +1255,26 @@
12551255
DisplayName = "Reflection Metadata Level";
12561256
},
12571257

1258+
// Address sanitizer options
1259+
{
1260+
Name = "SWIFT_SCUDO_SANITIZER";
1261+
Type = Boolean;
1262+
DefaultValue = "$(ENABLE_SCUDO_SANITIZER)";
1263+
CommandLineArgs = {
1264+
YES = (
1265+
"-sanitize=scudo",
1266+
);
1267+
NO = ();
1268+
};
1269+
AdditionalLinkerArgs = {
1270+
YES = (
1271+
"$($(LINKER_DRIVER)_LD_SCUDO_SANITIZER)",
1272+
);
1273+
NO = ();
1274+
};
1275+
// Not visible in the build settings editor
1276+
},
1277+
12581278
// Fuzzer option.
12591279
{
12601280
Name = "SWIFT_LIBFUZZER";

Tests/SWBTaskConstructionTests/TaskConstructionTests.swift

Lines changed: 118 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4065,16 +4065,20 @@ fileprivate struct TaskConstructionTests: CoreBasedTests {
40654065
}
40664066

40674067
/// Test that we properly generate commands for the compiler sanitizer features.
4068+
4069+
static let sanitizersTestData = [
4070+
(linkerDriver: "clang", expectedAddressArgument: "-fsanitize=address", expectedScudoArgument: "-fsanitize=scudo"),
4071+
(linkerDriver: "swiftc", expectedAddressArgument: "-sanitize=address", expectedScudoArgument: "-sanitize=scudo"),
4072+
]
4073+
40684074
@Test(
40694075
.requireSDKs(.macOS),
4070-
arguments:[
4071-
(linkerDriver: "clang", expectedArgument: "-fsanitize=address"),
4072-
(linkerDriver: "swiftc", expectedArgument: "-sanitize=address"),
4073-
],
4076+
arguments: Self.sanitizersTestData,
40744077
)
40754078
func sanitizers(
40764079
linkerDriver: String,
4077-
expectedArgument: String,
4080+
expectedAddressArgument: String,
4081+
expectedScudoArgument: String,
40784082
) async throws {
40794083
try await withTemporaryDirectory { tmpDir in
40804084
let targetName = "AppTarget"
@@ -4154,7 +4158,7 @@ fileprivate struct TaskConstructionTests: CoreBasedTests {
41544158
results.checkTask(.matchTarget(target), .matchRuleType("Ld")) { task in
41554159
task.checkCommandLineContains(
41564160
[
4157-
expectedArgument,
4161+
expectedAddressArgument,
41584162
"-fsanitize-stable-abi",
41594163
"\(SRCROOT)/build/Debug/\(targetName).app/Contents/MacOS/\(targetName)",
41604164
]
@@ -4447,6 +4451,114 @@ fileprivate struct TaskConstructionTests: CoreBasedTests {
44474451
}
44484452
}
44494453

4454+
@Test(
4455+
arguments: Self.sanitizersTestData,
4456+
)
4457+
func scudoSanitizer(
4458+
linkerDriver: String,
4459+
expectedAddressArgument: String,
4460+
expectedScudoArgument: String,
4461+
) async throws {
4462+
let swiftVersion = try await self.swiftVersion
4463+
try await withTemporaryDirectory { tmpDir in
4464+
let targetName = "TestTargetname"
4465+
let testProject = TestProject(
4466+
"aProject",
4467+
sourceRoot: tmpDir,
4468+
groupTree: TestGroup(
4469+
"SomeFiles",
4470+
path: "Sources",
4471+
children: [
4472+
TestFile("C_file.c"),
4473+
TestFile("SwiftFile.swift"),
4474+
]),
4475+
buildConfigurations: [
4476+
TestBuildConfiguration(
4477+
"Debug",
4478+
buildSettings: [
4479+
"INFOPLIST_FILE": "Info.plist",
4480+
"PRODUCT_NAME": "$(TARGET_NAME)",
4481+
"SWIFT_VERSION": swiftVersion,
4482+
"CLANG_USE_RESPONSE_FILE": "NO",
4483+
],
4484+
),
4485+
],
4486+
targets: [
4487+
TestStandardTarget(
4488+
targetName,
4489+
type: .commandLineTool,
4490+
buildConfigurations: [
4491+
TestBuildConfiguration("Debug"),
4492+
],
4493+
buildPhases: [
4494+
TestSourcesBuildPhase([
4495+
"C_file.c",
4496+
"SwiftFile.swift",
4497+
]),
4498+
],
4499+
),
4500+
],
4501+
)
4502+
let core = try await getCore()
4503+
let tester = try TaskConstructionTester(core, testProject)
4504+
let SRCROOT = tester.workspace.projects[0].sourceRoot.str
4505+
4506+
// Use the local filesystem since the sanitizer logic needs to access clang.
4507+
let fs = localFS
4508+
4509+
try fs.write(Path(SRCROOT).join("Info.plist"), contents: "<dict/>")
4510+
4511+
let toolchain = try #require(tester.core.toolchainRegistry.defaultToolchain)
4512+
let toolchainDirectory: Path = toolchain.path
4513+
let clangBinary = toolchainDirectory.join("./usr/bin").join(core.hostOperatingSystem.imageFormat.executableName(basename: "clang")).normalize()
4514+
let swiftcBinary = toolchainDirectory.join("./usr/bin").join(core.hostOperatingSystem.imageFormat.executableName(basename: "swiftc")).normalize()
4515+
4516+
// Check the Scudo sanitizer
4517+
await tester.checkBuild(
4518+
BuildParameters(
4519+
configuration: "Debug",
4520+
overrides: [
4521+
"ENABLE_SCUDO_SANITIZER": "YES",
4522+
"LINKER_DRIVER": linkerDriver,
4523+
],
4524+
),
4525+
runDestination: .host,
4526+
fs: fs,
4527+
) { results in
4528+
results.checkTarget(targetName) { target in
4529+
// There should be one Ld task.
4530+
results.checkTask(.matchTarget(target), .matchRuleType("Ld")) { task in
4531+
task.checkCommandLineContains(
4532+
[
4533+
expectedScudoArgument,
4534+
],
4535+
)
4536+
task.checkCommandLineDoesNotContain("YES")
4537+
task.checkCommandLineDoesNotContain("NO")
4538+
}
4539+
results.checkTask(.matchTarget(target), .matchRuleType("CompileC")) { task in
4540+
task.checkCommandLineContains([
4541+
clangBinary.str,
4542+
"-fsanitize=scudo",
4543+
])
4544+
task.checkCommandLineDoesNotContain("YES")
4545+
task.checkCommandLineDoesNotContain("NO")
4546+
}
4547+
results.checkTask(.matchTarget(target), .matchRuleType("SwiftDriver Compilation")) { task in
4548+
task.checkCommandLineContains([
4549+
swiftcBinary.str,
4550+
"-sanitize=scudo",
4551+
])
4552+
task.checkCommandLineDoesNotContain("YES")
4553+
task.checkCommandLineDoesNotContain("NO")
4554+
}
4555+
}
4556+
results.checkNoDiagnostics()
4557+
}
4558+
}
4559+
}
4560+
4561+
44504562
/// Check that missing target GUIDs are legal, not crashes.
44514563
///
44524564
/// This is important because we allowing this to be valid can simplify the client logic in some situations.

0 commit comments

Comments
 (0)