diff options
-rw-r--r-- | android/bazel.go | 19 | ||||
-rw-r--r-- | android/bazel_handler.go | 4 | ||||
-rw-r--r-- | android/makevars.go | 1 | ||||
-rw-r--r-- | cc/cc.go | 2 | ||||
-rw-r--r-- | cc/sanitize.go | 29 | ||||
-rw-r--r-- | mk2rbc/cmd/mk2rbc.go | 25 | ||||
-rw-r--r-- | mk2rbc/mk2rbc.go | 57 | ||||
-rw-r--r-- | rust/Android.bp | 1 | ||||
-rw-r--r-- | rust/binary.go | 5 | ||||
-rw-r--r-- | rust/config/allowed_list.go | 1 | ||||
-rw-r--r-- | rust/fuzz.go | 2 | ||||
-rw-r--r-- | rust/rust_test.go | 7 | ||||
-rw-r--r-- | rust/sanitize.go | 189 | ||||
-rw-r--r-- | rust/sanitize_test.go | 365 | ||||
-rw-r--r-- | rust/test.go | 4 | ||||
-rw-r--r-- | rust/testing.go | 10 | ||||
-rw-r--r-- | rust/vendor_snapshot_test.go | 34 | ||||
-rw-r--r-- | scripts/Android.bp | 94 | ||||
-rwxr-xr-x | scripts/manifest.py | 2 | ||||
-rwxr-xr-x | scripts/manifest_check.py | 4 | ||||
-rwxr-xr-x | scripts/manifest_fixer.py | 2 | ||||
-rwxr-xr-x | scripts/manifest_fixer_test.py | 109 | ||||
-rw-r--r-- | scripts/test_config_fixer.py | 2 | ||||
-rw-r--r-- | scripts/test_config_fixer_test.py | 6 |
24 files changed, 736 insertions, 238 deletions
diff --git a/android/bazel.go b/android/bazel.go index 3bc104d1d..26d70e48f 100644 --- a/android/bazel.go +++ b/android/bazel.go @@ -188,6 +188,7 @@ var ( "packages/apps/QuickSearchBox":/* recursive = */ true, "packages/apps/WallpaperPicker":/* recursive = */ false, + "prebuilts/gcc":/* recursive = */ true, "prebuilts/sdk":/* recursive = */ false, "prebuilts/sdk/current/extras/app-toolkit":/* recursive = */ false, "prebuilts/sdk/current/support":/* recursive = */ false, @@ -250,6 +251,8 @@ var ( // Per-module denylist to always opt modules out of both bp2build and mixed builds. bp2buildModuleDoNotConvertList = []string{ + "libprotobuf-cpp-full", "libprotobuf-cpp-lite", // Unsupported product&vendor suffix. b/204811222 and b/204810610. + "libc_malloc_debug", // depends on libunwindstack, which depends on unsupported module art_cc_library_statics "libbase_ndk", // http://b/186826477, fails to link libctscamera2_jni for device (required for CtsCameraTestCases) @@ -270,14 +273,8 @@ var ( "platform_tools_properties", "build_tools_source_properties", - // //external/libcap/... - "cap_names.h", // http://b/196105070 host toolchain misconfigurations for mixed builds - "libcap", // http://b/196105070 host toolchain misconfigurations for mixed builds - - "libminijail", // depends on unconverted modules: libcap - "getcap", // depends on unconverted modules: libcap - "setcap", // depends on unconverted modules: libcap - "minijail0", // depends on unconverted modules: libcap, libminijail + "libminijail", // b/202491296: Uses unsupported c_std property. + "minijail0", // depends on unconverted modules: libminijail "drop_privs", // depends on unconverted modules: libminijail // Tests. Handle later. @@ -381,7 +378,11 @@ func ShouldKeepExistingBuildFileForDir(dir string) bool { // MixedBuildsEnabled checks that a module is ready to be replaced by a // converted or handcrafted Bazel target. -func (b *BazelModuleBase) MixedBuildsEnabled(ctx BazelConversionPathContext) bool { +func (b *BazelModuleBase) MixedBuildsEnabled(ctx ModuleContext) bool { + if ctx.Os() == Windows { + // Windows toolchains are not currently supported. + return false + } if !ctx.Config().BazelContext.BazelEnabled() { return false } diff --git a/android/bazel_handler.go b/android/bazel_handler.go index 3c6212e0c..0052551f4 100644 --- a/android/bazel_handler.go +++ b/android/bazel_handler.go @@ -602,8 +602,6 @@ def get_arch(target): platform_name = build_options(target)["//command_line_option:platforms"][0].name if platform_name == "host": return "HOST" - elif platform_name.startswith("linux_glibc_"): - return platform_name[len("linux_glibc_"):] + "|" + platform_name[:len("linux_glibc_")-1] elif platform_name.startswith("android_"): return platform_name[len("android_"):] + "|" + platform_name[:len("android_")-1] elif platform_name.startswith("linux_"): @@ -865,7 +863,7 @@ func getConfigString(key cqueryKey) string { arch = "x86_64" } os := key.configKey.osType.Name - if len(os) == 0 || os == "common_os" { + if len(os) == 0 || os == "common_os" || os == "linux_glibc" { // Use host OS, which is currently hardcoded to be linux. os = "linux" } diff --git a/android/makevars.go b/android/makevars.go index 8825d1aa6..665d57625 100644 --- a/android/makevars.go +++ b/android/makevars.go @@ -422,6 +422,7 @@ func (s *makeVarsSingleton) writeLate(phonies []phony, dists []dist) []byte { fmt.Fprintln(buf) for _, dist := range dists { + fmt.Fprintf(buf, ".PHONY: %s\n", strings.Join(dist.goals, " ")) fmt.Fprintf(buf, "$(call dist-for-goals,%s,%s)\n", strings.Join(dist.goals, " "), strings.Join(dist.paths, " ")) } @@ -1717,7 +1717,7 @@ func (c *Module) maybeGenerateBazelActions(actx android.ModuleContext) bool { bazelActionsUsed := false // Mixed builds mode is disabled for modules outside of device OS. // TODO(b/200841190): Support non-device OS in mixed builds. - if c.MixedBuildsEnabled(actx) && c.bazelHandler != nil && actx.Os().Class == android.Device { + if c.MixedBuildsEnabled(actx) && c.bazelHandler != nil { bazelActionsUsed = c.bazelHandler.GenerateBazelBuildActions(actx, bazelModuleLabel) } return bazelActionsUsed diff --git a/cc/sanitize.go b/cc/sanitize.go index c7e841122..93d4b4c54 100644 --- a/cc/sanitize.go +++ b/cc/sanitize.go @@ -88,7 +88,7 @@ const ( intOverflow scs Fuzzer - memtag_heap + Memtag_heap cfi // cfi is last to prevent it running before incompatible mutators ) @@ -99,7 +99,7 @@ var Sanitizers = []SanitizerType{ intOverflow, scs, Fuzzer, - memtag_heap, + Memtag_heap, cfi, // cfi is last to prevent it running before incompatible mutators } @@ -118,7 +118,7 @@ func (t SanitizerType) variationName() string { return "cfi" case scs: return "scs" - case memtag_heap: + case Memtag_heap: return "memtag_heap" case Fuzzer: return "fuzzer" @@ -134,7 +134,7 @@ func (t SanitizerType) name() string { return "address" case Hwasan: return "hwaddress" - case memtag_heap: + case Memtag_heap: return "memtag_heap" case tsan: return "thread" @@ -156,7 +156,7 @@ func (t SanitizerType) registerMutators(ctx android.RegisterMutatorsContext) { case Asan, Hwasan, Fuzzer, scs, tsan, cfi: ctx.TopDown(t.variationName()+"_deps", sanitizerDepsMutator(t)) ctx.BottomUp(t.variationName(), sanitizerMutator(t)) - case memtag_heap, intOverflow: + case Memtag_heap, intOverflow: // do nothing default: panic(fmt.Errorf("unknown SanitizerType %d", t)) @@ -179,6 +179,8 @@ func (*Module) SanitizerSupported(t SanitizerType) bool { return true case Fuzzer: return true + case Memtag_heap: + return true default: return false } @@ -467,7 +469,7 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { s.Scs = nil } - // memtag_heap is only implemented on AArch64. + // Memtag_heap is only implemented on AArch64. if ctx.Arch().ArchType != android.Arm64 { s.Memtag_heap = nil } @@ -813,7 +815,7 @@ func (sanitize *sanitize) getSanitizerBoolPtr(t SanitizerType) *bool { return sanitize.Properties.Sanitize.Cfi case scs: return sanitize.Properties.Sanitize.Scs - case memtag_heap: + case Memtag_heap: return sanitize.Properties.Sanitize.Memtag_heap case Fuzzer: return sanitize.Properties.Sanitize.Fuzzer @@ -829,7 +831,7 @@ func (sanitize *sanitize) isUnsanitizedVariant() bool { !sanitize.isSanitizerEnabled(tsan) && !sanitize.isSanitizerEnabled(cfi) && !sanitize.isSanitizerEnabled(scs) && - !sanitize.isSanitizerEnabled(memtag_heap) && + !sanitize.isSanitizerEnabled(Memtag_heap) && !sanitize.isSanitizerEnabled(Fuzzer) } @@ -859,7 +861,7 @@ func (sanitize *sanitize) SetSanitizer(t SanitizerType, b bool) { sanitize.Properties.Sanitize.Cfi = bPtr case scs: sanitize.Properties.Sanitize.Scs = bPtr - case memtag_heap: + case Memtag_heap: sanitize.Properties.Sanitize.Memtag_heap = bPtr case Fuzzer: sanitize.Properties.Sanitize.Fuzzer = bPtr @@ -1148,7 +1150,7 @@ func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { if lib, ok := snapshot.StaticLibs[noteDep]; ok { noteDep = lib } - depTag := libraryDependencyTag{Kind: staticLibraryDependency, wholeStatic: true} + depTag := StaticDepTag(true) variations := append(mctx.Target().Variations(), blueprint.Variation{Mutator: "link", Variation: "static"}) if c.Device() { @@ -1318,6 +1320,10 @@ var _ PlatformSanitizeable = (*Module)(nil) func sanitizerMutator(t SanitizerType) func(android.BottomUpMutatorContext) { return func(mctx android.BottomUpMutatorContext) { if c, ok := mctx.Module().(PlatformSanitizeable); ok && c.SanitizePropDefined() { + + // Make sure we're not setting CFI to any value if it's not supported. + cfiSupported := mctx.Module().(PlatformSanitizeable).SanitizerSupported(cfi) + if c.Binary() && c.IsSanitizerEnabled(t) { modules := mctx.CreateVariations(t.variationName()) modules[0].(PlatformSanitizeable).SetSanitizer(t, true) @@ -1338,7 +1344,6 @@ func sanitizerMutator(t SanitizerType) func(android.BottomUpMutatorContext) { // is redirected to the sanitized variant of the dependent module. defaultVariation := t.variationName() // Not all PlatformSanitizeable modules support the CFI sanitizer - cfiSupported := mctx.Module().(PlatformSanitizeable).SanitizerSupported(cfi) mctx.SetDefaultDependencyVariation(&defaultVariation) modules := mctx.CreateVariations("", t.variationName()) @@ -1385,7 +1390,7 @@ func sanitizerMutator(t SanitizerType) func(android.BottomUpMutatorContext) { modules[0].(PlatformSanitizeable).SetInSanitizerDir() } - if mctx.Device() && t.incompatibleWithCfi() { + if mctx.Device() && t.incompatibleWithCfi() && cfiSupported { // TODO: Make sure that cfi mutator runs "after" any of the sanitizers that // are incompatible with cfi modules[0].(PlatformSanitizeable).SetSanitizer(cfi, false) diff --git a/mk2rbc/cmd/mk2rbc.go b/mk2rbc/cmd/mk2rbc.go index 0f030d3ea..7bb0246be 100644 --- a/mk2rbc/cmd/mk2rbc.go +++ b/mk2rbc/cmd/mk2rbc.go @@ -81,7 +81,7 @@ func init() { var backupSuffix string var tracedVariables []string -var errorLogger = errorsByType{data: make(map[string]datum)} +var errorLogger = errorSink{data: make(map[string]datum)} var makefileFinder = &LinuxMakefileFinder{} var versionDefaultsMk = filepath.Join("build", "make", "core", "version_defaults.mk") @@ -339,9 +339,7 @@ func convertOne(mkFile string) (ok bool) { WarnPartialSuccess: !*noWarn, SourceFS: os.DirFS(*rootDir), MakefileFinder: makefileFinder, - } - if *errstat { - mk2starRequest.ErrorLogger = errorLogger + ErrorLogger: errorLogger, } ss, err := mk2rbc.Convert(mk2starRequest) if err != nil { @@ -456,10 +454,8 @@ func printStats() { } } } - if *verbose { - fmt.Fprintf(os.Stderr, "%-16s%5d\n", "Succeeded:", nOk) - fmt.Fprintf(os.Stderr, "%-16s%5d\n", "Partial:", nPartial) - fmt.Fprintf(os.Stderr, "%-16s%5d\n", "Failed:", nFailed) + if *verbose && (nPartial > 0 || nFailed > 0) { + fmt.Fprintln(os.Stderr, "Succeeded: ", nOk, " Partial: ", nPartial, " Failed: ", nFailed) } } @@ -468,11 +464,18 @@ type datum struct { formattingArgs []string } -type errorsByType struct { +type errorSink struct { data map[string]datum } -func (ebt errorsByType) NewError(message string, node parser.Node, args ...interface{}) { +func (ebt errorSink) NewError(sourceFile string, sourceLine int, node parser.Node, message string, args ...interface{}) { + fmt.Fprintf(os.Stderr, "%s:%d ", sourceFile, sourceLine) + fmt.Fprintf(os.Stderr, message, args...) + fmt.Fprintln(os.Stderr) + if !*errstat { + return + } + v, exists := ebt.data[message] if exists { v.count++ @@ -497,7 +500,7 @@ func (ebt errorsByType) NewError(message string, node parser.Node, args ...inter ebt.data[message] = v } -func (ebt errorsByType) printStatistics() { +func (ebt errorSink) printStatistics() { if len(ebt.data) > 0 { fmt.Fprintln(os.Stderr, "Error counts:") } diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go index 0e39c3222..7ce183495 100644 --- a/mk2rbc/mk2rbc.go +++ b/mk2rbc/mk2rbc.go @@ -161,7 +161,7 @@ type Request struct { RootDir string // root directory path used to resolve included files OutputSuffix string // generated Starlark files suffix OutputDir string // if set, root of the output hierarchy - ErrorLogger ErrorMonitorCB + ErrorLogger ErrorLogger TracedVariables []string // trace assignment to these variables TraceCalls bool WarnPartialSuccess bool @@ -169,10 +169,10 @@ type Request struct { MakefileFinder MakefileFinder } -// An error sink allowing to gather error statistics. -// NewError is called on every error encountered during processing. -type ErrorMonitorCB interface { - NewError(s string, node mkparser.Node, args ...interface{}) +// ErrorLogger prints errors and gathers error statistics. +// Its NewError function is called on every error encountered during the conversion. +type ErrorLogger interface { + NewError(sourceFile string, sourceLine int, node mkparser.Node, text string, args ...interface{}) } // Derives module name for a given file. It is base name @@ -381,6 +381,7 @@ type StarlarkScript struct { warnPartialSuccess bool sourceFS fs.FS makefileFinder MakefileFinder + nodeLocator func(pos mkparser.Pos) int } func (ss *StarlarkScript) newNode(node starlarkNode) { @@ -406,7 +407,7 @@ type parseContext struct { fatalError error builtinMakeVars map[string]starlarkExpr outputSuffix string - errorLogger ErrorMonitorCB + errorLogger ErrorLogger tracedVariables map[string]bool // variables to be traced in the generated script variables map[string]variable varAssignments *varAssignmentScope @@ -973,25 +974,16 @@ func (ctx *parseContext) processBranch(check *mkparser.Directive) { ctx.pushReceiver(&block) for ctx.hasNodes() { node := ctx.getNode() - if ctx.handleSimpleStatement(node) { - continue - } - switch d := node.(type) { - case *mkparser.Directive: + if d, ok := node.(*mkparser.Directive); ok { switch d.Name { case "else", "elifdef", "elifndef", "elifeq", "elifneq", "endif": ctx.popReceiver() ctx.receiver.newNode(&block) ctx.backNode() return - case "ifdef", "ifndef", "ifeq", "ifneq": - ctx.handleIfBlock(d) - default: - ctx.errorf(d, "unexpected directive %s", d.Name) } - default: - ctx.errorf(node, "unexpected statement") } + ctx.handleSimpleStatement(node) } ctx.fatalError = fmt.Errorf("no matching endif for %s", check.Dump()) ctx.popReceiver() @@ -1031,7 +1023,7 @@ func (ctx *parseContext) parseCondition(check *mkparser.Directive) starlarkNode func (ctx *parseContext) newBadExpr(node mkparser.Node, text string, args ...interface{}) starlarkExpr { message := fmt.Sprintf(text, args...) if ctx.errorLogger != nil { - ctx.errorLogger.NewError(text, node, args) + ctx.errorLogger.NewError(ctx.script.mkFile, ctx.script.nodeLocator(node.Pos()), node, text, args...) } ctx.script.hasErrors = true return &badExpr{node, message} @@ -1493,9 +1485,7 @@ func (ctx *parseContext) parseMakeString(node mkparser.Node, mk *mkparser.MakeSt // Handles the statements whose treatment is the same in all contexts: comment, // assignment, variable (which is a macro call in reality) and all constructs that // do not handle in any context ('define directive and any unrecognized stuff). -// Return true if we handled it. -func (ctx *parseContext) handleSimpleStatement(node mkparser.Node) bool { - handled := true +func (ctx *parseContext) handleSimpleStatement(node mkparser.Node) { switch x := node.(type) { case *mkparser.Comment: ctx.maybeHandleAnnotation(x) @@ -1510,13 +1500,14 @@ func (ctx *parseContext) handleSimpleStatement(node mkparser.Node) bool { ctx.handleDefine(x) case "include", "-include": ctx.handleInclude(node, ctx.parseMakeString(node, x.Args), x.Name[0] != '-') + case "ifeq", "ifneq", "ifdef", "ifndef": + ctx.handleIfBlock(x) default: - handled = false + ctx.errorf(x, "unexpected directive %s", x.Name) } default: ctx.errorf(x, "unsupported line %s", strings.ReplaceAll(x.Dump(), "\n", "\n#")) } - return handled } // Processes annotation. An annotation is a comment that starts with #RBC# and provides @@ -1554,11 +1545,12 @@ func (ctx *parseContext) carryAsComment(failedNode mkparser.Node) { // records that the given node failed to be converted and includes an explanatory message func (ctx *parseContext) errorf(failedNode mkparser.Node, message string, args ...interface{}) { if ctx.errorLogger != nil { - ctx.errorLogger.NewError(message, failedNode, args...) + ctx.errorLogger.NewError(ctx.script.mkFile, ctx.script.nodeLocator(failedNode.Pos()), failedNode, message, args...) } message = fmt.Sprintf(message, args...) ctx.insertComment(fmt.Sprintf("# MK2RBC TRANSLATION ERROR: %s", message)) ctx.carryAsComment(failedNode) + ctx.script.hasErrors = true } @@ -1675,6 +1667,7 @@ func Convert(req Request) (*StarlarkScript, error) { warnPartialSuccess: req.WarnPartialSuccess, sourceFS: req.SourceFS, makefileFinder: req.MakefileFinder, + nodeLocator: func(pos mkparser.Pos) int { return parser.Unpack(pos).Line }, } ctx := newParseContext(starScript, nodes) ctx.outputSuffix = req.OutputSuffix @@ -1688,21 +1681,7 @@ func Convert(req Request) (*StarlarkScript, error) { } ctx.pushReceiver(starScript) for ctx.hasNodes() && ctx.fatalError == nil { - node := ctx.getNode() - if ctx.handleSimpleStatement(node) { - continue - } - switch x := node.(type) { - case *mkparser.Directive: - switch x.Name { - case "ifeq", "ifneq", "ifdef", "ifndef": - ctx.handleIfBlock(x) - default: - ctx.errorf(x, "unexpected directive %s", x.Name) - } - default: - ctx.errorf(x, "unsupported line") - } + ctx.handleSimpleStatement(ctx.getNode()) } if ctx.fatalError != nil { return nil, ctx.fatalError diff --git a/rust/Android.bp b/rust/Android.bp index 0ee673de4..cda2dbc6a 100644 --- a/rust/Android.bp +++ b/rust/Android.bp @@ -54,6 +54,7 @@ bootstrap_go_package { "project_json_test.go", "protobuf_test.go", "rust_test.go", + "sanitize_test.go", "source_provider_test.go", "test_test.go", "vendor_snapshot_test.go", diff --git a/rust/binary.go b/rust/binary.go index cba2f7232..db91ccb9a 100644 --- a/rust/binary.go +++ b/rust/binary.go @@ -34,6 +34,7 @@ type BinaryCompilerProperties struct { type binaryInterface interface { binary() bool staticallyLinked() bool + testBinary() bool } type binaryDecorator struct { @@ -172,3 +173,7 @@ func (binary *binaryDecorator) binary() bool { func (binary *binaryDecorator) staticallyLinked() bool { return Bool(binary.Properties.Static_executable) } + +func (binary *binaryDecorator) testBinary() bool { + return false +} diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go index d66db1467..9b88b6d81 100644 --- a/rust/config/allowed_list.go +++ b/rust/config/allowed_list.go @@ -17,6 +17,7 @@ var ( "external/vm_tools/p9", "frameworks/native/libs/binder/rust", "frameworks/proto_logging/stats", + "hardware/interfaces/security", "packages/modules/Bluetooth", "packages/modules/DnsResolver", "packages/modules/Uwb", diff --git a/rust/fuzz.go b/rust/fuzz.go index c52f5f9e2..55921ba4b 100644 --- a/rust/fuzz.go +++ b/rust/fuzz.go @@ -36,7 +36,7 @@ type fuzzDecorator struct { fuzzPackagedModule fuzz.FuzzPackagedModule } -var _ compiler = (*binaryDecorator)(nil) +var _ compiler = (*fuzzDecorator)(nil) // rust_binary produces a binary that is runnable on a device. func RustFuzzFactory() android.Module { diff --git a/rust/rust_test.go b/rust/rust_test.go index 9b518c8c5..b99b1e63b 100644 --- a/rust/rust_test.go +++ b/rust/rust_test.go @@ -442,3 +442,10 @@ func TestLibrarySizes(t *testing.T) { m.Output("unstripped/libwaldo.dylib.so.bloaty.csv") m.Output("libwaldo.dylib.so.bloaty.csv") } + +func assertString(t *testing.T, got, expected string) { + t.Helper() + if got != expected { + t.Errorf("expected %q got %q", expected, got) + } +} diff --git a/rust/sanitize.go b/rust/sanitize.go index baa383da6..fdb342d40 100644 --- a/rust/sanitize.go +++ b/rust/sanitize.go @@ -15,20 +15,39 @@ package rust import ( + "fmt" + "strings" + + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" + "android/soong/android" "android/soong/cc" "android/soong/rust/config" - "fmt" - "github.com/google/blueprint" ) +// TODO: When Rust has sanitizer-parity with CC, deduplicate this struct type SanitizeProperties struct { // enable AddressSanitizer, HWAddressSanitizer, and others. Sanitize struct { Address *bool `android:"arch_variant"` Hwaddress *bool `android:"arch_variant"` - Fuzzer *bool `android:"arch_variant"` - Never *bool `android:"arch_variant"` + + // Memory-tagging, only available on arm64 + // if diag.memtag unset or false, enables async memory tagging + Memtag_heap *bool `android:"arch_variant"` + Fuzzer *bool `android:"arch_variant"` + Never *bool `android:"arch_variant"` + + // Sanitizers to run in the diagnostic mode (as opposed to the release mode). + // Replaces abort() on error with a human-readable error message. + // Address and Thread sanitizers always run in diagnostic mode. + Diag struct { + // Memory-tagging, only available on arm64 + // requires sanitizer.memtag: true + // if set, enables sync memory tagging + Memtag_heap *bool `android:"arch_variant"` + } } SanitizerEnabled bool `blueprint:"mutated"` SanitizeDep bool `blueprint:"mutated"` @@ -59,9 +78,18 @@ var asanFlags = []string{ "-Z sanitizer=address", } +// See cc/sanitize.go's hwasanGlobalOptions for global hwasan options. var hwasanFlags = []string{ "-Z sanitizer=hwaddress", "-C target-feature=+tagged-globals", + + // Flags from cc/sanitize.go hwasanFlags + "-C llvm-args=--aarch64-enable-global-isel-at-O=-1", + "-C llvm-args=-fast-isel=false", + "-C llvm-args=-instcombine-lower-dbg-declare=0", + + // Additional flags for HWASAN-ified Rust/C interop + "-C llvm-args=--hwasan-with-ifunc", } func boolPtr(v bool) *bool { @@ -79,7 +107,85 @@ func (sanitize *sanitize) props() []interface{} { } func (sanitize *sanitize) begin(ctx BaseModuleContext) { - s := sanitize.Properties.Sanitize + s := &sanitize.Properties.Sanitize + + // Never always wins. + if Bool(s.Never) { + return + } + + // rust_test targets default to SYNC MemTag unless explicitly set to ASYNC (via diag: {Memtag_heap}). + if binary, ok := ctx.RustModule().compiler.(binaryInterface); ok && binary.testBinary() { + if s.Memtag_heap == nil { + s.Memtag_heap = proptools.BoolPtr(true) + } + if s.Diag.Memtag_heap == nil { + s.Diag.Memtag_heap = proptools.BoolPtr(true) + } + } + + var globalSanitizers []string + var globalSanitizersDiag []string + + if ctx.Host() { + if !ctx.Windows() { + globalSanitizers = ctx.Config().SanitizeHost() + } + } else { + arches := ctx.Config().SanitizeDeviceArch() + if len(arches) == 0 || android.InList(ctx.Arch().ArchType.Name, arches) { + globalSanitizers = ctx.Config().SanitizeDevice() + globalSanitizersDiag = ctx.Config().SanitizeDeviceDiag() + } + } + + if len(globalSanitizers) > 0 { + var found bool + + // Global Sanitizers + if found, globalSanitizers = android.RemoveFromList("hwaddress", globalSanitizers); found && s.Hwaddress == nil { + // TODO(b/180495975): HWASan for static Rust binaries isn't supported yet. + if !ctx.RustModule().StaticExecutable() { + s.Hwaddress = proptools.BoolPtr(true) + } + } + + if found, globalSanitizers = android.RemoveFromList("memtag_heap", globalSanitizers); found && s.Memtag_heap == nil { + if !ctx.Config().MemtagHeapDisabledForPath(ctx.ModuleDir()) { + s.Memtag_heap = proptools.BoolPtr(true) + } + } + + if found, globalSanitizers = android.RemoveFromList("address", globalSanitizers); found && s.Address == nil { + s.Address = proptools.BoolPtr(true) + } + + if found, globalSanitizers = android.RemoveFromList("fuzzer", globalSanitizers); found && s.Fuzzer == nil { + s.Fuzzer = proptools.BoolPtr(true) + } + + // Global Diag Sanitizers + if found, globalSanitizersDiag = android.RemoveFromList("memtag_heap", globalSanitizersDiag); found && + s.Diag.Memtag_heap == nil && Bool(s.Memtag_heap) { + s.Diag.Memtag_heap = proptools.BoolPtr(true) + } + } + + // Enable Memtag for all components in the include paths (for Aarch64 only) + if ctx.Arch().ArchType == android.Arm64 { + if ctx.Config().MemtagHeapSyncEnabledForPath(ctx.ModuleDir()) { + if s.Memtag_heap == nil { + s.Memtag_heap = proptools.BoolPtr(true) + } + if s.Diag.Memtag_heap == nil { + s.Diag.Memtag_heap = proptools.BoolPtr(true) + } + } else if ctx.Config().MemtagHeapAsyncEnabledForPath(ctx.ModuleDir()) { + if s.Memtag_heap == nil { + s.Memtag_heap = proptools.BoolPtr(true) + } + } + } // TODO:(b/178369775) // For now sanitizing is only supported on devices @@ -96,7 +202,22 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { s.Hwaddress = nil } - if ctx.Os() == android.Android && Bool(s.Hwaddress) { + // HWASan ramdisk (which is built from recovery) goes over some bootloader limit. + // Keep libc instrumented so that ramdisk / vendor_ramdisk / recovery can run hwasan-instrumented code if necessary. + if (ctx.RustModule().InRamdisk() || ctx.RustModule().InVendorRamdisk() || ctx.RustModule().InRecovery()) && !strings.HasPrefix(ctx.ModuleDir(), "bionic/libc") { + s.Hwaddress = nil + } + + if Bool(s.Hwaddress) { + s.Address = nil + } + + // Memtag_heap is only implemented on AArch64. + if ctx.Arch().ArchType != android.Arm64 { + s.Memtag_heap = nil + } + + if ctx.Os() == android.Android && (Bool(s.Hwaddress) || Bool(s.Address) || Bool(s.Memtag_heap)) { sanitize.Properties.SanitizerEnabled = true } } @@ -136,6 +257,26 @@ func rustSanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { return } + if Bool(mod.sanitize.Properties.Sanitize.Memtag_heap) && mod.Binary() { + noteDep := "note_memtag_heap_async" + if Bool(mod.sanitize.Properties.Sanitize.Diag.Memtag_heap) { + noteDep = "note_memtag_heap_sync" + } + // If we're using snapshots, redirect to snapshot whenever possible + // TODO(b/178470649): clean manual snapshot redirections + snapshot := mctx.Provider(cc.SnapshotInfoProvider).(cc.SnapshotInfo) + if lib, ok := snapshot.StaticLibs[noteDep]; ok { + noteDep = lib + } + depTag := cc.StaticDepTag(true) + variations := append(mctx.Target().Variations(), + blueprint.Variation{Mutator: "link", Variation: "static"}) + if mod.Device() { + variations = append(variations, mod.ImageVariation()) + } + mctx.AddFarVariationDependencies(variations, depTag, noteDep) + } + variations := mctx.Target().Variations() var depTag blueprint.DependencyTag var deps []string @@ -149,26 +290,23 @@ func rustSanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { } else if mod.IsSanitizerEnabled(cc.Hwasan) || (mod.IsSanitizerEnabled(cc.Fuzzer) && mctx.Arch().ArchType == android.Arm64) { // TODO(b/180495975): HWASan for static Rust binaries isn't supported yet. - if binary, ok := mod.compiler.(*binaryDecorator); ok { - if Bool(binary.Properties.Static_executable) { + if binary, ok := mod.compiler.(binaryInterface); ok { + if binary.staticallyLinked() { mctx.ModuleErrorf("HWASan is not supported for static Rust executables yet.") } } - if mod.StaticallyLinked() { - variations = append(variations, - blueprint.Variation{Mutator: "link", Variation: "static"}) - depTag = cc.StaticDepTag(false) - deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "hwasan_static")} - } else { - variations = append(variations, - blueprint.Variation{Mutator: "link", Variation: "shared"}) - depTag = cc.SharedDepTag() - deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "hwasan")} - } + // Always link against the shared library -- static binaries will pull in the static + // library during final link if necessary + variations = append(variations, + blueprint.Variation{Mutator: "link", Variation: "shared"}) + depTag = cc.SharedDepTag() + deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "hwasan")} } - mctx.AddFarVariationDependencies(variations, depTag, deps...) + if len(deps) > 0 { + mctx.AddFarVariationDependencies(variations, depTag, deps...) + } } } @@ -184,6 +322,9 @@ func (sanitize *sanitize) SetSanitizer(t cc.SanitizerType, b bool) { case cc.Hwasan: sanitize.Properties.Sanitize.Hwaddress = boolPtr(b) sanitizerSet = true + case cc.Memtag_heap: + sanitize.Properties.Sanitize.Memtag_heap = boolPtr(b) + sanitizerSet = true default: panic(fmt.Errorf("setting unsupported sanitizerType %d", t)) } @@ -243,6 +384,8 @@ func (sanitize *sanitize) getSanitizerBoolPtr(t cc.SanitizerType) *bool { return sanitize.Properties.Sanitize.Address case cc.Hwasan: return sanitize.Properties.Sanitize.Hwaddress + case cc.Memtag_heap: + return sanitize.Properties.Sanitize.Memtag_heap default: return nil } @@ -268,6 +411,12 @@ func (mod *Module) SanitizerSupported(t cc.SanitizerType) bool { case cc.Asan: return true case cc.Hwasan: + // TODO(b/180495975): HWASan for static Rust binaries isn't supported yet. + if mod.StaticExecutable() { + return false + } + return true + case cc.Memtag_heap: return true default: return false diff --git a/rust/sanitize_test.go b/rust/sanitize_test.go new file mode 100644 index 000000000..d6a14b295 --- /dev/null +++ b/rust/sanitize_test.go @@ -0,0 +1,365 @@ +package rust + +import ( + "fmt" + "strings" + "testing" + + "android/soong/android" +) + +type MemtagNoteType int + +const ( + None MemtagNoteType = iota + 1 + Sync + Async +) + +func (t MemtagNoteType) str() string { + switch t { + case None: + return "none" + case Sync: + return "sync" + case Async: + return "async" + default: + panic("type_note_invalid") + } +} + +func checkHasMemtagNote(t *testing.T, m android.TestingModule, expected MemtagNoteType) { + t.Helper() + note_async := "note_memtag_heap_async" + note_sync := "note_memtag_heap_sync" + + found := None + implicits := m.Rule("rustc").Implicits + for _, lib := range implicits { + if strings.Contains(lib.Rel(), note_async) { + found = Async + break + } else if strings.Contains(lib.Rel(), note_sync) { + found = Sync + break + } + } + + if found != expected { + t.Errorf("Wrong Memtag note in target %q: found %q, expected %q", m.Module().(*Module).Name(), found.str(), expected.str()) + } +} + +var prepareForTestWithMemtagHeap = android.GroupFixturePreparers( + android.FixtureModifyMockFS(func(fs android.MockFS) { + templateBp := ` + rust_test { + name: "unset_test_%[1]s", + srcs: ["foo.rs"], + } + + rust_test { + name: "no_memtag_test_%[1]s", + srcs: ["foo.rs"], + sanitize: { memtag_heap: false }, + } + + rust_test { + name: "set_memtag_test_%[1]s", + srcs: ["foo.rs"], + sanitize: { memtag_heap: true }, + } + + rust_test { + name: "set_memtag_set_async_test_%[1]s", + srcs: ["foo.rs"], + sanitize: { memtag_heap: true, diag: { memtag_heap: false } }, + } + + rust_test { + name: "set_memtag_set_sync_test_%[1]s", + srcs: ["foo.rs"], + sanitize: { memtag_heap: true, diag: { memtag_heap: true } }, + } + + rust_test { + name: "unset_memtag_set_sync_test_%[1]s", + srcs: ["foo.rs"], + sanitize: { diag: { memtag_heap: true } }, + } + + rust_binary { + name: "unset_binary_%[1]s", + srcs: ["foo.rs"], + } + + rust_binary { + name: "no_memtag_binary_%[1]s", + srcs: ["foo.rs"], + sanitize: { memtag_heap: false }, + } + + rust_binary { + name: "set_memtag_binary_%[1]s", + srcs: ["foo.rs"], + sanitize: { memtag_heap: true }, + } + + rust_binary { + name: "set_memtag_set_async_binary_%[1]s", + srcs: ["foo.rs"], + sanitize: { memtag_heap: true, diag: { memtag_heap: false } }, + } + + rust_binary { + name: "set_memtag_set_sync_binary_%[1]s", + srcs: ["foo.rs"], + sanitize: { memtag_heap: true, diag: { memtag_heap: true } }, + } + + rust_binary { + name: "unset_memtag_set_sync_binary_%[1]s", + srcs: ["foo.rs"], + sanitize: { diag: { memtag_heap: true } }, + } + ` + subdirNoOverrideBp := fmt.Sprintf(templateBp, "no_override") + subdirOverrideDefaultDisableBp := fmt.Sprintf(templateBp, "override_default_disable") + subdirSyncBp := fmt.Sprintf(templateBp, "override_default_sync") + subdirAsyncBp := fmt.Sprintf(templateBp, "override_default_async") + + fs.Merge(android.MockFS{ + "subdir_no_override/Android.bp": []byte(subdirNoOverrideBp), + "subdir_override_default_disable/Android.bp": []byte(subdirOverrideDefaultDisableBp), + "subdir_sync/Android.bp": []byte(subdirSyncBp), + "subdir_async/Android.bp": []byte(subdirAsyncBp), + }) + }), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.MemtagHeapExcludePaths = []string{"subdir_override_default_disable"} + // "subdir_override_default_disable" is covered by both include and override_default_disable paths. override_default_disable wins. + variables.MemtagHeapSyncIncludePaths = []string{"subdir_sync", "subdir_override_default_disable"} + variables.MemtagHeapAsyncIncludePaths = []string{"subdir_async", "subdir_override_default_disable"} + }), +) + +func TestSanitizeMemtagHeap(t *testing.T) { + variant := "android_arm64_armv8-a" + + result := android.GroupFixturePreparers( + prepareForRustTest, + prepareForTestWithMemtagHeap, + ).RunTest(t) + ctx := result.TestContext + + checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_no_override", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_async", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_sync", variant), None) + + checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_no_override", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_async", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_sync", variant), None) + + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_disable", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_disable", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_sync", variant), Async) + + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_disable", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_sync", variant), Async) + + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_no_override", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_no_override", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_sync", variant), Sync) +} + +func TestSanitizeMemtagHeapWithSanitizeDevice(t *testing.T) { + variant := "android_arm64_armv8-a" + + result := android.GroupFixturePreparers( + prepareForRustTest, + prepareForTestWithMemtagHeap, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.SanitizeDevice = []string{"memtag_heap"} + }), + ).RunTest(t) + ctx := result.TestContext + + checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_no_override", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_async", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_sync", variant), None) + + checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_no_override", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_async", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_sync", variant), None) + + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_disable", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_disable", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_sync", variant), Async) + + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_disable", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_sync", variant), Async) + + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_sync", variant), Sync) + + // should sanitize: { diag: { memtag: true } } result in Sync instead of None here? + checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_async", variant), Sync) + // should sanitize: { diag: { memtag: true } } result in Sync instead of None here? + checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_sync", variant), Sync) +} + +func TestSanitizeMemtagHeapWithSanitizeDeviceDiag(t *testing.T) { + variant := "android_arm64_armv8-a" + + result := android.GroupFixturePreparers( + prepareForRustTest, + prepareForTestWithMemtagHeap, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.SanitizeDevice = []string{"memtag_heap"} + variables.SanitizeDeviceDiag = []string{"memtag_heap"} + }), + ).RunTest(t) + ctx := result.TestContext + + checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_no_override", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_async", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_sync", variant), None) + + checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_no_override", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_async", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_sync", variant), None) + + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_disable", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_sync", variant), Async) + + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_disable", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_sync", variant), Async) + + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_async", variant), Sync) + // should sanitize: { diag: { memtag: true } } result in Sync instead of None here? + checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_sync", variant), Sync) +} diff --git a/rust/test.go b/rust/test.go index 56da509b5..bb877a9a5 100644 --- a/rust/test.go +++ b/rust/test.go @@ -196,3 +196,7 @@ func (test *testDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { return deps } + +func (test *testDecorator) testBinary() bool { + return true +} diff --git a/rust/testing.go b/rust/testing.go index dac04d6a8..9f8ed54d9 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -91,7 +91,12 @@ func GatherRequiredDepsForTest() string { no_libcrt: true, nocrt: true, system_shared_libs: [], - export_include_dirs: ["libprotobuf-cpp-full-includes"], + } + cc_library { + name: "libclang_rt.hwasan_static-aarch64-android", + no_libcrt: true, + nocrt: true, + system_shared_libs: [], } rust_library { name: "libstd", @@ -186,5 +191,8 @@ func registerRequiredBuildComponentsForTest(ctx android.RegistrationContext) { ctx.BottomUp("rust_begin", BeginMutator).Parallel() }) ctx.RegisterSingletonType("rust_project_generator", rustProjectGeneratorSingleton) + ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { + ctx.BottomUp("rust_sanitizers", rustSanitizerRuntimeMutator).Parallel() + }) registerRustSnapshotModules(ctx) } diff --git a/rust/vendor_snapshot_test.go b/rust/vendor_snapshot_test.go index 60ddb653f..bfa6f361a 100644 --- a/rust/vendor_snapshot_test.go +++ b/rust/vendor_snapshot_test.go @@ -562,6 +562,7 @@ func TestVendorSnapshotUse(t *testing.T) { "libvendor", "libvndk", "libclang_rt.builtins-aarch64-android", + "note_memtag_heap_sync", ], shared_libs: [ "libvendor_available", @@ -853,6 +854,20 @@ func TestVendorSnapshotUse(t *testing.T) { }, } + // Test sanitizers use the snapshot libraries + rust_binary { + name: "memtag_binary", + srcs: ["vendor/bin.rs"], + vendor: true, + compile_multilib: "64", + sanitize: { + memtag_heap: true, + diag: { + memtag_heap: true, + } + }, + } + // old snapshot module which has to be ignored vendor_snapshot_binary { name: "bin", @@ -880,11 +895,25 @@ func TestVendorSnapshotUse(t *testing.T) { }, }, } + + vendor_snapshot_static { + name: "note_memtag_heap_sync", + vendor: true, + target_arch: "arm64", + version: "30", + arch: { + arm64: { + src: "note_memtag_heap_sync.a", + }, + }, + } + ` mockFS := android.MockFS{ "framework/Android.bp": []byte(frameworkBp), "framework/bin.rs": nil, + "note_memtag_heap_sync.a": nil, "vendor/Android.bp": []byte(vendorProprietaryBp), "vendor/bin": nil, "vendor/bin32": nil, @@ -993,4 +1022,9 @@ func TestVendorSnapshotUse(t *testing.T) { if android.InList(binaryVariant, binVariants) { t.Errorf("bin must not have variant %#v, but it does", sharedVariant) } + + memtagStaticLibs := ctx.ModuleForTests("memtag_binary", "android_vendor.30_arm64_armv8-a").Module().(*Module).Properties.AndroidMkStaticLibs + if g, w := memtagStaticLibs, []string{"libclang_rt.builtins-aarch64-android.vendor", "note_memtag_heap_sync.vendor"}; !reflect.DeepEqual(g, w) { + t.Errorf("wanted memtag_binary AndroidMkStaticLibs %q, got %q", w, g) + } } diff --git a/scripts/Android.bp b/scripts/Android.bp index 635be10b3..730d7567e 100644 --- a/scripts/Android.bp +++ b/scripts/Android.bp @@ -1,5 +1,6 @@ package { default_applicable_licenses: ["Android-Apache-2.0"], + default_visibility: ["//build/soong:__subpackages__"], } python_binary_host { @@ -8,14 +9,6 @@ python_binary_host { srcs: [ "check_boot_jars/check_boot_jars.py", ], - version: { - py2: { - enabled: true, - }, - py3: { - enabled: false, - }, - }, } python_binary_host { @@ -24,14 +17,6 @@ python_binary_host { srcs: [ "manifest_fixer.py", ], - version: { - py2: { - enabled: true, - }, - py3: { - enabled: false, - }, - }, libs: [ "manifest_utils", ], @@ -45,11 +30,8 @@ python_test_host { "manifest_fixer.py", ], version: { - py2: { - enabled: true, - }, py3: { - enabled: false, + embedded_launcher: true, }, }, libs: [ @@ -67,12 +49,14 @@ python_library_host { ], version: { py2: { + // TODO(b/203436762) Remove when system/apex/apexer/apexer.py is converted enabled: true, }, py3: { - enabled: false, + enabled: true, }, }, + visibility: ["//system/apex/apexer:__pkg__"], } python_binary_host { @@ -81,14 +65,6 @@ python_binary_host { srcs: [ "manifest_check.py", ], - version: { - py2: { - enabled: true, - }, - py3: { - enabled: false, - }, - }, libs: [ "manifest_utils", ], @@ -101,14 +77,6 @@ python_test_host { "manifest_check_test.py", "manifest_check.py", ], - version: { - py2: { - enabled: true, - }, - py3: { - enabled: false, - }, - }, libs: [ "manifest_utils", ], @@ -123,14 +91,6 @@ python_binary_host { srcs: [ "jsonmodify.py", ], - version: { - py2: { - enabled: true, - }, - py3: { - enabled: false, - }, - }, } python_binary_host { @@ -139,14 +99,6 @@ python_binary_host { srcs: [ "test_config_fixer.py", ], - version: { - py2: { - enabled: true, - }, - py3: { - enabled: false, - }, - }, libs: [ "manifest_utils", ], @@ -159,14 +111,6 @@ python_test_host { "test_config_fixer_test.py", "test_config_fixer.py", ], - version: { - py2: { - enabled: true, - }, - py3: { - enabled: false, - }, - }, libs: [ "manifest_utils", ], @@ -179,14 +123,6 @@ python_binary_host { srcs: [ "construct_context.py", ], - version: { - py2: { - enabled: true, - }, - py3: { - enabled: false, - }, - }, libs: [ "manifest_utils", ], @@ -199,14 +135,6 @@ python_test_host { "construct_context_test.py", "construct_context.py", ], - version: { - py2: { - enabled: true, - }, - py3: { - enabled: false, - }, - }, libs: [ "manifest_utils", ], @@ -253,11 +181,7 @@ python_binary_host { "conv_linker_config.py", ], version: { - py2: { - enabled: false, - }, py3: { - enabled: true, embedded_launcher: true, }, }, @@ -272,12 +196,4 @@ python_binary_host { srcs: [ "get_clang_version.py", ], - version: { - py2: { - enabled: false, - }, - py3: { - enabled: true, - }, - }, } diff --git a/scripts/manifest.py b/scripts/manifest.py index 04f7405df..81f9c61a8 100755 --- a/scripts/manifest.py +++ b/scripts/manifest.py @@ -123,4 +123,4 @@ def get_indent(element, default_level): def write_xml(f, doc): f.write('<?xml version="1.0" encoding="utf-8"?>\n') for node in doc.childNodes: - f.write(node.toxml(encoding='utf-8') + '\n') + f.write(node.toxml() + '\n') diff --git a/scripts/manifest_check.py b/scripts/manifest_check.py index 8bed52a9f..c8d4f76c8 100755 --- a/scripts/manifest_check.py +++ b/scripts/manifest_check.py @@ -335,7 +335,7 @@ def main(): if is_apk: aapt = args.aapt if args.aapt is not None else 'aapt' manifest = subprocess.check_output( - [aapt, 'dump', 'badging', args.input]) + [aapt, 'dump', 'badging', args.input]).decode('utf-8') else: manifest = minidom.parse(args.input) @@ -381,7 +381,7 @@ def main(): if is_apk: raise RuntimeError('cannot save APK manifest as XML') - with open(args.output, 'wb') as f: + with open(args.output, 'w') as f: write_xml(f, manifest) # pylint: disable=broad-except diff --git a/scripts/manifest_fixer.py b/scripts/manifest_fixer.py index 55d0fd158..d80a617a1 100755 --- a/scripts/manifest_fixer.py +++ b/scripts/manifest_fixer.py @@ -352,7 +352,7 @@ def main(): if args.extract_native_libs is not None: add_extract_native_libs(doc, args.extract_native_libs) - with open(args.output, 'wb') as f: + with open(args.output, 'w') as f: write_xml(f, doc) # pylint: disable=broad-except diff --git a/scripts/manifest_fixer_test.py b/scripts/manifest_fixer_test.py index 3a0a25d1c..f6fcaafe5 100755 --- a/scripts/manifest_fixer_test.py +++ b/scripts/manifest_fixer_test.py @@ -16,16 +16,16 @@ # """Unit tests for manifest_fixer.py.""" -import StringIO +import io import sys import unittest from xml.dom import minidom +import xml.etree.ElementTree as ET import manifest_fixer sys.dont_write_bytecode = True - class CompareVersionGtTest(unittest.TestCase): """Unit tests for compare_version_gt function.""" @@ -59,7 +59,7 @@ class RaiseMinSdkVersionTest(unittest.TestCase): doc = minidom.parseString(input_manifest) manifest_fixer.raise_min_sdk_version(doc, min_sdk_version, target_sdk_version, library) - output = StringIO.StringIO() + output = io.StringIO() manifest_fixer.write_xml(output, doc) return output.getvalue() @@ -80,13 +80,16 @@ class RaiseMinSdkVersionTest(unittest.TestCase): attrs += ' ' + extra return ' <uses-sdk%s/>\n' % (attrs) + def assert_xml_equal(self, output, expected): + self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected)) + def test_no_uses_sdk(self): """Tests inserting a uses-sdk element into a manifest.""" manifest_input = self.manifest_tmpl % '' expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28') output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_no_min(self): """Tests inserting a minSdkVersion attribute into a uses-sdk element.""" @@ -95,7 +98,7 @@ class RaiseMinSdkVersionTest(unittest.TestCase): expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28', extra='extra="foo"') output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_raise_min(self): """Tests inserting a minSdkVersion attribute into a uses-sdk element.""" @@ -103,7 +106,7 @@ class RaiseMinSdkVersionTest(unittest.TestCase): manifest_input = self.manifest_tmpl % self.uses_sdk(min='27') expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28') output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_raise(self): """Tests raising a minSdkVersion attribute.""" @@ -111,7 +114,7 @@ class RaiseMinSdkVersionTest(unittest.TestCase): manifest_input = self.manifest_tmpl % self.uses_sdk(min='27') expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28') output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_no_raise_min(self): """Tests a minSdkVersion that doesn't need raising.""" @@ -119,7 +122,7 @@ class RaiseMinSdkVersionTest(unittest.TestCase): manifest_input = self.manifest_tmpl % self.uses_sdk(min='28') expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27') output = self.raise_min_sdk_version_test(manifest_input, '27', '27', False) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_raise_codename(self): """Tests raising a minSdkVersion attribute to a codename.""" @@ -127,7 +130,7 @@ class RaiseMinSdkVersionTest(unittest.TestCase): manifest_input = self.manifest_tmpl % self.uses_sdk(min='28') expected = self.manifest_tmpl % self.uses_sdk(min='P', target='P') output = self.raise_min_sdk_version_test(manifest_input, 'P', 'P', False) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_no_raise_codename(self): """Tests a minSdkVersion codename that doesn't need raising.""" @@ -135,7 +138,7 @@ class RaiseMinSdkVersionTest(unittest.TestCase): manifest_input = self.manifest_tmpl % self.uses_sdk(min='P') expected = self.manifest_tmpl % self.uses_sdk(min='P', target='28') output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_target(self): """Tests an existing targetSdkVersion is preserved.""" @@ -143,7 +146,7 @@ class RaiseMinSdkVersionTest(unittest.TestCase): manifest_input = self.manifest_tmpl % self.uses_sdk(min='26', target='27') expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27') output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_no_target(self): """Tests inserting targetSdkVersion when minSdkVersion exists.""" @@ -151,7 +154,7 @@ class RaiseMinSdkVersionTest(unittest.TestCase): manifest_input = self.manifest_tmpl % self.uses_sdk(min='27') expected = self.manifest_tmpl % self.uses_sdk(min='28', target='29') output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_target_no_min(self): """"Tests inserting targetSdkVersion when minSdkVersion exists.""" @@ -159,7 +162,7 @@ class RaiseMinSdkVersionTest(unittest.TestCase): manifest_input = self.manifest_tmpl % self.uses_sdk(target='27') expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27') output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_no_target_no_min(self): """Tests inserting targetSdkVersion when minSdkVersion does not exist.""" @@ -167,7 +170,7 @@ class RaiseMinSdkVersionTest(unittest.TestCase): manifest_input = self.manifest_tmpl % '' expected = self.manifest_tmpl % self.uses_sdk(min='28', target='29') output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_library_no_target(self): """Tests inserting targetSdkVersion when minSdkVersion exists.""" @@ -175,7 +178,7 @@ class RaiseMinSdkVersionTest(unittest.TestCase): manifest_input = self.manifest_tmpl % self.uses_sdk(min='27') expected = self.manifest_tmpl % self.uses_sdk(min='28', target='16') output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_library_target_no_min(self): """Tests inserting targetSdkVersion when minSdkVersion exists.""" @@ -183,7 +186,7 @@ class RaiseMinSdkVersionTest(unittest.TestCase): manifest_input = self.manifest_tmpl % self.uses_sdk(target='27') expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27') output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_library_no_target_no_min(self): """Tests inserting targetSdkVersion when minSdkVersion does not exist.""" @@ -191,7 +194,7 @@ class RaiseMinSdkVersionTest(unittest.TestCase): manifest_input = self.manifest_tmpl % '' expected = self.manifest_tmpl % self.uses_sdk(min='28', target='16') output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_extra(self): """Tests that extra attributes and elements are maintained.""" @@ -204,12 +207,12 @@ class RaiseMinSdkVersionTest(unittest.TestCase): # pylint: disable=line-too-long expected = self.manifest_tmpl % ( ' <!-- comment -->\n' - ' <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="29" extra="foo"/>\n' + ' <uses-sdk android:minSdkVersion="28" extra="foo" android:targetSdkVersion="29"/>\n' ' <application/>\n') output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_indent(self): """Tests that an inserted element copies the existing indentation.""" @@ -223,17 +226,20 @@ class RaiseMinSdkVersionTest(unittest.TestCase): output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) class AddLoggingParentTest(unittest.TestCase): """Unit tests for add_logging_parent function.""" + def assert_xml_equal(self, output, expected): + self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected)) + def add_logging_parent_test(self, input_manifest, logging_parent=None): doc = minidom.parseString(input_manifest) if logging_parent: manifest_fixer.add_logging_parent(doc, logging_parent) - output = StringIO.StringIO() + output = io.StringIO() manifest_fixer.write_xml(output, doc) return output.getvalue() @@ -257,23 +263,26 @@ class AddLoggingParentTest(unittest.TestCase): manifest_input = self.manifest_tmpl % '' expected = self.manifest_tmpl % self.uses_logging_parent() output = self.add_logging_parent_test(manifest_input) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_logging_parent(self): """Tests manifest_fixer with no logging_parent.""" manifest_input = self.manifest_tmpl % '' expected = self.manifest_tmpl % self.uses_logging_parent('FOO') output = self.add_logging_parent_test(manifest_input, 'FOO') - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) class AddUsesLibrariesTest(unittest.TestCase): """Unit tests for add_uses_libraries function.""" + def assert_xml_equal(self, output, expected): + self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected)) + def run_test(self, input_manifest, new_uses_libraries): doc = minidom.parseString(input_manifest) manifest_fixer.add_uses_libraries(doc, new_uses_libraries, True) - output = StringIO.StringIO() + output = io.StringIO() manifest_fixer.write_xml(output, doc) return output.getvalue() @@ -301,7 +310,7 @@ class AddUsesLibrariesTest(unittest.TestCase): ('bar', 'false')]) expected = manifest_input output = self.run_test(manifest_input, []) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_not_overwrite(self): """new_uses_libraries must not overwrite existing tags.""" @@ -310,7 +319,7 @@ class AddUsesLibrariesTest(unittest.TestCase): ('bar', 'false')]) expected = manifest_input output = self.run_test(manifest_input, ['foo', 'bar']) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_add(self): """New names are added with 'required:true'.""" @@ -323,7 +332,7 @@ class AddUsesLibrariesTest(unittest.TestCase): ('baz', 'true'), ('qux', 'true')]) output = self.run_test(manifest_input, ['bar', 'baz', 'qux']) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_no_application(self): """When there is no <application> tag, the tag is added.""" @@ -336,7 +345,7 @@ class AddUsesLibrariesTest(unittest.TestCase): ('foo', 'true'), ('bar', 'true')]) output = self.run_test(manifest_input, ['foo', 'bar']) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_empty_application(self): """Even when here is an empty <application/> tag, the libs are added.""" @@ -350,16 +359,19 @@ class AddUsesLibrariesTest(unittest.TestCase): ('foo', 'true'), ('bar', 'true')]) output = self.run_test(manifest_input, ['foo', 'bar']) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) class AddUsesNonSdkApiTest(unittest.TestCase): """Unit tests for add_uses_libraries function.""" + def assert_xml_equal(self, output, expected): + self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected)) + def run_test(self, input_manifest): doc = minidom.parseString(input_manifest) manifest_fixer.add_uses_non_sdk_api(doc) - output = StringIO.StringIO() + output = io.StringIO() manifest_fixer.write_xml(output, doc) return output.getvalue() @@ -377,23 +389,26 @@ class AddUsesNonSdkApiTest(unittest.TestCase): manifest_input = self.manifest_tmpl % self.uses_non_sdk_api(False) expected = self.manifest_tmpl % self.uses_non_sdk_api(True) output = self.run_test(manifest_input) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_already_set(self): """new_uses_libraries must not overwrite existing tags.""" manifest_input = self.manifest_tmpl % self.uses_non_sdk_api(True) expected = manifest_input output = self.run_test(manifest_input) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) class UseEmbeddedDexTest(unittest.TestCase): """Unit tests for add_use_embedded_dex function.""" + def assert_xml_equal(self, output, expected): + self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected)) + def run_test(self, input_manifest): doc = minidom.parseString(input_manifest) manifest_fixer.add_use_embedded_dex(doc) - output = StringIO.StringIO() + output = io.StringIO() manifest_fixer.write_xml(output, doc) return output.getvalue() @@ -410,13 +425,13 @@ class UseEmbeddedDexTest(unittest.TestCase): manifest_input = self.manifest_tmpl % '' expected = self.manifest_tmpl % self.use_embedded_dex('true') output = self.run_test(manifest_input) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_manifest_with_use_embedded_dex(self): manifest_input = self.manifest_tmpl % self.use_embedded_dex('true') expected = manifest_input output = self.run_test(manifest_input) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_manifest_with_not_use_embedded_dex(self): manifest_input = self.manifest_tmpl % self.use_embedded_dex('false') @@ -426,10 +441,13 @@ class UseEmbeddedDexTest(unittest.TestCase): class AddExtractNativeLibsTest(unittest.TestCase): """Unit tests for add_extract_native_libs function.""" + def assert_xml_equal(self, output, expected): + self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected)) + def run_test(self, input_manifest, value): doc = minidom.parseString(input_manifest) manifest_fixer.add_extract_native_libs(doc, value) - output = StringIO.StringIO() + output = io.StringIO() manifest_fixer.write_xml(output, doc) return output.getvalue() @@ -446,19 +464,19 @@ class AddExtractNativeLibsTest(unittest.TestCase): manifest_input = self.manifest_tmpl % '' expected = self.manifest_tmpl % self.extract_native_libs('true') output = self.run_test(manifest_input, True) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_set_false(self): manifest_input = self.manifest_tmpl % '' expected = self.manifest_tmpl % self.extract_native_libs('false') output = self.run_test(manifest_input, False) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_match(self): manifest_input = self.manifest_tmpl % self.extract_native_libs('true') expected = manifest_input output = self.run_test(manifest_input, True) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_conflict(self): manifest_input = self.manifest_tmpl % self.extract_native_libs('true') @@ -468,10 +486,13 @@ class AddExtractNativeLibsTest(unittest.TestCase): class AddNoCodeApplicationTest(unittest.TestCase): """Unit tests for set_has_code_to_false function.""" + def assert_xml_equal(self, output, expected): + self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected)) + def run_test(self, input_manifest): doc = minidom.parseString(input_manifest) manifest_fixer.set_has_code_to_false(doc) - output = StringIO.StringIO() + output = io.StringIO() manifest_fixer.write_xml(output, doc) return output.getvalue() @@ -485,26 +506,26 @@ class AddNoCodeApplicationTest(unittest.TestCase): manifest_input = self.manifest_tmpl % '' expected = self.manifest_tmpl % ' <application android:hasCode="false"/>\n' output = self.run_test(manifest_input) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_has_application_no_has_code(self): manifest_input = self.manifest_tmpl % ' <application/>\n' expected = self.manifest_tmpl % ' <application android:hasCode="false"/>\n' output = self.run_test(manifest_input) - self.assertEqual(output, expected) + self.assert_xml_equal(output, expected) def test_has_application_has_code_false(self): """ Do nothing if there's already an application elemeent. """ manifest_input = self.manifest_tmpl % ' <application android:hasCode="false"/>\n' output = self.run_test(manifest_input) - self.assertEqual(output, manifest_input) + self.assert_xml_equal(output, manifest_input) def test_has_application_has_code_true(self): """ Do nothing if there's already an application elemeent even if its hasCode attribute is true. """ manifest_input = self.manifest_tmpl % ' <application android:hasCode="true"/>\n' output = self.run_test(manifest_input) - self.assertEqual(output, manifest_input) + self.assert_xml_equal(output, manifest_input) if __name__ == '__main__': diff --git a/scripts/test_config_fixer.py b/scripts/test_config_fixer.py index 32d5b175e..c150e8cfd 100644 --- a/scripts/test_config_fixer.py +++ b/scripts/test_config_fixer.py @@ -86,7 +86,7 @@ def main(): if args.test_file_name: overwrite_test_file_name(doc, args.test_file_name) - with open(args.output, 'wb') as f: + with open(args.output, 'w') as f: write_xml(f, doc) # pylint: disable=broad-except diff --git a/scripts/test_config_fixer_test.py b/scripts/test_config_fixer_test.py index 1272c6b33..d00a59315 100644 --- a/scripts/test_config_fixer_test.py +++ b/scripts/test_config_fixer_test.py @@ -16,7 +16,7 @@ # """Unit tests for test_config_fixer.py.""" -import StringIO +import io import sys import unittest from xml.dom import minidom @@ -59,7 +59,7 @@ class OverwritePackageNameTest(unittest.TestCase): manifest = minidom.parseString(self.manifest) test_config_fixer.overwrite_package_name(doc, manifest, "com.soong.foo") - output = StringIO.StringIO() + output = io.StringIO() test_config_fixer.write_xml(output, doc) # Only the matching package name in a test node should be updated. @@ -86,7 +86,7 @@ class OverwriteTestFileNameTest(unittest.TestCase): doc = minidom.parseString(self.test_config % ("foo.apk")) test_config_fixer.overwrite_test_file_name(doc, "bar.apk") - output = StringIO.StringIO() + output = io.StringIO() test_config_fixer.write_xml(output, doc) # Only the matching package name in a test node should be updated. |