blob: 4162e97adea25ee9296736e6f365e2ed6736a394 [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"
Colin Cross16b23492016-01-06 14:41:07 -080024)
25
26type sanitizerType int
27
28func init() {
29 pctx.StaticVariable("clangAsanLibDir", "${clangPath}/lib64/clang/3.8/lib/linux")
30}
31
32const (
33 asan sanitizerType = iota + 1
34 tsan
35)
36
37func (t sanitizerType) String() string {
38 switch t {
39 case asan:
40 return "asan"
41 case tsan:
42 return "tsan"
43 default:
44 panic(fmt.Errorf("unknown sanitizerType %d", t))
45 }
46}
47
48type SanitizeProperties struct {
49 // enable AddressSanitizer, ThreadSanitizer, or UndefinedBehaviorSanitizer
50 Sanitize struct {
51 Never bool `android:"arch_variant"`
52
53 // main sanitizers
54 Address bool `android:"arch_variant"`
55 Thread bool `android:"arch_variant"`
56
57 // local sanitizers
58 Undefined bool `android:"arch_variant"`
59 All_undefined bool `android:"arch_variant"`
60 Misc_undefined []string `android:"arch_variant"`
61 Coverage bool `android:"arch_variant"`
Evgenii Stepanov0a8a0d02016-05-12 13:54:53 -070062 SafeStack bool `android:"arch_variant"`
Colin Cross16b23492016-01-06 14:41:07 -080063
64 // value to pass to -fsantitize-recover=
65 Recover []string
66
67 // value to pass to -fsanitize-blacklist
68 Blacklist *string
69 } `android:"arch_variant"`
70
71 SanitizerEnabled bool `blueprint:"mutated"`
72 SanitizeDep bool `blueprint:"mutated"`
Colin Cross30d5f512016-05-03 18:02:42 -070073 InData bool `blueprint:"mutated"`
Colin Cross16b23492016-01-06 14:41:07 -080074}
75
76type sanitize struct {
77 Properties SanitizeProperties
78}
79
80func (sanitize *sanitize) props() []interface{} {
81 return []interface{}{&sanitize.Properties}
82}
83
84func (sanitize *sanitize) begin(ctx BaseModuleContext) {
85 // Don't apply sanitizers to NDK code.
86 if ctx.sdk() {
87 sanitize.Properties.Sanitize.Never = true
88 }
89
90 // Never always wins.
91 if sanitize.Properties.Sanitize.Never {
92 return
93 }
94
95 if ctx.ContainsProperty("sanitize") {
96 sanitize.Properties.SanitizerEnabled = true
97 }
98
99 var globalSanitizers []string
100 if ctx.clang() {
101 if ctx.Host() {
102 globalSanitizers = ctx.AConfig().SanitizeHost()
103 } else {
104 globalSanitizers = ctx.AConfig().SanitizeDevice()
105 }
106 }
107
108 // The sanitizer specified by the environment wins over the module.
109 if len(globalSanitizers) > 0 {
110 // wipe the enabled sanitizers
111 sanitize.Properties = SanitizeProperties{}
112 var found bool
113 if found, globalSanitizers = removeFromList("undefined", globalSanitizers); found {
114 sanitize.Properties.Sanitize.All_undefined = true
115 } else if found, globalSanitizers = removeFromList("default-ub", globalSanitizers); found {
116 sanitize.Properties.Sanitize.Undefined = true
117 }
118
119 if found, globalSanitizers = removeFromList("address", globalSanitizers); found {
120 sanitize.Properties.Sanitize.Address = true
121 }
122
123 if found, globalSanitizers = removeFromList("thread", globalSanitizers); found {
124 sanitize.Properties.Sanitize.Thread = true
125 }
126
127 if found, globalSanitizers = removeFromList("coverage", globalSanitizers); found {
128 sanitize.Properties.Sanitize.Coverage = true
129 }
130
Evgenii Stepanov0a8a0d02016-05-12 13:54:53 -0700131 if found, globalSanitizers = removeFromList("safe-stack", globalSanitizers); found {
132 sanitize.Properties.Sanitize.SafeStack = true
133 }
134
Colin Cross16b23492016-01-06 14:41:07 -0800135 if len(globalSanitizers) > 0 {
136 ctx.ModuleErrorf("unknown global sanitizer option %s", globalSanitizers[0])
137 }
138 sanitize.Properties.SanitizerEnabled = true
139 }
140
Evgenii Stepanov0a8a0d02016-05-12 13:54:53 -0700141 if !ctx.toolchain().Is64Bit() {
142 // TSAN and SafeStack are not supported on 32-bit architectures
Colin Cross16b23492016-01-06 14:41:07 -0800143 sanitize.Properties.Sanitize.Thread = false
Evgenii Stepanov0a8a0d02016-05-12 13:54:53 -0700144 sanitize.Properties.Sanitize.SafeStack = false
Colin Cross16b23492016-01-06 14:41:07 -0800145 // TODO(ccross): error for compile_multilib = "32"?
146 }
147
148 if sanitize.Properties.Sanitize.Coverage {
149 if !sanitize.Properties.Sanitize.Address {
150 ctx.ModuleErrorf(`Use of "coverage" also requires "address"`)
151 }
152 }
153}
154
155func (sanitize *sanitize) deps(ctx BaseModuleContext, deps Deps) Deps {
156 if !sanitize.Properties.SanitizerEnabled { // || c.static() {
157 return deps
158 }
159
160 if ctx.Device() {
161 deps.SharedLibs = append(deps.SharedLibs, "libdl")
162 if sanitize.Properties.Sanitize.Address {
163 deps.StaticLibs = append(deps.StaticLibs, "libasan")
164 }
165 }
166
167 return deps
168}
169
170func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags {
171 if !sanitize.Properties.SanitizerEnabled {
172 return flags
173 }
174
175 if !ctx.clang() {
176 ctx.ModuleErrorf("Use of sanitizers requires clang")
177 }
178
179 var sanitizers []string
180
181 if sanitize.Properties.Sanitize.All_undefined {
182 sanitizers = append(sanitizers, "undefined")
183 if ctx.Device() {
184 ctx.ModuleErrorf("ubsan is not yet supported on the device")
185 }
186 } else {
187 if sanitize.Properties.Sanitize.Undefined {
188 sanitizers = append(sanitizers,
189 "bool",
190 "integer-divide-by-zero",
191 "return",
192 "returns-nonnull-attribute",
193 "shift-exponent",
194 "unreachable",
195 "vla-bound",
196 // TODO(danalbert): The following checks currently have compiler performance issues.
197 //"alignment",
198 //"bounds",
199 //"enum",
200 //"float-cast-overflow",
201 //"float-divide-by-zero",
202 //"nonnull-attribute",
203 //"null",
204 //"shift-base",
205 //"signed-integer-overflow",
206 // TODO(danalbert): Fix UB in libc++'s __tree so we can turn this on.
207 // https://llvm.org/PR19302
208 // http://reviews.llvm.org/D6974
209 // "object-size",
210 )
211 }
212 sanitizers = append(sanitizers, sanitize.Properties.Sanitize.Misc_undefined...)
213 }
214
215 if sanitize.Properties.Sanitize.Address {
Colin Cross635c3b02016-05-18 15:37:25 -0700216 if ctx.Arch().ArchType == android.Arm {
Colin Cross16b23492016-01-06 14:41:07 -0800217 // Frame pointer based unwinder in ASan requires ARM frame setup.
218 // TODO: put in flags?
219 flags.RequiredInstructionSet = "arm"
220 }
221 flags.CFlags = append(flags.CFlags, "-fno-omit-frame-pointer")
222 flags.LdFlags = append(flags.LdFlags, "-Wl,-u,__asan_preinit")
223
224 // ASan runtime library must be the first in the link order.
225 runtimeLibrary := ctx.toolchain().AddressSanitizerRuntimeLibrary()
226 if runtimeLibrary != "" {
227 flags.libFlags = append([]string{"${clangAsanLibDir}/" + runtimeLibrary}, flags.libFlags...)
228 }
229 if ctx.Host() {
230 // -nodefaultlibs (provided with libc++) prevents the driver from linking
231 // libraries needed with -fsanitize=address. http://b/18650275 (WAI)
232 flags.LdFlags = append(flags.LdFlags, "-lm", "-lpthread")
233 flags.LdFlags = append(flags.LdFlags, "-Wl,--no-as-needed")
234 } else {
235 flags.CFlags = append(flags.CFlags, "-mllvm", "-asan-globals=0")
236 flags.DynamicLinker = "/system/bin/linker_asan"
237 if flags.Toolchain.Is64Bit() {
238 flags.DynamicLinker += "64"
239 }
240 }
241 sanitizers = append(sanitizers, "address")
242 }
243
244 if sanitize.Properties.Sanitize.Coverage {
245 flags.CFlags = append(flags.CFlags, "-fsanitize-coverage=edge,indirect-calls,8bit-counters,trace-cmp")
246 }
247
Evgenii Stepanov0a8a0d02016-05-12 13:54:53 -0700248 if sanitize.Properties.Sanitize.SafeStack {
249 sanitizers = append(sanitizers, "safe-stack")
250 }
251
Colin Cross16b23492016-01-06 14:41:07 -0800252 if sanitize.Properties.Sanitize.Recover != nil {
253 flags.CFlags = append(flags.CFlags, "-fsanitize-recover="+
254 strings.Join(sanitize.Properties.Sanitize.Recover, ","))
255 }
256
257 if len(sanitizers) > 0 {
258 sanitizeArg := "-fsanitize=" + strings.Join(sanitizers, ",")
259 flags.CFlags = append(flags.CFlags, sanitizeArg)
260 if ctx.Host() {
261 flags.CFlags = append(flags.CFlags, "-fno-sanitize-recover=all")
262 flags.LdFlags = append(flags.LdFlags, sanitizeArg)
263 flags.LdFlags = append(flags.LdFlags, "-lrt", "-ldl")
264 } else {
265 if !sanitize.Properties.Sanitize.Address {
266 flags.CFlags = append(flags.CFlags, "-fsanitize-trap=all", "-ftrap-function=abort")
267 }
268 }
269 }
270
Colin Cross635c3b02016-05-18 15:37:25 -0700271 blacklist := android.OptionalPathForModuleSrc(ctx, sanitize.Properties.Sanitize.Blacklist)
Colin Cross16b23492016-01-06 14:41:07 -0800272 if blacklist.Valid() {
273 flags.CFlags = append(flags.CFlags, "-fsanitize-blacklist="+blacklist.String())
274 flags.CFlagsDeps = append(flags.CFlagsDeps, blacklist.Path())
275 }
276
277 return flags
278}
279
Colin Cross30d5f512016-05-03 18:02:42 -0700280func (sanitize *sanitize) inData() bool {
281 return sanitize.Properties.InData
282}
283
Colin Cross16b23492016-01-06 14:41:07 -0800284func (sanitize *sanitize) Sanitizer(t sanitizerType) bool {
285 if sanitize == nil {
286 return false
287 }
288
289 switch t {
290 case asan:
291 return sanitize.Properties.Sanitize.Address
292 case tsan:
293 return sanitize.Properties.Sanitize.Thread
294 default:
295 panic(fmt.Errorf("unknown sanitizerType %d", t))
296 }
297}
298
299func (sanitize *sanitize) SetSanitizer(t sanitizerType, b bool) {
300 switch t {
301 case asan:
302 sanitize.Properties.Sanitize.Address = b
303 case tsan:
304 sanitize.Properties.Sanitize.Thread = b
305 default:
306 panic(fmt.Errorf("unknown sanitizerType %d", t))
307 }
308 if b {
309 sanitize.Properties.SanitizerEnabled = true
310 }
311}
312
313// Propagate asan requirements down from binaries
Colin Cross635c3b02016-05-18 15:37:25 -0700314func sanitizerDepsMutator(t sanitizerType) func(android.TopDownMutatorContext) {
315 return func(mctx android.TopDownMutatorContext) {
Colin Cross16b23492016-01-06 14:41:07 -0800316 if c, ok := mctx.Module().(*Module); ok && c.sanitize.Sanitizer(t) {
317 mctx.VisitDepsDepthFirst(func(module blueprint.Module) {
318 if d, ok := mctx.Module().(*Module); ok && c.sanitize != nil &&
319 !c.sanitize.Properties.Sanitize.Never {
320 d.sanitize.Properties.SanitizeDep = true
321 }
322 })
323 }
324 }
325}
326
327// Create asan variants for modules that need them
Colin Cross635c3b02016-05-18 15:37:25 -0700328func sanitizerMutator(t sanitizerType) func(android.BottomUpMutatorContext) {
329 return func(mctx android.BottomUpMutatorContext) {
Colin Cross16b23492016-01-06 14:41:07 -0800330 if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil {
331 if d, ok := c.linker.(baseLinkerInterface); ok && d.isDependencyRoot() && c.sanitize.Sanitizer(t) {
Colin Cross30d5f512016-05-03 18:02:42 -0700332 modules := mctx.CreateVariations(t.String())
333 modules[0].(*Module).sanitize.SetSanitizer(t, true)
334 if mctx.AConfig().EmbeddedInMake() {
335 modules[0].(*Module).sanitize.Properties.InData = true
336 }
Colin Cross16b23492016-01-06 14:41:07 -0800337 } else if c.sanitize.Properties.SanitizeDep {
Colin Cross30d5f512016-05-03 18:02:42 -0700338 if mctx.AConfig().EmbeddedInMake() {
339 modules := mctx.CreateVariations(t.String())
340 modules[0].(*Module).sanitize.SetSanitizer(t, true)
341 modules[0].(*Module).sanitize.Properties.InData = true
342 } else {
343 modules := mctx.CreateVariations("", t.String())
344 modules[0].(*Module).sanitize.SetSanitizer(t, false)
345 modules[1].(*Module).sanitize.SetSanitizer(t, true)
346 modules[1].(*Module).appendVariantName("_" + t.String())
347 modules[0].(*Module).sanitize.Properties.SanitizeDep = false
348 modules[1].(*Module).sanitize.Properties.SanitizeDep = false
349 }
Colin Cross16b23492016-01-06 14:41:07 -0800350 }
351 c.sanitize.Properties.SanitizeDep = false
352 }
353 }
354}