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
15load("@bazel_skylib//lib:unittest.bzl", "analysistest")
16load(
17    "@soong_injection//cc_toolchain:sanitizer_constants.bzl",
18    _generated_sanitizer_constants = "constants",
19)
20load(
21    "//build/bazel/rules/cc/testing:transitions.bzl",
22    "compile_action_argv_aspect_generator",
23    "transition_deps_test_attrs",
24    "transition_deps_test_impl",
25)
26load(":cc_binary.bzl", "cc_binary")
27load(":cc_constants.bzl", "transition_constants")
28load(":cc_library_shared.bzl", "cc_library_shared")
29load(":cc_library_static.bzl", "cc_library_static")
30
31_compile_action_argv_aspect = compile_action_argv_aspect_generator({
32    "_cc_library_combiner": ["deps", "roots", "includes"],
33    "_cc_includes": ["deps"],
34    "_cc_library_shared_proxy": ["deps"],
35    "cc_binary": ["deps"],
36    "stripped_binary": ["src", "unstripped"],
37})
38
39_cfi_deps_test = analysistest.make(
40    transition_deps_test_impl,
41    attrs = transition_deps_test_attrs,
42    extra_target_under_test_aspects = [_compile_action_argv_aspect],
43)
44
45cfi_feature = "android_cfi"
46static_cpp_suffix = "_cpp"
47shared_or_binary_cpp_suffix = "__internal_root_cpp"
48binary_suffix = "__internal_root"
49
50def _test_cfi_propagates_to_static_deps():
51    name = "cfi_propagates_to_static_deps"
52    static_dep_name = name + "_static_dep"
53    static_dep_of_static_dep_name = static_dep_name + "_of_static_dep"
54    test_name = name + "_test"
55
56    cc_library_shared(
57        name = name,
58        srcs = ["foo.cpp"],
59        deps = [static_dep_name],
60        features = [cfi_feature],
61        tags = ["manual"],
62    )
63
64    cc_library_static(
65        name = static_dep_name,
66        srcs = ["bar.cpp"],
67        deps = [static_dep_of_static_dep_name],
68        tags = ["manual"],
69    )
70
71    cc_library_static(
72        name = static_dep_of_static_dep_name,
73        srcs = ["baz.cpp"],
74        tags = ["manual"],
75    )
76
77    _cfi_deps_test(
78        name = test_name,
79        target_under_test = name,
80        flags = [_generated_sanitizer_constants.CfiCrossDsoFlag],
81        targets_with_flag = [
82            name + shared_or_binary_cpp_suffix,
83            static_dep_name + static_cpp_suffix,
84            static_dep_of_static_dep_name + static_cpp_suffix,
85        ],
86        targets_without_flag = [],
87    )
88
89    return test_name
90
91def _test_cfi_does_not_propagate_to_shared_deps():
92    name = "cfi_does_not_propagate_to_shared_deps"
93    shared_dep_name = name + "shared_dep"
94    test_name = name + "_test"
95
96    cc_library_shared(
97        name = name,
98        srcs = ["foo.cpp"],
99        deps = [shared_dep_name],
100        features = [cfi_feature],
101        tags = ["manual"],
102    )
103
104    cc_library_shared(
105        name = shared_dep_name,
106        srcs = ["bar.cpp"],
107        tags = ["manual"],
108    )
109
110    _cfi_deps_test(
111        name = test_name,
112        target_under_test = name,
113        flags = [_generated_sanitizer_constants.CfiCrossDsoFlag],
114        targets_with_flag = [name + shared_or_binary_cpp_suffix],
115        targets_without_flag = [shared_dep_name + shared_or_binary_cpp_suffix],
116    )
117
118    return test_name
119
120def _test_cfi_disabled_propagates_to_static_deps():
121    name = "cfi_disabled_propagates_to_static_deps"
122    static_dep_name = name + "_static_dep"
123    test_name = name + "_test"
124
125    cc_library_shared(
126        name = name,
127        srcs = ["foo.cpp"],
128        deps = [static_dep_name],
129        tags = ["manual"],
130    )
131
132    cc_library_static(
133        name = static_dep_name,
134        srcs = ["bar.cpp"],
135        features = ["android_cfi"],
136        tags = ["manual"],
137    )
138
139    _cfi_deps_test(
140        name = test_name,
141        target_under_test = name,
142        flags = [_generated_sanitizer_constants.CfiCrossDsoFlag],
143        targets_with_flag = [],
144        targets_without_flag = [
145            name + shared_or_binary_cpp_suffix,
146            static_dep_name + static_cpp_suffix,
147        ],
148    )
149
150    return test_name
151
152def _test_cfi_binary_propagates_to_static_deps():
153    name = "cfi_binary_propagates_to_static_deps"
154    static_dep_name = name + "_static_dep"
155    test_name = name + "_test"
156
157    cc_binary(
158        name = name,
159        srcs = ["foo.cpp"],
160        deps = [static_dep_name],
161        features = [cfi_feature],
162        tags = ["manual"],
163    )
164
165    cc_library_static(
166        name = static_dep_name,
167        srcs = ["bar.cpp"],
168        tags = ["manual"],
169    )
170
171    _cfi_deps_test(
172        name = test_name,
173        target_under_test = name,
174        flags = [_generated_sanitizer_constants.CfiCrossDsoFlag],
175        targets_with_flag = [
176            name + shared_or_binary_cpp_suffix,
177            static_dep_name + static_cpp_suffix,
178        ],
179        targets_without_flag = [],
180    )
181
182    return test_name
183
184_cfi_deps_cfi_include_paths_test = analysistest.make(
185    transition_deps_test_impl,
186    attrs = transition_deps_test_attrs,
187    extra_target_under_test_aspects = [_compile_action_argv_aspect],
188    config_settings = {
189        transition_constants.cli_platforms_key: [
190            "@//build/bazel/tests/products:aosp_x86_for_testing_cfi_include_path",
191        ],
192    },
193)
194
195def _test_cfi_include_paths_enables_cfi_for_device():
196    name = "cfi_include_paths_enables_cfi_for_device"
197    test_name = name + "_test"
198
199    cc_library_shared(
200        name = name,
201        srcs = ["foo.cpp"],
202        tags = ["manual"],
203    )
204
205    _cfi_deps_cfi_include_paths_test(
206        name = test_name,
207        target_under_test = name,
208        flags = [_generated_sanitizer_constants.CfiCrossDsoFlag],
209        targets_with_flag = [name + shared_or_binary_cpp_suffix],
210        targets_without_flag = [],
211    )
212
213    return test_name
214
215_cfi_deps_cfi_includes_paths_host_no_cfi_test = analysistest.make(
216    transition_deps_test_impl,
217    attrs = transition_deps_test_attrs,
218    extra_target_under_test_aspects = [_compile_action_argv_aspect],
219    config_settings = {
220        transition_constants.cli_platforms_key: [
221            "@//build/bazel/tests/products:aosp_x86_for_testing_cfi_include_path_linux_x86",
222        ],
223    },
224)
225
226def _test_cfi_include_paths_host_no_cfi():
227    name = "cfi_include_paths_host_no_cfi"
228    test_name = name + "_test"
229
230    cc_library_shared(
231        name = name,
232        srcs = ["foo.cpp"],
233        tags = ["manual"],
234    )
235
236    _cfi_deps_cfi_includes_paths_host_no_cfi_test(
237        name = test_name,
238        target_under_test = name,
239        flags = [_generated_sanitizer_constants.CfiCrossDsoFlag],
240        targets_with_flag = [],
241        targets_without_flag = [name + shared_or_binary_cpp_suffix],
242    )
243
244    return test_name
245
246_cfi_exclude_paths_no_cfi_test = analysistest.make(
247    transition_deps_test_impl,
248    attrs = transition_deps_test_attrs,
249    extra_target_under_test_aspects = [_compile_action_argv_aspect],
250    config_settings = {
251        transition_constants.cli_platforms_key: [
252            "@//build/bazel/tests/products:aosp_x86_for_testing_cfi_exclude_path",
253        ],
254    },
255)
256
257def _test_cfi_exclude_paths_disable_cfi():
258    name = "cfi_exclude_paths_disable_cfi"
259    test_name = name + "_test"
260
261    cc_library_shared(
262        name = name,
263        srcs = ["foo.cpp"],
264        features = ["android_cfi"],
265        tags = ["manual"],
266    )
267
268    _cfi_exclude_paths_no_cfi_test(
269        name = test_name,
270        target_under_test = name,
271        flags = [_generated_sanitizer_constants.CfiCrossDsoFlag],
272        targets_with_flag = [],
273        targets_without_flag = [name + shared_or_binary_cpp_suffix],
274    )
275
276    return test_name
277
278_enable_cfi_false_no_cfi_test = analysistest.make(
279    transition_deps_test_impl,
280    attrs = transition_deps_test_attrs,
281    extra_target_under_test_aspects = [_compile_action_argv_aspect],
282    config_settings = {
283        transition_constants.enable_cfi_key: False,
284    },
285)
286
287def _test_enable_cfi_false_disables_cfi_globally():
288    name = "enable_cfi_false_disables_cfi_globally"
289    test_name = name + "_test"
290
291    cc_library_shared(
292        name = name,
293        srcs = ["foo.cpp"],
294        features = ["android_cfi"],
295        tags = ["manual"],
296    )
297
298    _enable_cfi_false_no_cfi_test(
299        name = test_name,
300        target_under_test = name,
301        flags = [_generated_sanitizer_constants.CfiCrossDsoFlag],
302        targets_with_flag = [],
303        targets_without_flag = [name + shared_or_binary_cpp_suffix],
304    )
305
306    return test_name
307
308def cfi_transition_test_suite(name):
309    native.test_suite(
310        name = name,
311        tests = [
312            _test_cfi_propagates_to_static_deps(),
313            _test_cfi_does_not_propagate_to_shared_deps(),
314            _test_cfi_disabled_propagates_to_static_deps(),
315            _test_cfi_binary_propagates_to_static_deps(),
316            _test_cfi_include_paths_enables_cfi_for_device(),
317            _test_cfi_include_paths_host_no_cfi(),
318            _test_cfi_exclude_paths_disable_cfi(),
319            _test_enable_cfi_false_disables_cfi_globally(),
320        ],
321    )
322