From ef69d47d0307b0cb8738323c2c28afe900b8867b Mon Sep 17 00:00:00 2001 From: Sam Delmerico Date: Tue, 18 Apr 2023 17:32:43 -0400 Subject: [PATCH] disable mixed builds for sanitized cc modules The Bazel rules don't currently support any sanitizers other than ubsan, so we should disable mixed builds for modules which are sanitized. Test: go test Bug: 278772861 Bug: 253433725 Change-Id: Ia01fb8cb59154bdfb21a111b04af0350e1876b0b --- cc/cc.go | 45 +++++++-- cc/cc_test.go | 258 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 295 insertions(+), 8 deletions(-) diff --git a/cc/cc.go b/cc/cc.go index 605422213..82cfe9079 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -1893,17 +1893,46 @@ func (c *Module) QueueBazelCall(ctx android.BaseModuleContext) { // IsMixedBuildSupported returns true if the module should be analyzed by Bazel // in any of the --bazel-mode(s). func (c *Module) IsMixedBuildSupported(ctx android.BaseModuleContext) bool { - // TODO(b/261058727): Remove this (enable mixed builds for modules with UBSan) - // Currently we can only support ubsan when minimum runtime is used. - return c.bazelHandler != nil && (!isUbsanEnabled(c) || c.MinimalRuntimeNeeded()) -} - -func isUbsanEnabled(c *Module) bool { - if c.sanitize == nil { + if !allEnabledSanitizersSupportedByBazel(c) { + //TODO(b/278772861) support sanitizers in Bazel rules return false } + return c.bazelHandler != nil +} + +func allEnabledSanitizersSupportedByBazel(c *Module) bool { + if c.sanitize == nil { + return true + } sanitizeProps := &c.sanitize.Properties.SanitizeMutated - return Bool(sanitizeProps.Integer_overflow) || len(sanitizeProps.Misc_undefined) > 0 + + unsupportedSanitizers := []*bool{ + sanitizeProps.Safestack, + sanitizeProps.Cfi, + sanitizeProps.Scudo, + BoolPtr(len(c.sanitize.Properties.Sanitize.Recover) > 0), + BoolPtr(c.sanitize.Properties.Sanitize.Blocklist != nil), + } + for _, san := range unsupportedSanitizers { + if Bool(san) { + return false + } + } + + for _, san := range Sanitizers { + if san == intOverflow { + // TODO(b/261058727): enable mixed builds for all modules with UBSan + // Currently we can only support ubsan when minimum runtime is used. + ubsanEnabled := Bool(sanitizeProps.Integer_overflow) || len(sanitizeProps.Misc_undefined) > 0 + if ubsanEnabled && !c.MinimalRuntimeNeeded() { + return false + } + } else if c.sanitize.isSanitizerEnabled(san) { + return false + } + } + + return true } func GetApexConfigKey(ctx android.BaseModuleContext) *android.ApexConfigKey { diff --git a/cc/cc_test.go b/cc/cc_test.go index b986511f0..830de40c0 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -3114,6 +3114,11 @@ func TestLibDepAndroidMkExportInMixedBuilds(t *testing.T) { whole_static_libs: ["whole_static_dep"], shared_libs: ["shared_dep"], gtest: false, + sanitize: { + // cc_test modules default to memtag_heap: true, + // but this adds extra dependencies that we don't care about + never: true, + } } cc_binary { name: "binary", @@ -5101,3 +5106,256 @@ func TestDclaLibraryInApex(t *testing.T) { expectedOutputFiles := []string{"outputbase/execroot/__main__/foo.so"} android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings()) } + +func TestDisableSanitizerVariantsInMixedBuilds(t *testing.T) { + t.Parallel() + bp := ` + cc_library_static { + name: "foo_ubsan_minimal", + srcs: ["foo.cc"], + bazel_module: { label: "//foo_ubsan_minimal" }, + sanitize: { + all_undefined: true, + integer_overflow: true, + }, + } + cc_library_static { + name: "foo", + srcs: ["foo.cc"], + bazel_module: { label: "//foo" }, + sanitize: { + address: true, + hwaddress: true, + fuzzer: true, + integer_overflow: true, + scs: true, + }, + } + cc_library_static { + name: "foo_tsan", + srcs: ["foo.cc"], + bazel_module: { label: "//foo_tsan" }, + sanitize: { + thread: true, + }, + } + cc_library_static { + name: "foo_cfi", + srcs: ["foo.cc"], + bazel_module: { label: "//foo_cfi" }, + sanitize: { + cfi: true, + }, + } + cc_library_static { + name: "foo_memtag_stack", + srcs: ["foo.cc"], + bazel_module: { label: "//foo_memtag_stack" }, + sanitize: { + memtag_stack: true, + }, + } + cc_library_static { + name: "foo_memtag_heap", + srcs: ["foo.cc"], + bazel_module: { label: "//foo_memtag_heap" }, + sanitize: { + memtag_heap: true, + }, + } + cc_library_static { + name: "foo_safestack", + srcs: ["foo.cc"], + bazel_module: { label: "//foo_safestack" }, + sanitize: { + safestack: true, + }, + } + cc_library_static { + name: "foo_scudo", + srcs: ["foo.cc"], + bazel_module: { label: "//foo_scudo" }, + sanitize: { + scudo: true, + }, + } + ` + testcases := []struct { + name string + variant string + expectedOutputPaths []string + }{ + { + name: "foo_ubsan_minimal", + variant: "android_arm64_armv8-a_static_apex28", + expectedOutputPaths: []string{ + "outputbase/execroot/__main__/foo_ubsan_minimal.a", + }, + }, + { + name: "foo", + variant: "android_arm64_armv8-a_static_apex28", + expectedOutputPaths: []string{ + "outputbase/execroot/__main__/foo.a", + }, + }, + { + name: "foo", + variant: "android_arm_armv7-a-neon_static_asan_apex28", + expectedOutputPaths: []string{ + "out/soong/.intermediates/foo/android_arm_armv7-a-neon_static_asan_apex28/foo.a", + }, + }, + { + name: "foo", + variant: "android_arm64_armv8-a_static_hwasan_apex28", + expectedOutputPaths: []string{ + "out/soong/.intermediates/foo/android_arm64_armv8-a_static_hwasan_apex28/foo.a", + }, + }, + { + name: "foo", + variant: "android_arm64_armv8-a_static_fuzzer_apex28", + expectedOutputPaths: []string{ + "out/soong/.intermediates/foo/android_arm64_armv8-a_static_fuzzer_apex28/foo.a", + }, + }, + { + name: "foo", + variant: "android_arm_armv7-a-neon_static_asan_fuzzer_apex28", + expectedOutputPaths: []string{ + "out/soong/.intermediates/foo/android_arm_armv7-a-neon_static_asan_fuzzer_apex28/foo.a", + }, + }, + { + name: "foo", + variant: "android_arm64_armv8-a_static_hwasan_fuzzer_apex28", + expectedOutputPaths: []string{ + "out/soong/.intermediates/foo/android_arm64_armv8-a_static_hwasan_fuzzer_apex28/foo.a", + }, + }, + { + name: "foo", + variant: "android_arm64_armv8-a_static_scs_apex28", + expectedOutputPaths: []string{ + "out/soong/.intermediates/foo/android_arm64_armv8-a_static_scs_apex28/foo.a", + }, + }, + { + name: "foo", + variant: "android_arm64_armv8-a_static_hwasan_scs_apex28", + expectedOutputPaths: []string{ + "out/soong/.intermediates/foo/android_arm64_armv8-a_static_hwasan_scs_apex28/foo.a", + }, + }, + { + name: "foo", + variant: "android_arm64_armv8-a_static_hwasan_scs_fuzzer_apex28", + expectedOutputPaths: []string{ + "out/soong/.intermediates/foo/android_arm64_armv8-a_static_hwasan_scs_fuzzer_apex28/foo.a", + }, + }, + { + name: "foo_tsan", + variant: "android_arm64_armv8-a_static_apex28", + expectedOutputPaths: []string{ + "outputbase/execroot/__main__/foo_tsan.a", + }, + }, + { + name: "foo_tsan", + variant: "android_arm64_armv8-a_static_tsan_apex28", + expectedOutputPaths: []string{ + "out/soong/.intermediates/foo_tsan/android_arm64_armv8-a_static_tsan_apex28/foo_tsan.a", + }, + }, + { + name: "foo_cfi", + variant: "android_arm64_armv8-a_static_apex28", + expectedOutputPaths: []string{ + "outputbase/execroot/__main__/foo_cfi.a", + }, + }, + { + name: "foo_cfi", + variant: "android_arm64_armv8-a_static_cfi_apex28", + expectedOutputPaths: []string{ + "out/soong/.intermediates/foo_cfi/android_arm64_armv8-a_static_cfi_apex28/foo_cfi.a", + }, + }, + { + name: "foo_memtag_stack", + variant: "android_arm64_armv8-a_static_apex28", + expectedOutputPaths: []string{ + "out/soong/.intermediates/foo_memtag_stack/android_arm64_armv8-a_static_apex28/foo_memtag_stack.a", + }, + }, + { + name: "foo_memtag_heap", + variant: "android_arm64_armv8-a_static_apex28", + expectedOutputPaths: []string{ + "out/soong/.intermediates/foo_memtag_heap/android_arm64_armv8-a_static_apex28/foo_memtag_heap.a", + }, + }, + { + name: "foo_safestack", + variant: "android_arm64_armv8-a_static_apex28", + expectedOutputPaths: []string{ + "out/soong/.intermediates/foo_safestack/android_arm64_armv8-a_static_apex28/foo_safestack.a", + }, + }, + { + name: "foo_scudo", + variant: "android_arm64_armv8-a_static_apex28", + expectedOutputPaths: []string{ + "out/soong/.intermediates/foo_scudo/android_arm64_armv8-a_static_apex28/foo_scudo.a", + }, + }, + } + + ctx := android.GroupFixturePreparers( + prepareForCcTest, + prepareForAsanTest, + android.FixtureRegisterWithContext(registerTestMutators), + android.FixtureModifyConfig(func(config android.Config) { + config.BazelContext = android.MockBazelContext{ + OutputBaseDir: "outputbase", + LabelToCcInfo: map[string]cquery.CcInfo{ + "//foo_ubsan_minimal": { + RootStaticArchives: []string{"foo_ubsan_minimal.a"}, + }, + "//foo": { + RootStaticArchives: []string{"foo.a"}, + }, + "//foo_tsan": { + RootStaticArchives: []string{"foo_tsan.a"}, + }, + "//foo_cfi": { + RootStaticArchives: []string{"foo_cfi.a"}, + }, + "//foo_memtag_stack": { + RootStaticArchives: []string{"INVALID_ARCHIVE.a"}, + }, + "//foo_memtag_heap": { + RootStaticArchives: []string{"INVALID_ARCHIVE.a"}, + }, + "//foo_safestack": { + RootStaticArchives: []string{"INVALID_ARCHIVE.a"}, + }, + "//foo_scudo": { + RootStaticArchives: []string{"INVALID_ARCHIVE.a"}, + }, + }, + } + }), + ).RunTestWithBp(t, bp).TestContext + + for _, tc := range testcases { + fooMod := ctx.ModuleForTests(tc.name, tc.variant).Module() + outputFiles, err := fooMod.(android.OutputFileProducer).OutputFiles("") + if err != nil { + t.Errorf("Unexpected error getting cc_object outputfiles %s", err) + } + android.AssertPathsRelativeToTopEquals(t, "output files", tc.expectedOutputPaths, outputFiles) + } +}