From a292ef6ce6bd05c0a73c335f6bbbbc6d65b5a3c2 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Mon, 29 Sep 2025 14:39:10 -0700 Subject: [PATCH] [BoundsSafety] Add build settings to control the bounds check mode for `-fbounds-safety` This patch introduces two new build settings The first is `CLANG_BOUNDS_SAFETY_BRINGUP_MISSING_CHECKS`. This setting can be used to control which new bounds checks are enabled. It takes two special values: 1. `none` - This disables all the new bounds checks. This corresponds to `-fno-bounds-safety-bringup-missing-checks`. 2. `default` - This will use the compiler default (i.e. the build system won't pass the `-fbounds-safety-bringup-missing-checks=` flag). If the build setting value is not any of the special values it is passed directly as an argument to `-fbounds-safety-bringup-missing-checks=`. This allows enabling a specific set of checks. E.g.: ``` CLANG_BOUNDS_SAFETY_BRINGUP_MISSING_CHECKS=access_size,return_size ``` would pass `-fbounds-safety-bringup-missing-checks=access_size,return-size`. The second build setting is `CLANG_BOUNDS_SAFETY_BRINGUP_MISSING_CHECKS_OPT_OUTS`. This setting is intended to complement the previous build setting by providing a way to opt out of specific bounds checks. E.g.: ``` CLANG_BOUNDS_SAFETY_BRINGUP_MISSING_CHECKS=batch_0 CLANG_BOUNDS_SAFETY_BRINGUP_MISSING_CHECKS_OPT_OUTS=access_size ``` This is equivalent to ``` -fbound-safety-bringup-missing-checks=batch_0 -fno-bounds-safety-bringup-missing-checks=access_size ``` This opts the compilation unit into all checks in the `batch_0` group except the `access_size` bounds check. These new build settings only apply when all of the following are true: * `CLANG_ENABLE_BOUNDS_SAFETY` or `CLANG_ENABLE_BOUNDS_ATTRIBUTES` is enabled. * For C source files The existing `boundsSafetyCLanguageExtension` test case has been modified to test the behavior of these new flags. rdar://161599307 --- .../SWBUniversalPlatform/Specs/Clang.xcspec | 38 +++++++++++ .../TaskConstructionTests.swift | 66 +++++++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/Sources/SWBUniversalPlatform/Specs/Clang.xcspec b/Sources/SWBUniversalPlatform/Specs/Clang.xcspec index c1fc1295..4f189ce3 100644 --- a/Sources/SWBUniversalPlatform/Specs/Clang.xcspec +++ b/Sources/SWBUniversalPlatform/Specs/Clang.xcspec @@ -543,6 +543,44 @@ }; // Hidden. }, + { + Name = "CLANG_BOUNDS_SAFETY_BRINGUP_MISSING_CHECKS"; + Type = Enumeration; + FileTypes = ( + "sourcecode.c.c", + ); + Values = ( + "none", + "default", + ); + DefaultValue = "default"; + CommandLineArgs = { + "none" = ( "-fno-bounds-safety-bringup-missing-checks" ); + // Use the compiler default + "default" = (); + // E.g. `batch_0` or `all` or comma separated lists of checks to enable + "<>" = ( "-fbounds-safety-bringup-missing-checks=$(value)" ); + }; + + Condition = "$(CLANG_ENABLE_BOUNDS_ATTRIBUTES) || $(CLANG_ENABLE_BOUNDS_SAFETY)"; + // Hidden + }, + { + Name = "CLANG_BOUNDS_SAFETY_BRINGUP_MISSING_CHECKS_OPT_OUTS"; + Type = String; + FileTypes = ( + "sourcecode.c.c", + ); + DefaultValue = ""; + CommandLineArgs = { + "" = (); + // Comma separated list of checks to disable + "<>" = ( "-fno-bounds-safety-bringup-missing-checks=$(value)" ); + }; + Condition = "$(CLANG_ENABLE_BOUNDS_ATTRIBUTES) || $(CLANG_ENABLE_BOUNDS_SAFETY)"; + AppearsAfter = "CLANG_BOUNDS_SAFETY_BRINGUP_MISSING_CHECKS"; + // Hidden + }, { Name = "CLANG_ENABLE_APP_EXTENSION"; Type = Boolean; diff --git a/Tests/SWBTaskConstructionTests/TaskConstructionTests.swift b/Tests/SWBTaskConstructionTests/TaskConstructionTests.swift index a1015a45..e9250240 100644 --- a/Tests/SWBTaskConstructionTests/TaskConstructionTests.swift +++ b/Tests/SWBTaskConstructionTests/TaskConstructionTests.swift @@ -9185,6 +9185,72 @@ fileprivate struct TaskConstructionTests: CoreBasedTests { } } } + + // Test missing check build settings + let boundsSafetyMissingChecksSetting = "CLANG_BOUNDS_SAFETY_BRINGUP_MISSING_CHECKS" + let enableBoundsAttributesSetting = "CLANG_ENABLE_BOUNDS_ATTRIBUTES" + let boundsSafetyMissingChecksOptOutsSetting = "CLANG_BOUNDS_SAFETY_BRINGUP_MISSING_CHECKS_OPT_OUTS" + + for (enableBoundsSafetyBuildSetting, enableBoundsSafetyFlag) in [ + (enableBoundsSafetySetting,"-fbounds-safety"), + (enableBoundsAttributesSetting, "-fbounds-attributes")] { + + // Maps an array of build overrides to a closure that tests properties of the build overrides + let missingChecksOverrides = [ + [ enableBoundsSafetyBuildSetting: "YES", boundsSafetyMissingChecksSetting: "none"]: { (task: any PlannedTask) in + task.checkCommandLineContains(["-fno-bounds-safety-bringup-missing-checks"]) + }, + + // Default behavior is not pass the compiler flag and thus use the compiler default + [ enableBoundsSafetyBuildSetting: "YES", boundsSafetyMissingChecksSetting: "default"]: { (task: any PlannedTask) in + task.checkCommandLineDoesNotContain("-fno-bounds-safety-bringup-missing-checks") + task.checkCommandLineDoesNotContain("-fbounds-safety-bringup-missing-checks") + }, + [ enableBoundsSafetyBuildSetting: "YES"]: { (task: any PlannedTask) in + task.checkCommandLineDoesNotContain("-fno-bounds-safety-bringup-missing-checks") + task.checkCommandLineDoesNotContain("-fbounds-safety-bringup-missing-checks") + }, + + + [ enableBoundsSafetyBuildSetting: "YES", boundsSafetyMissingChecksSetting: "batch_0"]: { (task: any PlannedTask) in + task.checkCommandLineContains(["-fbounds-safety-bringup-missing-checks=batch_0"]) + task.checkCommandLineDoesNotContain("-fno-bounds-safety-bringup-missing-checks") + }, + [ enableBoundsSafetyBuildSetting: "YES", boundsSafetyMissingChecksSetting: "access_size,return_size"]: { (task: any PlannedTask) in + task.checkCommandLineContains(["-fbounds-safety-bringup-missing-checks=access_size,return_size"]) + task.checkCommandLineDoesNotContain("-fno-bounds-safety-bringup-missing-checks") + }, + + // Opt-outs + [ enableBoundsSafetyBuildSetting: "YES", + boundsSafetyMissingChecksSetting: "batch_0", + boundsSafetyMissingChecksOptOutsSetting: "access_size"]: { (task: any PlannedTask) in + task.checkCommandLineContains([ + "-fbounds-safety-bringup-missing-checks=batch_0", + "-fno-bounds-safety-bringup-missing-checks=access_size"]) + }, + [ enableBoundsSafetyBuildSetting: "YES", + boundsSafetyMissingChecksSetting: "batch_0", + boundsSafetyMissingChecksOptOutsSetting: "access_size,return_size"]: { (task: any PlannedTask) in + task.checkCommandLineContains([ + "-fbounds-safety-bringup-missing-checks=batch_0", + "-fno-bounds-safety-bringup-missing-checks=access_size,return_size"]) + }, + ] + + for (overrides, checkOverrideProperties) in missingChecksOverrides { + await tester.checkBuild(BuildParameters(configuration: "Debug", overrides: overrides), runDestination: .macOS, fs: fs) { results -> Void in + results.checkTarget("AppTarget") { target -> Void in + results.checkTask(.matchTarget(target), .matchRuleType("CompileC"), body: {task in + // Check the overrides contains -fbounds-safety or -fbounds-attributes + task.checkCommandLineContains([enableBoundsSafetyFlag]) + // Check properties specific to this array of overrides + checkOverrideProperties(task) + }) + } + } + } + } } }