xref: /aosp_15_r20/bionic/tests/libs/memtag_globals_dso.cpp (revision 8d67ca893c1523eb926b9080dbe4e2ffd2a27ba1)
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *  * Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  *  * Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in
12  *    the documentation and/or other materials provided with the
13  *    distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <stdint.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <vector>
33 
34 #include "memtag_globals.h"
35 
36 // Adapted from the LLD test suite: lld/test/ELF/Inputs/aarch64-memtag-globals.s
37 
38 int global_extern;
39 static int global_extern_hidden;
40 __attribute__((no_sanitize("memtag"))) int global_extern_untagged;
41 __attribute__((no_sanitize("memtag"))) int global_extern_untagged_definition_but_tagged_import;
42 
assertion_failure()43 void assertion_failure() {
44   exit(1);
45 }
46 
check_tagged(const void * a)47 void check_tagged(const void* a) {
48   uintptr_t a_uptr = reinterpret_cast<uintptr_t>(a);
49 #if defined(__aarch64__)
50   if ((a_uptr >> 56) == 0) {
51     fprintf(stderr, "**********************************\n");
52     fprintf(stderr, "Failed assertion:\n");
53     fprintf(stderr, "  tag(0x%zx) != 0\n", a_uptr);
54     fprintf(stderr, "**********************************\n");
55 
56     assertion_failure();
57   }
58 #endif  // defined(__aarch64__)
59 }
60 
check_untagged(const void * a)61 void check_untagged(const void* a) {
62   uintptr_t a_uptr = reinterpret_cast<uintptr_t>(a);
63 #if defined(__aarch64__)
64   if ((a_uptr >> 56) != 0) {
65     fprintf(stderr, "**********************************\n");
66     fprintf(stderr, "Failed assertion:\n");
67     fprintf(stderr, "  tag(0x%zx) == 0\n", a_uptr);
68     fprintf(stderr, "**********************************\n");
69 
70     assertion_failure();
71   }
72 #endif  // defined(__aarch64__)
73 }
74 
check_matching_tags(const void * a,const void * b)75 void check_matching_tags(const void* a, const void* b) {
76   uintptr_t a_uptr = reinterpret_cast<uintptr_t>(a);
77   uintptr_t b_uptr = reinterpret_cast<uintptr_t>(b);
78 #if defined(__aarch64__)
79   if (a_uptr >> 56 != b_uptr >> 56) {
80     fprintf(stderr, "**********************************\n");
81     fprintf(stderr, "Failed assertion:\n");
82     fprintf(stderr, "  tag(0x%zx) != tag(0x%zx)\n", a_uptr, b_uptr);
83     fprintf(stderr, "**********************************\n");
84 
85     assertion_failure();
86   }
87 #endif  // defined(__aarch64__)
88 }
89 
check_eq(const void * a,const void * b)90 void check_eq(const void* a, const void* b) {
91   if (a != b) {
92     fprintf(stderr, "**********************************\n");
93     fprintf(stderr, "Failed assertion:\n");
94     fprintf(stderr, "  %p != %p\n", a, b);
95     fprintf(stderr, "**********************************\n");
96 
97     assertion_failure();
98   }
99 }
100 
101 #define LONGEST_VARIABLE_NAME "51"
print_variable_address(const char * name,const void * ptr)102 void print_variable_address(const char* name, const void* ptr) {
103   printf("%" LONGEST_VARIABLE_NAME "s: %16p\n", name, ptr);
104 }
105 
get_expected_tagged_vars()106 static const std::vector<std::pair<const char*, const void*>>& get_expected_tagged_vars() {
107   static std::vector<std::pair<const char*, const void*>> expected_tagged_vars = {
108       {"global_extern", &global_extern},
109       {"global_extern_hidden", &global_extern_hidden},
110   };
111   return expected_tagged_vars;
112 }
113 
get_expected_untagged_vars()114 static const std::vector<std::pair<const char*, const void*>>& get_expected_untagged_vars() {
115   static std::vector<std::pair<const char*, const void*>> expected_untagged_vars = {
116       {"global_extern_untagged", &global_extern_untagged},
117       {"global_extern_untagged_definition_but_tagged_import",
118        &global_extern_untagged_definition_but_tagged_import},
119   };
120   return expected_untagged_vars;
121 }
122 
dso_print_variables()123 void dso_print_variables() {
124   print_variables("  Variables declared in the DSO:\n", get_expected_tagged_vars(),
125                   get_expected_untagged_vars());
126 }
127 
print_variables(const char * header,const std::vector<std::pair<const char *,const void * >> & tagged_variables,const std::vector<std::pair<const char *,const void * >> & untagged_variables)128 void print_variables(const char* header,
129                      const std::vector<std::pair<const char*, const void*>>& tagged_variables,
130                      const std::vector<std::pair<const char*, const void*>>& untagged_variables) {
131   printf("==========================================================\n");
132   printf("%s", header);
133   printf("==========================================================\n");
134   printf(" Variables expected to be tagged:\n");
135   printf("----------------------------------------------------------\n");
136   for (const auto& [name, pointer] : tagged_variables) {
137     print_variable_address(name, pointer);
138   }
139 
140   printf("\n----------------------------------------------------------\n");
141   printf(" Variables expected to be untagged:\n");
142   printf("----------------------------------------------------------\n");
143   for (const auto& [name, pointer] : untagged_variables) {
144     print_variable_address(name, pointer);
145   }
146   printf("\n");
147 }
148 
dso_check_assertions(bool check_pointers_are_tagged)149 void dso_check_assertions(bool check_pointers_are_tagged) {
150   // Check that non-const variables are writeable.
151   global_extern = 0;
152   global_extern_hidden = 0;
153   global_extern_untagged = 0;
154   global_extern_untagged_definition_but_tagged_import = 0;
155 
156   if (check_pointers_are_tagged) {
157     for (const auto& [_, pointer] : get_expected_tagged_vars()) {
158       check_tagged(pointer);
159     }
160   }
161 
162   for (const auto& [_, pointer] : get_expected_untagged_vars()) {
163     check_untagged(pointer);
164   }
165 }
166