1// Copyright 2016 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package cc
16
17import (
18	"fmt"
19	"sort"
20	"strings"
21	"sync"
22
23	"github.com/google/blueprint"
24
25	"android/soong/android"
26	"android/soong/cc/config"
27)
28
29var (
30	// Any C flags added by sanitizer which libTooling tools may not
31	// understand also need to be added to ClangLibToolingUnknownCflags in
32	// cc/config/clang.go
33
34	asanCflags = []string{
35		"-fno-omit-frame-pointer",
36		"-fno-experimental-new-pass-manager",
37	}
38	asanLdflags = []string{"-Wl,-u,__asan_preinit"}
39
40	hwasanCflags = []string{"-fno-omit-frame-pointer", "-Wno-frame-larger-than=",
41		"-fsanitize-hwaddress-abi=platform",
42		"-fno-experimental-new-pass-manager",
43		// The following improves debug location information
44		// availability at the cost of its accuracy. It increases
45		// the likelihood of a stack variable's frame offset
46		// to be recorded in the debug info, which is important
47		// for the quality of hwasan reports. The downside is a
48		// higher number of "optimized out" stack variables.
49		// b/112437883.
50		"-mllvm", "-instcombine-lower-dbg-declare=0",
51		// TODO(b/159343917): HWASan and GlobalISel don't play nicely, and
52		// GlobalISel is the default at -O0 on aarch64.
53		"-mllvm", "--aarch64-enable-global-isel-at-O=-1",
54		"-mllvm", "-fast-isel=false",
55	}
56
57	cfiCflags = []string{"-flto", "-fsanitize-cfi-cross-dso",
58		"-fsanitize-blacklist=external/compiler-rt/lib/cfi/cfi_blocklist.txt"}
59	// -flto and -fvisibility are required by clang when -fsanitize=cfi is
60	// used, but have no effect on assembly files
61	cfiAsflags = []string{"-flto", "-fvisibility=default"}
62	cfiLdflags = []string{"-flto", "-fsanitize-cfi-cross-dso", "-fsanitize=cfi",
63		"-Wl,-plugin-opt,O1"}
64	cfiExportsMapPath = "build/soong/cc/config/cfi_exports.map"
65
66	intOverflowCflags = []string{"-fsanitize-blacklist=build/soong/cc/config/integer_overflow_blocklist.txt"}
67
68	minimalRuntimeFlags = []string{"-fsanitize-minimal-runtime", "-fno-sanitize-trap=integer,undefined",
69		"-fno-sanitize-recover=integer,undefined"}
70	hwasanGlobalOptions = []string{"heap_history_size=1023", "stack_history_size=512",
71		"export_memory_stats=0", "max_malloc_fill_size=0"}
72)
73
74type SanitizerType int
75
76func boolPtr(v bool) *bool {
77	if v {
78		return &v
79	} else {
80		return nil
81	}
82}
83
84const (
85	Asan SanitizerType = iota + 1
86	Hwasan
87	tsan
88	intOverflow
89	cfi
90	scs
91	Fuzzer
92	memtag_heap
93)
94
95// Name of the sanitizer variation for this sanitizer type
96func (t SanitizerType) variationName() string {
97	switch t {
98	case Asan:
99		return "asan"
100	case Hwasan:
101		return "hwasan"
102	case tsan:
103		return "tsan"
104	case intOverflow:
105		return "intOverflow"
106	case cfi:
107		return "cfi"
108	case scs:
109		return "scs"
110	case memtag_heap:
111		return "memtag_heap"
112	case Fuzzer:
113		return "fuzzer"
114	default:
115		panic(fmt.Errorf("unknown SanitizerType %d", t))
116	}
117}
118
119// This is the sanitizer names in SANITIZE_[TARGET|HOST]
120func (t SanitizerType) name() string {
121	switch t {
122	case Asan:
123		return "address"
124	case Hwasan:
125		return "hwaddress"
126	case memtag_heap:
127		return "memtag_heap"
128	case tsan:
129		return "thread"
130	case intOverflow:
131		return "integer_overflow"
132	case cfi:
133		return "cfi"
134	case scs:
135		return "shadow-call-stack"
136	case Fuzzer:
137		return "fuzzer"
138	default:
139		panic(fmt.Errorf("unknown SanitizerType %d", t))
140	}
141}
142
143func (*Module) SanitizerSupported(t SanitizerType) bool {
144	switch t {
145	case Asan:
146		return true
147	case Hwasan:
148		return true
149	case tsan:
150		return true
151	case intOverflow:
152		return true
153	case cfi:
154		return true
155	case scs:
156		return true
157	case Fuzzer:
158		return true
159	default:
160		return false
161	}
162}
163
164// incompatibleWithCfi returns true if a sanitizer is incompatible with CFI.
165func (t SanitizerType) incompatibleWithCfi() bool {
166	return t == Asan || t == Fuzzer || t == Hwasan
167}
168
169type SanitizeUserProps struct {
170	Never *bool `android:"arch_variant"`
171
172	// main sanitizers
173	Address   *bool `android:"arch_variant"`
174	Thread    *bool `android:"arch_variant"`
175	Hwaddress *bool `android:"arch_variant"`
176
177	// local sanitizers
178	Undefined        *bool    `android:"arch_variant"`
179	All_undefined    *bool    `android:"arch_variant"`
180	Misc_undefined   []string `android:"arch_variant"`
181	Fuzzer           *bool    `android:"arch_variant"`
182	Safestack        *bool    `android:"arch_variant"`
183	Cfi              *bool    `android:"arch_variant"`
184	Integer_overflow *bool    `android:"arch_variant"`
185	Scudo            *bool    `android:"arch_variant"`
186	Scs              *bool    `android:"arch_variant"`
187	Memtag_heap      *bool    `android:"arch_variant"`
188
189	// A modifier for ASAN and HWASAN for write only instrumentation
190	Writeonly *bool `android:"arch_variant"`
191
192	// Sanitizers to run in the diagnostic mode (as opposed to the release mode).
193	// Replaces abort() on error with a human-readable error message.
194	// Address and Thread sanitizers always run in diagnostic mode.
195	Diag struct {
196		Undefined        *bool    `android:"arch_variant"`
197		Cfi              *bool    `android:"arch_variant"`
198		Integer_overflow *bool    `android:"arch_variant"`
199		Memtag_heap      *bool    `android:"arch_variant"`
200		Misc_undefined   []string `android:"arch_variant"`
201		No_recover       []string `android:"arch_variant"`
202	} `android:"arch_variant"`
203
204	// Sanitizers to run with flag configuration specified
205	Config struct {
206		// Enables CFI support flags for assembly-heavy libraries
207		Cfi_assembly_support *bool `android:"arch_variant"`
208	} `android:"arch_variant"`
209
210	// value to pass to -fsanitize-recover=
211	Recover []string
212
213	// value to pass to -fsanitize-blacklist
214	Blocklist *string
215}
216
217type SanitizeProperties struct {
218	// Enable AddressSanitizer, ThreadSanitizer, UndefinedBehaviorSanitizer, and
219	// others. Please see SanitizerUserProps in build/soong/cc/sanitize.go for
220	// details.
221	Sanitize          SanitizeUserProps `android:"arch_variant"`
222	SanitizerEnabled  bool              `blueprint:"mutated"`
223	SanitizeDep       bool              `blueprint:"mutated"`
224	MinimalRuntimeDep bool              `blueprint:"mutated"`
225	BuiltinsDep       bool              `blueprint:"mutated"`
226	UbsanRuntimeDep   bool              `blueprint:"mutated"`
227	InSanitizerDir    bool              `blueprint:"mutated"`
228	Sanitizers        []string          `blueprint:"mutated"`
229	DiagSanitizers    []string          `blueprint:"mutated"`
230}
231
232type sanitize struct {
233	Properties SanitizeProperties
234}
235
236// Mark this tag with a check to see if apex dependency check should be skipped
237func (t libraryDependencyTag) SkipApexAllowedDependenciesCheck() bool {
238	return t.skipApexAllowedDependenciesCheck
239}
240
241var _ android.SkipApexAllowedDependenciesCheck = (*libraryDependencyTag)(nil)
242
243func init() {
244	android.RegisterMakeVarsProvider(pctx, cfiMakeVarsProvider)
245	android.RegisterMakeVarsProvider(pctx, hwasanMakeVarsProvider)
246}
247
248func (sanitize *sanitize) props() []interface{} {
249	return []interface{}{&sanitize.Properties}
250}
251
252func (sanitize *sanitize) begin(ctx BaseModuleContext) {
253	s := &sanitize.Properties.Sanitize
254
255	// Don't apply sanitizers to NDK code.
256	if ctx.useSdk() {
257		s.Never = BoolPtr(true)
258	}
259
260	// Sanitizers do not work on Fuchsia yet.
261	if ctx.Fuchsia() {
262		s.Never = BoolPtr(true)
263	}
264
265	// Never always wins.
266	if Bool(s.Never) {
267		return
268	}
269
270	// cc_test targets default to SYNC MemTag unless explicitly set to ASYNC (via diag: {memtag_heap}).
271	if ctx.testBinary() && s.Memtag_heap == nil {
272		s.Memtag_heap = boolPtr(true)
273		s.Diag.Memtag_heap = boolPtr(true)
274	}
275
276	var globalSanitizers []string
277	var globalSanitizersDiag []string
278
279	if ctx.Host() {
280		if !ctx.Windows() {
281			globalSanitizers = ctx.Config().SanitizeHost()
282		}
283	} else {
284		arches := ctx.Config().SanitizeDeviceArch()
285		if len(arches) == 0 || inList(ctx.Arch().ArchType.Name, arches) {
286			globalSanitizers = ctx.Config().SanitizeDevice()
287			globalSanitizersDiag = ctx.Config().SanitizeDeviceDiag()
288		}
289	}
290
291	if len(globalSanitizers) > 0 {
292		var found bool
293		if found, globalSanitizers = removeFromList("undefined", globalSanitizers); found && s.All_undefined == nil {
294			s.All_undefined = boolPtr(true)
295		}
296
297		if found, globalSanitizers = removeFromList("default-ub", globalSanitizers); found && s.Undefined == nil {
298			s.Undefined = boolPtr(true)
299		}
300
301		if found, globalSanitizers = removeFromList("address", globalSanitizers); found && s.Address == nil {
302			s.Address = boolPtr(true)
303		}
304
305		if found, globalSanitizers = removeFromList("thread", globalSanitizers); found && s.Thread == nil {
306			s.Thread = boolPtr(true)
307		}
308
309		if found, globalSanitizers = removeFromList("fuzzer", globalSanitizers); found && s.Fuzzer == nil {
310			s.Fuzzer = boolPtr(true)
311		}
312
313		if found, globalSanitizers = removeFromList("safe-stack", globalSanitizers); found && s.Safestack == nil {
314			s.Safestack = boolPtr(true)
315		}
316
317		if found, globalSanitizers = removeFromList("cfi", globalSanitizers); found && s.Cfi == nil {
318			if !ctx.Config().CFIDisabledForPath(ctx.ModuleDir()) {
319				s.Cfi = boolPtr(true)
320			}
321		}
322
323		// Global integer_overflow builds do not support static libraries.
324		if found, globalSanitizers = removeFromList("integer_overflow", globalSanitizers); found && s.Integer_overflow == nil {
325			if !ctx.Config().IntegerOverflowDisabledForPath(ctx.ModuleDir()) && !ctx.static() {
326				s.Integer_overflow = boolPtr(true)
327			}
328		}
329
330		if found, globalSanitizers = removeFromList("scudo", globalSanitizers); found && s.Scudo == nil {
331			s.Scudo = boolPtr(true)
332		}
333
334		if found, globalSanitizers = removeFromList("hwaddress", globalSanitizers); found && s.Hwaddress == nil {
335			s.Hwaddress = boolPtr(true)
336		}
337
338		if found, globalSanitizers = removeFromList("writeonly", globalSanitizers); found && s.Writeonly == nil {
339			// Hwaddress and Address are set before, so we can check them here
340			// If they aren't explicitly set in the blueprint/SANITIZE_(HOST|TARGET), they would be nil instead of false
341			if s.Address == nil && s.Hwaddress == nil {
342				ctx.ModuleErrorf("writeonly modifier cannot be used without 'address' or 'hwaddress'")
343			}
344			s.Writeonly = boolPtr(true)
345		}
346		if found, globalSanitizers = removeFromList("memtag_heap", globalSanitizers); found && s.Memtag_heap == nil {
347			if !ctx.Config().MemtagHeapDisabledForPath(ctx.ModuleDir()) {
348				s.Memtag_heap = boolPtr(true)
349			}
350		}
351
352		if len(globalSanitizers) > 0 {
353			ctx.ModuleErrorf("unknown global sanitizer option %s", globalSanitizers[0])
354		}
355
356		// Global integer_overflow builds do not support static library diagnostics.
357		if found, globalSanitizersDiag = removeFromList("integer_overflow", globalSanitizersDiag); found &&
358			s.Diag.Integer_overflow == nil && Bool(s.Integer_overflow) && !ctx.static() {
359			s.Diag.Integer_overflow = boolPtr(true)
360		}
361
362		if found, globalSanitizersDiag = removeFromList("cfi", globalSanitizersDiag); found &&
363			s.Diag.Cfi == nil && Bool(s.Cfi) {
364			s.Diag.Cfi = boolPtr(true)
365		}
366
367		if found, globalSanitizersDiag = removeFromList("memtag_heap", globalSanitizersDiag); found &&
368			s.Diag.Memtag_heap == nil && Bool(s.Memtag_heap) {
369			s.Diag.Memtag_heap = boolPtr(true)
370		}
371
372		if len(globalSanitizersDiag) > 0 {
373			ctx.ModuleErrorf("unknown global sanitizer diagnostics option %s", globalSanitizersDiag[0])
374		}
375	}
376
377	// Enable Memtag for all components in the include paths (for Aarch64 only)
378	if ctx.Arch().ArchType == android.Arm64 {
379		if ctx.Config().MemtagHeapSyncEnabledForPath(ctx.ModuleDir()) {
380			if s.Memtag_heap == nil {
381				s.Memtag_heap = boolPtr(true)
382			}
383			if s.Diag.Memtag_heap == nil {
384				s.Diag.Memtag_heap = boolPtr(true)
385			}
386		} else if ctx.Config().MemtagHeapAsyncEnabledForPath(ctx.ModuleDir()) {
387			if s.Memtag_heap == nil {
388				s.Memtag_heap = boolPtr(true)
389			}
390		}
391	}
392
393	// Enable CFI for all components in the include paths (for Aarch64 only)
394	if s.Cfi == nil && ctx.Config().CFIEnabledForPath(ctx.ModuleDir()) && ctx.Arch().ArchType == android.Arm64 {
395		s.Cfi = boolPtr(true)
396		if inList("cfi", ctx.Config().SanitizeDeviceDiag()) {
397			s.Diag.Cfi = boolPtr(true)
398		}
399	}
400
401	// Is CFI actually enabled?
402	if !ctx.Config().EnableCFI() {
403		s.Cfi = boolPtr(false)
404		s.Diag.Cfi = boolPtr(false)
405	}
406
407	// HWASan requires AArch64 hardware feature (top-byte-ignore).
408	if ctx.Arch().ArchType != android.Arm64 {
409		s.Hwaddress = nil
410	}
411
412	// SCS is only implemented on AArch64.
413	if ctx.Arch().ArchType != android.Arm64 {
414		s.Scs = nil
415	}
416
417	// memtag_heap is only implemented on AArch64.
418	if ctx.Arch().ArchType != android.Arm64 {
419		s.Memtag_heap = nil
420	}
421
422	// Also disable CFI if ASAN is enabled.
423	if Bool(s.Address) || Bool(s.Hwaddress) {
424		s.Cfi = boolPtr(false)
425		s.Diag.Cfi = boolPtr(false)
426	}
427
428	// Disable sanitizers that depend on the UBSan runtime for windows/darwin builds.
429	if !ctx.Os().Linux() {
430		s.Cfi = boolPtr(false)
431		s.Diag.Cfi = boolPtr(false)
432		s.Misc_undefined = nil
433		s.Undefined = nil
434		s.All_undefined = nil
435		s.Integer_overflow = nil
436	}
437
438	// Also disable CFI for VNDK variants of components
439	if ctx.isVndk() && ctx.useVndk() {
440		if ctx.static() {
441			// Cfi variant for static vndk should be captured as vendor snapshot,
442			// so don't strictly disable Cfi.
443			s.Cfi = nil
444			s.Diag.Cfi = nil
445		} else {
446			s.Cfi = boolPtr(false)
447			s.Diag.Cfi = boolPtr(false)
448		}
449	}
450
451	// HWASan ramdisk (which is built from recovery) goes over some bootloader limit.
452	// Keep libc instrumented so that ramdisk / vendor_ramdisk / recovery can run hwasan-instrumented code if necessary.
453	if (ctx.inRamdisk() || ctx.inVendorRamdisk() || ctx.inRecovery()) && !strings.HasPrefix(ctx.ModuleDir(), "bionic/libc") {
454		s.Hwaddress = nil
455	}
456
457	if ctx.staticBinary() {
458		s.Address = nil
459		s.Fuzzer = nil
460		s.Thread = nil
461	}
462
463	if Bool(s.All_undefined) {
464		s.Undefined = nil
465	}
466
467	if !ctx.toolchain().Is64Bit() {
468		// TSAN and SafeStack are not supported on 32-bit architectures
469		s.Thread = nil
470		s.Safestack = nil
471		// TODO(ccross): error for compile_multilib = "32"?
472	}
473
474	if ctx.Os() != android.Windows && (Bool(s.All_undefined) || Bool(s.Undefined) || Bool(s.Address) || Bool(s.Thread) ||
475		Bool(s.Fuzzer) || Bool(s.Safestack) || Bool(s.Cfi) || Bool(s.Integer_overflow) || len(s.Misc_undefined) > 0 ||
476		Bool(s.Scudo) || Bool(s.Hwaddress) || Bool(s.Scs) || Bool(s.Memtag_heap)) {
477		sanitize.Properties.SanitizerEnabled = true
478	}
479
480	// Disable Scudo if ASan or TSan is enabled, or if it's disabled globally.
481	if Bool(s.Address) || Bool(s.Thread) || Bool(s.Hwaddress) || ctx.Config().DisableScudo() {
482		s.Scudo = nil
483	}
484
485	if Bool(s.Hwaddress) {
486		s.Address = nil
487		s.Thread = nil
488		// Disable ubsan diagnosic as a workaround for a compiler bug.
489		// TODO(b/191808836): re-enable.
490		s.Diag.Undefined = nil
491		s.Diag.Integer_overflow = nil
492		s.Diag.Misc_undefined = nil
493	}
494
495	// TODO(b/131771163): CFI transiently depends on LTO, and thus Fuzzer is
496	// mutually incompatible.
497	if Bool(s.Fuzzer) {
498		s.Cfi = boolPtr(false)
499	}
500}
501
502func (sanitize *sanitize) deps(ctx BaseModuleContext, deps Deps) Deps {
503	if !sanitize.Properties.SanitizerEnabled { // || c.static() {
504		return deps
505	}
506
507	return deps
508}
509
510func toDisableImplicitIntegerChange(flags []string) bool {
511	// Returns true if any flag is fsanitize*integer, and there is
512	// no explicit flag about sanitize=implicit-integer-sign-change.
513	for _, f := range flags {
514		if strings.Contains(f, "sanitize=implicit-integer-sign-change") {
515			return false
516		}
517	}
518	for _, f := range flags {
519		if strings.HasPrefix(f, "-fsanitize") && strings.Contains(f, "integer") {
520			return true
521		}
522	}
523	return false
524}
525
526func toDisableUnsignedShiftBaseChange(flags []string) bool {
527	// Returns true if any flag is fsanitize*integer, and there is
528	// no explicit flag about sanitize=unsigned-shift-base.
529	for _, f := range flags {
530		if strings.Contains(f, "sanitize=unsigned-shift-base") {
531			return false
532		}
533	}
534	for _, f := range flags {
535		if strings.HasPrefix(f, "-fsanitize") && strings.Contains(f, "integer") {
536			return true
537		}
538	}
539	return false
540}
541
542func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags {
543	minimalRuntimeLib := config.UndefinedBehaviorSanitizerMinimalRuntimeLibrary(ctx.toolchain()) + ".a"
544	minimalRuntimePath := "${config.ClangAsanLibDir}/" + minimalRuntimeLib
545	builtinsRuntimeLib := config.BuiltinsRuntimeLibrary(ctx.toolchain()) + ".a"
546	builtinsRuntimePath := "${config.ClangAsanLibDir}/" + builtinsRuntimeLib
547
548	if sanitize.Properties.MinimalRuntimeDep {
549		flags.Local.LdFlags = append(flags.Local.LdFlags,
550			minimalRuntimePath,
551			"-Wl,--exclude-libs,"+minimalRuntimeLib)
552	}
553
554	if sanitize.Properties.BuiltinsDep {
555		flags.libFlags = append([]string{builtinsRuntimePath}, flags.libFlags...)
556	}
557
558	if !sanitize.Properties.SanitizerEnabled && !sanitize.Properties.UbsanRuntimeDep {
559		return flags
560	}
561
562	if Bool(sanitize.Properties.Sanitize.Address) {
563		if ctx.Arch().ArchType == android.Arm {
564			// Frame pointer based unwinder in ASan requires ARM frame setup.
565			// TODO: put in flags?
566			flags.RequiredInstructionSet = "arm"
567		}
568		flags.Local.CFlags = append(flags.Local.CFlags, asanCflags...)
569		flags.Local.LdFlags = append(flags.Local.LdFlags, asanLdflags...)
570
571		if Bool(sanitize.Properties.Sanitize.Writeonly) {
572			flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", "-asan-instrument-reads=0")
573		}
574
575		if ctx.Host() {
576			// -nodefaultlibs (provided with libc++) prevents the driver from linking
577			// libraries needed with -fsanitize=address. http://b/18650275 (WAI)
578			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--no-as-needed")
579		} else {
580			flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", "-asan-globals=0")
581			if ctx.bootstrap() {
582				flags.DynamicLinker = "/system/bin/bootstrap/linker_asan"
583			} else {
584				flags.DynamicLinker = "/system/bin/linker_asan"
585			}
586			if flags.Toolchain.Is64Bit() {
587				flags.DynamicLinker += "64"
588			}
589		}
590	}
591
592	if Bool(sanitize.Properties.Sanitize.Hwaddress) {
593		flags.Local.CFlags = append(flags.Local.CFlags, hwasanCflags...)
594		if Bool(sanitize.Properties.Sanitize.Writeonly) {
595			flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", "-hwasan-instrument-reads=0")
596		}
597	}
598
599	if Bool(sanitize.Properties.Sanitize.Fuzzer) {
600		flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize=fuzzer-no-link")
601
602		// TODO(b/131771163): LTO and Fuzzer support is mutually incompatible.
603		_, flags.Local.LdFlags = removeFromList("-flto", flags.Local.LdFlags)
604		_, flags.Local.CFlags = removeFromList("-flto", flags.Local.CFlags)
605		flags.Local.LdFlags = append(flags.Local.LdFlags, "-fno-lto")
606		flags.Local.CFlags = append(flags.Local.CFlags, "-fno-lto")
607
608		// TODO(b/142430592): Upstream linker scripts for sanitizer runtime libraries
609		// discard the sancov_lowest_stack symbol, because it's emulated TLS (and thus
610		// doesn't match the linker script due to the "__emutls_v." prefix).
611		flags.Local.LdFlags = append(flags.Local.LdFlags, "-fno-sanitize-coverage=stack-depth")
612		flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-coverage=stack-depth")
613
614		// TODO(b/133876586): Experimental PM breaks sanitizer coverage.
615		flags.Local.CFlags = append(flags.Local.CFlags, "-fno-experimental-new-pass-manager")
616
617		// Disable fortify for fuzzing builds. Generally, we'll be building with
618		// UBSan or ASan here and the fortify checks pollute the stack traces.
619		flags.Local.CFlags = append(flags.Local.CFlags, "-U_FORTIFY_SOURCE")
620
621		// Build fuzzer-sanitized libraries with an $ORIGIN DT_RUNPATH. Android's
622		// linker uses DT_RUNPATH, not DT_RPATH. When we deploy cc_fuzz targets and
623		// their libraries to /data/fuzz/<arch>/lib, any transient shared library gets
624		// the DT_RUNPATH from the shared library above it, and not the executable,
625		// meaning that the lookup falls back to the system. Adding the $ORIGIN to the
626		// DT_RUNPATH here means that transient shared libraries can be found
627		// colocated with their parents.
628		flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN`)
629	}
630
631	if Bool(sanitize.Properties.Sanitize.Cfi) {
632		if ctx.Arch().ArchType == android.Arm {
633			// __cfi_check needs to be built as Thumb (see the code in linker_cfi.cpp). LLVM is not set up
634			// to do this on a function basis, so force Thumb on the entire module.
635			flags.RequiredInstructionSet = "thumb"
636		}
637
638		flags.Local.CFlags = append(flags.Local.CFlags, cfiCflags...)
639		flags.Local.AsFlags = append(flags.Local.AsFlags, cfiAsflags...)
640		if Bool(sanitize.Properties.Sanitize.Config.Cfi_assembly_support) {
641			flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-cfi-canonical-jump-tables")
642		}
643		// Only append the default visibility flag if -fvisibility has not already been set
644		// to hidden.
645		if !inList("-fvisibility=hidden", flags.Local.CFlags) {
646			flags.Local.CFlags = append(flags.Local.CFlags, "-fvisibility=default")
647		}
648		flags.Local.LdFlags = append(flags.Local.LdFlags, cfiLdflags...)
649
650		if ctx.staticBinary() {
651			_, flags.Local.CFlags = removeFromList("-fsanitize-cfi-cross-dso", flags.Local.CFlags)
652			_, flags.Local.LdFlags = removeFromList("-fsanitize-cfi-cross-dso", flags.Local.LdFlags)
653		}
654	}
655
656	if Bool(sanitize.Properties.Sanitize.Integer_overflow) {
657		flags.Local.CFlags = append(flags.Local.CFlags, intOverflowCflags...)
658	}
659
660	if len(sanitize.Properties.Sanitizers) > 0 {
661		sanitizeArg := "-fsanitize=" + strings.Join(sanitize.Properties.Sanitizers, ",")
662
663		flags.Local.CFlags = append(flags.Local.CFlags, sanitizeArg)
664		flags.Local.AsFlags = append(flags.Local.AsFlags, sanitizeArg)
665		if ctx.Host() {
666			// Host sanitizers only link symbols in the final executable, so
667			// there will always be undefined symbols in intermediate libraries.
668			_, flags.Global.LdFlags = removeFromList("-Wl,--no-undefined", flags.Global.LdFlags)
669			flags.Local.LdFlags = append(flags.Local.LdFlags, sanitizeArg)
670
671			// non-Bionic toolchain prebuilts are missing UBSan's vptr and function sanitizers
672			if !ctx.toolchain().Bionic() {
673				flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize=vptr,function")
674			}
675		}
676
677		if enableMinimalRuntime(sanitize) {
678			flags.Local.CFlags = append(flags.Local.CFlags, strings.Join(minimalRuntimeFlags, " "))
679			flags.libFlags = append([]string{minimalRuntimePath}, flags.libFlags...)
680			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--exclude-libs,"+minimalRuntimeLib)
681			if !ctx.toolchain().Bionic() {
682				flags.libFlags = append([]string{builtinsRuntimePath}, flags.libFlags...)
683			}
684		}
685
686		if Bool(sanitize.Properties.Sanitize.Fuzzer) {
687			// When fuzzing, we wish to crash with diagnostics on any bug.
688			flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-trap=all", "-fno-sanitize-recover=all")
689		} else if ctx.Host() {
690			flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-recover=all")
691		} else {
692			flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-trap=all", "-ftrap-function=abort")
693		}
694		// http://b/119329758, Android core does not boot up with this sanitizer yet.
695		if toDisableImplicitIntegerChange(flags.Local.CFlags) {
696			flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize=implicit-integer-sign-change")
697		}
698		// http://b/171275751, Android doesn't build with this sanitizer yet.
699		if toDisableUnsignedShiftBaseChange(flags.Local.CFlags) {
700			flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize=unsigned-shift-base")
701		}
702	}
703
704	if len(sanitize.Properties.DiagSanitizers) > 0 {
705		flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-trap="+strings.Join(sanitize.Properties.DiagSanitizers, ","))
706	}
707	// FIXME: enable RTTI if diag + (cfi or vptr)
708
709	if sanitize.Properties.Sanitize.Recover != nil {
710		flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-recover="+
711			strings.Join(sanitize.Properties.Sanitize.Recover, ","))
712	}
713
714	if sanitize.Properties.Sanitize.Diag.No_recover != nil {
715		flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-recover="+
716			strings.Join(sanitize.Properties.Sanitize.Diag.No_recover, ","))
717	}
718
719	blocklist := android.OptionalPathForModuleSrc(ctx, sanitize.Properties.Sanitize.Blocklist)
720	if blocklist.Valid() {
721		flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-blacklist="+blocklist.String())
722		flags.CFlagsDeps = append(flags.CFlagsDeps, blocklist.Path())
723	}
724
725	return flags
726}
727
728func (sanitize *sanitize) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
729	// Add a suffix for cfi/hwasan/scs-enabled static/header libraries to allow surfacing
730	// both the sanitized and non-sanitized variants to make without a name conflict.
731	if entries.Class == "STATIC_LIBRARIES" || entries.Class == "HEADER_LIBRARIES" {
732		if Bool(sanitize.Properties.Sanitize.Cfi) {
733			entries.SubName += ".cfi"
734		}
735		if Bool(sanitize.Properties.Sanitize.Hwaddress) {
736			entries.SubName += ".hwasan"
737		}
738		if Bool(sanitize.Properties.Sanitize.Scs) {
739			entries.SubName += ".scs"
740		}
741	}
742}
743
744func (sanitize *sanitize) inSanitizerDir() bool {
745	return sanitize.Properties.InSanitizerDir
746}
747
748// getSanitizerBoolPtr returns the SanitizerTypes associated bool pointer from SanitizeProperties.
749func (sanitize *sanitize) getSanitizerBoolPtr(t SanitizerType) *bool {
750	switch t {
751	case Asan:
752		return sanitize.Properties.Sanitize.Address
753	case Hwasan:
754		return sanitize.Properties.Sanitize.Hwaddress
755	case tsan:
756		return sanitize.Properties.Sanitize.Thread
757	case intOverflow:
758		return sanitize.Properties.Sanitize.Integer_overflow
759	case cfi:
760		return sanitize.Properties.Sanitize.Cfi
761	case scs:
762		return sanitize.Properties.Sanitize.Scs
763	case memtag_heap:
764		return sanitize.Properties.Sanitize.Memtag_heap
765	case Fuzzer:
766		return sanitize.Properties.Sanitize.Fuzzer
767	default:
768		panic(fmt.Errorf("unknown SanitizerType %d", t))
769	}
770}
771
772// isUnsanitizedVariant returns true if no sanitizers are enabled.
773func (sanitize *sanitize) isUnsanitizedVariant() bool {
774	return !sanitize.isSanitizerEnabled(Asan) &&
775		!sanitize.isSanitizerEnabled(Hwasan) &&
776		!sanitize.isSanitizerEnabled(tsan) &&
777		!sanitize.isSanitizerEnabled(cfi) &&
778		!sanitize.isSanitizerEnabled(scs) &&
779		!sanitize.isSanitizerEnabled(memtag_heap) &&
780		!sanitize.isSanitizerEnabled(Fuzzer)
781}
782
783// isVariantOnProductionDevice returns true if variant is for production devices (no non-production sanitizers enabled).
784func (sanitize *sanitize) isVariantOnProductionDevice() bool {
785	return !sanitize.isSanitizerEnabled(Asan) &&
786		!sanitize.isSanitizerEnabled(Hwasan) &&
787		!sanitize.isSanitizerEnabled(tsan) &&
788		!sanitize.isSanitizerEnabled(Fuzzer)
789}
790
791func (sanitize *sanitize) SetSanitizer(t SanitizerType, b bool) {
792	switch t {
793	case Asan:
794		sanitize.Properties.Sanitize.Address = boolPtr(b)
795	case Hwasan:
796		sanitize.Properties.Sanitize.Hwaddress = boolPtr(b)
797	case tsan:
798		sanitize.Properties.Sanitize.Thread = boolPtr(b)
799	case intOverflow:
800		sanitize.Properties.Sanitize.Integer_overflow = boolPtr(b)
801	case cfi:
802		sanitize.Properties.Sanitize.Cfi = boolPtr(b)
803	case scs:
804		sanitize.Properties.Sanitize.Scs = boolPtr(b)
805	case memtag_heap:
806		sanitize.Properties.Sanitize.Memtag_heap = boolPtr(b)
807	case Fuzzer:
808		sanitize.Properties.Sanitize.Fuzzer = boolPtr(b)
809	default:
810		panic(fmt.Errorf("unknown SanitizerType %d", t))
811	}
812	if b {
813		sanitize.Properties.SanitizerEnabled = true
814	}
815}
816
817// Check if the sanitizer is explicitly disabled (as opposed to nil by
818// virtue of not being set).
819func (sanitize *sanitize) isSanitizerExplicitlyDisabled(t SanitizerType) bool {
820	if sanitize == nil {
821		return false
822	}
823
824	sanitizerVal := sanitize.getSanitizerBoolPtr(t)
825	return sanitizerVal != nil && *sanitizerVal == false
826}
827
828// There isn't an analog of the method above (ie:isSanitizerExplicitlyEnabled)
829// because enabling a sanitizer either directly (via the blueprint) or
830// indirectly (via a mutator) sets the bool ptr to true, and you can't
831// distinguish between the cases. It isn't needed though - both cases can be
832// treated identically.
833func (sanitize *sanitize) isSanitizerEnabled(t SanitizerType) bool {
834	if sanitize == nil {
835		return false
836	}
837
838	sanitizerVal := sanitize.getSanitizerBoolPtr(t)
839	return sanitizerVal != nil && *sanitizerVal == true
840}
841
842// IsSanitizableDependencyTag returns true if the dependency tag is sanitizable.
843func IsSanitizableDependencyTag(tag blueprint.DependencyTag) bool {
844	switch t := tag.(type) {
845	case dependencyTag:
846		return t == reuseObjTag || t == objDepTag
847	case libraryDependencyTag:
848		return true
849	default:
850		return false
851	}
852}
853
854func (m *Module) SanitizableDepTagChecker() SantizableDependencyTagChecker {
855	return IsSanitizableDependencyTag
856}
857
858// Determines if the current module is a static library going to be captured
859// as vendor snapshot. Such modules must create both cfi and non-cfi variants,
860// except for ones which explicitly disable cfi.
861func needsCfiForVendorSnapshot(mctx android.TopDownMutatorContext) bool {
862	if isVendorProprietaryModule(mctx) {
863		return false
864	}
865
866	c := mctx.Module().(PlatformSanitizeable)
867
868	if !c.InVendor() {
869		return false
870	}
871
872	if !c.StaticallyLinked() {
873		return false
874	}
875
876	if c.IsPrebuilt() {
877		return false
878	}
879
880	if !c.SanitizerSupported(cfi) {
881		return false
882	}
883
884	return c.SanitizePropDefined() &&
885		!c.SanitizeNever() &&
886		!c.IsSanitizerExplicitlyDisabled(cfi)
887}
888
889// Propagate sanitizer requirements down from binaries
890func sanitizerDepsMutator(t SanitizerType) func(android.TopDownMutatorContext) {
891	return func(mctx android.TopDownMutatorContext) {
892		if c, ok := mctx.Module().(PlatformSanitizeable); ok {
893			enabled := c.IsSanitizerEnabled(t)
894			if t == cfi && needsCfiForVendorSnapshot(mctx) {
895				// We shouldn't change the result of isSanitizerEnabled(cfi) to correctly
896				// determine defaultVariation in sanitizerMutator below.
897				// Instead, just mark SanitizeDep to forcefully create cfi variant.
898				enabled = true
899				c.SetSanitizeDep(true)
900			}
901			if enabled {
902				isSanitizableDependencyTag := c.SanitizableDepTagChecker()
903				mctx.WalkDeps(func(child, parent android.Module) bool {
904					if !isSanitizableDependencyTag(mctx.OtherModuleDependencyTag(child)) {
905						return false
906					}
907					if d, ok := child.(PlatformSanitizeable); ok && d.SanitizePropDefined() &&
908						!d.SanitizeNever() &&
909						!d.IsSanitizerExplicitlyDisabled(t) {
910						if t == cfi || t == Hwasan || t == scs || t == Asan {
911							if d.StaticallyLinked() && d.SanitizerSupported(t) {
912								// Rust does not support some of these sanitizers, so we need to check if it's
913								// supported before setting this true.
914								d.SetSanitizeDep(true)
915							}
916						} else {
917							d.SetSanitizeDep(true)
918						}
919					}
920					return true
921				})
922			}
923		} else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok {
924			// If an APEX module includes a lib which is enabled for a sanitizer T, then
925			// the APEX module is also enabled for the same sanitizer type.
926			mctx.VisitDirectDeps(func(child android.Module) {
927				if c, ok := child.(*Module); ok && c.sanitize.isSanitizerEnabled(t) {
928					sanitizeable.EnableSanitizer(t.name())
929				}
930			})
931		}
932	}
933}
934
935func (c *Module) SanitizeNever() bool {
936	return Bool(c.sanitize.Properties.Sanitize.Never)
937}
938
939func (c *Module) IsSanitizerExplicitlyDisabled(t SanitizerType) bool {
940	return c.sanitize.isSanitizerExplicitlyDisabled(t)
941}
942
943// Propagate the ubsan minimal runtime dependency when there are integer overflow sanitized static dependencies.
944func sanitizerRuntimeDepsMutator(mctx android.TopDownMutatorContext) {
945	// Change this to PlatformSanitizable when/if non-cc modules support ubsan sanitizers.
946	if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil {
947		isSanitizableDependencyTag := c.SanitizableDepTagChecker()
948		mctx.WalkDeps(func(child, parent android.Module) bool {
949			if !isSanitizableDependencyTag(mctx.OtherModuleDependencyTag(child)) {
950				return false
951			}
952
953			d, ok := child.(*Module)
954			if !ok || !d.static() {
955				return false
956			}
957			if d.sanitize != nil {
958				if enableMinimalRuntime(d.sanitize) {
959					// If a static dependency is built with the minimal runtime,
960					// make sure we include the ubsan minimal runtime.
961					c.sanitize.Properties.MinimalRuntimeDep = true
962				} else if enableUbsanRuntime(d.sanitize) {
963					// If a static dependency runs with full ubsan diagnostics,
964					// make sure we include the ubsan runtime.
965					c.sanitize.Properties.UbsanRuntimeDep = true
966				}
967
968				if c.sanitize.Properties.MinimalRuntimeDep &&
969					c.sanitize.Properties.UbsanRuntimeDep {
970					// both flags that this mutator might set are true, so don't bother recursing
971					return false
972				}
973
974				if c.Os() == android.Linux {
975					c.sanitize.Properties.BuiltinsDep = true
976				}
977
978				return true
979			}
980
981			if p, ok := d.linker.(*snapshotLibraryDecorator); ok {
982				if Bool(p.properties.Sanitize_minimal_dep) {
983					c.sanitize.Properties.MinimalRuntimeDep = true
984				}
985				if Bool(p.properties.Sanitize_ubsan_dep) {
986					c.sanitize.Properties.UbsanRuntimeDep = true
987				}
988			}
989
990			return false
991		})
992	}
993}
994
995// Add the dependency to the runtime library for each of the sanitizer variants
996func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) {
997	if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil {
998		if !c.Enabled() {
999			return
1000		}
1001		var sanitizers []string
1002		var diagSanitizers []string
1003
1004		if Bool(c.sanitize.Properties.Sanitize.All_undefined) {
1005			sanitizers = append(sanitizers, "undefined")
1006		} else {
1007			if Bool(c.sanitize.Properties.Sanitize.Undefined) {
1008				sanitizers = append(sanitizers,
1009					"bool",
1010					"integer-divide-by-zero",
1011					"return",
1012					"returns-nonnull-attribute",
1013					"shift-exponent",
1014					"unreachable",
1015					"vla-bound",
1016					// TODO(danalbert): The following checks currently have compiler performance issues.
1017					//"alignment",
1018					//"bounds",
1019					//"enum",
1020					//"float-cast-overflow",
1021					//"float-divide-by-zero",
1022					//"nonnull-attribute",
1023					//"null",
1024					//"shift-base",
1025					//"signed-integer-overflow",
1026					// TODO(danalbert): Fix UB in libc++'s __tree so we can turn this on.
1027					// https://llvm.org/PR19302
1028					// http://reviews.llvm.org/D6974
1029					// "object-size",
1030				)
1031			}
1032			sanitizers = append(sanitizers, c.sanitize.Properties.Sanitize.Misc_undefined...)
1033		}
1034
1035		if Bool(c.sanitize.Properties.Sanitize.Diag.Undefined) {
1036			diagSanitizers = append(diagSanitizers, "undefined")
1037		}
1038
1039		diagSanitizers = append(diagSanitizers, c.sanitize.Properties.Sanitize.Diag.Misc_undefined...)
1040
1041		if Bool(c.sanitize.Properties.Sanitize.Address) {
1042			sanitizers = append(sanitizers, "address")
1043			diagSanitizers = append(diagSanitizers, "address")
1044		}
1045
1046		if Bool(c.sanitize.Properties.Sanitize.Hwaddress) {
1047			sanitizers = append(sanitizers, "hwaddress")
1048		}
1049
1050		if Bool(c.sanitize.Properties.Sanitize.Thread) {
1051			sanitizers = append(sanitizers, "thread")
1052		}
1053
1054		if Bool(c.sanitize.Properties.Sanitize.Safestack) {
1055			sanitizers = append(sanitizers, "safe-stack")
1056		}
1057
1058		if Bool(c.sanitize.Properties.Sanitize.Cfi) {
1059			sanitizers = append(sanitizers, "cfi")
1060
1061			if Bool(c.sanitize.Properties.Sanitize.Diag.Cfi) {
1062				diagSanitizers = append(diagSanitizers, "cfi")
1063			}
1064		}
1065
1066		if Bool(c.sanitize.Properties.Sanitize.Integer_overflow) {
1067			sanitizers = append(sanitizers, "unsigned-integer-overflow")
1068			sanitizers = append(sanitizers, "signed-integer-overflow")
1069			if Bool(c.sanitize.Properties.Sanitize.Diag.Integer_overflow) {
1070				diagSanitizers = append(diagSanitizers, "unsigned-integer-overflow")
1071				diagSanitizers = append(diagSanitizers, "signed-integer-overflow")
1072			}
1073		}
1074
1075		if Bool(c.sanitize.Properties.Sanitize.Scudo) {
1076			sanitizers = append(sanitizers, "scudo")
1077		}
1078
1079		if Bool(c.sanitize.Properties.Sanitize.Scs) {
1080			sanitizers = append(sanitizers, "shadow-call-stack")
1081		}
1082
1083		if Bool(c.sanitize.Properties.Sanitize.Memtag_heap) && c.Binary() {
1084			noteDep := "note_memtag_heap_async"
1085			if Bool(c.sanitize.Properties.Sanitize.Diag.Memtag_heap) {
1086				noteDep = "note_memtag_heap_sync"
1087			}
1088			// If we're using snapshots, redirect to snapshot whenever possible
1089			// TODO(b/178470649): clean manual snapshot redirections
1090			snapshot := mctx.Provider(SnapshotInfoProvider).(SnapshotInfo)
1091			if lib, ok := snapshot.StaticLibs[noteDep]; ok {
1092				noteDep = lib
1093			}
1094			depTag := libraryDependencyTag{Kind: staticLibraryDependency, wholeStatic: true}
1095			variations := append(mctx.Target().Variations(),
1096				blueprint.Variation{Mutator: "link", Variation: "static"})
1097			if c.Device() {
1098				variations = append(variations, c.ImageVariation())
1099			}
1100			mctx.AddFarVariationDependencies(variations, depTag, noteDep)
1101		}
1102
1103		if Bool(c.sanitize.Properties.Sanitize.Fuzzer) {
1104			sanitizers = append(sanitizers, "fuzzer-no-link")
1105		}
1106
1107		// Save the list of sanitizers. These will be used again when generating
1108		// the build rules (for Cflags, etc.)
1109		c.sanitize.Properties.Sanitizers = sanitizers
1110		c.sanitize.Properties.DiagSanitizers = diagSanitizers
1111
1112		// TODO(b/150822854) Hosts have a different default behavior and assume the runtime library is used.
1113		if c.Host() {
1114			diagSanitizers = sanitizers
1115		}
1116
1117		// Determine the runtime library required
1118		runtimeLibrary := ""
1119		var extraStaticDeps []string
1120		toolchain := c.toolchain(mctx)
1121		if Bool(c.sanitize.Properties.Sanitize.Address) {
1122			runtimeLibrary = config.AddressSanitizerRuntimeLibrary(toolchain)
1123		} else if Bool(c.sanitize.Properties.Sanitize.Hwaddress) {
1124			if c.staticBinary() {
1125				runtimeLibrary = config.HWAddressSanitizerStaticLibrary(toolchain)
1126				extraStaticDeps = []string{"libdl"}
1127			} else {
1128				runtimeLibrary = config.HWAddressSanitizerRuntimeLibrary(toolchain)
1129			}
1130		} else if Bool(c.sanitize.Properties.Sanitize.Thread) {
1131			runtimeLibrary = config.ThreadSanitizerRuntimeLibrary(toolchain)
1132		} else if Bool(c.sanitize.Properties.Sanitize.Scudo) {
1133			if len(diagSanitizers) == 0 && !c.sanitize.Properties.UbsanRuntimeDep {
1134				runtimeLibrary = config.ScudoMinimalRuntimeLibrary(toolchain)
1135			} else {
1136				runtimeLibrary = config.ScudoRuntimeLibrary(toolchain)
1137			}
1138		} else if len(diagSanitizers) > 0 || c.sanitize.Properties.UbsanRuntimeDep ||
1139			Bool(c.sanitize.Properties.Sanitize.Fuzzer) ||
1140			Bool(c.sanitize.Properties.Sanitize.Undefined) ||
1141			Bool(c.sanitize.Properties.Sanitize.All_undefined) {
1142			runtimeLibrary = config.UndefinedBehaviorSanitizerRuntimeLibrary(toolchain)
1143			if c.staticBinary() {
1144				runtimeLibrary += ".static"
1145			}
1146		}
1147
1148		if runtimeLibrary != "" && (toolchain.Bionic() || c.sanitize.Properties.UbsanRuntimeDep) {
1149			// UBSan is supported on non-bionic linux host builds as well
1150
1151			// Adding dependency to the runtime library. We are using *FarVariation*
1152			// because the runtime libraries themselves are not mutated by sanitizer
1153			// mutators and thus don't have sanitizer variants whereas this module
1154			// has been already mutated.
1155			//
1156			// Note that by adding dependency with {static|shared}DepTag, the lib is
1157			// added to libFlags and LOCAL_SHARED_LIBRARIES by cc.Module
1158			if c.staticBinary() {
1159				deps := append(extraStaticDeps, runtimeLibrary)
1160				// If we're using snapshots, redirect to snapshot whenever possible
1161				snapshot := mctx.Provider(SnapshotInfoProvider).(SnapshotInfo)
1162				for idx, dep := range deps {
1163					if lib, ok := snapshot.StaticLibs[dep]; ok {
1164						deps[idx] = lib
1165					}
1166				}
1167
1168				// static executable gets static runtime libs
1169				depTag := libraryDependencyTag{Kind: staticLibraryDependency}
1170				variations := append(mctx.Target().Variations(),
1171					blueprint.Variation{Mutator: "link", Variation: "static"})
1172				if c.Device() {
1173					variations = append(variations, c.ImageVariation())
1174				}
1175				mctx.AddFarVariationDependencies(variations, depTag, deps...)
1176			} else if !c.static() && !c.Header() {
1177				// If we're using snapshots, redirect to snapshot whenever possible
1178				snapshot := mctx.Provider(SnapshotInfoProvider).(SnapshotInfo)
1179				if lib, ok := snapshot.SharedLibs[runtimeLibrary]; ok {
1180					runtimeLibrary = lib
1181				}
1182
1183				// Skip apex dependency check for sharedLibraryDependency
1184				// when sanitizer diags are enabled. Skipping the check will allow
1185				// building with diag libraries without having to list the
1186				// dependency in Apex's allowed_deps file.
1187				diagEnabled := len(diagSanitizers) > 0
1188				// dynamic executable and shared libs get shared runtime libs
1189				depTag := libraryDependencyTag{
1190					Kind:  sharedLibraryDependency,
1191					Order: earlyLibraryDependency,
1192
1193					skipApexAllowedDependenciesCheck: diagEnabled,
1194				}
1195				variations := append(mctx.Target().Variations(),
1196					blueprint.Variation{Mutator: "link", Variation: "shared"})
1197				if c.Device() {
1198					variations = append(variations, c.ImageVariation())
1199				}
1200				c.addSharedLibDependenciesWithVersions(mctx, variations, depTag, runtimeLibrary, "", true)
1201			}
1202			// static lib does not have dependency to the runtime library. The
1203			// dependency will be added to the executables or shared libs using
1204			// the static lib.
1205		}
1206	}
1207}
1208
1209type Sanitizeable interface {
1210	android.Module
1211	IsSanitizerEnabled(ctx android.BaseModuleContext, sanitizerName string) bool
1212	EnableSanitizer(sanitizerName string)
1213	AddSanitizerDependencies(ctx android.BottomUpMutatorContext, sanitizerName string)
1214}
1215
1216func (c *Module) MinimalRuntimeDep() bool {
1217	return c.sanitize.Properties.MinimalRuntimeDep
1218}
1219
1220func (c *Module) UbsanRuntimeDep() bool {
1221	return c.sanitize.Properties.UbsanRuntimeDep
1222}
1223
1224func (c *Module) SanitizePropDefined() bool {
1225	return c.sanitize != nil
1226}
1227
1228func (c *Module) IsSanitizerEnabled(t SanitizerType) bool {
1229	return c.sanitize.isSanitizerEnabled(t)
1230}
1231
1232func (c *Module) SanitizeDep() bool {
1233	return c.sanitize.Properties.SanitizeDep
1234}
1235
1236func (c *Module) StaticallyLinked() bool {
1237	return c.static()
1238}
1239
1240func (c *Module) SetInSanitizerDir() {
1241	if c.sanitize != nil {
1242		c.sanitize.Properties.InSanitizerDir = true
1243	}
1244}
1245
1246func (c *Module) SetSanitizer(t SanitizerType, b bool) {
1247	if c.sanitize != nil {
1248		c.sanitize.SetSanitizer(t, b)
1249	}
1250}
1251
1252func (c *Module) SetSanitizeDep(b bool) {
1253	if c.sanitize != nil {
1254		c.sanitize.Properties.SanitizeDep = b
1255	}
1256}
1257
1258var _ PlatformSanitizeable = (*Module)(nil)
1259
1260// Create sanitized variants for modules that need them
1261func sanitizerMutator(t SanitizerType) func(android.BottomUpMutatorContext) {
1262	return func(mctx android.BottomUpMutatorContext) {
1263		if c, ok := mctx.Module().(PlatformSanitizeable); ok && c.SanitizePropDefined() {
1264			if c.IsDependencyRoot() && c.IsSanitizerEnabled(t) {
1265				modules := mctx.CreateVariations(t.variationName())
1266				modules[0].(PlatformSanitizeable).SetSanitizer(t, true)
1267			} else if c.IsSanitizerEnabled(t) || c.SanitizeDep() {
1268				isSanitizerEnabled := c.IsSanitizerEnabled(t)
1269				if c.StaticallyLinked() || c.Header() || t == Fuzzer {
1270					// Static and header libs are split into non-sanitized and sanitized variants.
1271					// Shared libs are not split. However, for asan and fuzzer, we split even for shared
1272					// libs because a library sanitized for asan/fuzzer can't be linked from a library
1273					// that isn't sanitized for asan/fuzzer.
1274					//
1275					// Note for defaultVariation: since we don't split for shared libs but for static/header
1276					// libs, it is possible for the sanitized variant of a static/header lib to depend
1277					// on non-sanitized variant of a shared lib. Such unfulfilled variation causes an
1278					// error when the module is split. defaultVariation is the name of the variation that
1279					// will be used when such a dangling dependency occurs during the split of the current
1280					// module. By setting it to the name of the sanitized variation, the dangling dependency
1281					// is redirected to the sanitized variant of the dependent module.
1282					defaultVariation := t.variationName()
1283					// Not all PlatformSanitizeable modules support the CFI sanitizer
1284					cfiSupported := mctx.Module().(PlatformSanitizeable).SanitizerSupported(cfi)
1285					mctx.SetDefaultDependencyVariation(&defaultVariation)
1286
1287					modules := mctx.CreateVariations("", t.variationName())
1288					modules[0].(PlatformSanitizeable).SetSanitizer(t, false)
1289					modules[1].(PlatformSanitizeable).SetSanitizer(t, true)
1290					modules[0].(PlatformSanitizeable).SetSanitizeDep(false)
1291					modules[1].(PlatformSanitizeable).SetSanitizeDep(false)
1292
1293					if mctx.Device() && t.incompatibleWithCfi() && cfiSupported {
1294						// TODO: Make sure that cfi mutator runs "after" any of the sanitizers that
1295						// are incompatible with cfi
1296						modules[1].(PlatformSanitizeable).SetSanitizer(cfi, false)
1297					}
1298
1299					// For cfi/scs/hwasan, we can export both sanitized and un-sanitized variants
1300					// to Make, because the sanitized version has a different suffix in name.
1301					// For other types of sanitizers, suppress the variation that is disabled.
1302					if t != cfi && t != scs && t != Hwasan {
1303						if isSanitizerEnabled {
1304							modules[0].(PlatformSanitizeable).SetPreventInstall()
1305							modules[0].(PlatformSanitizeable).SetHideFromMake()
1306						} else {
1307							modules[1].(PlatformSanitizeable).SetPreventInstall()
1308							modules[1].(PlatformSanitizeable).SetHideFromMake()
1309						}
1310					}
1311
1312					// Export the static lib name to make
1313					if c.StaticallyLinked() && c.ExportedToMake() {
1314						if t == cfi {
1315							cfiStaticLibs(mctx.Config()).add(c, c.Module().Name())
1316						} else if t == Hwasan {
1317							hwasanStaticLibs(mctx.Config()).add(c, c.Module().Name())
1318						}
1319					}
1320				} else {
1321					// Shared libs are not split. Only the sanitized variant is created.
1322					modules := mctx.CreateVariations(t.variationName())
1323					modules[0].(PlatformSanitizeable).SetSanitizer(t, true)
1324					modules[0].(PlatformSanitizeable).SetSanitizeDep(false)
1325
1326					// locate the asan libraries under /data/asan
1327					if mctx.Device() && t == Asan && isSanitizerEnabled {
1328						modules[0].(PlatformSanitizeable).SetInSanitizerDir()
1329					}
1330
1331					if mctx.Device() && t.incompatibleWithCfi() {
1332						// TODO: Make sure that cfi mutator runs "after" any of the sanitizers that
1333						// are incompatible with cfi
1334						modules[0].(PlatformSanitizeable).SetSanitizer(cfi, false)
1335					}
1336				}
1337			}
1338			c.SetSanitizeDep(false)
1339		} else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok && sanitizeable.IsSanitizerEnabled(mctx, t.name()) {
1340			// APEX modules fall here
1341			sanitizeable.AddSanitizerDependencies(mctx, t.name())
1342			mctx.CreateVariations(t.variationName())
1343		} else if c, ok := mctx.Module().(*Module); ok {
1344			//TODO: When Rust modules have vendor support, enable this path for PlatformSanitizeable
1345
1346			// Check if it's a snapshot module supporting sanitizer
1347			if s, ok := c.linker.(snapshotSanitizer); ok && s.isSanitizerEnabled(t) {
1348				// Set default variation as above.
1349				defaultVariation := t.variationName()
1350				mctx.SetDefaultDependencyVariation(&defaultVariation)
1351				modules := mctx.CreateVariations("", t.variationName())
1352				modules[0].(*Module).linker.(snapshotSanitizer).setSanitizerVariation(t, false)
1353				modules[1].(*Module).linker.(snapshotSanitizer).setSanitizerVariation(t, true)
1354
1355				// Export the static lib name to make
1356				if c.static() && c.ExportedToMake() {
1357					if t == cfi {
1358						// use BaseModuleName which is the name for Make.
1359						cfiStaticLibs(mctx.Config()).add(c, c.BaseModuleName())
1360					}
1361				}
1362			}
1363		}
1364	}
1365}
1366
1367type sanitizerStaticLibsMap struct {
1368	// libsMap contains one list of modules per each image and each arch.
1369	// e.g. libs[vendor]["arm"] contains arm modules installed to vendor
1370	libsMap       map[ImageVariantType]map[string][]string
1371	libsMapLock   sync.Mutex
1372	sanitizerType SanitizerType
1373}
1374
1375func newSanitizerStaticLibsMap(t SanitizerType) *sanitizerStaticLibsMap {
1376	return &sanitizerStaticLibsMap{
1377		sanitizerType: t,
1378		libsMap:       make(map[ImageVariantType]map[string][]string),
1379	}
1380}
1381
1382// Add the current module to sanitizer static libs maps
1383// Each module should pass its exported name as names of Make and Soong can differ.
1384func (s *sanitizerStaticLibsMap) add(c LinkableInterface, name string) {
1385	image := GetImageVariantType(c)
1386	arch := c.Module().Target().Arch.ArchType.String()
1387
1388	s.libsMapLock.Lock()
1389	defer s.libsMapLock.Unlock()
1390
1391	if _, ok := s.libsMap[image]; !ok {
1392		s.libsMap[image] = make(map[string][]string)
1393	}
1394
1395	s.libsMap[image][arch] = append(s.libsMap[image][arch], name)
1396}
1397
1398// Exports makefile variables in the following format:
1399// SOONG_{sanitizer}_{image}_{arch}_STATIC_LIBRARIES
1400// e.g. SOONG_cfi_core_x86_STATIC_LIBRARIES
1401// These are to be used by use_soong_sanitized_static_libraries.
1402// See build/make/core/binary.mk for more details.
1403func (s *sanitizerStaticLibsMap) exportToMake(ctx android.MakeVarsContext) {
1404	for _, image := range android.SortedStringKeys(s.libsMap) {
1405		archMap := s.libsMap[ImageVariantType(image)]
1406		for _, arch := range android.SortedStringKeys(archMap) {
1407			libs := archMap[arch]
1408			sort.Strings(libs)
1409
1410			key := fmt.Sprintf(
1411				"SOONG_%s_%s_%s_STATIC_LIBRARIES",
1412				s.sanitizerType.variationName(),
1413				image, // already upper
1414				arch)
1415
1416			ctx.Strict(key, strings.Join(libs, " "))
1417		}
1418	}
1419}
1420
1421var cfiStaticLibsKey = android.NewOnceKey("cfiStaticLibs")
1422
1423func cfiStaticLibs(config android.Config) *sanitizerStaticLibsMap {
1424	return config.Once(cfiStaticLibsKey, func() interface{} {
1425		return newSanitizerStaticLibsMap(cfi)
1426	}).(*sanitizerStaticLibsMap)
1427}
1428
1429var hwasanStaticLibsKey = android.NewOnceKey("hwasanStaticLibs")
1430
1431func hwasanStaticLibs(config android.Config) *sanitizerStaticLibsMap {
1432	return config.Once(hwasanStaticLibsKey, func() interface{} {
1433		return newSanitizerStaticLibsMap(Hwasan)
1434	}).(*sanitizerStaticLibsMap)
1435}
1436
1437func enableMinimalRuntime(sanitize *sanitize) bool {
1438	if !Bool(sanitize.Properties.Sanitize.Address) &&
1439		!Bool(sanitize.Properties.Sanitize.Hwaddress) &&
1440		!Bool(sanitize.Properties.Sanitize.Fuzzer) &&
1441
1442		(Bool(sanitize.Properties.Sanitize.Integer_overflow) ||
1443			len(sanitize.Properties.Sanitize.Misc_undefined) > 0 ||
1444			Bool(sanitize.Properties.Sanitize.Undefined) ||
1445			Bool(sanitize.Properties.Sanitize.All_undefined)) &&
1446
1447		!(Bool(sanitize.Properties.Sanitize.Diag.Integer_overflow) ||
1448			Bool(sanitize.Properties.Sanitize.Diag.Cfi) ||
1449			Bool(sanitize.Properties.Sanitize.Diag.Undefined) ||
1450			len(sanitize.Properties.Sanitize.Diag.Misc_undefined) > 0) {
1451
1452		return true
1453	}
1454	return false
1455}
1456
1457func (m *Module) UbsanRuntimeNeeded() bool {
1458	return enableUbsanRuntime(m.sanitize)
1459}
1460
1461func (m *Module) MinimalRuntimeNeeded() bool {
1462	return enableMinimalRuntime(m.sanitize)
1463}
1464
1465func enableUbsanRuntime(sanitize *sanitize) bool {
1466	return Bool(sanitize.Properties.Sanitize.Diag.Integer_overflow) ||
1467		Bool(sanitize.Properties.Sanitize.Diag.Undefined) ||
1468		len(sanitize.Properties.Sanitize.Diag.Misc_undefined) > 0
1469}
1470
1471func cfiMakeVarsProvider(ctx android.MakeVarsContext) {
1472	cfiStaticLibs(ctx.Config()).exportToMake(ctx)
1473}
1474
1475func hwasanMakeVarsProvider(ctx android.MakeVarsContext) {
1476	hwasanStaticLibs(ctx.Config()).exportToMake(ctx)
1477}
1478