blob: 8023933c1a8ba021cf94b31445d528dd65095485 [file] [log] [blame]
Colin Cross16b23492016-01-06 14:41:07 -08001// 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 "strings"
20
21 "github.com/google/blueprint"
22
Colin Cross635c3b02016-05-18 15:37:25 -070023 "android/soong/android"
Evgenii Stepanovaf36db12016-08-15 14:18:24 -070024 "android/soong/cc/config"
Colin Cross16b23492016-01-06 14:41:07 -080025)
26
27type sanitizerType int
28
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -070029func boolPtr(v bool) *bool {
30 if v {
31 return &v
32 } else {
33 return nil
34 }
35}
36
Colin Cross16b23492016-01-06 14:41:07 -080037const (
38 asan sanitizerType = iota + 1
39 tsan
40)
41
42func (t sanitizerType) String() string {
43 switch t {
44 case asan:
45 return "asan"
46 case tsan:
47 return "tsan"
48 default:
49 panic(fmt.Errorf("unknown sanitizerType %d", t))
50 }
51}
52
53type SanitizeProperties struct {
54 // enable AddressSanitizer, ThreadSanitizer, or UndefinedBehaviorSanitizer
55 Sanitize struct {
56 Never bool `android:"arch_variant"`
57
58 // main sanitizers
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -070059 Address *bool `android:"arch_variant"`
60 Thread *bool `android:"arch_variant"`
Colin Cross16b23492016-01-06 14:41:07 -080061
62 // local sanitizers
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -070063 Undefined *bool `android:"arch_variant"`
64 All_undefined *bool `android:"arch_variant"`
Colin Cross16b23492016-01-06 14:41:07 -080065 Misc_undefined []string `android:"arch_variant"`
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -070066 Coverage *bool `android:"arch_variant"`
67 Safestack *bool `android:"arch_variant"`
Colin Cross16b23492016-01-06 14:41:07 -080068
69 // value to pass to -fsantitize-recover=
70 Recover []string
71
72 // value to pass to -fsanitize-blacklist
73 Blacklist *string
74 } `android:"arch_variant"`
75
76 SanitizerEnabled bool `blueprint:"mutated"`
77 SanitizeDep bool `blueprint:"mutated"`
Colin Cross30d5f512016-05-03 18:02:42 -070078 InData bool `blueprint:"mutated"`
Colin Cross16b23492016-01-06 14:41:07 -080079}
80
81type sanitize struct {
82 Properties SanitizeProperties
83}
84
85func (sanitize *sanitize) props() []interface{} {
86 return []interface{}{&sanitize.Properties}
87}
88
89func (sanitize *sanitize) begin(ctx BaseModuleContext) {
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -070090 s := &sanitize.Properties.Sanitize
91
Colin Cross16b23492016-01-06 14:41:07 -080092 // Don't apply sanitizers to NDK code.
93 if ctx.sdk() {
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -070094 s.Never = true
Colin Cross16b23492016-01-06 14:41:07 -080095 }
96
97 // Never always wins.
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -070098 if s.Never {
Colin Cross16b23492016-01-06 14:41:07 -080099 return
100 }
101
Colin Cross16b23492016-01-06 14:41:07 -0800102 var globalSanitizers []string
103 if ctx.clang() {
104 if ctx.Host() {
105 globalSanitizers = ctx.AConfig().SanitizeHost()
106 } else {
107 globalSanitizers = ctx.AConfig().SanitizeDevice()
108 }
109 }
110
Colin Cross16b23492016-01-06 14:41:07 -0800111 if len(globalSanitizers) > 0 {
Evgenii Stepanov05bafd32016-07-07 17:38:41 +0000112 var found bool
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -0700113 if found, globalSanitizers = removeFromList("undefined", globalSanitizers); found && s.All_undefined == nil {
114 s.All_undefined = boolPtr(true)
Evgenii Stepanov05bafd32016-07-07 17:38:41 +0000115 }
Colin Cross16b23492016-01-06 14:41:07 -0800116
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -0700117 if found, globalSanitizers = removeFromList("default-ub", globalSanitizers); found && s.Undefined == nil {
118 s.Undefined = boolPtr(true)
Evgenii Stepanov05bafd32016-07-07 17:38:41 +0000119 }
120
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -0700121 if found, globalSanitizers = removeFromList("address", globalSanitizers); found && s.Address == nil {
122 s.Address = boolPtr(true)
Evgenii Stepanov05bafd32016-07-07 17:38:41 +0000123 }
124
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -0700125 if found, globalSanitizers = removeFromList("thread", globalSanitizers); found && s.Thread == nil {
126 s.Thread = boolPtr(true)
Evgenii Stepanov05bafd32016-07-07 17:38:41 +0000127 }
128
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -0700129 if found, globalSanitizers = removeFromList("coverage", globalSanitizers); found && s.Coverage == nil {
130 s.Coverage = boolPtr(true)
131 }
132
133 if found, globalSanitizers = removeFromList("safe-stack", globalSanitizers); found && s.Safestack == nil {
134 s.Safestack = boolPtr(true)
Evgenii Stepanov05bafd32016-07-07 17:38:41 +0000135 }
136
137 if len(globalSanitizers) > 0 {
138 ctx.ModuleErrorf("unknown global sanitizer option %s", globalSanitizers[0])
139 }
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -0700140 }
Colin Cross3c344ef2016-07-18 15:44:56 -0700141
142 if ctx.staticBinary() {
143 s.Address = nil
Colin Cross91169fe2016-08-11 15:54:20 -0700144 s.Coverage = nil
Colin Cross3c344ef2016-07-18 15:44:56 -0700145 s.Thread = nil
Colin Cross16b23492016-01-06 14:41:07 -0800146 }
147
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -0700148 if Bool(s.All_undefined) {
149 s.Undefined = nil
150 }
151
Evgenii Stepanov0a8a0d02016-05-12 13:54:53 -0700152 if !ctx.toolchain().Is64Bit() {
153 // TSAN and SafeStack are not supported on 32-bit architectures
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -0700154 s.Thread = nil
155 s.Safestack = nil
Colin Cross16b23492016-01-06 14:41:07 -0800156 // TODO(ccross): error for compile_multilib = "32"?
157 }
158
Colin Cross3c344ef2016-07-18 15:44:56 -0700159 if Bool(s.All_undefined) || Bool(s.Undefined) || Bool(s.Address) ||
160 Bool(s.Thread) || Bool(s.Coverage) || Bool(s.Safestack) {
161 sanitize.Properties.SanitizerEnabled = true
162 }
163
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -0700164 if Bool(s.Coverage) {
165 if !Bool(s.Address) {
Colin Cross16b23492016-01-06 14:41:07 -0800166 ctx.ModuleErrorf(`Use of "coverage" also requires "address"`)
167 }
168 }
169}
170
171func (sanitize *sanitize) deps(ctx BaseModuleContext, deps Deps) Deps {
172 if !sanitize.Properties.SanitizerEnabled { // || c.static() {
173 return deps
174 }
175
176 if ctx.Device() {
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -0700177 if Bool(sanitize.Properties.Sanitize.Address) {
Colin Cross16b23492016-01-06 14:41:07 -0800178 deps.StaticLibs = append(deps.StaticLibs, "libasan")
179 }
Colin Cross263abbd2016-07-15 13:10:48 -0700180 if Bool(sanitize.Properties.Sanitize.Address) || Bool(sanitize.Properties.Sanitize.Thread) {
181 deps.SharedLibs = append(deps.SharedLibs, "libdl")
182 }
Colin Cross16b23492016-01-06 14:41:07 -0800183 }
184
185 return deps
186}
187
188func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags {
189 if !sanitize.Properties.SanitizerEnabled {
190 return flags
191 }
192
193 if !ctx.clang() {
194 ctx.ModuleErrorf("Use of sanitizers requires clang")
195 }
196
197 var sanitizers []string
198
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -0700199 if Bool(sanitize.Properties.Sanitize.All_undefined) {
Colin Cross16b23492016-01-06 14:41:07 -0800200 sanitizers = append(sanitizers, "undefined")
201 if ctx.Device() {
202 ctx.ModuleErrorf("ubsan is not yet supported on the device")
203 }
204 } else {
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -0700205 if Bool(sanitize.Properties.Sanitize.Undefined) {
Colin Cross16b23492016-01-06 14:41:07 -0800206 sanitizers = append(sanitizers,
207 "bool",
208 "integer-divide-by-zero",
209 "return",
210 "returns-nonnull-attribute",
211 "shift-exponent",
212 "unreachable",
213 "vla-bound",
214 // TODO(danalbert): The following checks currently have compiler performance issues.
215 //"alignment",
216 //"bounds",
217 //"enum",
218 //"float-cast-overflow",
219 //"float-divide-by-zero",
220 //"nonnull-attribute",
221 //"null",
222 //"shift-base",
223 //"signed-integer-overflow",
224 // TODO(danalbert): Fix UB in libc++'s __tree so we can turn this on.
225 // https://llvm.org/PR19302
226 // http://reviews.llvm.org/D6974
227 // "object-size",
228 )
229 }
230 sanitizers = append(sanitizers, sanitize.Properties.Sanitize.Misc_undefined...)
231 }
232
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -0700233 if Bool(sanitize.Properties.Sanitize.Address) {
Colin Cross635c3b02016-05-18 15:37:25 -0700234 if ctx.Arch().ArchType == android.Arm {
Colin Cross16b23492016-01-06 14:41:07 -0800235 // Frame pointer based unwinder in ASan requires ARM frame setup.
236 // TODO: put in flags?
237 flags.RequiredInstructionSet = "arm"
238 }
239 flags.CFlags = append(flags.CFlags, "-fno-omit-frame-pointer")
240 flags.LdFlags = append(flags.LdFlags, "-Wl,-u,__asan_preinit")
241
242 // ASan runtime library must be the first in the link order.
Evgenii Stepanovaf36db12016-08-15 14:18:24 -0700243 runtimeLibrary := config.AddressSanitizerRuntimeLibrary(ctx.toolchain())
Colin Cross16b23492016-01-06 14:41:07 -0800244 if runtimeLibrary != "" {
Colin Crossb98c8b02016-07-29 13:44:28 -0700245 flags.libFlags = append([]string{"${config.ClangAsanLibDir}/" + runtimeLibrary}, flags.libFlags...)
Colin Cross16b23492016-01-06 14:41:07 -0800246 }
247 if ctx.Host() {
248 // -nodefaultlibs (provided with libc++) prevents the driver from linking
249 // libraries needed with -fsanitize=address. http://b/18650275 (WAI)
250 flags.LdFlags = append(flags.LdFlags, "-lm", "-lpthread")
251 flags.LdFlags = append(flags.LdFlags, "-Wl,--no-as-needed")
252 } else {
253 flags.CFlags = append(flags.CFlags, "-mllvm", "-asan-globals=0")
254 flags.DynamicLinker = "/system/bin/linker_asan"
255 if flags.Toolchain.Is64Bit() {
256 flags.DynamicLinker += "64"
257 }
258 }
259 sanitizers = append(sanitizers, "address")
260 }
261
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -0700262 if Bool(sanitize.Properties.Sanitize.Coverage) {
Colin Cross16b23492016-01-06 14:41:07 -0800263 flags.CFlags = append(flags.CFlags, "-fsanitize-coverage=edge,indirect-calls,8bit-counters,trace-cmp")
264 }
265
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -0700266 if Bool(sanitize.Properties.Sanitize.Safestack) {
Evgenii Stepanov0a8a0d02016-05-12 13:54:53 -0700267 sanitizers = append(sanitizers, "safe-stack")
268 }
269
Colin Cross16b23492016-01-06 14:41:07 -0800270 if sanitize.Properties.Sanitize.Recover != nil {
271 flags.CFlags = append(flags.CFlags, "-fsanitize-recover="+
272 strings.Join(sanitize.Properties.Sanitize.Recover, ","))
273 }
274
275 if len(sanitizers) > 0 {
276 sanitizeArg := "-fsanitize=" + strings.Join(sanitizers, ",")
277 flags.CFlags = append(flags.CFlags, sanitizeArg)
278 if ctx.Host() {
279 flags.CFlags = append(flags.CFlags, "-fno-sanitize-recover=all")
280 flags.LdFlags = append(flags.LdFlags, sanitizeArg)
281 flags.LdFlags = append(flags.LdFlags, "-lrt", "-ldl")
282 } else {
Colin Cross263abbd2016-07-15 13:10:48 -0700283 flags.CFlags = append(flags.CFlags, "-fsanitize-trap=all", "-ftrap-function=abort")
284 if Bool(sanitize.Properties.Sanitize.Address) || Bool(sanitize.Properties.Sanitize.Thread) {
285 flags.CFlags = append(flags.CFlags, "-fno-sanitize-trap=address,thread")
Colin Cross16b23492016-01-06 14:41:07 -0800286 }
287 }
288 }
289
Colin Cross635c3b02016-05-18 15:37:25 -0700290 blacklist := android.OptionalPathForModuleSrc(ctx, sanitize.Properties.Sanitize.Blacklist)
Colin Cross16b23492016-01-06 14:41:07 -0800291 if blacklist.Valid() {
292 flags.CFlags = append(flags.CFlags, "-fsanitize-blacklist="+blacklist.String())
293 flags.CFlagsDeps = append(flags.CFlagsDeps, blacklist.Path())
294 }
295
296 return flags
297}
298
Colin Cross30d5f512016-05-03 18:02:42 -0700299func (sanitize *sanitize) inData() bool {
300 return sanitize.Properties.InData
301}
302
Colin Cross16b23492016-01-06 14:41:07 -0800303func (sanitize *sanitize) Sanitizer(t sanitizerType) bool {
304 if sanitize == nil {
305 return false
306 }
307
308 switch t {
309 case asan:
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -0700310 return Bool(sanitize.Properties.Sanitize.Address)
Colin Cross16b23492016-01-06 14:41:07 -0800311 case tsan:
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -0700312 return Bool(sanitize.Properties.Sanitize.Thread)
Colin Cross16b23492016-01-06 14:41:07 -0800313 default:
314 panic(fmt.Errorf("unknown sanitizerType %d", t))
315 }
316}
317
318func (sanitize *sanitize) SetSanitizer(t sanitizerType, b bool) {
319 switch t {
320 case asan:
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -0700321 sanitize.Properties.Sanitize.Address = boolPtr(b)
Colin Cross91169fe2016-08-11 15:54:20 -0700322 if !b {
323 sanitize.Properties.Sanitize.Coverage = nil
324 }
Colin Cross16b23492016-01-06 14:41:07 -0800325 case tsan:
Evgenii Stepanovfcfe56d2016-07-07 10:54:07 -0700326 sanitize.Properties.Sanitize.Thread = boolPtr(b)
Colin Cross16b23492016-01-06 14:41:07 -0800327 default:
328 panic(fmt.Errorf("unknown sanitizerType %d", t))
329 }
330 if b {
331 sanitize.Properties.SanitizerEnabled = true
332 }
333}
334
335// Propagate asan requirements down from binaries
Colin Cross635c3b02016-05-18 15:37:25 -0700336func sanitizerDepsMutator(t sanitizerType) func(android.TopDownMutatorContext) {
337 return func(mctx android.TopDownMutatorContext) {
Colin Cross16b23492016-01-06 14:41:07 -0800338 if c, ok := mctx.Module().(*Module); ok && c.sanitize.Sanitizer(t) {
339 mctx.VisitDepsDepthFirst(func(module blueprint.Module) {
340 if d, ok := mctx.Module().(*Module); ok && c.sanitize != nil &&
341 !c.sanitize.Properties.Sanitize.Never {
342 d.sanitize.Properties.SanitizeDep = true
343 }
344 })
345 }
346 }
347}
348
349// Create asan variants for modules that need them
Colin Cross635c3b02016-05-18 15:37:25 -0700350func sanitizerMutator(t sanitizerType) func(android.BottomUpMutatorContext) {
351 return func(mctx android.BottomUpMutatorContext) {
Colin Cross16b23492016-01-06 14:41:07 -0800352 if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil {
Colin Crossb916a382016-07-29 17:28:03 -0700353 if c.isDependencyRoot() && c.sanitize.Sanitizer(t) {
Colin Cross30d5f512016-05-03 18:02:42 -0700354 modules := mctx.CreateVariations(t.String())
355 modules[0].(*Module).sanitize.SetSanitizer(t, true)
Colin Crossb36ab1a2016-05-25 12:35:53 -0700356 if mctx.AConfig().EmbeddedInMake() && !c.Host() {
Colin Cross30d5f512016-05-03 18:02:42 -0700357 modules[0].(*Module).sanitize.Properties.InData = true
358 }
Colin Cross16b23492016-01-06 14:41:07 -0800359 } else if c.sanitize.Properties.SanitizeDep {
Colin Crossb36ab1a2016-05-25 12:35:53 -0700360 if c.Host() {
361 modules := mctx.CreateVariations(t.String())
362 modules[0].(*Module).sanitize.SetSanitizer(t, true)
363 modules[0].(*Module).sanitize.Properties.SanitizeDep = false
364 } else {
365 modules := mctx.CreateVariations("", t.String())
366 modules[0].(*Module).sanitize.SetSanitizer(t, false)
367 modules[1].(*Module).sanitize.SetSanitizer(t, true)
368 modules[0].(*Module).sanitize.Properties.SanitizeDep = false
369 modules[1].(*Module).sanitize.Properties.SanitizeDep = false
370 modules[1].(*Module).sanitize.Properties.InData = true
371 if mctx.AConfig().EmbeddedInMake() {
372 modules[0].(*Module).Properties.HideFromMake = true
373 }
Colin Cross30d5f512016-05-03 18:02:42 -0700374 }
Colin Cross16b23492016-01-06 14:41:07 -0800375 }
376 c.sanitize.Properties.SanitizeDep = false
377 }
378 }
379}