xref: /aosp_15_r20/build/soong/cc/sanitize.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
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	"github.com/google/blueprint/proptools"
25
26	"android/soong/android"
27	"android/soong/cc/config"
28	"android/soong/etc"
29)
30
31var (
32	// Any C flags added by sanitizer which libTooling tools may not
33	// understand also need to be added to ClangLibToolingUnknownCflags in
34	// cc/config/clang.go
35
36	asanCflags = []string{
37		"-fno-omit-frame-pointer",
38	}
39
40	// DO NOT ADD MLLVM FLAGS HERE! ADD THEM BELOW TO hwasanCommonFlags.
41	hwasanCflags = []string{
42		"-fno-omit-frame-pointer",
43		"-Wno-frame-larger-than=",
44		"-fsanitize-hwaddress-abi=platform",
45	}
46
47	// ThinLTO performs codegen during link time, thus these flags need to
48	// passed to both CFLAGS and LDFLAGS.
49	hwasanCommonflags = []string{
50		// The following improves debug location information
51		// availability at the cost of its accuracy. It increases
52		// the likelihood of a stack variable's frame offset
53		// to be recorded in the debug info, which is important
54		// for the quality of hwasan reports. The downside is a
55		// higher number of "optimized out" stack variables.
56		// b/112437883.
57		"-instcombine-lower-dbg-declare=0",
58		"-dom-tree-reachability-max-bbs-to-explore=128",
59	}
60
61	sanitizeIgnorelistPrefix = "-fsanitize-ignorelist="
62
63	cfiBlocklistPath     = "external/compiler-rt/lib/cfi"
64	cfiBlocklistFilename = "cfi_blocklist.txt"
65	cfiEnableFlag        = "-fsanitize=cfi"
66	cfiCrossDsoFlag      = "-fsanitize-cfi-cross-dso"
67	cfiCflags            = []string{"-flto", cfiCrossDsoFlag,
68		sanitizeIgnorelistPrefix + cfiBlocklistPath + "/" + cfiBlocklistFilename}
69	// -flto and -fvisibility are required by clang when -fsanitize=cfi is
70	// used, but have no effect on assembly files
71	cfiAsflags = []string{"-flto", "-fvisibility=default"}
72	cfiLdflags = []string{"-flto", cfiCrossDsoFlag, cfiEnableFlag,
73		"-Wl,-plugin-opt,O1"}
74	cfiExportsMapPath      = "build/soong/cc/config"
75	cfiExportsMapFilename  = "cfi_exports.map"
76	cfiAssemblySupportFlag = "-fno-sanitize-cfi-canonical-jump-tables"
77
78	intOverflowCflags = []string{"-fsanitize-ignorelist=build/soong/cc/config/integer_overflow_blocklist.txt"}
79
80	minimalRuntimeFlags = []string{"-fsanitize-minimal-runtime", "-fno-sanitize-trap=integer,undefined",
81		"-fno-sanitize-recover=integer,undefined"}
82	memtagStackCommonFlags = []string{"-march=armv8-a+memtag"}
83	memtagStackLlvmFlags   = []string{"-dom-tree-reachability-max-bbs-to-explore=128"}
84
85	hostOnlySanitizeFlags   = []string{"-fno-sanitize-recover=all"}
86	deviceOnlySanitizeFlags = []string{"-fsanitize-trap=all"}
87
88	noSanitizeLinkRuntimeFlag = "-fno-sanitize-link-runtime"
89)
90
91type SanitizerType int
92
93const (
94	Asan SanitizerType = iota + 1
95	Hwasan
96	tsan
97	intOverflow
98	scs
99	Fuzzer
100	Memtag_heap
101	Memtag_stack
102	Memtag_globals
103	cfi // cfi is last to prevent it running before incompatible mutators
104)
105
106var Sanitizers = []SanitizerType{
107	Asan,
108	Hwasan,
109	tsan,
110	intOverflow,
111	scs,
112	Fuzzer,
113	Memtag_heap,
114	Memtag_stack,
115	Memtag_globals,
116	cfi, // cfi is last to prevent it running before incompatible mutators
117}
118
119// Name of the sanitizer variation for this sanitizer type
120func (t SanitizerType) variationName() string {
121	switch t {
122	case Asan:
123		return "asan"
124	case Hwasan:
125		return "hwasan"
126	case tsan:
127		return "tsan"
128	case intOverflow:
129		return "intOverflow"
130	case cfi:
131		return "cfi"
132	case scs:
133		return "scs"
134	case Memtag_heap:
135		return "memtag_heap"
136	case Memtag_stack:
137		return "memtag_stack"
138	case Memtag_globals:
139		return "memtag_globals"
140	case Fuzzer:
141		return "fuzzer"
142	default:
143		panic(fmt.Errorf("unknown SanitizerType %d", t))
144	}
145}
146
147// This is the sanitizer names in SANITIZE_[TARGET|HOST]
148func (t SanitizerType) name() string {
149	switch t {
150	case Asan:
151		return "address"
152	case Hwasan:
153		return "hwaddress"
154	case Memtag_heap:
155		return "memtag_heap"
156	case Memtag_stack:
157		return "memtag_stack"
158	case Memtag_globals:
159		return "memtag_globals"
160	case tsan:
161		return "thread"
162	case intOverflow:
163		return "integer_overflow"
164	case cfi:
165		return "cfi"
166	case scs:
167		return "shadow-call-stack"
168	case Fuzzer:
169		return "fuzzer"
170	default:
171		panic(fmt.Errorf("unknown SanitizerType %d", t))
172	}
173}
174
175func (t SanitizerType) registerMutators(ctx android.RegisterMutatorsContext) {
176	switch t {
177	case cfi, Hwasan, Asan, tsan, Fuzzer, scs, Memtag_stack:
178		sanitizer := &sanitizerSplitMutator{t}
179		ctx.BottomUp(t.variationName()+"_markapexes", sanitizer.markSanitizableApexesMutator)
180		ctx.Transition(t.variationName(), sanitizer)
181	case Memtag_heap, Memtag_globals, intOverflow:
182		// do nothing
183	default:
184		panic(fmt.Errorf("unknown SanitizerType %d", t))
185	}
186}
187
188// shouldPropagateToSharedLibraryDeps returns whether a sanitizer type should propagate to share
189// dependencies. In most cases, sanitizers only propagate to static dependencies; however, some
190// sanitizers also must be enabled for shared libraries for linking.
191func (t SanitizerType) shouldPropagateToSharedLibraryDeps() bool {
192	switch t {
193	case Fuzzer:
194		// Typically, shared libs are not split. However, for fuzzer, we split even for shared libs
195		// because a library sanitized for fuzzer can't be linked from a library that isn't sanitized
196		// for fuzzer.
197		return true
198	default:
199		return false
200	}
201}
202func (*Module) SanitizerSupported(t SanitizerType) bool {
203	switch t {
204	case Asan:
205		return true
206	case Hwasan:
207		return true
208	case tsan:
209		return true
210	case intOverflow:
211		return true
212	case cfi:
213		return true
214	case scs:
215		return true
216	case Fuzzer:
217		return true
218	case Memtag_heap:
219		return true
220	case Memtag_stack:
221		return true
222	case Memtag_globals:
223		return true
224	default:
225		return false
226	}
227}
228
229// incompatibleWithCfi returns true if a sanitizer is incompatible with CFI.
230func (t SanitizerType) incompatibleWithCfi() bool {
231	return t == Asan || t == Fuzzer || t == Hwasan
232}
233
234type SanitizeUserProps struct {
235	// Prevent use of any sanitizers on this module
236	Never *bool `android:"arch_variant"`
237
238	// ASan (Address sanitizer), incompatible with static binaries.
239	// Always runs in a diagnostic mode.
240	// Use of address sanitizer disables cfi sanitizer.
241	// Hwaddress sanitizer takes precedence over this sanitizer.
242	Address *bool `android:"arch_variant"`
243	// TSan (Thread sanitizer), incompatible with static binaries and 32 bit architectures.
244	// Always runs in a diagnostic mode.
245	// Use of thread sanitizer disables cfi and scudo sanitizers.
246	// Hwaddress sanitizer takes precedence over this sanitizer.
247	Thread *bool `android:"arch_variant"`
248	// HWASan (Hardware Address sanitizer).
249	// Use of hwasan sanitizer disables cfi, address, thread, and scudo sanitizers.
250	Hwaddress *bool `android:"arch_variant"`
251
252	// Undefined behavior sanitizer
253	All_undefined *bool `android:"arch_variant"`
254	// Subset of undefined behavior sanitizer
255	Undefined *bool `android:"arch_variant"`
256	// List of specific undefined behavior sanitizers to enable
257	Misc_undefined []string `android:"arch_variant"`
258	// Fuzzer, incompatible with static binaries.
259	Fuzzer *bool `android:"arch_variant"`
260	// safe-stack sanitizer, incompatible with 32-bit architectures.
261	Safestack *bool `android:"arch_variant"`
262	// cfi sanitizer, incompatible with asan, hwasan, fuzzer, or Darwin
263	Cfi *bool `android:"arch_variant"`
264	// signed/unsigned integer overflow sanitizer, incompatible with Darwin.
265	Integer_overflow *bool `android:"arch_variant"`
266	// scudo sanitizer, incompatible with asan, hwasan, tsan
267	// This should not be used in Android 11+ : https://source.android.com/devices/tech/debug/scudo
268	// deprecated
269	Scudo *bool `android:"arch_variant"`
270	// shadow-call-stack sanitizer, only available on arm64/riscv64.
271	Scs *bool `android:"arch_variant"`
272	// Memory-tagging, only available on arm64
273	// if diag.memtag unset or false, enables async memory tagging
274	Memtag_heap *bool `android:"arch_variant"`
275	// Memory-tagging stack instrumentation, only available on arm64
276	// Adds instrumentation to detect stack buffer overflows and use-after-scope using MTE.
277	Memtag_stack *bool `android:"arch_variant"`
278	// Memory-tagging globals instrumentation, only available on arm64
279	// Adds instrumentation to detect global buffer overflows using MTE.
280	Memtag_globals *bool `android:"arch_variant"`
281
282	// A modifier for ASAN and HWASAN for write only instrumentation
283	Writeonly *bool `android:"arch_variant"`
284
285	// Sanitizers to run in the diagnostic mode (as opposed to the release mode).
286	// Replaces abort() on error with a human-readable error message.
287	// Address and Thread sanitizers always run in diagnostic mode.
288	Diag struct {
289		// Undefined behavior sanitizer, diagnostic mode
290		Undefined *bool `android:"arch_variant"`
291		// cfi sanitizer, diagnostic mode, incompatible with asan, hwasan, fuzzer, or Darwin
292		Cfi *bool `android:"arch_variant"`
293		// signed/unsigned integer overflow sanitizer, diagnostic mode, incompatible with Darwin.
294		Integer_overflow *bool `android:"arch_variant"`
295		// Memory-tagging, only available on arm64
296		// requires sanitizer.memtag: true
297		// if set, enables sync memory tagging
298		Memtag_heap *bool `android:"arch_variant"`
299		// List of specific undefined behavior sanitizers to enable in diagnostic mode
300		Misc_undefined []string `android:"arch_variant"`
301		// List of sanitizers to pass to -fno-sanitize-recover
302		// results in only the first detected error for these sanitizers being reported and program then
303		// exits with a non-zero exit code.
304		No_recover []string `android:"arch_variant"`
305	} `android:"arch_variant"`
306
307	// Sanitizers to run with flag configuration specified
308	Config struct {
309		// Enables CFI support flags for assembly-heavy libraries
310		Cfi_assembly_support *bool `android:"arch_variant"`
311	} `android:"arch_variant"`
312
313	// List of sanitizers to pass to -fsanitize-recover
314	// allows execution to continue for these sanitizers to detect multiple errors rather than only
315	// the first one
316	Recover []string
317
318	// value to pass to -fsanitize-ignorelist
319	Blocklist *string
320}
321
322type sanitizeMutatedProperties struct {
323	// Whether sanitizers can be enabled on this module
324	Never *bool `blueprint:"mutated"`
325
326	// Whether ASan (Address sanitizer) is enabled for this module.
327	// Hwaddress sanitizer takes precedence over this sanitizer.
328	Address *bool `blueprint:"mutated"`
329	// Whether TSan (Thread sanitizer) is enabled for this module
330	Thread *bool `blueprint:"mutated"`
331	// Whether HWASan (Hardware Address sanitizer) is enabled for this module
332	Hwaddress *bool `blueprint:"mutated"`
333
334	// Whether Undefined behavior sanitizer is enabled for this module
335	All_undefined *bool `blueprint:"mutated"`
336	// Whether undefined behavior sanitizer subset is enabled for this module
337	Undefined *bool `blueprint:"mutated"`
338	// List of specific undefined behavior sanitizers enabled for this module
339	Misc_undefined []string `blueprint:"mutated"`
340	// Whether Fuzzeris enabled for this module
341	Fuzzer *bool `blueprint:"mutated"`
342	// whether safe-stack sanitizer is enabled for this module
343	Safestack *bool `blueprint:"mutated"`
344	// Whether cfi sanitizer is enabled for this module
345	Cfi *bool `blueprint:"mutated"`
346	// Whether signed/unsigned integer overflow sanitizer is enabled for this module
347	Integer_overflow *bool `blueprint:"mutated"`
348	// Whether scudo sanitizer is enabled for this module
349	Scudo *bool `blueprint:"mutated"`
350	// Whether shadow-call-stack sanitizer is enabled for this module.
351	Scs *bool `blueprint:"mutated"`
352	// Whether Memory-tagging is enabled for this module
353	Memtag_heap *bool `blueprint:"mutated"`
354	// Whether Memory-tagging stack instrumentation is enabled for this module
355	Memtag_stack *bool `blueprint:"mutated"`
356	// Whether Memory-tagging globals instrumentation is enabled for this module
357	Memtag_globals *bool `android:"arch_variant"`
358
359	// Whether a modifier for ASAN and HWASAN for write only instrumentation is enabled for this
360	// module
361	Writeonly *bool `blueprint:"mutated"`
362
363	// Sanitizers to run in the diagnostic mode (as opposed to the release mode).
364	Diag struct {
365		// Whether Undefined behavior sanitizer, diagnostic mode is enabled for this module
366		Undefined *bool `blueprint:"mutated"`
367		// Whether cfi sanitizer, diagnostic mode is enabled for this module
368		Cfi *bool `blueprint:"mutated"`
369		// Whether signed/unsigned integer overflow sanitizer, diagnostic mode is enabled for this
370		// module
371		Integer_overflow *bool `blueprint:"mutated"`
372		// Whether Memory-tagging, diagnostic mode is enabled for this module
373		Memtag_heap *bool `blueprint:"mutated"`
374		// List of specific undefined behavior sanitizers enabled in diagnostic mode
375		Misc_undefined []string `blueprint:"mutated"`
376	} `blueprint:"mutated"`
377}
378
379type SanitizeProperties struct {
380	Sanitize        SanitizeUserProps         `android:"arch_variant"`
381	SanitizeMutated sanitizeMutatedProperties `blueprint:"mutated"`
382
383	// ForceDisable is set by the version mutator to disable sanitization of stubs variants
384	ForceDisable bool `blueprint:"mutated"`
385
386	// SanitizerEnabled is set by begin() if any of the sanitize boolean properties are set after
387	// applying the logic that enables globally enabled sanitizers and disables any unsupported
388	// sanitizers.
389	// TODO(b/349906293): this has some unintuitive behavior.  It is set in begin() before the sanitize
390	//  mutator is run if any of the individual sanitizes  properties are set, and then the individual
391	//  sanitize properties are cleared in the non-sanitized variants, but this value is never cleared.
392	//  That results in SanitizerEnabled being set in variants that have no sanitizers enabled, causing
393	//  some of the sanitizer logic in flags() to be applied to the non-sanitized variant.
394	SanitizerEnabled bool `blueprint:"mutated"`
395
396	MinimalRuntimeDep bool     `blueprint:"mutated"`
397	BuiltinsDep       bool     `blueprint:"mutated"`
398	UbsanRuntimeDep   bool     `blueprint:"mutated"`
399	InSanitizerDir    bool     `blueprint:"mutated"`
400	Sanitizers        []string `blueprint:"mutated"`
401	DiagSanitizers    []string `blueprint:"mutated"`
402}
403
404type sanitize struct {
405	Properties SanitizeProperties
406}
407
408// Mark this tag with a check to see if apex dependency check should be skipped
409func (t libraryDependencyTag) SkipApexAllowedDependenciesCheck() bool {
410	return t.skipApexAllowedDependenciesCheck
411}
412
413var _ android.SkipApexAllowedDependenciesCheck = (*libraryDependencyTag)(nil)
414
415func init() {
416	pctx.StaticVariable("HostOnlySanitizeFlags", strings.Join(hostOnlySanitizeFlags, " "))
417
418	android.RegisterMakeVarsProvider(pctx, cfiMakeVarsProvider)
419	android.RegisterMakeVarsProvider(pctx, hwasanMakeVarsProvider)
420	android.RegisterMakeVarsProvider(pctx, memtagStackMakeVarsProvider)
421
422	RegisterSanitizerLibrariesTxtType(android.InitRegistrationContext)
423}
424
425func (sanitize *sanitize) props() []interface{} {
426	return []interface{}{&sanitize.Properties}
427}
428
429func (p *sanitizeMutatedProperties) copyUserPropertiesToMutated(userProps *SanitizeUserProps) {
430	p.Never = userProps.Never
431	p.Address = userProps.Address
432	p.All_undefined = userProps.All_undefined
433	p.Cfi = userProps.Cfi
434	p.Fuzzer = userProps.Fuzzer
435	p.Hwaddress = userProps.Hwaddress
436	p.Integer_overflow = userProps.Integer_overflow
437	p.Memtag_heap = userProps.Memtag_heap
438	p.Memtag_stack = userProps.Memtag_stack
439	p.Memtag_globals = userProps.Memtag_globals
440	p.Safestack = userProps.Safestack
441	p.Scs = userProps.Scs
442	p.Scudo = userProps.Scudo
443	p.Thread = userProps.Thread
444	p.Undefined = userProps.Undefined
445	p.Writeonly = userProps.Writeonly
446
447	p.Misc_undefined = make([]string, 0, len(userProps.Misc_undefined))
448	for _, v := range userProps.Misc_undefined {
449		p.Misc_undefined = append(p.Misc_undefined, v)
450	}
451
452	p.Diag.Cfi = userProps.Diag.Cfi
453	p.Diag.Integer_overflow = userProps.Diag.Integer_overflow
454	p.Diag.Memtag_heap = userProps.Diag.Memtag_heap
455	p.Diag.Undefined = userProps.Diag.Undefined
456
457	p.Diag.Misc_undefined = make([]string, 0, len(userProps.Diag.Misc_undefined))
458	for _, v := range userProps.Diag.Misc_undefined {
459		p.Diag.Misc_undefined = append(p.Diag.Misc_undefined, v)
460	}
461}
462
463func (sanitize *sanitize) begin(ctx BaseModuleContext) {
464	s := &sanitize.Properties.SanitizeMutated
465	s.copyUserPropertiesToMutated(&sanitize.Properties.Sanitize)
466
467	if sanitize.Properties.ForceDisable {
468		return
469	}
470
471	// Don't apply sanitizers to NDK code.
472	if ctx.useSdk() {
473		s.Never = BoolPtr(true)
474	}
475
476	// Never always wins.
477	if Bool(s.Never) {
478		return
479	}
480
481	// cc_test targets default to SYNC MemTag unless explicitly set to ASYNC (via diag: {memtag_heap: false}).
482	if ctx.testBinary() {
483		if s.Memtag_heap == nil {
484			s.Memtag_heap = proptools.BoolPtr(true)
485		}
486		if s.Diag.Memtag_heap == nil {
487			s.Diag.Memtag_heap = proptools.BoolPtr(true)
488		}
489	}
490
491	var globalSanitizers []string
492	var globalSanitizersDiag []string
493
494	if ctx.Host() {
495		if !ctx.Windows() {
496			globalSanitizers = ctx.Config().SanitizeHost()
497		}
498	} else {
499		arches := ctx.Config().SanitizeDeviceArch()
500		if len(arches) == 0 || inList(ctx.Arch().ArchType.Name, arches) {
501			globalSanitizers = ctx.Config().SanitizeDevice()
502			globalSanitizersDiag = ctx.Config().SanitizeDeviceDiag()
503		}
504	}
505
506	if len(globalSanitizers) > 0 {
507		var found bool
508		if found, globalSanitizers = removeFromList("undefined", globalSanitizers); found && s.All_undefined == nil {
509			s.All_undefined = proptools.BoolPtr(true)
510		}
511
512		if found, globalSanitizers = removeFromList("default-ub", globalSanitizers); found && s.Undefined == nil {
513			s.Undefined = proptools.BoolPtr(true)
514		}
515
516		if found, globalSanitizers = removeFromList("address", globalSanitizers); found && s.Address == nil {
517			s.Address = proptools.BoolPtr(true)
518		}
519
520		if found, globalSanitizers = removeFromList("thread", globalSanitizers); found && s.Thread == nil {
521			s.Thread = proptools.BoolPtr(true)
522		}
523
524		if found, globalSanitizers = removeFromList("fuzzer", globalSanitizers); found && s.Fuzzer == nil {
525			s.Fuzzer = proptools.BoolPtr(true)
526		}
527
528		if found, globalSanitizers = removeFromList("safe-stack", globalSanitizers); found && s.Safestack == nil {
529			s.Safestack = proptools.BoolPtr(true)
530		}
531
532		if found, globalSanitizers = removeFromList("cfi", globalSanitizers); found && s.Cfi == nil {
533			if !ctx.Config().CFIDisabledForPath(ctx.ModuleDir()) {
534				s.Cfi = proptools.BoolPtr(true)
535			}
536		}
537
538		// Global integer_overflow builds do not support static libraries.
539		if found, globalSanitizers = removeFromList("integer_overflow", globalSanitizers); found && s.Integer_overflow == nil {
540			if !ctx.Config().IntegerOverflowDisabledForPath(ctx.ModuleDir()) && !ctx.static() {
541				s.Integer_overflow = proptools.BoolPtr(true)
542			}
543		}
544
545		if found, globalSanitizers = removeFromList("scudo", globalSanitizers); found && s.Scudo == nil {
546			s.Scudo = proptools.BoolPtr(true)
547		}
548
549		if found, globalSanitizers = removeFromList("hwaddress", globalSanitizers); found && s.Hwaddress == nil {
550			if !ctx.Config().HWASanDisabledForPath(ctx.ModuleDir()) {
551				s.Hwaddress = proptools.BoolPtr(true)
552			}
553		}
554
555		if found, globalSanitizers = removeFromList("writeonly", globalSanitizers); found && s.Writeonly == nil {
556			// Hwaddress and Address are set before, so we can check them here
557			// If they aren't explicitly set in the blueprint/SANITIZE_(HOST|TARGET), they would be nil instead of false
558			if s.Address == nil && s.Hwaddress == nil {
559				ctx.ModuleErrorf("writeonly modifier cannot be used without 'address' or 'hwaddress'")
560			}
561			s.Writeonly = proptools.BoolPtr(true)
562		}
563		if found, globalSanitizers = removeFromList("memtag_heap", globalSanitizers); found && s.Memtag_heap == nil {
564			if !ctx.Config().MemtagHeapDisabledForPath(ctx.ModuleDir()) {
565				s.Memtag_heap = proptools.BoolPtr(true)
566			}
567		}
568
569		if found, globalSanitizers = removeFromList("memtag_stack", globalSanitizers); found && s.Memtag_stack == nil {
570			s.Memtag_stack = proptools.BoolPtr(true)
571		}
572
573		if found, globalSanitizers = removeFromList("memtag_globals", globalSanitizers); found && s.Memtag_globals == nil {
574			s.Memtag_globals = proptools.BoolPtr(true)
575		}
576
577		if len(globalSanitizers) > 0 {
578			ctx.ModuleErrorf("unknown global sanitizer option %s", globalSanitizers[0])
579		}
580
581		// Global integer_overflow builds do not support static library diagnostics.
582		if found, globalSanitizersDiag = removeFromList("integer_overflow", globalSanitizersDiag); found &&
583			s.Diag.Integer_overflow == nil && Bool(s.Integer_overflow) && !ctx.static() {
584			s.Diag.Integer_overflow = proptools.BoolPtr(true)
585		}
586
587		if found, globalSanitizersDiag = removeFromList("cfi", globalSanitizersDiag); found &&
588			s.Diag.Cfi == nil && Bool(s.Cfi) {
589			s.Diag.Cfi = proptools.BoolPtr(true)
590		}
591
592		if found, globalSanitizersDiag = removeFromList("memtag_heap", globalSanitizersDiag); found &&
593			s.Diag.Memtag_heap == nil && Bool(s.Memtag_heap) {
594			s.Diag.Memtag_heap = proptools.BoolPtr(true)
595		}
596
597		if len(globalSanitizersDiag) > 0 {
598			ctx.ModuleErrorf("unknown global sanitizer diagnostics option %s", globalSanitizersDiag[0])
599		}
600	}
601
602	// Enable Memtag for all components in the include paths (for Aarch64 only)
603	if ctx.Arch().ArchType == android.Arm64 && ctx.toolchain().Bionic() {
604		if ctx.Config().MemtagHeapSyncEnabledForPath(ctx.ModuleDir()) {
605			if s.Memtag_heap == nil {
606				s.Memtag_heap = proptools.BoolPtr(true)
607			}
608			if s.Diag.Memtag_heap == nil {
609				s.Diag.Memtag_heap = proptools.BoolPtr(true)
610			}
611		} else if ctx.Config().MemtagHeapAsyncEnabledForPath(ctx.ModuleDir()) {
612			if s.Memtag_heap == nil {
613				s.Memtag_heap = proptools.BoolPtr(true)
614			}
615		}
616	}
617
618	// Enable HWASan for all components in the include paths (for Aarch64 only)
619	if s.Hwaddress == nil && ctx.Config().HWASanEnabledForPath(ctx.ModuleDir()) &&
620		ctx.Arch().ArchType == android.Arm64 && ctx.toolchain().Bionic() {
621		s.Hwaddress = proptools.BoolPtr(true)
622	}
623
624	// Enable CFI for non-host components in the include paths
625	if s.Cfi == nil && ctx.Config().CFIEnabledForPath(ctx.ModuleDir()) && !ctx.Host() {
626		s.Cfi = proptools.BoolPtr(true)
627		if inList("cfi", ctx.Config().SanitizeDeviceDiag()) {
628			s.Diag.Cfi = proptools.BoolPtr(true)
629		}
630	}
631
632	// Is CFI actually enabled?
633	if !ctx.Config().EnableCFI() {
634		s.Cfi = nil
635		s.Diag.Cfi = nil
636	}
637
638	// HWASan requires AArch64 hardware feature (top-byte-ignore).
639	if ctx.Arch().ArchType != android.Arm64 || !ctx.toolchain().Bionic() {
640		s.Hwaddress = nil
641	}
642
643	// SCS is only implemented on AArch64/riscv64.
644	if (ctx.Arch().ArchType != android.Arm64 && ctx.Arch().ArchType != android.Riscv64) || !ctx.toolchain().Bionic() {
645		s.Scs = nil
646	}
647
648	// Memtag_heap is only implemented on AArch64.
649	// Memtag ABI is Android specific for now, so disable for host.
650	if ctx.Arch().ArchType != android.Arm64 || !ctx.toolchain().Bionic() || ctx.Host() {
651		s.Memtag_heap = nil
652		s.Memtag_stack = nil
653		s.Memtag_globals = nil
654	}
655
656	// Also disable CFI if ASAN is enabled.
657	if Bool(s.Address) || Bool(s.Hwaddress) {
658		s.Cfi = nil
659		s.Diag.Cfi = nil
660		// HWASAN and ASAN win against MTE.
661		s.Memtag_heap = nil
662		s.Memtag_stack = nil
663		s.Memtag_globals = nil
664	}
665
666	// Disable sanitizers that depend on the UBSan runtime for windows/darwin builds.
667	if !ctx.Os().Linux() {
668		s.Cfi = nil
669		s.Diag.Cfi = nil
670		s.Misc_undefined = nil
671		s.Undefined = nil
672		s.All_undefined = nil
673		s.Integer_overflow = nil
674	}
675
676	// Disable CFI for musl
677	if ctx.toolchain().Musl() {
678		s.Cfi = nil
679		s.Diag.Cfi = nil
680	}
681
682	// TODO(b/280478629): runtimes don't exist for musl arm64 yet.
683	if ctx.toolchain().Musl() && ctx.Arch().ArchType == android.Arm64 {
684		s.Address = nil
685		s.Hwaddress = nil
686		s.Thread = nil
687		s.Scudo = nil
688		s.Fuzzer = nil
689		s.Cfi = nil
690		s.Diag.Cfi = nil
691		s.Misc_undefined = nil
692		s.Undefined = nil
693		s.All_undefined = nil
694		s.Integer_overflow = nil
695	}
696
697	if ctx.inRamdisk() || ctx.inVendorRamdisk() || ctx.inRecovery() {
698		// HWASan ramdisk (which is built from recovery) goes over some bootloader limit.
699		// Keep libc instrumented so that ramdisk / vendor_ramdisk / recovery can run hwasan-instrumented code if necessary.
700		if !strings.HasPrefix(ctx.ModuleDir(), "bionic/libc") {
701			s.Hwaddress = nil
702		}
703		// Memtag stack in ramdisk makes pKVM unhappy.
704		s.Memtag_stack = nil
705	}
706
707	if ctx.staticBinary() {
708		s.Address = nil
709		s.Fuzzer = nil
710		s.Thread = nil
711	}
712
713	if Bool(s.All_undefined) {
714		s.Undefined = nil
715	}
716
717	if !ctx.toolchain().Is64Bit() {
718		// TSAN and SafeStack are not supported on 32-bit architectures
719		s.Thread = nil
720		s.Safestack = nil
721		// TODO(ccross): error for compile_multilib = "32"?
722	}
723
724	if ctx.Os() != android.Windows && (Bool(s.All_undefined) || Bool(s.Undefined) || Bool(s.Address) || Bool(s.Thread) ||
725		Bool(s.Fuzzer) || Bool(s.Safestack) || Bool(s.Cfi) || Bool(s.Integer_overflow) || len(s.Misc_undefined) > 0 ||
726		Bool(s.Scudo) || Bool(s.Hwaddress) || Bool(s.Scs) || Bool(s.Memtag_heap) || Bool(s.Memtag_stack) ||
727		Bool(s.Memtag_globals)) {
728		sanitize.Properties.SanitizerEnabled = true
729	}
730
731	// Disable Scudo if ASan or TSan is enabled, or if it's disabled globally.
732	if Bool(s.Address) || Bool(s.Thread) || Bool(s.Hwaddress) || ctx.Config().DisableScudo() {
733		s.Scudo = nil
734	}
735
736	if Bool(s.Hwaddress) {
737		s.Address = nil
738		s.Thread = nil
739	}
740
741	// TODO(b/131771163): CFI transiently depends on LTO, and thus Fuzzer is
742	// mutually incompatible.
743	if Bool(s.Fuzzer) {
744		s.Cfi = nil
745	}
746}
747
748func toDisableImplicitIntegerChange(flags []string) bool {
749	// Returns true if any flag is fsanitize*integer, and there is
750	// no explicit flag about sanitize=implicit-integer-sign-change.
751	for _, f := range flags {
752		if strings.Contains(f, "sanitize=implicit-integer-sign-change") {
753			return false
754		}
755	}
756	for _, f := range flags {
757		if strings.HasPrefix(f, "-fsanitize") && strings.Contains(f, "integer") {
758			return true
759		}
760	}
761	return false
762}
763
764func toDisableUnsignedShiftBaseChange(flags []string) bool {
765	// Returns true if any flag is fsanitize*integer, and there is
766	// no explicit flag about sanitize=unsigned-shift-base.
767	for _, f := range flags {
768		if strings.Contains(f, "sanitize=unsigned-shift-base") {
769			return false
770		}
771	}
772	for _, f := range flags {
773		if strings.HasPrefix(f, "-fsanitize") && strings.Contains(f, "integer") {
774			return true
775		}
776	}
777	return false
778}
779
780func (s *sanitize) flags(ctx ModuleContext, flags Flags) Flags {
781	if s.Properties.ForceDisable {
782		return flags
783	}
784
785	if !s.Properties.SanitizerEnabled && !s.Properties.UbsanRuntimeDep {
786		return flags
787	}
788	sanProps := &s.Properties.SanitizeMutated
789
790	if Bool(sanProps.Address) {
791		if ctx.Arch().ArchType == android.Arm {
792			// Frame pointer based unwinder in ASan requires ARM frame setup.
793			// TODO: put in flags?
794			flags.RequiredInstructionSet = "arm"
795		}
796		flags.Local.CFlags = append(flags.Local.CFlags, asanCflags...)
797
798		if Bool(sanProps.Writeonly) {
799			flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", "-asan-instrument-reads=0")
800		}
801
802		if ctx.Host() {
803			if !ctx.Darwin() { // ld64.lld doesn't know about '--no-as-needed'
804				// -nodefaultlibs (provided with libc++) prevents the driver from linking
805				// libraries needed with -fsanitize=address. http://b/18650275 (WAI)
806				flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--no-as-needed")
807			}
808		} else {
809			flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", "-asan-globals=0")
810			if ctx.bootstrap() {
811				flags.DynamicLinker = "/system/bin/bootstrap/linker_asan"
812			} else {
813				flags.DynamicLinker = "/system/bin/linker_asan"
814			}
815			if flags.Toolchain.Is64Bit() {
816				flags.DynamicLinker += "64"
817			}
818		}
819	}
820
821	if Bool(sanProps.Hwaddress) {
822		flags.Local.CFlags = append(flags.Local.CFlags, hwasanCflags...)
823
824		for _, flag := range hwasanCommonflags {
825			flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", flag)
826		}
827		for _, flag := range hwasanCommonflags {
828			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,"+flag)
829		}
830
831		if Bool(sanProps.Writeonly) {
832			flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", "-hwasan-instrument-reads=0")
833		}
834		if !ctx.staticBinary() && !ctx.Host() {
835			if ctx.bootstrap() {
836				flags.DynamicLinker = "/system/bin/bootstrap/linker_hwasan64"
837			} else {
838				flags.DynamicLinker = "/system/bin/linker_hwasan64"
839			}
840		}
841	}
842
843	if Bool(sanProps.Fuzzer) {
844		flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize=fuzzer-no-link")
845
846		// TODO(b/131771163): LTO and Fuzzer support is mutually incompatible.
847		_, flags.Local.LdFlags = removeFromList("-flto", flags.Local.LdFlags)
848		_, flags.Local.CFlags = removeFromList("-flto", flags.Local.CFlags)
849		flags.Local.LdFlags = append(flags.Local.LdFlags, "-fno-lto")
850		flags.Local.CFlags = append(flags.Local.CFlags, "-fno-lto")
851
852		// TODO(b/142430592): Upstream linker scripts for sanitizer runtime libraries
853		// discard the sancov_lowest_stack symbol, because it's emulated TLS (and thus
854		// doesn't match the linker script due to the "__emutls_v." prefix).
855		flags.Local.LdFlags = append(flags.Local.LdFlags, "-fno-sanitize-coverage=stack-depth")
856		flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-coverage=stack-depth")
857
858		// Disable fortify for fuzzing builds. Generally, we'll be building with
859		// UBSan or ASan here and the fortify checks pollute the stack traces.
860		flags.Local.CFlags = append(flags.Local.CFlags, "-U_FORTIFY_SOURCE")
861
862		// Build fuzzer-sanitized libraries with an $ORIGIN DT_RUNPATH. Android's
863		// linker uses DT_RUNPATH, not DT_RPATH. When we deploy cc_fuzz targets and
864		// their libraries to /data/fuzz/<arch>/lib, any transient shared library gets
865		// the DT_RUNPATH from the shared library above it, and not the executable,
866		// meaning that the lookup falls back to the system. Adding the $ORIGIN to the
867		// DT_RUNPATH here means that transient shared libraries can be found
868		// colocated with their parents.
869		flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN`)
870	}
871
872	if Bool(sanProps.Cfi) {
873		if ctx.Arch().ArchType == android.Arm {
874			// __cfi_check needs to be built as Thumb (see the code in linker_cfi.cpp). LLVM is not set up
875			// to do this on a function basis, so force Thumb on the entire module.
876			flags.RequiredInstructionSet = "thumb"
877		}
878
879		flags.Local.CFlags = append(flags.Local.CFlags, cfiCflags...)
880		flags.Local.AsFlags = append(flags.Local.AsFlags, cfiAsflags...)
881		flags.CFlagsDeps = append(flags.CFlagsDeps, android.PathForSource(ctx, cfiBlocklistPath+"/"+cfiBlocklistFilename))
882		if Bool(s.Properties.Sanitize.Config.Cfi_assembly_support) {
883			flags.Local.CFlags = append(flags.Local.CFlags, cfiAssemblySupportFlag)
884		}
885		// Only append the default visibility flag if -fvisibility has not already been set
886		// to hidden.
887		if !inList("-fvisibility=hidden", flags.Local.CFlags) {
888			flags.Local.CFlags = append(flags.Local.CFlags, "-fvisibility=default")
889		}
890		flags.Local.LdFlags = append(flags.Local.LdFlags, cfiLdflags...)
891
892		if ctx.staticBinary() {
893			_, flags.Local.CFlags = removeFromList("-fsanitize-cfi-cross-dso", flags.Local.CFlags)
894			_, flags.Local.LdFlags = removeFromList("-fsanitize-cfi-cross-dso", flags.Local.LdFlags)
895		}
896	}
897
898	if Bool(sanProps.Memtag_stack) {
899		flags.Local.CFlags = append(flags.Local.CFlags, memtagStackCommonFlags...)
900		flags.Local.AsFlags = append(flags.Local.AsFlags, memtagStackCommonFlags...)
901		flags.Local.LdFlags = append(flags.Local.LdFlags, memtagStackCommonFlags...)
902
903		for _, flag := range memtagStackLlvmFlags {
904			flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", flag)
905		}
906		for _, flag := range memtagStackLlvmFlags {
907			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,"+flag)
908		}
909	}
910
911	if (Bool(sanProps.Memtag_heap) || Bool(sanProps.Memtag_stack) || Bool(sanProps.Memtag_globals)) && ctx.binary() {
912		if Bool(sanProps.Diag.Memtag_heap) {
913			flags.Local.LdFlags = append(flags.Local.LdFlags, "-fsanitize-memtag-mode=sync")
914		} else {
915			flags.Local.LdFlags = append(flags.Local.LdFlags, "-fsanitize-memtag-mode=async")
916		}
917	}
918
919	if Bool(sanProps.Integer_overflow) {
920		flags.Local.CFlags = append(flags.Local.CFlags, intOverflowCflags...)
921	}
922
923	if len(s.Properties.Sanitizers) > 0 {
924		sanitizeArg := "-fsanitize=" + strings.Join(s.Properties.Sanitizers, ",")
925		flags.Local.CFlags = append(flags.Local.CFlags, sanitizeArg)
926		flags.Local.AsFlags = append(flags.Local.AsFlags, sanitizeArg)
927		flags.Local.LdFlags = append(flags.Local.LdFlags, sanitizeArg)
928
929		if ctx.toolchain().Bionic() || ctx.toolchain().Musl() {
930			// Bionic and musl sanitizer runtimes have already been added as dependencies so that
931			// the right variant of the runtime will be used (with the "-android" or "-musl"
932			// suffixes), so don't let clang the runtime library.
933			flags.Local.LdFlags = append(flags.Local.LdFlags, noSanitizeLinkRuntimeFlag)
934		} else {
935			// Host sanitizers only link symbols in the final executable, so
936			// there will always be undefined symbols in intermediate libraries.
937			_, flags.Global.LdFlags = removeFromList("-Wl,--no-undefined", flags.Global.LdFlags)
938		}
939
940		if !ctx.toolchain().Bionic() {
941			// non-Bionic toolchain prebuilts are missing UBSan's vptr and function san.
942			// Musl toolchain prebuilts have vptr and function sanitizers, but enabling them
943			// implicitly enables RTTI which causes RTTI mismatch issues with dependencies.
944
945			flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize=vptr,function")
946		}
947
948		if Bool(sanProps.Fuzzer) {
949			// When fuzzing, we wish to crash with diagnostics on any bug.
950			flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-trap=all", "-fno-sanitize-recover=all")
951		} else if ctx.Host() {
952			flags.Local.CFlags = append(flags.Local.CFlags, hostOnlySanitizeFlags...)
953		} else {
954			flags.Local.CFlags = append(flags.Local.CFlags, deviceOnlySanitizeFlags...)
955		}
956
957		if enableMinimalRuntime(s) {
958			flags.Local.CFlags = append(flags.Local.CFlags, strings.Join(minimalRuntimeFlags, " "))
959		}
960
961		// http://b/119329758, Android core does not boot up with this sanitizer yet.
962		if toDisableImplicitIntegerChange(flags.Local.CFlags) {
963			flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize=implicit-integer-sign-change")
964		}
965		// http://b/171275751, Android doesn't build with this sanitizer yet.
966		if toDisableUnsignedShiftBaseChange(flags.Local.CFlags) {
967			flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize=unsigned-shift-base")
968		}
969	}
970
971	if len(s.Properties.DiagSanitizers) > 0 {
972		flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-trap="+strings.Join(s.Properties.DiagSanitizers, ","))
973	}
974	// FIXME: enable RTTI if diag + (cfi or vptr)
975
976	if s.Properties.Sanitize.Recover != nil {
977		flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-recover="+
978			strings.Join(s.Properties.Sanitize.Recover, ","))
979	}
980
981	if s.Properties.Sanitize.Diag.No_recover != nil {
982		flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-recover="+
983			strings.Join(s.Properties.Sanitize.Diag.No_recover, ","))
984	}
985
986	blocklist := android.OptionalPathForModuleSrc(ctx, s.Properties.Sanitize.Blocklist)
987	if blocklist.Valid() {
988		flags.Local.CFlags = append(flags.Local.CFlags, sanitizeIgnorelistPrefix+blocklist.String())
989		flags.CFlagsDeps = append(flags.CFlagsDeps, blocklist.Path())
990	}
991
992	return flags
993}
994
995func (s *sanitize) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) {
996	// Add a suffix for cfi/hwasan/scs-enabled static/header libraries to allow surfacing
997	// both the sanitized and non-sanitized variants to make without a name conflict.
998	if entries.Class == "STATIC_LIBRARIES" || entries.Class == "HEADER_LIBRARIES" {
999		if Bool(s.Properties.SanitizeMutated.Cfi) {
1000			entries.SubName += ".cfi"
1001		}
1002		if Bool(s.Properties.SanitizeMutated.Hwaddress) {
1003			entries.SubName += ".hwasan"
1004		}
1005		if Bool(s.Properties.SanitizeMutated.Scs) {
1006			entries.SubName += ".scs"
1007		}
1008	}
1009}
1010
1011func (s *sanitize) inSanitizerDir() bool {
1012	return s.Properties.InSanitizerDir
1013}
1014
1015// getSanitizerBoolPtr returns the SanitizerTypes associated bool pointer from SanitizeProperties.
1016func (s *sanitize) getSanitizerBoolPtr(t SanitizerType) *bool {
1017	switch t {
1018	case Asan:
1019		return s.Properties.SanitizeMutated.Address
1020	case Hwasan:
1021		return s.Properties.SanitizeMutated.Hwaddress
1022	case tsan:
1023		return s.Properties.SanitizeMutated.Thread
1024	case intOverflow:
1025		return s.Properties.SanitizeMutated.Integer_overflow
1026	case cfi:
1027		return s.Properties.SanitizeMutated.Cfi
1028	case scs:
1029		return s.Properties.SanitizeMutated.Scs
1030	case Memtag_heap:
1031		return s.Properties.SanitizeMutated.Memtag_heap
1032	case Memtag_stack:
1033		return s.Properties.SanitizeMutated.Memtag_stack
1034	case Memtag_globals:
1035		return s.Properties.SanitizeMutated.Memtag_globals
1036	case Fuzzer:
1037		return s.Properties.SanitizeMutated.Fuzzer
1038	default:
1039		panic(fmt.Errorf("unknown SanitizerType %d", t))
1040	}
1041}
1042
1043// isUnsanitizedVariant returns true if no sanitizers are enabled.
1044func (sanitize *sanitize) isUnsanitizedVariant() bool {
1045	return !sanitize.isSanitizerEnabled(Asan) &&
1046		!sanitize.isSanitizerEnabled(Hwasan) &&
1047		!sanitize.isSanitizerEnabled(tsan) &&
1048		!sanitize.isSanitizerEnabled(cfi) &&
1049		!sanitize.isSanitizerEnabled(scs) &&
1050		!sanitize.isSanitizerEnabled(Memtag_heap) &&
1051		!sanitize.isSanitizerEnabled(Memtag_stack) &&
1052		!sanitize.isSanitizerEnabled(Memtag_globals) &&
1053		!sanitize.isSanitizerEnabled(Fuzzer)
1054}
1055
1056// isVariantOnProductionDevice returns true if variant is for production devices (no non-production sanitizers enabled).
1057func (sanitize *sanitize) isVariantOnProductionDevice() bool {
1058	return !sanitize.isSanitizerEnabled(Asan) &&
1059		!sanitize.isSanitizerEnabled(Hwasan) &&
1060		!sanitize.isSanitizerEnabled(tsan) &&
1061		!sanitize.isSanitizerEnabled(Fuzzer)
1062}
1063
1064func (sanitize *sanitize) SetSanitizer(t SanitizerType, b bool) {
1065	bPtr := proptools.BoolPtr(b)
1066	if !b {
1067		bPtr = nil
1068	}
1069	switch t {
1070	case Asan:
1071		sanitize.Properties.SanitizeMutated.Address = bPtr
1072		// For ASAN variant, we need to disable Memtag_stack
1073		sanitize.Properties.SanitizeMutated.Memtag_stack = nil
1074		sanitize.Properties.SanitizeMutated.Memtag_globals = nil
1075	case Hwasan:
1076		sanitize.Properties.SanitizeMutated.Hwaddress = bPtr
1077		// For HWAsan variant, we need to disable Memtag_stack
1078		sanitize.Properties.SanitizeMutated.Memtag_stack = nil
1079		sanitize.Properties.SanitizeMutated.Memtag_globals = nil
1080	case tsan:
1081		sanitize.Properties.SanitizeMutated.Thread = bPtr
1082	case intOverflow:
1083		sanitize.Properties.SanitizeMutated.Integer_overflow = bPtr
1084	case cfi:
1085		sanitize.Properties.SanitizeMutated.Cfi = bPtr
1086	case scs:
1087		sanitize.Properties.SanitizeMutated.Scs = bPtr
1088	case Memtag_heap:
1089		sanitize.Properties.SanitizeMutated.Memtag_heap = bPtr
1090	case Memtag_stack:
1091		sanitize.Properties.SanitizeMutated.Memtag_stack = bPtr
1092		// We do not need to disable ASAN or HWASan here, as there is no Memtag_stack variant.
1093	case Memtag_globals:
1094		sanitize.Properties.Sanitize.Memtag_globals = bPtr
1095	case Fuzzer:
1096		sanitize.Properties.SanitizeMutated.Fuzzer = bPtr
1097	default:
1098		panic(fmt.Errorf("unknown SanitizerType %d", t))
1099	}
1100	if b {
1101		sanitize.Properties.SanitizerEnabled = true
1102	}
1103}
1104
1105// Check if the sanitizer is explicitly disabled (as opposed to nil by
1106// virtue of not being set).
1107func (sanitize *sanitize) isSanitizerExplicitlyDisabled(t SanitizerType) bool {
1108	if sanitize == nil {
1109		return false
1110	}
1111
1112	sanitizerVal := sanitize.getSanitizerBoolPtr(t)
1113	return sanitizerVal != nil && *sanitizerVal == false
1114}
1115
1116// There isn't an analog of the method above (ie:isSanitizerExplicitlyEnabled)
1117// because enabling a sanitizer either directly (via the blueprint) or
1118// indirectly (via a mutator) sets the bool ptr to true, and you can't
1119// distinguish between the cases. It isn't needed though - both cases can be
1120// treated identically.
1121func (s *sanitize) isSanitizerEnabled(t SanitizerType) bool {
1122	if s == nil {
1123		return false
1124	}
1125	if s.Properties.ForceDisable || proptools.Bool(s.Properties.SanitizeMutated.Never) {
1126		return false
1127	}
1128
1129	sanitizerVal := s.getSanitizerBoolPtr(t)
1130	return sanitizerVal != nil && *sanitizerVal == true
1131}
1132
1133// IsSanitizableDependencyTag returns true if the dependency tag is sanitizable.
1134func IsSanitizableDependencyTag(tag blueprint.DependencyTag) bool {
1135	switch t := tag.(type) {
1136	case dependencyTag:
1137		return t == reuseObjTag || t == objDepTag
1138	case libraryDependencyTag:
1139		return true
1140	default:
1141		return false
1142	}
1143}
1144
1145func (m *Module) SanitizableDepTagChecker() SantizableDependencyTagChecker {
1146	return IsSanitizableDependencyTag
1147}
1148
1149type sanitizerSplitMutator struct {
1150	sanitizer SanitizerType
1151}
1152
1153// If an APEX is sanitized or not depends on whether it contains at least one
1154// sanitized module. Transition mutators cannot propagate information up the
1155// dependency graph this way, so we need an auxiliary mutator to do so.
1156func (s *sanitizerSplitMutator) markSanitizableApexesMutator(ctx android.BottomUpMutatorContext) {
1157	if sanitizeable, ok := ctx.Module().(Sanitizeable); ok {
1158		enabled := sanitizeable.IsSanitizerEnabled(ctx.Config(), s.sanitizer.name())
1159		ctx.VisitDirectDeps(func(dep android.Module) {
1160			if c, ok := dep.(PlatformSanitizeable); ok && c.IsSanitizerEnabled(s.sanitizer) {
1161				enabled = true
1162			}
1163		})
1164
1165		if enabled {
1166			sanitizeable.EnableSanitizer(s.sanitizer.name())
1167		}
1168	}
1169}
1170
1171func (s *sanitizerSplitMutator) Split(ctx android.BaseModuleContext) []string {
1172	if c, ok := ctx.Module().(PlatformSanitizeable); ok && c.SanitizePropDefined() {
1173		// If the given sanitizer is not requested in the .bp file for a module, it
1174		// won't automatically build the sanitized variation.
1175		if !c.IsSanitizerEnabled(s.sanitizer) {
1176			return []string{""}
1177		}
1178
1179		if c.Binary() {
1180			// If a sanitizer is enabled for a binary, we do not build the version
1181			// without the sanitizer
1182			return []string{s.sanitizer.variationName()}
1183		} else if c.StaticallyLinked() || c.Header() {
1184			// For static libraries, we build both versions. Some Make modules
1185			// apparently depend on this behavior.
1186			return []string{"", s.sanitizer.variationName()}
1187		} else {
1188			// We only build the requested variation of dynamic libraries
1189			return []string{s.sanitizer.variationName()}
1190		}
1191	}
1192
1193	if _, ok := ctx.Module().(JniSanitizeable); ok {
1194		// TODO: this should call into JniSanitizable.IsSanitizerEnabledForJni but
1195		// that is short-circuited for now
1196		return []string{""}
1197	}
1198
1199	// If an APEX has a sanitized dependency, we build the APEX in the sanitized
1200	// variation. This is useful because such APEXes require extra dependencies.
1201	if sanitizeable, ok := ctx.Module().(Sanitizeable); ok {
1202		enabled := sanitizeable.IsSanitizerEnabled(ctx.Config(), s.sanitizer.name())
1203		if enabled {
1204			return []string{s.sanitizer.variationName()}
1205		} else {
1206			return []string{""}
1207		}
1208	}
1209
1210	return []string{""}
1211}
1212
1213func (s *sanitizerSplitMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
1214	if c, ok := ctx.Module().(PlatformSanitizeable); ok {
1215		if !c.SanitizableDepTagChecker()(ctx.DepTag()) {
1216			// If the dependency is through a non-sanitizable tag, use the
1217			// non-sanitized variation
1218			return ""
1219		}
1220
1221		return sourceVariation
1222	} else if _, ok := ctx.Module().(JniSanitizeable); ok {
1223		// TODO: this should call into JniSanitizable.IsSanitizerEnabledForJni but
1224		// that is short-circuited for now
1225		return ""
1226	} else {
1227		// Otherwise, do not rock the boat.
1228		return sourceVariation
1229	}
1230}
1231
1232func (s *sanitizerSplitMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
1233	if d, ok := ctx.Module().(PlatformSanitizeable); ok {
1234		if !d.SanitizePropDefined() ||
1235			d.SanitizeNever() ||
1236			d.IsSanitizerExplicitlyDisabled(s.sanitizer) ||
1237			!d.SanitizerSupported(s.sanitizer) {
1238			// If a module opts out of a sanitizer, use its non-sanitized variation
1239			return ""
1240		}
1241
1242		// Binaries are always built in the variation they requested.
1243		if d.Binary() {
1244			if d.IsSanitizerEnabled(s.sanitizer) {
1245				return s.sanitizer.variationName()
1246			} else {
1247				return ""
1248			}
1249		}
1250
1251		// If a shared library requests to be sanitized, it will be built for that
1252		// sanitizer. Otherwise, some sanitizers propagate through shared library
1253		// dependency edges, some do not.
1254		if !d.StaticallyLinked() && !d.Header() {
1255			if d.IsSanitizerEnabled(s.sanitizer) {
1256				return s.sanitizer.variationName()
1257			}
1258
1259			// Some sanitizers do not propagate to shared dependencies
1260			if !s.sanitizer.shouldPropagateToSharedLibraryDeps() {
1261				return ""
1262			}
1263		}
1264
1265		// Static and header libraries inherit whether they are sanitized from the
1266		// module they are linked into
1267		return incomingVariation
1268	} else if d, ok := ctx.Module().(Sanitizeable); ok {
1269		// If an APEX contains a sanitized module, it will be built in the variation
1270		// corresponding to that sanitizer.
1271		enabled := d.IsSanitizerEnabled(ctx.Config(), s.sanitizer.name())
1272		if enabled {
1273			return s.sanitizer.variationName()
1274		}
1275
1276		return incomingVariation
1277	}
1278
1279	return ""
1280}
1281
1282func (s *sanitizerSplitMutator) Mutate(mctx android.BottomUpMutatorContext, variationName string) {
1283	sanitizerVariation := variationName == s.sanitizer.variationName()
1284
1285	if c, ok := mctx.Module().(PlatformSanitizeable); ok && c.SanitizePropDefined() {
1286		sanitizerEnabled := c.IsSanitizerEnabled(s.sanitizer)
1287
1288		oneMakeVariation := false
1289		if c.StaticallyLinked() || c.Header() {
1290			if s.sanitizer != cfi && s.sanitizer != scs && s.sanitizer != Hwasan {
1291				// These sanitizers export only one variation to Make. For the rest,
1292				// Make targets can depend on both the sanitized and non-sanitized
1293				// versions.
1294				oneMakeVariation = true
1295			}
1296		} else if !c.Binary() {
1297			// Shared library. These are the sanitizers that do propagate through shared
1298			// library dependencies and therefore can cause multiple variations of a
1299			// shared library to be built.
1300			if s.sanitizer != cfi && s.sanitizer != Hwasan && s.sanitizer != scs && s.sanitizer != Asan {
1301				oneMakeVariation = true
1302			}
1303		}
1304
1305		if oneMakeVariation {
1306			if sanitizerEnabled != sanitizerVariation {
1307				c.SetPreventInstall()
1308				c.SetHideFromMake()
1309			}
1310		}
1311
1312		if sanitizerVariation {
1313			c.SetSanitizer(s.sanitizer, true)
1314
1315			// CFI is incompatible with ASAN so disable it in ASAN variations
1316			if s.sanitizer.incompatibleWithCfi() {
1317				cfiSupported := mctx.Module().(PlatformSanitizeable).SanitizerSupported(cfi)
1318				if mctx.Device() && cfiSupported {
1319					c.SetSanitizer(cfi, false)
1320				}
1321			}
1322
1323			// locate the asan libraries under /data/asan
1324			if !c.Binary() && !c.StaticallyLinked() && !c.Header() && mctx.Device() && s.sanitizer == Asan && sanitizerEnabled {
1325				c.SetInSanitizerDir()
1326			}
1327
1328			if c.StaticallyLinked() && c.ExportedToMake() {
1329				if s.sanitizer == Hwasan {
1330					hwasanStaticLibs(mctx.Config()).add(c, c.Module().Name())
1331				} else if s.sanitizer == cfi {
1332					cfiStaticLibs(mctx.Config()).add(c, c.Module().Name())
1333				} else if s.sanitizer == Memtag_stack {
1334					memtagStackStaticLibs(mctx.Config()).add(c, c.Module().Name())
1335				}
1336			}
1337		} else if c.IsSanitizerEnabled(s.sanitizer) {
1338			// Disable the sanitizer for the non-sanitized variation
1339			c.SetSanitizer(s.sanitizer, false)
1340		}
1341	} else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok {
1342		// If an APEX has sanitized dependencies, it gets a few more dependencies
1343		if sanitizerVariation {
1344			sanitizeable.AddSanitizerDependencies(mctx, s.sanitizer.name())
1345		}
1346	}
1347}
1348
1349func (c *Module) SanitizeNever() bool {
1350	return c.sanitize.Properties.ForceDisable || Bool(c.sanitize.Properties.SanitizeMutated.Never)
1351}
1352
1353func (c *Module) IsSanitizerExplicitlyDisabled(t SanitizerType) bool {
1354	return c.sanitize.isSanitizerExplicitlyDisabled(t)
1355}
1356
1357// Propagate the ubsan minimal runtime dependency when there are integer overflow sanitized static dependencies.
1358func sanitizerRuntimeDepsMutator(mctx android.BottomUpMutatorContext) {
1359	// Change this to PlatformSanitizable when/if non-cc modules support ubsan sanitizers.
1360	if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil {
1361		if c.sanitize.Properties.ForceDisable {
1362			return
1363		}
1364		isSanitizableDependencyTag := c.SanitizableDepTagChecker()
1365		mctx.WalkDeps(func(child, parent android.Module) bool {
1366			if !isSanitizableDependencyTag(mctx.OtherModuleDependencyTag(child)) {
1367				return false
1368			}
1369
1370			d, ok := child.(*Module)
1371			if !ok || !d.static() {
1372				return false
1373			}
1374			if d.sanitize != nil && !d.sanitize.Properties.ForceDisable {
1375				if enableMinimalRuntime(d.sanitize) {
1376					// If a static dependency is built with the minimal runtime,
1377					// make sure we include the ubsan minimal runtime.
1378					c.sanitize.Properties.MinimalRuntimeDep = true
1379				} else if enableUbsanRuntime(d.sanitize) {
1380					// If a static dependency runs with full ubsan diagnostics,
1381					// make sure we include the ubsan runtime.
1382					c.sanitize.Properties.UbsanRuntimeDep = true
1383				}
1384
1385				if c.sanitize.Properties.MinimalRuntimeDep &&
1386					c.sanitize.Properties.UbsanRuntimeDep {
1387					// both flags that this mutator might set are true, so don't bother recursing
1388					return false
1389				}
1390
1391				if c.Os() == android.Linux {
1392					c.sanitize.Properties.BuiltinsDep = true
1393				}
1394
1395				return true
1396			}
1397
1398			return false
1399		})
1400	}
1401}
1402
1403// Add the dependency to the runtime library for each of the sanitizer variants
1404func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) {
1405	if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil {
1406		if !c.Enabled(mctx) {
1407			return
1408		}
1409		if c.sanitize.Properties.ForceDisable {
1410			return
1411		}
1412
1413		var sanitizers []string
1414		var diagSanitizers []string
1415
1416		sanProps := &c.sanitize.Properties.SanitizeMutated
1417
1418		if Bool(sanProps.All_undefined) {
1419			sanitizers = append(sanitizers, "undefined")
1420		} else {
1421			if Bool(sanProps.Undefined) {
1422				sanitizers = append(sanitizers,
1423					"bool",
1424					"integer-divide-by-zero",
1425					"return",
1426					"returns-nonnull-attribute",
1427					"shift-exponent",
1428					"unreachable",
1429					"vla-bound",
1430					// TODO(danalbert): The following checks currently have compiler performance issues.
1431					//"alignment",
1432					//"bounds",
1433					//"enum",
1434					//"float-cast-overflow",
1435					//"float-divide-by-zero",
1436					//"nonnull-attribute",
1437					//"null",
1438					//"shift-base",
1439					//"signed-integer-overflow",
1440				)
1441
1442				if mctx.Config().ReleaseBuildObjectSizeSanitizer() {
1443					sanitizers = append(sanitizers, "object-size")
1444				}
1445			}
1446			sanitizers = append(sanitizers, sanProps.Misc_undefined...)
1447		}
1448
1449		if Bool(sanProps.Diag.Undefined) {
1450			diagSanitizers = append(diagSanitizers, "undefined")
1451		}
1452
1453		diagSanitizers = append(diagSanitizers, sanProps.Diag.Misc_undefined...)
1454
1455		if Bool(sanProps.Address) {
1456			sanitizers = append(sanitizers, "address")
1457			diagSanitizers = append(diagSanitizers, "address")
1458		}
1459
1460		if Bool(sanProps.Hwaddress) {
1461			sanitizers = append(sanitizers, "hwaddress")
1462		}
1463
1464		if Bool(sanProps.Thread) {
1465			sanitizers = append(sanitizers, "thread")
1466		}
1467
1468		if Bool(sanProps.Safestack) {
1469			sanitizers = append(sanitizers, "safe-stack")
1470		}
1471
1472		if Bool(sanProps.Cfi) {
1473			sanitizers = append(sanitizers, "cfi")
1474
1475			if Bool(sanProps.Diag.Cfi) {
1476				diagSanitizers = append(diagSanitizers, "cfi")
1477			}
1478		}
1479
1480		if Bool(sanProps.Integer_overflow) {
1481			sanitizers = append(sanitizers, "unsigned-integer-overflow")
1482			sanitizers = append(sanitizers, "signed-integer-overflow")
1483			if Bool(sanProps.Diag.Integer_overflow) {
1484				diagSanitizers = append(diagSanitizers, "unsigned-integer-overflow")
1485				diagSanitizers = append(diagSanitizers, "signed-integer-overflow")
1486			}
1487		}
1488
1489		if Bool(sanProps.Scudo) {
1490			sanitizers = append(sanitizers, "scudo")
1491		}
1492
1493		if Bool(sanProps.Scs) {
1494			sanitizers = append(sanitizers, "shadow-call-stack")
1495		}
1496
1497		if Bool(sanProps.Memtag_heap) && c.Binary() {
1498			sanitizers = append(sanitizers, "memtag-heap")
1499		}
1500
1501		if Bool(sanProps.Memtag_stack) {
1502			sanitizers = append(sanitizers, "memtag-stack")
1503		}
1504
1505		if Bool(sanProps.Memtag_globals) {
1506			sanitizers = append(sanitizers, "memtag-globals")
1507		}
1508
1509		if Bool(sanProps.Fuzzer) {
1510			sanitizers = append(sanitizers, "fuzzer-no-link")
1511		}
1512
1513		// Save the list of sanitizers. These will be used again when generating
1514		// the build rules (for Cflags, etc.)
1515		c.sanitize.Properties.Sanitizers = sanitizers
1516		c.sanitize.Properties.DiagSanitizers = diagSanitizers
1517
1518		// TODO(b/150822854) Hosts have a different default behavior and assume the runtime library is used.
1519		if c.Host() {
1520			diagSanitizers = sanitizers
1521		}
1522
1523		addStaticDeps := func(dep string, hideSymbols bool) {
1524			// static executable gets static runtime libs
1525			depTag := libraryDependencyTag{Kind: staticLibraryDependency, unexportedSymbols: hideSymbols}
1526			variations := append(mctx.Target().Variations(),
1527				blueprint.Variation{Mutator: "link", Variation: "static"})
1528			if c.Device() {
1529				variations = append(variations, c.ImageVariation())
1530			}
1531			if c.UseSdk() {
1532				variations = append(variations,
1533					blueprint.Variation{Mutator: "sdk", Variation: "sdk"})
1534			}
1535			mctx.AddFarVariationDependencies(variations, depTag, dep)
1536		}
1537
1538		// Determine the runtime library required
1539		runtimeSharedLibrary := ""
1540		toolchain := c.toolchain(mctx)
1541		if Bool(sanProps.Address) {
1542			if toolchain.Musl() || (c.staticBinary() && toolchain.Bionic()) {
1543				// Use a static runtime for musl to match what clang does for glibc.
1544				addStaticDeps(config.AddressSanitizerStaticRuntimeLibrary(), false)
1545				addStaticDeps(config.AddressSanitizerCXXStaticRuntimeLibrary(), false)
1546			} else {
1547				runtimeSharedLibrary = config.AddressSanitizerRuntimeLibrary()
1548			}
1549		} else if Bool(sanProps.Hwaddress) {
1550			if c.staticBinary() {
1551				addStaticDeps(config.HWAddressSanitizerStaticLibrary(), true)
1552				addStaticDeps("libdl", false)
1553			} else {
1554				runtimeSharedLibrary = config.HWAddressSanitizerRuntimeLibrary()
1555			}
1556		} else if Bool(sanProps.Thread) {
1557			runtimeSharedLibrary = config.ThreadSanitizerRuntimeLibrary()
1558		} else if Bool(sanProps.Scudo) {
1559			if len(diagSanitizers) == 0 && !c.sanitize.Properties.UbsanRuntimeDep {
1560				runtimeSharedLibrary = config.ScudoMinimalRuntimeLibrary()
1561			} else {
1562				runtimeSharedLibrary = config.ScudoRuntimeLibrary()
1563			}
1564		} else if len(diagSanitizers) > 0 || c.sanitize.Properties.UbsanRuntimeDep ||
1565			Bool(sanProps.Fuzzer) ||
1566			Bool(sanProps.Undefined) ||
1567			Bool(sanProps.All_undefined) {
1568			if toolchain.Musl() || c.staticBinary() {
1569				// Use a static runtime for static binaries.  For sanitized glibc binaries the runtime is
1570				// added automatically by clang, but for static glibc binaries that are not sanitized but
1571				// have a sanitized dependency the runtime needs to be added manually.
1572				// Also manually add a static runtime for musl to match what clang does for glibc.
1573				// Otherwise dlopening libraries that depend on libclang_rt.ubsan_standalone.so fails with:
1574				// Error relocating ...: initial-exec TLS resolves to dynamic definition
1575				addStaticDeps(config.UndefinedBehaviorSanitizerRuntimeLibrary()+".static", true)
1576			} else {
1577				runtimeSharedLibrary = config.UndefinedBehaviorSanitizerRuntimeLibrary()
1578			}
1579		}
1580
1581		if enableMinimalRuntime(c.sanitize) || c.sanitize.Properties.MinimalRuntimeDep {
1582			addStaticDeps(config.UndefinedBehaviorSanitizerMinimalRuntimeLibrary(), true)
1583		}
1584		if c.sanitize.Properties.BuiltinsDep {
1585			addStaticDeps(config.BuiltinsRuntimeLibrary(), true)
1586		}
1587
1588		if runtimeSharedLibrary != "" && (toolchain.Bionic() || toolchain.Musl()) {
1589			// UBSan is supported on non-bionic linux host builds as well
1590
1591			// Adding dependency to the runtime library. We are using *FarVariation*
1592			// because the runtime libraries themselves are not mutated by sanitizer
1593			// mutators and thus don't have sanitizer variants whereas this module
1594			// has been already mutated.
1595			//
1596			// Note that by adding dependency with {static|shared}DepTag, the lib is
1597			// added to libFlags and LOCAL_SHARED_LIBRARIES by cc.Module
1598			if c.staticBinary() {
1599				// Most sanitizers are either disabled for static binaries or have already
1600				// handled the static binary case above through a direct call to addStaticDeps.
1601				// If not, treat the runtime shared library as a static library and hope for
1602				// the best.
1603				addStaticDeps(runtimeSharedLibrary, true)
1604			} else if !c.static() && !c.Header() {
1605				// Skip apex dependency check for sharedLibraryDependency
1606				// when sanitizer diags are enabled. Skipping the check will allow
1607				// building with diag libraries without having to list the
1608				// dependency in Apex's allowed_deps file.
1609				diagEnabled := len(diagSanitizers) > 0
1610				// dynamic executable and shared libs get shared runtime libs
1611				depTag := libraryDependencyTag{
1612					Kind:  sharedLibraryDependency,
1613					Order: earlyLibraryDependency,
1614
1615					skipApexAllowedDependenciesCheck: diagEnabled,
1616				}
1617				variations := append(mctx.Target().Variations(),
1618					blueprint.Variation{Mutator: "link", Variation: "shared"})
1619				if c.Device() {
1620					variations = append(variations, c.ImageVariation())
1621				}
1622				if c.UseSdk() {
1623					variations = append(variations,
1624						blueprint.Variation{Mutator: "sdk", Variation: "sdk"})
1625				}
1626				AddSharedLibDependenciesWithVersions(mctx, c, variations, depTag, runtimeSharedLibrary, "", true)
1627			}
1628			// static lib does not have dependency to the runtime library. The
1629			// dependency will be added to the executables or shared libs using
1630			// the static lib.
1631		}
1632	}
1633}
1634
1635type Sanitizeable interface {
1636	android.Module
1637	IsSanitizerEnabled(config android.Config, sanitizerName string) bool
1638	EnableSanitizer(sanitizerName string)
1639	AddSanitizerDependencies(ctx android.BottomUpMutatorContext, sanitizerName string)
1640}
1641
1642type JniSanitizeable interface {
1643	android.Module
1644	IsSanitizerEnabledForJni(ctx android.BaseModuleContext, sanitizerName string) bool
1645}
1646
1647func (c *Module) MinimalRuntimeDep() bool {
1648	return c.sanitize.Properties.MinimalRuntimeDep
1649}
1650
1651func (c *Module) UbsanRuntimeDep() bool {
1652	return c.sanitize.Properties.UbsanRuntimeDep
1653}
1654
1655func (c *Module) SanitizePropDefined() bool {
1656	return c.sanitize != nil
1657}
1658
1659func (c *Module) IsSanitizerEnabled(t SanitizerType) bool {
1660	return c.sanitize.isSanitizerEnabled(t)
1661}
1662
1663func (c *Module) StaticallyLinked() bool {
1664	return c.static()
1665}
1666
1667func (c *Module) SetInSanitizerDir() {
1668	if c.sanitize != nil {
1669		c.sanitize.Properties.InSanitizerDir = true
1670	}
1671}
1672
1673func (c *Module) SetSanitizer(t SanitizerType, b bool) {
1674	if c.sanitize != nil {
1675		c.sanitize.SetSanitizer(t, b)
1676	}
1677}
1678
1679var _ PlatformSanitizeable = (*Module)(nil)
1680
1681type sanitizerStaticLibsMap struct {
1682	// libsMap contains one list of modules per each image and each arch.
1683	// e.g. libs[vendor]["arm"] contains arm modules installed to vendor
1684	libsMap       map[ImageVariantType]map[string][]string
1685	libsMapLock   sync.Mutex
1686	sanitizerType SanitizerType
1687}
1688
1689func newSanitizerStaticLibsMap(t SanitizerType) *sanitizerStaticLibsMap {
1690	return &sanitizerStaticLibsMap{
1691		sanitizerType: t,
1692		libsMap:       make(map[ImageVariantType]map[string][]string),
1693	}
1694}
1695
1696// Add the current module to sanitizer static libs maps
1697// Each module should pass its exported name as names of Make and Soong can differ.
1698func (s *sanitizerStaticLibsMap) add(c LinkableInterface, name string) {
1699	image := GetImageVariantType(c)
1700	arch := c.Module().Target().Arch.ArchType.String()
1701
1702	s.libsMapLock.Lock()
1703	defer s.libsMapLock.Unlock()
1704
1705	if _, ok := s.libsMap[image]; !ok {
1706		s.libsMap[image] = make(map[string][]string)
1707	}
1708
1709	s.libsMap[image][arch] = append(s.libsMap[image][arch], name)
1710}
1711
1712// Exports makefile variables in the following format:
1713// SOONG_{sanitizer}_{image}_{arch}_STATIC_LIBRARIES
1714// e.g. SOONG_cfi_core_x86_STATIC_LIBRARIES
1715// These are to be used by use_soong_sanitized_static_libraries.
1716// See build/make/core/binary.mk for more details.
1717func (s *sanitizerStaticLibsMap) exportToMake(ctx android.MakeVarsContext) {
1718	for _, image := range android.SortedKeys(s.libsMap) {
1719		archMap := s.libsMap[ImageVariantType(image)]
1720		for _, arch := range android.SortedKeys(archMap) {
1721			libs := archMap[arch]
1722			sort.Strings(libs)
1723
1724			key := fmt.Sprintf(
1725				"SOONG_%s_%s_%s_STATIC_LIBRARIES",
1726				s.sanitizerType.variationName(),
1727				image, // already upper
1728				arch)
1729
1730			ctx.Strict(key, strings.Join(libs, " "))
1731		}
1732	}
1733}
1734
1735var cfiStaticLibsKey = android.NewOnceKey("cfiStaticLibs")
1736
1737func cfiStaticLibs(config android.Config) *sanitizerStaticLibsMap {
1738	return config.Once(cfiStaticLibsKey, func() interface{} {
1739		return newSanitizerStaticLibsMap(cfi)
1740	}).(*sanitizerStaticLibsMap)
1741}
1742
1743var hwasanStaticLibsKey = android.NewOnceKey("hwasanStaticLibs")
1744
1745func hwasanStaticLibs(config android.Config) *sanitizerStaticLibsMap {
1746	return config.Once(hwasanStaticLibsKey, func() interface{} {
1747		return newSanitizerStaticLibsMap(Hwasan)
1748	}).(*sanitizerStaticLibsMap)
1749}
1750
1751var memtagStackStaticLibsKey = android.NewOnceKey("memtagStackStaticLibs")
1752
1753func memtagStackStaticLibs(config android.Config) *sanitizerStaticLibsMap {
1754	return config.Once(memtagStackStaticLibsKey, func() interface{} {
1755		return newSanitizerStaticLibsMap(Memtag_stack)
1756	}).(*sanitizerStaticLibsMap)
1757}
1758
1759func enableMinimalRuntime(sanitize *sanitize) bool {
1760	if sanitize.isSanitizerEnabled(Asan) {
1761		return false
1762	} else if sanitize.isSanitizerEnabled(Hwasan) {
1763		return false
1764	} else if sanitize.isSanitizerEnabled(Fuzzer) {
1765		return false
1766	}
1767
1768	if enableUbsanRuntime(sanitize) {
1769		return false
1770	}
1771
1772	sanitizeProps := &sanitize.Properties.SanitizeMutated
1773	if Bool(sanitizeProps.Diag.Cfi) {
1774		return false
1775	}
1776
1777	return Bool(sanitizeProps.Integer_overflow) ||
1778		len(sanitizeProps.Misc_undefined) > 0 ||
1779		Bool(sanitizeProps.Undefined) ||
1780		Bool(sanitizeProps.All_undefined)
1781}
1782
1783func (m *Module) UbsanRuntimeNeeded() bool {
1784	return enableUbsanRuntime(m.sanitize)
1785}
1786
1787func (m *Module) MinimalRuntimeNeeded() bool {
1788	return enableMinimalRuntime(m.sanitize)
1789}
1790
1791func enableUbsanRuntime(sanitize *sanitize) bool {
1792	sanitizeProps := &sanitize.Properties.SanitizeMutated
1793	return Bool(sanitizeProps.Diag.Integer_overflow) ||
1794		Bool(sanitizeProps.Diag.Undefined) ||
1795		len(sanitizeProps.Diag.Misc_undefined) > 0
1796}
1797
1798func cfiMakeVarsProvider(ctx android.MakeVarsContext) {
1799	cfiStaticLibs(ctx.Config()).exportToMake(ctx)
1800}
1801
1802func hwasanMakeVarsProvider(ctx android.MakeVarsContext) {
1803	hwasanStaticLibs(ctx.Config()).exportToMake(ctx)
1804}
1805
1806func memtagStackMakeVarsProvider(ctx android.MakeVarsContext) {
1807	memtagStackStaticLibs(ctx.Config()).exportToMake(ctx)
1808}
1809
1810type sanitizerLibrariesTxtModule struct {
1811	android.ModuleBase
1812
1813	outputFile android.Path
1814}
1815
1816var _ etc.PrebuiltEtcModule = (*sanitizerLibrariesTxtModule)(nil)
1817
1818func RegisterSanitizerLibrariesTxtType(ctx android.RegistrationContext) {
1819	ctx.RegisterModuleType("sanitizer_libraries_txt", sanitizerLibrariesTxtFactory)
1820}
1821
1822func sanitizerLibrariesTxtFactory() android.Module {
1823	m := &sanitizerLibrariesTxtModule{}
1824	android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
1825	return m
1826}
1827
1828type sanitizerLibraryDependencyTag struct {
1829	blueprint.BaseDependencyTag
1830	android.AlwaysAllowDisabledModuleDependencyTag
1831}
1832
1833var _ android.AllowDisabledModuleDependency = (*sanitizerLibraryDependencyTag)(nil)
1834
1835func (txt *sanitizerLibrariesTxtModule) DepsMutator(actx android.BottomUpMutatorContext) {
1836	targets := actx.Config().Targets[android.Android]
1837	depTag := sanitizerLibraryDependencyTag{}
1838
1839	for _, target := range targets {
1840		variation := append(target.Variations(),
1841			blueprint.Variation{Mutator: "image", Variation: ""},
1842			blueprint.Variation{Mutator: "sdk", Variation: ""},
1843			blueprint.Variation{Mutator: "link", Variation: "shared"},
1844		)
1845		for _, lib := range android.SortedStringValues(sanitizerVariables) {
1846			if actx.OtherModuleFarDependencyVariantExists(variation, lib) {
1847				actx.AddFarVariationDependencies(variation, depTag, lib)
1848			}
1849
1850			prebuiltLibName := "prebuilt_" + lib
1851			if actx.OtherModuleFarDependencyVariantExists(variation, prebuiltLibName) {
1852				actx.AddFarVariationDependencies(variation, depTag, prebuiltLibName)
1853			}
1854		}
1855	}
1856
1857}
1858
1859func (txt *sanitizerLibrariesTxtModule) getSanitizerLibs(ctx android.ModuleContext) string {
1860	var sanitizerLibStems []string
1861
1862	ctx.VisitDirectDepsIf(func(m android.Module) bool {
1863		if !m.Enabled(ctx) {
1864			return false
1865		}
1866
1867		ccModule, _ := m.(*Module)
1868		if ccModule == nil || ccModule.library == nil || !ccModule.library.shared() {
1869			return false
1870		}
1871
1872		targets := ctx.Config().Targets[android.Android]
1873
1874		for _, target := range targets {
1875			if m.Target().Os == target.Os && m.Target().Arch.ArchType == target.Arch.ArchType {
1876				return true
1877			}
1878		}
1879
1880		return false
1881	}, func(m android.Module) {
1882		ccModule, _ := m.(*Module)
1883		outputFile := ccModule.outputFile
1884		if outputFile.Valid() {
1885			sanitizerLibStems = append(sanitizerLibStems, outputFile.Path().Base())
1886		}
1887	})
1888
1889	sanitizerLibStems = android.SortedUniqueStrings(sanitizerLibStems)
1890	return strings.Join(sanitizerLibStems, "\n")
1891}
1892
1893func (txt *sanitizerLibrariesTxtModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
1894	filename := txt.Name()
1895
1896	outputFile := android.PathForModuleOut(ctx, filename)
1897	android.WriteFileRule(ctx, outputFile, txt.getSanitizerLibs(ctx))
1898
1899	installPath := android.PathForModuleInstall(ctx, "etc")
1900	ctx.InstallFile(installPath, filename, outputFile)
1901
1902	ctx.SetOutputFiles(android.Paths{outputFile}, "")
1903	txt.outputFile = outputFile
1904}
1905
1906func (txt *sanitizerLibrariesTxtModule) PrepareAndroidMKProviderInfo(config android.Config) *android.AndroidMkProviderInfo {
1907	return &android.AndroidMkProviderInfo{
1908		PrimaryInfo: android.AndroidMkInfo{
1909			Class:      "ETC",
1910			OutputFile: android.OptionalPathForPath(txt.outputFile),
1911		},
1912	}
1913}
1914
1915// PrebuiltEtcModule interface
1916func (txt *sanitizerLibrariesTxtModule) BaseDir() string {
1917	return "etc"
1918}
1919
1920// PrebuiltEtcModule interface
1921func (txt *sanitizerLibrariesTxtModule) SubDir() string {
1922	return ""
1923}
1924