diff --git a/Sources/SWBCore/Specs/CoreBuildSystem.xcspec b/Sources/SWBCore/Specs/CoreBuildSystem.xcspec index 0514414a..b1ad1195 100644 --- a/Sources/SWBCore/Specs/CoreBuildSystem.xcspec +++ b/Sources/SWBCore/Specs/CoreBuildSystem.xcspec @@ -3535,6 +3535,33 @@ For more information on mergeable libraries, see [Configuring your project to us Category = BuildOptions; Description = "Enables building with code coverage instrumentation. This is only used when the build has code coverage enabled, which is typically done via the Xcode scheme or test plan settings."; }, + { Name = ENABLE_ENHANCED_SECURITY; + Type = Boolean; + DefaultValue = NO; + Category = SecurityPolicy; + }, + { Name = ENABLE_POINTER_AUTHENTICATION; + Type = Boolean; + DefaultValue = "$(ENABLE_ENHANCED_SECURITY)"; + Category = SecurityPolicy; + }, + { Name = ENABLE_SECURITY_COMPILER_WARNINGS; + Type = Boolean; + DefaultValue = "$(ENABLE_ENHANCED_SECURITY)"; + Category = SecurityPolicy; + }, + { + Name = "ENABLE_C_BOUNDS_SAFETY"; + Type = Boolean; + DefaultValue = NO; + Category = Security; + }, + { + Name = "ENABLE_CPLUSPLUS_BOUNDS_SAFE_BUFFERS"; + Type = Boolean; + DefaultValue = NO; + Category = Security; + }, { Name = ENABLE_TESTABILITY; Type = Boolean; DefaultValue = NO; diff --git a/Sources/SWBCore/Specs/en.lproj/CoreBuildSystem.strings b/Sources/SWBCore/Specs/en.lproj/CoreBuildSystem.strings index 4aeafd33..d2482add 100644 --- a/Sources/SWBCore/Specs/en.lproj/CoreBuildSystem.strings +++ b/Sources/SWBCore/Specs/en.lproj/CoreBuildSystem.strings @@ -669,6 +669,35 @@ Typically this path is not set per target, but is provided as an option on the c "[MODULE_STOP]-name" = "Module Stop Routine"; "[MODULE_STOP]-description" = "This defines the name of the kernel module stop routine. This is only used when building kernel extensions."; +// Security Settings + +"[SecurityPolicy]-category" = "Security"; + +"[ENABLE_ENHANCED_SECURITY]-name" = "Enable Enhanced Security"; +"[ENABLE_ENHANCED_SECURITY]-description" = "Enables a set of security build settings, including pointer authentication, typed allocator support, hardened C++ standard library, and security-related compiler warnings. These settings can be disabled individually."; +"[ENABLE_ENHANCED_SECURITY]-value-[YES]" = "Yes"; +"[ENABLE_ENHANCED_SECURITY]-value-[NO]" = "No"; + +"[ENABLE_POINTER_AUTHENTICATION]-name" = "Enable Pointer Authentication"; +"[ENABLE_POINTER_AUTHENTICATION]-description" = "Builds the target with pointer authentication enabled. Adds an additional architectural slice (arm64e) with pointer authentication instructions."; +"[ENABLE_POINTER_AUTHENTICATION]-value-[YES]" = "Yes"; +"[ENABLE_POINTER_AUTHENTICATION]-value-[NO]" = "No"; + +"[ENABLE_SECURITY_COMPILER_WARNINGS]-name" = "Enable Security-Relevant Compiler Warnings"; +"[ENABLE_SECURITY_COMPILER_WARNINGS]-description" = "Enables a set of security-relevant compiler warnings that check for common bounds-safety and lifetime-safety issues."; +"[ENABLE_SECURITY_COMPILER_WARNINGS]-value-[YES]" = "Yes"; +"[ENABLE_SECURITY_COMPILER_WARNINGS]-value-[NO]" = "No"; + +"[ENABLE_C_BOUNDS_SAFETY]-name" = "Enable Language Extension for Bounds Safety in C"; +"[ENABLE_C_BOUNDS_SAFETY]-description" = "Enables the -fbounds-safety language extension, which guarantees bounds safety for C"; +"[ENABLE_C_BOUNDS_SAFETY]-value-[NO]" = "No"; +"[ENABLE_C_BOUNDS_SAFETY]-value-[YES]" = "Yes"; + +"[ENABLE_CPLUSPLUS_BOUNDS_SAFE_BUFFERS]-name" = "Enforce Bounds-Safe Buffer Usage in C++"; +"[ENABLE_CPLUSPLUS_BOUNDS_SAFE_BUFFERS]-description" = "Enables a strict programming model that guarantees bounds safety in C++ by rejecting raw pointer arithmetic (enabling the -Wunsafe-buffer-usage warning as an error) and requiring the use of hardened C++ Standard Library APIs for buffer manipulation."; +"[ENABLE_CPLUSPLUS_BOUNDS_SAFE_BUFFERS]-value-[NO]" = "No"; +"[ENABLE_CPLUSPLUS_BOUNDS_SAFE_BUFFERS]-value-[YES]" = "Yes"; + // Compiler Version "[GCC_VERSION]-name" = "Compiler for C/C++/Objective-C"; diff --git a/Sources/SWBUniversalPlatform/Specs/Clang.xcspec b/Sources/SWBUniversalPlatform/Specs/Clang.xcspec index f7ce248e..60e91aeb 100644 --- a/Sources/SWBUniversalPlatform/Specs/Clang.xcspec +++ b/Sources/SWBUniversalPlatform/Specs/Clang.xcspec @@ -536,7 +536,7 @@ FileTypes = ( "sourcecode.c.c", ); - DefaultValue = NO; + DefaultValue = "$(ENABLE_C_BOUNDS_SAFETY)"; CommandLineArgs = { YES = ( "-fbounds-safety" ); NO = (); @@ -640,14 +640,74 @@ Category = LanguageCXX; }, { - Name = __LIBRARY_HARDENING_DEFAULT_VALUE_0; + Name = __ENHANCED_SECURITY_OR_BOUNDS_SAFE_BUFFERS_YES_YES; + Type = String; + DefaultValue = "YES"; + }, + { + Name = __ENHANCED_SECURITY_OR_BOUNDS_SAFE_BUFFERS_YES_NO; + Type = String; + DefaultValue = "YES"; + }, + { + Name = __ENHANCED_SECURITY_OR_BOUNDS_SAFE_BUFFERS_NO_YES; + Type = String; + DefaultValue = "YES"; + }, + { + Name = __ENHANCED_SECURITY_OR_BOUNDS_SAFE_BUFFERS_NO_NO; + Type = String; + DefaultValue = "NO"; + }, + { + Name = __ENHANCED_SECURITY_OR_BOUNDS_SAFE_BUFFERS; + Type = String; + DefaultValue = "$(__ENHANCED_SECURITY_OR_BOUNDS_SAFE_BUFFERS_$(ENABLE_ENHANCED_SECURITY)_$(ENABLE_CPLUSPLUS_BOUNDS_SAFE_BUFFERS))"; + }, + { + Name = __LIBRARY_HARDENING_DEFAULT_VALUE_OPT_LEVEL_0_ENHANCED_SECURITY_OR_BOUNDS_SAFE_BUFFERS_YES; + Type = String; + DefaultValue = "debug"; + }, + { + Name = __LIBRARY_HARDENING_DEFAULT_VALUE_OPT_LEVEL_0_ENHANCED_SECURITY_OR_BOUNDS_SAFE_BUFFERS_NO; Type = String; DefaultValue = "debug"; }, + { + Name = __LIBRARY_HARDENING_DEFAULT_VALUE_OPT_LEVEL_1_ENHANCED_SECURITY_OR_BOUNDS_SAFE_BUFFERS_YES; + Type = String; + DefaultValue = "fast"; + }, + { + Name = __LIBRARY_HARDENING_DEFAULT_VALUE_OPT_LEVEL_2_ENHANCED_SECURITY_OR_BOUNDS_SAFE_BUFFERS_YES; + Type = String; + DefaultValue = "fast"; + }, + { + Name = __LIBRARY_HARDENING_DEFAULT_VALUE_OPT_LEVEL_3_ENHANCED_SECURITY_OR_BOUNDS_SAFE_BUFFERS_YES; + Type = String; + DefaultValue = "fast"; + }, + { + Name = __LIBRARY_HARDENING_DEFAULT_VALUE_OPT_LEVEL_s_ENHANCED_SECURITY_OR_BOUNDS_SAFE_BUFFERS_YES; + Type = String; + DefaultValue = "fast"; + }, + { + Name = __LIBRARY_HARDENING_DEFAULT_VALUE_OPT_LEVEL_fast_ENHANCED_SECURITY_OR_BOUNDS_SAFE_BUFFERS_YES; + Type = String; + DefaultValue = "fast"; + }, + { + Name = __LIBRARY_HARDENING_DEFAULT_VALUE_OPT_LEVEL_z_ENHANCED_SECURITY_OR_BOUNDS_SAFE_BUFFERS_YES; + Type = String; + DefaultValue = "fast"; + }, { Name = __LIBRARY_HARDENING_DEFAULT_VALUE; Type = String; - DefaultValue = "$(__LIBRARY_HARDENING_DEFAULT_VALUE_$(GCC_OPTIMIZATION_LEVEL))"; + DefaultValue = "$(__LIBRARY_HARDENING_DEFAULT_VALUE_OPT_LEVEL_$(GCC_OPTIMIZATION_LEVEL)_ENHANCED_SECURITY_OR_BOUNDS_SAFE_BUFFERS_$(__ENHANCED_SECURITY_OR_BOUNDS_SAFE_BUFFERS))"; }, { Name = "CLANG_CXX_STANDARD_LIBRARY_HARDENING"; @@ -736,11 +796,26 @@ ); Category = LanguageCXX; }, + { + Name = "_UNSAFE_BUFFER_USAGE_DEFAULT_ENABLE_SAFE_BUFFERS_NO"; + Type = String; + DefaultValue = "DEFAULT"; + }, + { + Name = "_UNSAFE_BUFFER_USAGE_DEFAULT_ENABLE_SAFE_BUFFERS_YES"; + Type = String; + DefaultValue = "YES_ERROR"; + }, + { + Name = "_UNSAFE_BUFFER_USAGE_DEFAULT"; + Type = String; + DefaultValue = "$(_UNSAFE_BUFFER_USAGE_DEFAULT_ENABLE_SAFE_BUFFERS_$(ENABLE_CPLUSPLUS_BOUNDS_SAFE_BUFFERS))"; + }, { Name = "CLANG_WARN_UNSAFE_BUFFER_USAGE"; Type = Enumeration; Values = ( DEFAULT, YES, YES_ERROR, NO ); - DefaultValue = DEFAULT; + DefaultValue = "$(_UNSAFE_BUFFER_USAGE_DEFAULT)"; CommandLineArgs = { DEFAULT = (); NO = ( "-Wno-unsafe-buffer-usage" ); @@ -801,7 +876,7 @@ { Name = "GCC_OPTIMIZATION_LEVEL"; Type = Enumeration; - // NOTE: Updating these values requires updating LLVM_OPTIMIZATION_LEVEL_VAL_X. + // NOTE: Updating these values requires updating LLVM_OPTIMIZATION_LEVEL_VAL_X and CLANG_CXX_STANDARD_LIBRARY_HARDENING. Values = ( 0, 1, @@ -945,6 +1020,22 @@ }; Category = WarningsPolicy; }, + { Name = CLANG_ENABLE_SECURITY_COMPILER_WARNINGS; + Type = Boolean; + DefaultValue = "$(ENABLE_SECURITY_COMPILER_WARNINGS)"; + CommandLineArgs = { + YES = ("-Wbuiltin-memcpy-chk-size", + "-Wformat-nonliteral", + "-Warray-bounds", + "-Warray-bounds-pointer-arithmetic", + "-Wsuspicious-memaccess", + "-Wsizeof-array-div", + "-Wsizeof-pointer-div", + "-Wreturn-stack-address"); + NO = (); + }; + // Hidden. + }, { Name = "GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS"; Type = Boolean; @@ -1381,7 +1472,7 @@ { Name = "CLANG_WARN_EMPTY_BODY"; Type = Boolean; - DefaultValue = NO; + DefaultValue = "$(CLANG_ENABLE_SECURITY_COMPILER_WARNINGS)"; CommandLineArgs = { YES = ( "-Wempty-body" ); NO = ( "-Wno-empty-body" ); @@ -1447,7 +1538,7 @@ { Name = "GCC_WARN_SHADOW"; Type = Boolean; - DefaultValue = NO; + DefaultValue = "$(CLANG_ENABLE_SECURITY_COMPILER_WARNINGS)"; CommandLineArgs = { YES = ( "-Wshadow", @@ -1800,6 +1891,27 @@ }; Category = Warnings; }, + { + Name = "CLANG_ENABLE_STACK_ZERO_INIT"; + Type = Boolean; + DefaultValue = "$(ENABLE_ENHANCED_SECURITY)"; + Category = Security; + }, + { + Name = "_CLANG_TRIVIAL_AUTO_VAR_INIT_DEFAULT_ENABLE_ZERO_INIT_YES"; + Type = Boolean; + DefaultValue = "zero"; + }, + { + Name = "_CLANG_TRIVIAL_AUTO_VAR_INIT_DEFAULT_ENABLE_ZERO_INIT_NO"; + Type = Boolean; + DefaultValue = "default"; + }, + { + Name = "_CLANG_TRIVIAL_AUTO_VAR_INIT_DEFAULT"; + Type = String; + DefaultValue = "$(_CLANG_TRIVIAL_AUTO_VAR_INIT_DEFAULT_ENABLE_ZERO_INIT_$(CLANG_ENABLE_STACK_ZERO_INIT))"; + }, { Name = "CLANG_TRIVIAL_AUTO_VAR_INIT"; Type = Enumeration; @@ -1809,7 +1921,7 @@ zero, pattern, ); - DefaultValue = default; + DefaultValue = "$(_CLANG_TRIVIAL_AUTO_VAR_INIT_DEFAULT)"; CommandLineArgs = { default = ( ); uninitialized = ( "-ftrivial-auto-var-init=uninitialized" ); @@ -2900,7 +3012,17 @@ Condition = "$(CLANG_UNDEFINED_BEHAVIOR_SANITIZER_TRAP_ON_SECURITY_ISSUES) && $(GCC_OPTIMIZATION_LEVEL) != 0"; }, { - Name = "CLANG_ENABLE_C_TYPED_ALLOCATOR_SUPPORT"; + Name = "_CLANG_ENABLE_TYPED_ALLOCATOR_SUPPORT_DEFAULT_ENHANCED_SECURITY_YES"; + Type = Enumeration; + Values = ( + compiler-default, + YES, + NO, + ); + DefaultValue = YES; + }, + { + Name = "_CLANG_ENABLE_TYPED_ALLOCATOR_SUPPORT_DEFAULT_ENHANCED_SECURITY_NO"; Type = Enumeration; Values = ( compiler-default, @@ -2908,11 +3030,32 @@ NO, ); DefaultValue = compiler-default; + }, + { + Name = "_CLANG_ENABLE_TYPED_ALLOCATOR_SUPPORT_DEFAULT"; + Type = Enumeration; + Values = ( + compiler-default, + YES, + NO, + ); + DefaultValue = "$(_CLANG_ENABLE_TYPED_ALLOCATOR_SUPPORT_DEFAULT_ENHANCED_SECURITY_$(ENABLE_ENHANCED_SECURITY))"; + }, + { + Name = "CLANG_ENABLE_C_TYPED_ALLOCATOR_SUPPORT"; + Type = Enumeration; + Values = ( + compiler-default, + YES, + NO, + ); + DefaultValue = "$(_CLANG_ENABLE_TYPED_ALLOCATOR_SUPPORT_DEFAULT)"; CommandLineArgs = { compiler-default = (); YES = ("-ftyped-memory-operations"); NO = ("-fno-typed-memory-operations"); }; + Category = Language; }, { Name = "CLANG_ENABLE_CPLUSPLUS_TYPED_ALLOCATOR_SUPPORT"; @@ -2922,7 +3065,7 @@ YES, NO, ); - DefaultValue = compiler-default; + DefaultValue = "$(_CLANG_ENABLE_TYPED_ALLOCATOR_SUPPORT_DEFAULT)"; CommandLineArgs = { compiler-default = (); YES = ("-ftyped-cxx-new-delete", "-ftyped-cxx-delete"); @@ -2933,6 +3076,7 @@ YES = ("-ftyped-cxx-new-delete", "-ftyped-cxx-delete"); NO = (); }; + Category = LanguageCXX; }, // Index-while-building options, not visible in build settings. { diff --git a/Sources/SWBUniversalPlatform/Specs/Ld.xcspec b/Sources/SWBUniversalPlatform/Specs/Ld.xcspec index b39abe90..6a9d0d46 100644 --- a/Sources/SWBUniversalPlatform/Specs/Ld.xcspec +++ b/Sources/SWBUniversalPlatform/Specs/Ld.xcspec @@ -736,7 +736,6 @@ ); }; }, - { Name = "__CREATE_INFOPLIST_SECTION_IN_BINARY"; Type = Boolean; diff --git a/Sources/SWBUniversalPlatform/Specs/en.lproj/Apple Clang.strings b/Sources/SWBUniversalPlatform/Specs/en.lproj/Apple Clang.strings index 8a159c12..bd8b3100 100644 --- a/Sources/SWBUniversalPlatform/Specs/en.lproj/Apple Clang.strings +++ b/Sources/SWBUniversalPlatform/Specs/en.lproj/Apple Clang.strings @@ -695,6 +695,23 @@ The restrictions on `offsetof` may be relaxed in a future version of the C++ sta "[CLANG_ENABLE_MODULES]-value-[YES]" = "Yes"; "[CLANG_ENABLE_MODULES]-value-[NO]" = "No"; +"[CLANG_ENABLE_STACK_ZERO_INIT]-name" = "Enable Stack Zero Initialization"; +"[CLANG_ENABLE_STACK_ZERO_INIT]-description" = "Automatically initializes stack variables to zero as a security protection."; +"[CLANG_ENABLE_STACK_ZERO_INIT]-value-[YES]" = "Yes"; +"[CLANG_ENABLE_STACK_ZERO_INIT]-value-[NO]" = "No"; + +"[CLANG_ENABLE_C_TYPED_ALLOCATOR_SUPPORT]-name" = "Enable Typed Allocator in C"; +"[CLANG_ENABLE_C_TYPED_ALLOCATOR_SUPPORT]-description" = "Enables compiler rewriting of allocation calls in C to provide type information to the allocator. Mitigates use-after-free security vulnerabilities."; +"[CLANG_ENABLE_C_TYPED_ALLOCATOR_SUPPORT]-value-[YES]" = "Yes"; +"[CLANG_ENABLE_C_TYPED_ALLOCATOR_SUPPORT]-value-[NO]" = "No"; +"[CLANG_ENABLE_C_TYPED_ALLOCATOR_SUPPORT]-value-[compiler-default]" = "Compiler Default"; + +"[CLANG_ENABLE_CPLUSPLUS_TYPED_ALLOCATOR_SUPPORT]-name" = "Enable Typed Allocator in C++"; +"[CLANG_ENABLE_CPLUSPLUS_TYPED_ALLOCATOR_SUPPORT]-description" = "Enables compiler rewriting of allocation calls in C++ to provide type information to the allocator. Mitigates use-after-free security vulnerabilities."; +"[CLANG_ENABLE_CPLUSPLUS_TYPED_ALLOCATOR_SUPPORT]-value-[YES]" = "Yes"; +"[CLANG_ENABLE_CPLUSPLUS_TYPED_ALLOCATOR_SUPPORT]-value-[NO]" = "No"; +"[CLANG_ENABLE_CPLUSPLUS_TYPED_ALLOCATOR_SUPPORT]-value-[compiler-default]" = "Compiler Default"; + "[CLANG_MODULES_AUTOLINK]-name" = "Link Frameworks Automatically"; "[CLANG_MODULES_AUTOLINK]-description" = "Automatically link SDK frameworks that are referenced using `#import` or `#include`. This feature requires also enabling support for modules. This build setting only applies to C-family languages."; "[CLANG_MODULES_AUTOLINK]-value-[YES]" = "Yes (when modules are enabled)"; diff --git a/Tests/SWBBuildSystemTests/BuildOperationTests.swift b/Tests/SWBBuildSystemTests/BuildOperationTests.swift index 68dd3c20..869029c6 100644 --- a/Tests/SWBBuildSystemTests/BuildOperationTests.swift +++ b/Tests/SWBBuildSystemTests/BuildOperationTests.swift @@ -6680,10 +6680,10 @@ That command depends on command in Target 'agg2' (project \'aProject\'): script } @Test(.requireSDKs(.iOS)) - func pointerAuthenticationBuildSetting() async throws { + func pointerAuthenticationBuildSetting_iOS() async throws { func test(buildSettings: [String: String], expectedArchs: [String], line: UInt = #line) async throws { - try await withTemporaryDirectory { tmpDirPath async throws -> Void in + try await withTemporaryDirectory { (tmpDirPath: Path) async throws -> Void in let testWorkspace = try await TestWorkspace( "Test", sourceRoot: tmpDirPath.join("Test"), @@ -6719,7 +6719,7 @@ That command depends on command in Target 'agg2' (project \'aProject\'): script try await tester.fs.writeFileContents(swiftFile) { stream in } } - try await tester.checkBuild(runDestination: .anyiOSDevice) { results in + try await tester.checkBuild(runDestination: .anyiOSDevice) { results -> Void in results.checkNoErrors() for arch in expectedArchs { @@ -6727,6 +6727,7 @@ That command depends on command in Target 'agg2' (project \'aProject\'): script results.checkTask(.matchRuleType("CompileC"), .matchRuleItemPattern(.suffix("File.m")), .matchRuleItem(arch)) { _ in } results.checkTask(.matchRuleType("SwiftCompile"), .matchRuleItem(arch)) { _ in } results.checkTask(.matchRuleType("SwiftEmitModule"), .matchRuleItem(arch)) { _ in } + } } } @@ -6734,6 +6735,83 @@ That command depends on command in Target 'agg2' (project \'aProject\'): script try await test(buildSettings: ["ENABLE_POINTER_AUTHENTICATION": "YES"], expectedArchs: ["arm64", "arm64e"]) try await test(buildSettings: ["ENABLE_POINTER_AUTHENTICATION": "NO"], expectedArchs: ["arm64"]) + + // ENABLE_ENHANCED_SECURITY enables pointer authentication unless ENABLE_POINTER_AUTHENTICATION is explicitly disabled. + try await test(buildSettings: ["ENABLE_ENHANCED_SECURITY": "YES"], expectedArchs: ["arm64", "arm64e"]) + try await test(buildSettings: ["ENABLE_ENHANCED_SECURITY": "NO"], expectedArchs: ["arm64"]) + try await test(buildSettings: ["ENABLE_ENHANCED_SECURITY": "YES", "ENABLE_POINTER_AUTHENTICATION": "NO"], expectedArchs: ["arm64"]) + try await test(buildSettings: ["ENABLE_ENHANCED_SECURITY": "NO", "ENABLE_POINTER_AUTHENTICATION": "YES"], expectedArchs: ["arm64e"]) + } + + @Test(.requireSDKs(.macOS)) + func pointerAuthenticationBuildSetting_macOS() async throws { + func test(buildSettings: [String: String], expectedArchs: [String], line: UInt = #line) async throws { + + try await withTemporaryDirectory { (tmpDirPath: Path) async throws -> Void in + let testWorkspace = try await TestWorkspace( + "Test", + sourceRoot: tmpDirPath.join("Test"), + projects: [ + TestProject( + "aProject", + groupTree: TestGroup("Sources", children: [ + TestFile("File.c"), + TestFile("File.swift"), + TestFile("File.m"), + ]), + buildConfigurations: [TestBuildConfiguration( + "Debug", + buildSettings: [ + "SDKROOT": "macosx", + "DONT_GENERATE_INFOPLIST_FILE": "YES", + "PRODUCT_NAME": "$(TARGET_NAME)", + "SWIFT_VERSION": swiftVersion, + ])], + targets: [ + TestStandardTarget( + "aFramework", type: .framework, + buildConfigurations: [TestBuildConfiguration("Debug", buildSettings: buildSettings)], + buildPhases: [ + TestSourcesBuildPhase(["File.c", "File.swift", "File.m"]), + ]), + TestStandardTarget( + "anApp", type: .application, + buildConfigurations: [TestBuildConfiguration("Debug", buildSettings: buildSettings)], + buildPhases: [ + TestSourcesBuildPhase(["File.c", "File.swift", "File.m"]), + ]) + ])]) + + let tester = try await BuildOperationTester(getCore(), testWorkspace, simulated: false) + + // create the files + for file in ["File.swift", "File.c", "File.m"] { + let swiftFile = testWorkspace.sourceRoot.join("aProject/\(file)") + try await tester.fs.writeFileContents(swiftFile) { stream in } + } + + try await tester.checkBuild(runDestination: .anyMac) { results -> Void in + results.checkNoErrors() + + + for arch in expectedArchs { + results.checkTask(.matchRuleType("CompileC"), .matchRuleItemPattern(.suffix("File.c")), .matchRuleItem(arch)) { _ in } + results.checkTask(.matchRuleType("CompileC"), .matchRuleItemPattern(.suffix("File.m")), .matchRuleItem(arch)) { _ in } + results.checkTask(.matchRuleType("SwiftCompile"), .matchRuleItem(arch)) { _ in } + results.checkTask(.matchRuleType("SwiftEmitModule"), .matchRuleItem(arch)) { _ in } + } + } + } + } + + try await test(buildSettings: ["ENABLE_POINTER_AUTHENTICATION": "YES"], expectedArchs: ["x86_64", "arm64", "arm64e"]) + try await test(buildSettings: ["ENABLE_POINTER_AUTHENTICATION": "NO"], expectedArchs: ["x86_64", "arm64"]) + + // ENABLE_ENHANCED_SECURITY enables pointer authentication unless ENABLE_POINTER_AUTHENTICATION is explicitly disabled. + try await test(buildSettings: ["ENABLE_ENHANCED_SECURITY": "YES"], expectedArchs: ["x86_64", "arm64", "arm64e"]) + try await test(buildSettings: ["ENABLE_ENHANCED_SECURITY": "NO"], expectedArchs: ["x86_64", "arm64"]) + try await test(buildSettings: ["ENABLE_ENHANCED_SECURITY": "YES", "ENABLE_POINTER_AUTHENTICATION": "NO"], expectedArchs: ["x86_64", "arm64"]) + try await test(buildSettings: ["ENABLE_ENHANCED_SECURITY": "NO", "ENABLE_POINTER_AUTHENTICATION": "YES"], expectedArchs: ["x86_64", "arm64e"]) } @Test(.requireSDKs(.macOS)) diff --git a/Tests/SWBTaskConstructionTests/TaskConstructionTests.swift b/Tests/SWBTaskConstructionTests/TaskConstructionTests.swift index d2c11ff1..ea146fcd 100644 --- a/Tests/SWBTaskConstructionTests/TaskConstructionTests.swift +++ b/Tests/SWBTaskConstructionTests/TaskConstructionTests.swift @@ -8428,6 +8428,82 @@ fileprivate struct TaskConstructionTests: CoreBasedTests { } } + @Test(.requireSDKs(.macOS)) + func zeroStackInit() async throws { + try await withTemporaryDirectory { tmpDir in + let testProject = TestProject( + "aProject", + sourceRoot: tmpDir, + groupTree: TestGroup( + "SomeFiles", path: "Sources", + children: [ + TestFile("SourceFile.c"), + ]), + buildConfigurations: [ + TestBuildConfiguration("Debug") + ], + targets: [ + TestStandardTarget( + "AppTarget", + type: .application, + buildConfigurations: [ + TestBuildConfiguration("Debug", buildSettings: [ + "GENERATE_INFOPLIST_FILE": "YES" + ]) + ], + buildPhases: [ + TestSourcesBuildPhase([ + "SourceFile.c" + ]) + ] + )] + ) + + let fs = PseudoFS() + + let core = try await getCore() + let tester = try TaskConstructionTester(core, testProject) + let enableStackZeroInitSetting = "CLANG_ENABLE_STACK_ZERO_INIT"; + let enableEnhancedSecuritySetting = "ENABLE_ENHANCED_SECURITY" + + func test(task: any PlannedTask, overrides: [String: String]) -> Void { + if let val = overrides[enableStackZeroInitSetting] { + if val == "YES" { + task.checkCommandLineContains(["-ftrivial-auto-var-init=zero"]) + } else if val == "NO" { + task.checkCommandLineNoMatch([.contains("-ftrivial-auto-var-init")]) + } + } else if let val = overrides[enableEnhancedSecuritySetting] { + if val == "YES" { + task.checkCommandLineContains(["-ftrivial-auto-var-init=zero"]) + } else if val == "NO" { + task.checkCommandLineNoMatch([.contains("-ftrivial-auto-var-init")]) + } + } else { + task.checkCommandLineNoMatch([.contains("-ftrivial-auto-var-init")]) + } + } + + let overrides = [ + [:], + [enableStackZeroInitSetting: "YES"], + [enableStackZeroInitSetting: "NO"], + + [enableStackZeroInitSetting: "YES", enableEnhancedSecuritySetting: "YES"], + [enableStackZeroInitSetting: "YES", enableEnhancedSecuritySetting: "NO"], + [enableStackZeroInitSetting: "NO", enableEnhancedSecuritySetting: "YES"], + ] + + for override in overrides { + await tester.checkBuild(BuildParameters(configuration: "Debug", overrides: override), runDestination: .macOS, fs: fs) { results -> Void in + results.checkTarget("AppTarget") { target -> Void in + results.checkTask(.matchTarget(target), .matchRuleType("CompileC"), body: {task in test(task: task, overrides: override)}) + } + } + } + } + } + @Test(.requireSDKs(.macOS)) func typedMemoryOperations() async throws { try await withTemporaryDirectory { tmpDir in @@ -8465,8 +8541,10 @@ fileprivate struct TaskConstructionTests: CoreBasedTests { let tester = try TaskConstructionTester(core, testProject) let typedMemoryOperationsC = "CLANG_ENABLE_C_TYPED_ALLOCATOR_SUPPORT"; let typedMemoryOperationsCXX = "CLANG_ENABLE_CPLUSPLUS_TYPED_ALLOCATOR_SUPPORT"; + let enableEnhancedSecuritySetting = "ENABLE_ENHANCED_SECURITY" func test(task: any PlannedTask, overrides: [String: String]) -> Void { + if let val = overrides[typedMemoryOperationsC] { if val == "YES" { task.checkCommandLineContains(["-ftyped-memory-operations"]) @@ -8487,6 +8565,16 @@ fileprivate struct TaskConstructionTests: CoreBasedTests { task.checkCommandLineDoesNotContain("-fno-typed-cxx-new-delete") task.checkCommandLineDoesNotContain("-fno-typed-cxx-delete") } + } else if let val = overrides[enableEnhancedSecuritySetting] { + if val == "YES" { + task.checkCommandLineContains(["-ftyped-memory-operations"]) + task.checkCommandLineContains(["-ftyped-cxx-new-delete", "-ftyped-cxx-delete"]) + } else if val == "NO" { + task.checkCommandLineDoesNotContain("-ftyped-cxx-new-delete") + task.checkCommandLineDoesNotContain("-ftyped-cxx-delete") + task.checkCommandLineDoesNotContain("-fno-typed-cxx-new-delete") + task.checkCommandLineDoesNotContain("-fno-typed-cxx-delete") + } } } @@ -8497,6 +8585,22 @@ fileprivate struct TaskConstructionTests: CoreBasedTests { [typedMemoryOperationsCXX: "YES"], [typedMemoryOperationsCXX: "NO"], [typedMemoryOperationsCXX: "compiler-default"], + + [enableEnhancedSecuritySetting: "YES"], + [enableEnhancedSecuritySetting: "NO"], + [enableEnhancedSecuritySetting: "NO", typedMemoryOperationsC: "NO"], + [enableEnhancedSecuritySetting: "NO", typedMemoryOperationsC: "YES"], + [enableEnhancedSecuritySetting: "YES", typedMemoryOperationsC: "NO"], + [enableEnhancedSecuritySetting: "YES", typedMemoryOperationsC: "YES"], + [enableEnhancedSecuritySetting: "YES", typedMemoryOperationsC: "compiler-default"], + [enableEnhancedSecuritySetting: "YES", typedMemoryOperationsC: "compiler-default"], + + [enableEnhancedSecuritySetting: "NO", typedMemoryOperationsCXX: "NO"], + [enableEnhancedSecuritySetting: "NO", typedMemoryOperationsCXX: "YES"], + [enableEnhancedSecuritySetting: "YES", typedMemoryOperationsCXX: "NO"], + [enableEnhancedSecuritySetting: "YES", typedMemoryOperationsCXX: "YES"], + [enableEnhancedSecuritySetting: "YES", typedMemoryOperationsCXX: "compiler-default"], + [enableEnhancedSecuritySetting: "YES", typedMemoryOperationsCXX: "compiler-default"], ] for override in overrides { @@ -8514,6 +8618,268 @@ fileprivate struct TaskConstructionTests: CoreBasedTests { } } + @Test(.requireSDKs(.macOS)) + func warnShadow() async throws { + try await withTemporaryDirectory { tmpDir in + let testProject = TestProject( + "aProject", + sourceRoot: tmpDir, + groupTree: TestGroup( + "SomeFiles", path: "Sources", + children: [ + TestFile("SourceFile.c"), + ]), + buildConfigurations: [ + TestBuildConfiguration("Debug") + ], + targets: [ + TestStandardTarget( + "AppTarget", + type: .application, + buildConfigurations: [ + TestBuildConfiguration("Debug", buildSettings: [ + "GENERATE_INFOPLIST_FILE": "YES" + ]) + ], + buildPhases: [ + TestSourcesBuildPhase([ + "SourceFile.c" + ]) + ] + )] + ) + + let fs = PseudoFS() + + let core = try await getCore() + let tester = try TaskConstructionTester(core, testProject) + let warnShadowSetting = "GCC_WARN_SHADOW"; + let enableEnhancedSecuritySetting = "ENABLE_ENHANCED_SECURITY" + + func test(task: any PlannedTask, overrides: [String: String]) -> Void { + if let val = overrides[warnShadowSetting] { + if val == "YES" { + task.checkCommandLineContains(["-Wshadow"]) + } else if (val == "NO") { + task.checkCommandLineContains(["-Wno-shadow"]) + } + } else if let val = overrides[enableEnhancedSecuritySetting] { + if val == "YES" { + task.checkCommandLineContains(["-Wshadow"]) + } else if val == "NO" { + task.checkCommandLineDoesNotContain("-Wshadow") + task.checkCommandLineContains(["-Wno-shadow"]) + } + } + } + + let overrides = [ + [warnShadowSetting: "YES"], + [warnShadowSetting: "NO"], + [enableEnhancedSecuritySetting: "YES"], + [enableEnhancedSecuritySetting: "NO"], + + [warnShadowSetting: "NO", enableEnhancedSecuritySetting: "YES"], + [warnShadowSetting: "YES", enableEnhancedSecuritySetting: "NO"], + ] + + for override in overrides { + await tester.checkBuild(BuildParameters(configuration: "Debug", overrides: override), runDestination: .macOS, fs: fs) { results -> Void in + results.checkTarget("AppTarget") { target -> Void in + results.checkTask(.matchTarget(target), .matchRuleType("CompileC"), body: {task in test(task: task, overrides: override)}) + } + } + } + } + } + + @Test(.requireSDKs(.macOS)) + func warnEmptyBody() async throws { + try await withTemporaryDirectory { tmpDir in + let testProject = TestProject( + "aProject", + sourceRoot: tmpDir, + groupTree: TestGroup( + "SomeFiles", path: "Sources", + children: [ + TestFile("SourceFile.c"), + ]), + buildConfigurations: [ + TestBuildConfiguration("Debug") + ], + targets: [ + TestStandardTarget( + "AppTarget", + type: .application, + buildConfigurations: [ + TestBuildConfiguration("Debug", buildSettings: [ + "GENERATE_INFOPLIST_FILE": "YES" + ]) + ], + buildPhases: [ + TestSourcesBuildPhase([ + "SourceFile.c" + ]) + ] + )] + ) + + let fs = PseudoFS() + + let core = try await getCore() + let tester = try TaskConstructionTester(core, testProject) + let warnEmptyBodySetting = "CLANG_WARN_EMPTY_BODY"; + let enableEnhancedSecuritySetting = "ENABLE_ENHANCED_SECURITY" + + func test(task: any PlannedTask, overrides: [String: String]) -> Void { + if let val = overrides[warnEmptyBodySetting] { + if val == "YES" { + task.checkCommandLineContains(["-Wempty-body"]) + } else if (val == "NO") { + task.checkCommandLineContains(["-Wno-empty-body"]) + } + } else if let val = overrides[enableEnhancedSecuritySetting] { + if val == "YES" { + task.checkCommandLineContains(["-Wempty-body"]) + } else if val == "NO" { + task.checkCommandLineDoesNotContain("-Wempty-body") + task.checkCommandLineContains(["-Wno-empty-body"]) + } + } + } + + let overrides = [ + [warnEmptyBodySetting: "YES"], + [warnEmptyBodySetting: "NO"], + [enableEnhancedSecuritySetting: "YES"], + [enableEnhancedSecuritySetting: "NO"], + + [warnEmptyBodySetting: "NO", enableEnhancedSecuritySetting: "YES"], + [warnEmptyBodySetting: "YES", enableEnhancedSecuritySetting: "NO"], + ] + + for override in overrides { + await tester.checkBuild(BuildParameters(configuration: "Debug", overrides: override), runDestination: .macOS, fs: fs) { results -> Void in + results.checkTarget("AppTarget") { target -> Void in + results.checkTask(.matchTarget(target), .matchRuleType("CompileC"), body: {task in test(task: task, overrides: override)}) + } + } + } + } + } + + @Test(.requireSDKs(.macOS)) + func securityCompilerWarnings() async throws { + try await withTemporaryDirectory { tmpDir in + let testProject = TestProject( + "aProject", + sourceRoot: tmpDir, + groupTree: TestGroup( + "SomeFiles", path: "Sources", + children: [ + TestFile("SourceFile.c"), + ]), + buildConfigurations: [ + TestBuildConfiguration("Debug") + ], + targets: [ + TestStandardTarget( + "AppTarget", + type: .application, + buildConfigurations: [ + TestBuildConfiguration("Debug", buildSettings: [ + "GENERATE_INFOPLIST_FILE": "YES" + ]) + ], + buildPhases: [ + TestSourcesBuildPhase([ + "SourceFile.c" + ]) + ] + )] + ) + + let fs = PseudoFS() + + let core = try await getCore() + let tester = try TaskConstructionTester(core, testProject) + let enableSecurityCompilerWarningsSetting = "ENABLE_SECURITY_COMPILER_WARNINGS"; + let enableEnhancedSecuritySetting = "ENABLE_ENHANCED_SECURITY" + + func generateWarningFlags(enabled: Bool) -> [String] { + let prefix = enabled ? "-W" : "-Wno-" + return ["\(prefix)builtin-memcpy-chk-size", + "\(prefix)format-nonliteral", + "\(prefix)array-bounds", + "\(prefix)array-bounds-pointer-arithmetic", + "\(prefix)suspicious-memaccess", + "\(prefix)sizeof-array-div", + "\(prefix)sizeof-pointer-div", + "\(prefix)return-stack-address",] + } + + func test(task: any PlannedTask, overrides: [String: String]) -> Void { + + if let val = overrides[enableSecurityCompilerWarningsSetting] { + if val == "YES" { + for enabledWarning in generateWarningFlags(enabled: true) { + task.checkCommandLineContains([enabledWarning]) + } + for disabledWarning in generateWarningFlags(enabled: false) { + task.checkCommandLineDoesNotContain(disabledWarning) + } + } else if val == "NO" { + // Pass nothing on NO + for enabledWarning in generateWarningFlags(enabled: true) { + task.checkCommandLineDoesNotContain(enabledWarning) + } + for disabledWarning in generateWarningFlags(enabled: false) { + task.checkCommandLineDoesNotContain(disabledWarning) + } + } + } else if let val = overrides[enableEnhancedSecuritySetting] { + if val == "YES" { + for enabledWarning in generateWarningFlags(enabled: true) { + task.checkCommandLineContains([enabledWarning]) + } + for disabledWarning in generateWarningFlags(enabled: false) { + task.checkCommandLineDoesNotContain(disabledWarning) + } + } else if val == "NO" { + // Pass nothing on NO + for enabledWarning in generateWarningFlags(enabled: true) { + task.checkCommandLineDoesNotContain(enabledWarning) + } + for disabledWarning in generateWarningFlags(enabled: false) { + task.checkCommandLineDoesNotContain(disabledWarning) + } + } + } + } + + let overrides = [ + [enableSecurityCompilerWarningsSetting: "YES"], + [enableSecurityCompilerWarningsSetting: "NO"], + + [enableEnhancedSecuritySetting: "YES"], + [enableEnhancedSecuritySetting: "NO"], + [enableEnhancedSecuritySetting: "NO", enableSecurityCompilerWarningsSetting: "NO"], + [enableEnhancedSecuritySetting: "NO", enableSecurityCompilerWarningsSetting: "YES"], + [enableEnhancedSecuritySetting: "YES", enableSecurityCompilerWarningsSetting: "NO"], + [enableEnhancedSecuritySetting: "YES", enableSecurityCompilerWarningsSetting: "YES"], + ] + + for override in overrides { + await tester.checkBuild(BuildParameters(configuration: "Debug", overrides: override), runDestination: .macOS, fs: fs) { results -> Void in + results.checkTarget("AppTarget") { target -> Void in + results.checkTask(.matchTarget(target), .matchRuleType("CompileC"), body: {task in test(task: task, overrides: override)}) + } + } + } + } + } + + @Test(.requireSDKs(.macOS)) func unsafeBufferUsage() async throws { try await withTemporaryDirectory { tmpDir in @@ -8549,7 +8915,10 @@ fileprivate struct TaskConstructionTests: CoreBasedTests { let core = try await getCore() let tester = try TaskConstructionTester(core, testProject) - let unsafeBufferUsageWarn = "CLANG_WARN_UNSAFE_BUFFER_USAGE"; + let unsafeBufferUsageWarn = "CLANG_WARN_UNSAFE_BUFFER_USAGE" + + // This setting enables both the CLANG_WARN_UNSAFE_BUFFER_USAGE and CLANG_CXX_STANDARD_LIBRARY_HARDENING + let enableBoundsSafeBuffers = "ENABLE_CPLUSPLUS_BOUNDS_SAFE_BUFFERS" func test(task: any PlannedTask, overrides: [String: String]) -> Void { if let val = overrides[unsafeBufferUsageWarn] { @@ -8563,6 +8932,15 @@ fileprivate struct TaskConstructionTests: CoreBasedTests { task.checkCommandLineDoesNotContain("-Wunsafe-buffer-usage") task.checkCommandLineDoesNotContain("-Wno-unsafe-buffer-usage") } + } else if let val = overrides[enableBoundsSafeBuffers] { + // When CLANG_WARN_UNSAFE_BUFFER_USAGE is not explicitly set, enable -Wunsafe-buffer-usage as on error when ENABLE_CPLUSPLUS_BOUNDS_SAFE_BUFFERS is YES. + if (val == "YES") { + task.checkCommandLineContains(["-Werror=unsafe-buffer-usage"]) + } else if (val == "NO") { + task.checkCommandLineDoesNotContain("-Wunsafe-buffer-usage") + task.checkCommandLineDoesNotContain("-Wno-unsafe-buffer-usage") + task.checkCommandLineDoesNotContain("-Werror=unsafe-buffer-usage") + } } } @@ -8571,6 +8949,233 @@ fileprivate struct TaskConstructionTests: CoreBasedTests { [unsafeBufferUsageWarn: "NO"], [unsafeBufferUsageWarn: "YES_ERROR"], [unsafeBufferUsageWarn: "DEFAULT"], + + [enableBoundsSafeBuffers: "YES"], + [enableBoundsSafeBuffers: "NO"], + + [enableBoundsSafeBuffers: "YES", unsafeBufferUsageWarn: "NO"], + [enableBoundsSafeBuffers: "NO", unsafeBufferUsageWarn: "YES"], + [enableBoundsSafeBuffers: "NO", unsafeBufferUsageWarn: "YES_ERROR"], + [enableBoundsSafeBuffers: "NO", unsafeBufferUsageWarn: "YES_DEFAULT"], + + ] + + for override in overrides { + await tester.checkBuild(BuildParameters(configuration: "Debug", overrides: override), runDestination: .macOS, fs: fs) { results -> Void in + results.checkTarget("AppTarget") { target -> Void in + results.checkTask(.matchTarget(target), .matchRuleType("CompileC"), body: {task in test(task: task, overrides: override)}) + } + } + } + } + } + + @Test(.requireSDKs(.macOS)) + func boundsSafetyCLanguageExtension() async throws { + try await withTemporaryDirectory { tmpDir in + let testProject = TestProject( + "aProject", + sourceRoot: tmpDir, + groupTree: TestGroup( + "SomeFiles", path: "Sources", + children: [ + TestFile("SourceFile.c"), + ]), + buildConfigurations: [ + TestBuildConfiguration("Debug") + ], + targets: [ + TestStandardTarget( + "AppTarget", + type: .application, + buildConfigurations: [ + TestBuildConfiguration("Debug", buildSettings: [ + "GENERATE_INFOPLIST_FILE": "YES" + ]) + ], + buildPhases: [ + TestSourcesBuildPhase([ + "SourceFile.c" + ]) + ] + )] + ) + + let fs = PseudoFS() + + let core = try await getCore() + let tester = try TaskConstructionTester(core, testProject) + let enableBoundsSafetySetting = "CLANG_ENABLE_BOUNDS_SAFETY"; + + func test(task: any PlannedTask, overrides: [String: String]) -> Void { + if let val = overrides[enableBoundsSafetySetting] { + if val == "YES" { + task.checkCommandLineContains(["-fbounds-safety"]) + } else if (val == "NO") { + task.checkCommandLineDoesNotContain("-fbounds-safety") + } + } + } + + let overrides = [ + [enableBoundsSafetySetting: "YES"], + [enableBoundsSafetySetting: "NO"], + ] + + for override in overrides { + await tester.checkBuild(BuildParameters(configuration: "Debug", overrides: override), runDestination: .macOS, fs: fs) { results -> Void in + results.checkTarget("AppTarget") { target -> Void in + results.checkTask(.matchTarget(target), .matchRuleType("CompileC"), body: {task in test(task: task, overrides: override)}) + } + } + } + } + } + + + @Test(.requireSDKs(.macOS)) + func libCPPLibraryHardening() async throws { + try await withTemporaryDirectory { tmpDir in + let testProject = TestProject( + "aProject", + sourceRoot: tmpDir, + groupTree: TestGroup( + "SomeFiles", path: "Sources", + children: [ + TestFile("SourceFile.cpp"), + ]), + buildConfigurations: [ + TestBuildConfiguration("Debug") + ], + targets: [ + TestStandardTarget( + "AppTarget", + type: .application, + buildConfigurations: [ + TestBuildConfiguration("Debug", buildSettings: [ + "GENERATE_INFOPLIST_FILE": "YES" + ]) + ], + buildPhases: [ + TestSourcesBuildPhase([ + "SourceFile.cpp" + ]) + ] + )] + ) + + let fs = PseudoFS() + + let core = try await getCore() + let tester = try TaskConstructionTester(core, testProject) + let cppHardeningSetting = "CLANG_CXX_STANDARD_LIBRARY_HARDENING" + let gccOptimizationLevelSetting = "GCC_OPTIMIZATION_LEVEL" + + // When either ENABLE_ENHANCED_SECURITY or ENABLE_CPLUSPLUS_BOUNDS_SAFE_BUFFERS are YES and CLANG_CXX_STANDARD_LIBRARY_HARDENING + // is not explicitly set, then fast hardening mode should be enabled for all but debug builds. + let enableEnhancedSecuritySetting = "ENABLE_ENHANCED_SECURITY" + let enableBoundsSafeBuffersSetting = "ENABLE_CPLUSPLUS_BOUNDS_SAFE_BUFFERS" + + func test(task: any PlannedTask, overrides: [String: String]) -> Void { + enum HardeningMode { + case NONE + case FAST + case EXTENSIVE + case DEBUG + } + + func checkCommandLineHardening(mode: HardeningMode, sourceLocation: SourceLocation = #_sourceLocation) { + task.checkCommandLineContains(["-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_\(mode)"]) + } + + func checkCommandLineNoHardening(sourceLocation: SourceLocation = #_sourceLocation) { + task.checkCommandLineNoMatch([.contains("-D_LIBCPP_HARDENING_MODE")]) + } + + + if let cppHardeningSettingVal = overrides[cppHardeningSetting] { + // When CLANG_CXX_STANDARD_LIBRARY_HARDENING is set, it wins and sets hardening mode policy + switch cppHardeningSettingVal { + case "": + // When the value is not set, no hardening should be passed so that the compiler can determine the appropriate default + // if any, based on the target triple. + checkCommandLineNoHardening() + case "none": + checkCommandLineHardening(mode: .NONE) + case "fast": + checkCommandLineHardening(mode: .FAST) + case "extensive": + checkCommandLineHardening(mode: .EXTENSIVE) + case "debug": + checkCommandLineHardening(mode: .DEBUG) + default: + assertionFailure("Unexpected CLANG_CXX_STANDARD_LIBRARY_HARDENING override") + } + } else { + // When CLANG_CXX_STANDARD_LIBRARY_HARDENING is not set, the command-line depends on GCC_OPTIMIZATION_LEVEL and ENABLE_ENHANCED_SECURITY + + // If the optimization level is set and it is -O0, then the hardening is DEBUG. + // Otherwise, the hardening level depends on ENABLE_ENHANCED_SECURITY. If enhanced security is enabled, then the default for non -O0 is FAST; otherwise + // the default is to not set the hardening level. + + let isOptLevelZero = (overrides[gccOptimizationLevelSetting] == .some("0")) + let isEnhancedSecurityEnabled = (overrides[enableEnhancedSecuritySetting] == .some("YES")) + let isEnableBoundsSafeBuffersEnabled = (overrides[enableBoundsSafeBuffersSetting] == .some("YES")) + + if isOptLevelZero { + checkCommandLineHardening(mode: .DEBUG) + } else if isEnhancedSecurityEnabled || isEnableBoundsSafeBuffersEnabled { + checkCommandLineHardening(mode: .FAST) + } else { + checkCommandLineNoHardening() + } + } + } + + let overrides = [ + [gccOptimizationLevelSetting: "0"], + [gccOptimizationLevelSetting: "1"], + [gccOptimizationLevelSetting: "2"], + [gccOptimizationLevelSetting: "3"], + [gccOptimizationLevelSetting: "fast"], + [gccOptimizationLevelSetting: "s"], + [gccOptimizationLevelSetting: "z"], + + [cppHardeningSetting: ""], + [cppHardeningSetting: "none"], + [cppHardeningSetting: "fast"], + [cppHardeningSetting: "extensive"], + [cppHardeningSetting: "debug"], + + [gccOptimizationLevelSetting: "0", enableEnhancedSecuritySetting: "YES", cppHardeningSetting: "none"], + + [gccOptimizationLevelSetting: "0", enableEnhancedSecuritySetting: "YES"], + [gccOptimizationLevelSetting: "1", enableEnhancedSecuritySetting: "YES"], + [gccOptimizationLevelSetting: "2", enableEnhancedSecuritySetting: "YES"], + [gccOptimizationLevelSetting: "3", enableEnhancedSecuritySetting: "YES"], + [gccOptimizationLevelSetting: "fast", enableEnhancedSecuritySetting: "YES"], + [gccOptimizationLevelSetting: "s", enableEnhancedSecuritySetting: "YES"], + [gccOptimizationLevelSetting: "z", enableEnhancedSecuritySetting: "YES"], + + [gccOptimizationLevelSetting: "0", enableBoundsSafeBuffersSetting: "YES"], + [gccOptimizationLevelSetting: "1", enableBoundsSafeBuffersSetting: "YES"], + [gccOptimizationLevelSetting: "2", enableBoundsSafeBuffersSetting: "YES"], + [gccOptimizationLevelSetting: "3", enableBoundsSafeBuffersSetting: "YES"], + [gccOptimizationLevelSetting: "fast", enableBoundsSafeBuffersSetting: "YES"], + [gccOptimizationLevelSetting: "s", enableBoundsSafeBuffersSetting: "YES"], + [gccOptimizationLevelSetting: "z", enableBoundsSafeBuffersSetting: "YES"], + + [gccOptimizationLevelSetting: "0", enableEnhancedSecuritySetting: "YES", enableBoundsSafeBuffersSetting: "YES"], + [gccOptimizationLevelSetting: "0", enableEnhancedSecuritySetting: "YES", enableBoundsSafeBuffersSetting: "NO"], + [gccOptimizationLevelSetting: "0", enableEnhancedSecuritySetting: "NO", enableBoundsSafeBuffersSetting: "YES"], + [gccOptimizationLevelSetting: "0", enableEnhancedSecuritySetting: "NO", enableBoundsSafeBuffersSetting: "NO"], + [gccOptimizationLevelSetting: "s", enableEnhancedSecuritySetting: "YES", enableBoundsSafeBuffersSetting: "YES"], + [gccOptimizationLevelSetting: "s", enableEnhancedSecuritySetting: "YES", enableBoundsSafeBuffersSetting: "NO"], + [gccOptimizationLevelSetting: "s", enableEnhancedSecuritySetting: "NO", enableBoundsSafeBuffersSetting: "YES"], + [gccOptimizationLevelSetting: "s", enableEnhancedSecuritySetting: "NO", enableBoundsSafeBuffersSetting: "NO"], + + [enableEnhancedSecuritySetting: "YES"], + [enableBoundsSafeBuffersSetting: "YES"], ] for override in overrides { @@ -8583,6 +9188,7 @@ fileprivate struct TaskConstructionTests: CoreBasedTests { } } + @Test(.requireSDKs(.macOS)) func warningSuppression() async throws { try await withTemporaryDirectory { tmpDir in