1// Copyright 2021 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	"testing"
19
20	"android/soong/android"
21)
22
23var prepareForAsanTest = android.FixtureAddFile("asan/Android.bp", []byte(`
24	cc_library_shared {
25		name: "libclang_rt.asan-aarch64-android",
26	}
27
28	cc_library_shared {
29		name: "libclang_rt.asan-arm-android",
30	}
31`))
32
33func TestAsan(t *testing.T) {
34	bp := `
35		cc_binary {
36			name: "bin_with_asan",
37			host_supported: true,
38			shared_libs: [
39				"libshared",
40				"libasan",
41			],
42			static_libs: [
43				"libstatic",
44				"libnoasan",
45			],
46			sanitize: {
47				address: true,
48			}
49		}
50
51		cc_binary {
52			name: "bin_no_asan",
53			host_supported: true,
54			shared_libs: [
55				"libshared",
56				"libasan",
57			],
58			static_libs: [
59				"libstatic",
60				"libnoasan",
61			],
62		}
63
64		cc_library_shared {
65			name: "libshared",
66			host_supported: true,
67			shared_libs: ["libtransitive"],
68		}
69
70		cc_library_shared {
71			name: "libasan",
72			host_supported: true,
73			shared_libs: ["libtransitive"],
74			sanitize: {
75				address: true,
76			}
77		}
78
79		cc_library_shared {
80			name: "libtransitive",
81			host_supported: true,
82		}
83
84		cc_library_static {
85			name: "libstatic",
86			host_supported: true,
87		}
88
89		cc_library_static {
90			name: "libnoasan",
91			host_supported: true,
92			sanitize: {
93				address: false,
94			}
95		}
96	`
97
98	result := android.GroupFixturePreparers(
99		prepareForCcTest,
100		prepareForAsanTest,
101	).RunTestWithBp(t, bp)
102
103	check := func(t *testing.T, result *android.TestResult, variant string) {
104		asanVariant := variant + "_asan"
105		sharedVariant := variant + "_shared"
106		sharedAsanVariant := sharedVariant + "_asan"
107		staticVariant := variant + "_static"
108		staticAsanVariant := staticVariant + "_asan"
109
110		// The binaries, one with asan and one without
111		binWithAsan := result.ModuleForTests("bin_with_asan", asanVariant)
112		binNoAsan := result.ModuleForTests("bin_no_asan", variant)
113
114		// Shared libraries that don't request asan
115		libShared := result.ModuleForTests("libshared", sharedVariant)
116		libTransitive := result.ModuleForTests("libtransitive", sharedVariant)
117
118		// Shared library that requests asan
119		libAsan := result.ModuleForTests("libasan", sharedAsanVariant)
120
121		// Static library that uses an asan variant for bin_with_asan and a non-asan variant
122		// for bin_no_asan.
123		libStaticAsanVariant := result.ModuleForTests("libstatic", staticAsanVariant)
124		libStaticNoAsanVariant := result.ModuleForTests("libstatic", staticVariant)
125
126		// Static library that never uses asan.
127		libNoAsan := result.ModuleForTests("libnoasan", staticVariant)
128
129		// expectSharedLinkDep verifies that the from module links against the to module as a
130		// shared library.
131		expectSharedLinkDep := func(from, to android.TestingModule) {
132			t.Helper()
133			fromLink := from.Description("link")
134			toLink := to.Description("strip")
135
136			if g, w := fromLink.OrderOnly.Strings(), toLink.Output.String(); !android.InList(w, g) {
137				t.Errorf("%s should link against %s, expected %q, got %q",
138					from.Module(), to.Module(), w, g)
139			}
140		}
141
142		// expectStaticLinkDep verifies that the from module links against the to module as a
143		// static library.
144		expectStaticLinkDep := func(from, to android.TestingModule) {
145			t.Helper()
146			fromLink := from.Description("link")
147			toLink := to.Description("static link")
148
149			if g, w := fromLink.Implicits.Strings(), toLink.Output.String(); !android.InList(w, g) {
150				t.Errorf("%s should link against %s, expected %q, got %q",
151					from.Module(), to.Module(), w, g)
152			}
153
154		}
155
156		// expectInstallDep verifies that the install rule of the from module depends on the
157		// install rule of the to module.
158		expectInstallDep := func(from, to android.TestingModule) {
159			t.Helper()
160			fromInstalled := from.Description("install")
161			toInstalled := to.Description("install")
162
163			// combine implicits and order-only dependencies, host uses implicit but device uses
164			// order-only.
165			got := append(fromInstalled.Implicits.Strings(), fromInstalled.OrderOnly.Strings()...)
166			want := toInstalled.Output.String()
167			if !android.InList(want, got) {
168				t.Errorf("%s installation should depend on %s, expected %q, got %q",
169					from.Module(), to.Module(), want, got)
170			}
171		}
172
173		expectSharedLinkDep(binWithAsan, libShared)
174		expectSharedLinkDep(binWithAsan, libAsan)
175		expectSharedLinkDep(libShared, libTransitive)
176		expectSharedLinkDep(libAsan, libTransitive)
177
178		expectStaticLinkDep(binWithAsan, libStaticAsanVariant)
179		expectStaticLinkDep(binWithAsan, libNoAsan)
180
181		expectInstallDep(binWithAsan, libShared)
182		expectInstallDep(binWithAsan, libAsan)
183		expectInstallDep(binWithAsan, libTransitive)
184		expectInstallDep(libShared, libTransitive)
185		expectInstallDep(libAsan, libTransitive)
186
187		expectSharedLinkDep(binNoAsan, libShared)
188		expectSharedLinkDep(binNoAsan, libAsan)
189		expectSharedLinkDep(libShared, libTransitive)
190		expectSharedLinkDep(libAsan, libTransitive)
191
192		expectStaticLinkDep(binNoAsan, libStaticNoAsanVariant)
193		expectStaticLinkDep(binNoAsan, libNoAsan)
194
195		expectInstallDep(binNoAsan, libShared)
196		expectInstallDep(binNoAsan, libAsan)
197		expectInstallDep(binNoAsan, libTransitive)
198		expectInstallDep(libShared, libTransitive)
199		expectInstallDep(libAsan, libTransitive)
200	}
201
202	t.Run("host", func(t *testing.T) { check(t, result, result.Config.BuildOSTarget.String()) })
203	t.Run("device", func(t *testing.T) { check(t, result, "android_arm64_armv8-a") })
204}
205