• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (C) 2023 The Android Open Source Project
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
15# This logic checks for the enablement of sanitizers to update the relevant
16# config_setting for the purpose of controlling the addition of sanitizer
17# blocklists.
18
19load("@bazel_skylib//lib:unittest.bzl", "analysistest")
20load("//build/bazel/rules/cc:cc_binary.bzl", "cc_binary")
21load("//build/bazel/rules/cc:cc_library_shared.bzl", "cc_library_shared")
22load("//build/bazel/rules/cc:cc_library_static.bzl", "cc_library_static")
23load(
24    "//build/bazel/rules/cc/testing:transitions.bzl",
25    "compile_action_argv_aspect_generator",
26    "transition_deps_test_attrs",
27    "transition_deps_test_impl",
28)
29
30static_cpp_suffix = "_cpp"
31shared_and_binary_cpp_suffix = "__internal_root_cpp"
32
33_compile_action_argv_aspect = compile_action_argv_aspect_generator({
34    "_cc_library_combiner": ["deps", "roots", "includes"],
35    "_cc_includes": ["deps"],
36    "_cc_library_shared_proxy": ["deps"],
37    "stripped_binary": ["androidmk_deps"],
38})
39
40sanitizer_blocklist_test = analysistest.make(
41    transition_deps_test_impl,
42    attrs = transition_deps_test_attrs,
43    extra_target_under_test_aspects = [_compile_action_argv_aspect],
44)
45
46sanitizer_blocklist_name = "foo_blocklist.txt"
47sanitizer_blocklist_flag = (
48    "-fsanitize-ignorelist=build/bazel/rules/cc/" +
49    sanitizer_blocklist_name
50)
51
52# TODO: b/294868620 - This select can be made into a normal list when completing
53#                     the bug
54sanitizer_blocklist_select = select({
55    "//build/bazel/rules/cc:sanitizers_enabled": [sanitizer_blocklist_flag],
56    "//conditions:default": [],
57})
58
59def test_sanitizer_blocklist_with_ubsan_static():
60    name = "sanitizer_blocklist_with_ubsan_static"
61    cc_library_static(
62        name = name,
63        srcs = ["foo.cpp"],
64        features = ["ubsan_integer"],
65        copts = sanitizer_blocklist_select,
66        additional_compiler_inputs = [sanitizer_blocklist_name],
67        tags = ["manual"],
68    )
69
70    test_name = name + "_test"
71    sanitizer_blocklist_test(
72        name = test_name,
73        target_under_test = name,
74        targets_with_flag = [name + static_cpp_suffix],
75        flags = [sanitizer_blocklist_flag],
76    )
77
78    return test_name
79
80def test_sanitizer_blocklist_with_cfi_static():
81    name = "sanitizer_blocklist_with_cfi_static"
82    cc_library_static(
83        name = name,
84        srcs = ["foo.cpp"],
85        features = ["android_cfi"],
86        copts = sanitizer_blocklist_select,
87        additional_compiler_inputs = [sanitizer_blocklist_name],
88        tags = ["manual"],
89    )
90
91    test_name = name + "_test"
92    sanitizer_blocklist_test(
93        name = test_name,
94        target_under_test = name,
95        targets_with_flag = [name + static_cpp_suffix],
96        flags = [sanitizer_blocklist_flag],
97    )
98
99    return test_name
100
101def test_no_sanitizer_blocklist_without_sanitizer_static():
102    name = "no_sanitizer_blocklist_without_sanitizer_static"
103    cc_library_static(
104        name = name,
105        srcs = ["foo.cpp"],
106        copts = sanitizer_blocklist_select,
107        additional_compiler_inputs = [sanitizer_blocklist_name],
108        tags = ["manual"],
109    )
110
111    test_name = name + "_test"
112    sanitizer_blocklist_test(
113        name = test_name,
114        target_under_test = name,
115        targets_without_flag = [name + static_cpp_suffix],
116        flags = [sanitizer_blocklist_flag],
117    )
118
119    return test_name
120
121def test_sanitizer_blocklist_with_ubsan_shared():
122    name = "sanitizer_blocklist_with_ubsan_shared"
123    cc_library_shared(
124        name = name,
125        srcs = ["foo.cpp"],
126        features = ["ubsan_integer"],
127        copts = sanitizer_blocklist_select,
128        additional_compiler_inputs = [sanitizer_blocklist_name],
129        tags = ["manual"],
130    )
131
132    test_name = name + "_test"
133    sanitizer_blocklist_test(
134        name = test_name,
135        target_under_test = name,
136        targets_with_flag = [name + shared_and_binary_cpp_suffix],
137        flags = [sanitizer_blocklist_flag],
138    )
139
140    return test_name
141
142def test_sanitizer_blocklist_with_cfi_shared():
143    name = "sanitizer_blocklist_with_cfi_shared"
144    cc_library_shared(
145        name = name,
146        srcs = ["foo.cpp"],
147        features = ["android_cfi"],
148        copts = sanitizer_blocklist_select,
149        additional_compiler_inputs = [sanitizer_blocklist_name],
150        tags = ["manual"],
151    )
152
153    test_name = name + "_test"
154    sanitizer_blocklist_test(
155        name = test_name,
156        target_under_test = name,
157        targets_with_flag = [name + shared_and_binary_cpp_suffix],
158        flags = [sanitizer_blocklist_flag],
159    )
160
161    return test_name
162
163def test_no_sanitizer_blocklist_without_sanitizer_shared():
164    name = "no_sanitizer_blocklist_without_sanitizer_shared"
165    cc_library_shared(
166        name = name,
167        srcs = ["foo.cpp"],
168        copts = sanitizer_blocklist_select,
169        additional_compiler_inputs = [sanitizer_blocklist_name],
170        tags = ["manual"],
171    )
172
173    test_name = name + "_test"
174    sanitizer_blocklist_test(
175        name = test_name,
176        target_under_test = name,
177        targets_without_flag = [name + shared_and_binary_cpp_suffix],
178        flags = [sanitizer_blocklist_flag],
179    )
180
181    return test_name
182
183def test_sanitizer_blocklist_with_ubsan_binary():
184    name = "sanitizer_blocklist_with_ubsan_binary"
185    cc_binary(
186        name = name,
187        srcs = ["foo.cpp"],
188        features = ["ubsan_integer"],
189        copts = sanitizer_blocklist_select,
190        additional_compiler_inputs = [sanitizer_blocklist_name],
191        tags = ["manual"],
192    )
193
194    test_name = name + "_test"
195    sanitizer_blocklist_test(
196        name = test_name,
197        target_under_test = name,
198        targets_with_flag = [name + shared_and_binary_cpp_suffix],
199        flags = [sanitizer_blocklist_flag],
200    )
201
202    return test_name
203
204def test_sanitizer_blocklist_with_cfi_binary():
205    name = "sanitizer_blocklist_with_cfi_binary"
206    cc_binary(
207        name = name,
208        srcs = ["foo.cpp"],
209        features = ["android_cfi"],
210        copts = sanitizer_blocklist_select,
211        additional_compiler_inputs = [sanitizer_blocklist_name],
212        tags = ["manual"],
213    )
214
215    test_name = name + "_test"
216    sanitizer_blocklist_test(
217        name = test_name,
218        target_under_test = name,
219        targets_with_flag = [name + shared_and_binary_cpp_suffix],
220        flags = [sanitizer_blocklist_flag],
221    )
222
223    return test_name
224
225def test_no_sanitizer_blocklist_without_sanitizer_binary():
226    name = "no_sanitizer_blocklist_without_sanitizer_binary"
227    cc_binary(
228        name = name,
229        srcs = ["foo.cpp"],
230        copts = sanitizer_blocklist_select,
231        additional_compiler_inputs = [sanitizer_blocklist_name],
232        tags = ["manual"],
233    )
234
235    test_name = name + "_test"
236    sanitizer_blocklist_test(
237        name = test_name,
238        target_under_test = name,
239        targets_without_flag = [name + shared_and_binary_cpp_suffix],
240        flags = [sanitizer_blocklist_flag],
241    )
242
243    return test_name
244
245def test_sanitizer_blocklist_on_dep_with_cfi():
246    name = "sanitizer_blocklist_on_dep_with_cfi"
247    requested_target_name = name + "_requested_target"
248    dep_name = name + "_dep"
249    cc_library_shared(
250        name = requested_target_name,
251        deps = [dep_name],
252        features = ["android_cfi"],
253        tags = ["manual"],
254    )
255    cc_library_static(
256        name = dep_name,
257        srcs = ["foo.cpp"],
258        copts = sanitizer_blocklist_select,
259        additional_compiler_inputs = [sanitizer_blocklist_name],
260        tags = ["manual"],
261    )
262
263    test_name = name + "_test"
264    sanitizer_blocklist_test(
265        name = test_name,
266        target_under_test = requested_target_name,
267        targets_with_flag = [dep_name + static_cpp_suffix],
268        flags = [sanitizer_blocklist_flag],
269    )
270
271    return test_name
272
273def test_no_sanitizer_blocklist_on_dep_without_cfi():
274    name = "no_sanitizer_blocklist_on_dep_without_cfi"
275    requested_target_name = name + "_requested_target"
276    dep_name = name + "_dep"
277    cc_library_shared(
278        name = requested_target_name,
279        deps = [dep_name],
280        tags = ["manual"],
281    )
282    cc_library_static(
283        name = dep_name,
284        srcs = ["foo.cpp"],
285        copts = sanitizer_blocklist_select,
286        additional_compiler_inputs = [sanitizer_blocklist_name],
287        tags = ["manual"],
288    )
289
290    test_name = name + "_test"
291    sanitizer_blocklist_test(
292        name = test_name,
293        target_under_test = requested_target_name,
294        targets_without_flag = [dep_name + static_cpp_suffix],
295        flags = [sanitizer_blocklist_flag],
296    )
297
298    return test_name
299
300# We test this because UBSan propagates the runtime up its rdep graph
301def test_no_sanitizer_blocklist_on_rdep_with_ubsan():
302    name = "no_sanitizer_blocklist_on_rdep_with_ubsan"
303    requested_target_name = name + "_requested_target"
304    dep_name = name + "_dep"
305    cc_library_static(
306        name = requested_target_name,
307        srcs = ["foo.cpp"],
308        deps = [dep_name],
309        copts = sanitizer_blocklist_select,
310        additional_compiler_inputs = [sanitizer_blocklist_name],
311        tags = ["manual"],
312    )
313    cc_library_shared(
314        name = dep_name,
315        srcs = ["bar.cpp"],
316        features = ["ubsan_integer"],
317        tags = ["manual"],
318    )
319
320    test_name = name + "_test"
321    sanitizer_blocklist_test(
322        name = test_name,
323        target_under_test = requested_target_name,
324        targets_without_flag = [requested_target_name + static_cpp_suffix],
325        flags = [sanitizer_blocklist_flag],
326    )
327
328    return test_name
329
330def test_sanitizer_blocklist_multiple_deps():
331    name = "sanitizer_blocklist_multiple_deps"
332    requested_target_name = name + "_requested_target"
333    dep_name = name + "_dep"
334    dep_of_dep_name = name + "_dep_of_dep"
335    other_dep_name = name + "_other_dep"
336    cc_library_shared(
337        name = requested_target_name,
338        srcs = ["foo.cpp"],
339        implementation_deps = [dep_name, other_dep_name],
340        features = ["android_cfi"],
341        tags = ["manual"],
342    )
343
344    cc_library_static(
345        name = dep_name,
346        srcs = ["bar.cpp"],
347        implementation_dynamic_deps = [dep_of_dep_name],
348        features = ["android_cfi"],
349        copts = sanitizer_blocklist_select,
350        additional_compiler_inputs = [sanitizer_blocklist_name],
351        tags = ["manual"],
352    )
353
354    cc_library_shared(
355        name = other_dep_name,
356        srcs = ["blah.cpp"],
357        implementation_dynamic_deps = [dep_of_dep_name],
358        tags = ["manual"],
359    )
360
361    cc_library_shared(
362        name = dep_of_dep_name,
363        srcs = ["baz.cpp"],
364        features = ["android_cfi"],
365        tags = ["manual"],
366    )
367
368    test_name = name + "_test"
369    sanitizer_blocklist_test(
370        name = test_name,
371        target_under_test = requested_target_name,
372        targets_with_flag = [dep_name + static_cpp_suffix],
373        flags = [sanitizer_blocklist_flag],
374    )
375
376    return test_name
377
378def sanitizer_blocklist_test_suite(name):
379    native.test_suite(
380        name = name,
381        tests = [
382            test_sanitizer_blocklist_with_ubsan_static(),
383            test_sanitizer_blocklist_with_cfi_static(),
384            test_no_sanitizer_blocklist_without_sanitizer_static(),
385            test_sanitizer_blocklist_with_ubsan_shared(),
386            test_sanitizer_blocklist_with_cfi_shared(),
387            test_no_sanitizer_blocklist_without_sanitizer_shared(),
388            test_sanitizer_blocklist_with_ubsan_binary(),
389            test_sanitizer_blocklist_with_cfi_binary(),
390            test_no_sanitizer_blocklist_without_sanitizer_binary(),
391            test_sanitizer_blocklist_on_dep_with_cfi(),
392            test_no_sanitizer_blocklist_on_dep_without_cfi(),
393            test_no_sanitizer_blocklist_on_rdep_with_ubsan(),
394            test_sanitizer_blocklist_multiple_deps(),
395        ],
396    )
397