| author | |
| committer | |
| log | dbaea8d67e680121f4e917458a99bc538b473d9d |
| tree | e3af41c263074ee293a1640b0011d92a4e8163c4 |
| parent | e79b4e907a3ceed4984a252fb2bccab7f31ec383 |
| signature |
74 files changed, 1910 insertions(+), 555 deletions(-)
lib/libtsan/LICENSE.TXT created+311| ... | ... | @@ -0,0 +1,311 @@ |
| 1 | ============================================================================== | |
| 2 | The LLVM Project is under the Apache License v2.0 with LLVM Exceptions: | |
| 3 | ============================================================================== | |
| 4 | ||
| 5 | Apache License | |
| 6 | Version 2.0, January 2004 | |
| 7 | http://www.apache.org/licenses/ | |
| 8 | ||
| 9 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | |
| 10 | ||
| 11 | 1. Definitions. | |
| 12 | ||
| 13 | "License" shall mean the terms and conditions for use, reproduction, | |
| 14 | and distribution as defined by Sections 1 through 9 of this document. | |
| 15 | ||
| 16 | "Licensor" shall mean the copyright owner or entity authorized by | |
| 17 | the copyright owner that is granting the License. | |
| 18 | ||
| 19 | "Legal Entity" shall mean the union of the acting entity and all | |
| 20 | other entities that control, are controlled by, or are under common | |
| 21 | control with that entity. For the purposes of this definition, | |
| 22 | "control" means (i) the power, direct or indirect, to cause the | |
| 23 | direction or management of such entity, whether by contract or | |
| 24 | otherwise, or (ii) ownership of fifty percent (50%) or more of the | |
| 25 | outstanding shares, or (iii) beneficial ownership of such entity. | |
| 26 | ||
| 27 | "You" (or "Your") shall mean an individual or Legal Entity | |
| 28 | exercising permissions granted by this License. | |
| 29 | ||
| 30 | "Source" form shall mean the preferred form for making modifications, | |
| 31 | including but not limited to software source code, documentation | |
| 32 | source, and configuration files. | |
| 33 | ||
| 34 | "Object" form shall mean any form resulting from mechanical | |
| 35 | transformation or translation of a Source form, including but | |
| 36 | not limited to compiled object code, generated documentation, | |
| 37 | and conversions to other media types. | |
| 38 | ||
| 39 | "Work" shall mean the work of authorship, whether in Source or | |
| 40 | Object form, made available under the License, as indicated by a | |
| 41 | copyright notice that is included in or attached to the work | |
| 42 | (an example is provided in the Appendix below). | |
| 43 | ||
| 44 | "Derivative Works" shall mean any work, whether in Source or Object | |
| 45 | form, that is based on (or derived from) the Work and for which the | |
| 46 | editorial revisions, annotations, elaborations, or other modifications | |
| 47 | represent, as a whole, an original work of authorship. For the purposes | |
| 48 | of this License, Derivative Works shall not include works that remain | |
| 49 | separable from, or merely link (or bind by name) to the interfaces of, | |
| 50 | the Work and Derivative Works thereof. | |
| 51 | ||
| 52 | "Contribution" shall mean any work of authorship, including | |
| 53 | the original version of the Work and any modifications or additions | |
| 54 | to that Work or Derivative Works thereof, that is intentionally | |
| 55 | submitted to Licensor for inclusion in the Work by the copyright owner | |
| 56 | or by an individual or Legal Entity authorized to submit on behalf of | |
| 57 | the copyright owner. For the purposes of this definition, "submitted" | |
| 58 | means any form of electronic, verbal, or written communication sent | |
| 59 | to the Licensor or its representatives, including but not limited to | |
| 60 | communication on electronic mailing lists, source code control systems, | |
| 61 | and issue tracking systems that are managed by, or on behalf of, the | |
| 62 | Licensor for the purpose of discussing and improving the Work, but | |
| 63 | excluding communication that is conspicuously marked or otherwise | |
| 64 | designated in writing by the copyright owner as "Not a Contribution." | |
| 65 | ||
| 66 | "Contributor" shall mean Licensor and any individual or Legal Entity | |
| 67 | on behalf of whom a Contribution has been received by Licensor and | |
| 68 | subsequently incorporated within the Work. | |
| 69 | ||
| 70 | 2. Grant of Copyright License. Subject to the terms and conditions of | |
| 71 | this License, each Contributor hereby grants to You a perpetual, | |
| 72 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |
| 73 | copyright license to reproduce, prepare Derivative Works of, | |
| 74 | publicly display, publicly perform, sublicense, and distribute the | |
| 75 | Work and such Derivative Works in Source or Object form. | |
| 76 | ||
| 77 | 3. Grant of Patent License. Subject to the terms and conditions of | |
| 78 | this License, each Contributor hereby grants to You a perpetual, | |
| 79 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |
| 80 | (except as stated in this section) patent license to make, have made, | |
| 81 | use, offer to sell, sell, import, and otherwise transfer the Work, | |
| 82 | where such license applies only to those patent claims licensable | |
| 83 | by such Contributor that are necessarily infringed by their | |
| 84 | Contribution(s) alone or by combination of their Contribution(s) | |
| 85 | with the Work to which such Contribution(s) was submitted. If You | |
| 86 | institute patent litigation against any entity (including a | |
| 87 | cross-claim or counterclaim in a lawsuit) alleging that the Work | |
| 88 | or a Contribution incorporated within the Work constitutes direct | |
| 89 | or contributory patent infringement, then any patent licenses | |
| 90 | granted to You under this License for that Work shall terminate | |
| 91 | as of the date such litigation is filed. | |
| 92 | ||
| 93 | 4. Redistribution. You may reproduce and distribute copies of the | |
| 94 | Work or Derivative Works thereof in any medium, with or without | |
| 95 | modifications, and in Source or Object form, provided that You | |
| 96 | meet the following conditions: | |
| 97 | ||
| 98 | (a) You must give any other recipients of the Work or | |
| 99 | Derivative Works a copy of this License; and | |
| 100 | ||
| 101 | (b) You must cause any modified files to carry prominent notices | |
| 102 | stating that You changed the files; and | |
| 103 | ||
| 104 | (c) You must retain, in the Source form of any Derivative Works | |
| 105 | that You distribute, all copyright, patent, trademark, and | |
| 106 | attribution notices from the Source form of the Work, | |
| 107 | excluding those notices that do not pertain to any part of | |
| 108 | the Derivative Works; and | |
| 109 | ||
| 110 | (d) If the Work includes a "NOTICE" text file as part of its | |
| 111 | distribution, then any Derivative Works that You distribute must | |
| 112 | include a readable copy of the attribution notices contained | |
| 113 | within such NOTICE file, excluding those notices that do not | |
| 114 | pertain to any part of the Derivative Works, in at least one | |
| 115 | of the following places: within a NOTICE text file distributed | |
| 116 | as part of the Derivative Works; within the Source form or | |
| 117 | documentation, if provided along with the Derivative Works; or, | |
| 118 | within a display generated by the Derivative Works, if and | |
| 119 | wherever such third-party notices normally appear. The contents | |
| 120 | of the NOTICE file are for informational purposes only and | |
| 121 | do not modify the License. You may add Your own attribution | |
| 122 | notices within Derivative Works that You distribute, alongside | |
| 123 | or as an addendum to the NOTICE text from the Work, provided | |
| 124 | that such additional attribution notices cannot be construed | |
| 125 | as modifying the License. | |
| 126 | ||
| 127 | You may add Your own copyright statement to Your modifications and | |
| 128 | may provide additional or different license terms and conditions | |
| 129 | for use, reproduction, or distribution of Your modifications, or | |
| 130 | for any such Derivative Works as a whole, provided Your use, | |
| 131 | reproduction, and distribution of the Work otherwise complies with | |
| 132 | the conditions stated in this License. | |
| 133 | ||
| 134 | 5. Submission of Contributions. Unless You explicitly state otherwise, | |
| 135 | any Contribution intentionally submitted for inclusion in the Work | |
| 136 | by You to the Licensor shall be under the terms and conditions of | |
| 137 | this License, without any additional terms or conditions. | |
| 138 | Notwithstanding the above, nothing herein shall supersede or modify | |
| 139 | the terms of any separate license agreement you may have executed | |
| 140 | with Licensor regarding such Contributions. | |
| 141 | ||
| 142 | 6. Trademarks. This License does not grant permission to use the trade | |
| 143 | names, trademarks, service marks, or product names of the Licensor, | |
| 144 | except as required for reasonable and customary use in describing the | |
| 145 | origin of the Work and reproducing the content of the NOTICE file. | |
| 146 | ||
| 147 | 7. Disclaimer of Warranty. Unless required by applicable law or | |
| 148 | agreed to in writing, Licensor provides the Work (and each | |
| 149 | Contributor provides its Contributions) on an "AS IS" BASIS, | |
| 150 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | |
| 151 | implied, including, without limitation, any warranties or conditions | |
| 152 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | |
| 153 | PARTICULAR PURPOSE. You are solely responsible for determining the | |
| 154 | appropriateness of using or redistributing the Work and assume any | |
| 155 | risks associated with Your exercise of permissions under this License. | |
| 156 | ||
| 157 | 8. Limitation of Liability. In no event and under no legal theory, | |
| 158 | whether in tort (including negligence), contract, or otherwise, | |
| 159 | unless required by applicable law (such as deliberate and grossly | |
| 160 | negligent acts) or agreed to in writing, shall any Contributor be | |
| 161 | liable to You for damages, including any direct, indirect, special, | |
| 162 | incidental, or consequential damages of any character arising as a | |
| 163 | result of this License or out of the use or inability to use the | |
| 164 | Work (including but not limited to damages for loss of goodwill, | |
| 165 | work stoppage, computer failure or malfunction, or any and all | |
| 166 | other commercial damages or losses), even if such Contributor | |
| 167 | has been advised of the possibility of such damages. | |
| 168 | ||
| 169 | 9. Accepting Warranty or Additional Liability. While redistributing | |
| 170 | the Work or Derivative Works thereof, You may choose to offer, | |
| 171 | and charge a fee for, acceptance of support, warranty, indemnity, | |
| 172 | or other liability obligations and/or rights consistent with this | |
| 173 | License. However, in accepting such obligations, You may act only | |
| 174 | on Your own behalf and on Your sole responsibility, not on behalf | |
| 175 | of any other Contributor, and only if You agree to indemnify, | |
| 176 | defend, and hold each Contributor harmless for any liability | |
| 177 | incurred by, or claims asserted against, such Contributor by reason | |
| 178 | of your accepting any such warranty or additional liability. | |
| 179 | ||
| 180 | END OF TERMS AND CONDITIONS | |
| 181 | ||
| 182 | APPENDIX: How to apply the Apache License to your work. | |
| 183 | ||
| 184 | To apply the Apache License to your work, attach the following | |
| 185 | boilerplate notice, with the fields enclosed by brackets "[]" | |
| 186 | replaced with your own identifying information. (Don't include | |
| 187 | the brackets!) The text should be enclosed in the appropriate | |
| 188 | comment syntax for the file format. We also recommend that a | |
| 189 | file or class name and description of purpose be included on the | |
| 190 | same "printed page" as the copyright notice for easier | |
| 191 | identification within third-party archives. | |
| 192 | ||
| 193 | Copyright [yyyy] [name of copyright owner] | |
| 194 | ||
| 195 | Licensed under the Apache License, Version 2.0 (the "License"); | |
| 196 | you may not use this file except in compliance with the License. | |
| 197 | You may obtain a copy of the License at | |
| 198 | ||
| 199 | http://www.apache.org/licenses/LICENSE-2.0 | |
| 200 | ||
| 201 | Unless required by applicable law or agreed to in writing, software | |
| 202 | distributed under the License is distributed on an "AS IS" BASIS, | |
| 203 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 204 | See the License for the specific language governing permissions and | |
| 205 | limitations under the License. | |
| 206 | ||
| 207 | ||
| 208 | ---- LLVM Exceptions to the Apache 2.0 License ---- | |
| 209 | ||
| 210 | As an exception, if, as a result of your compiling your source code, portions | |
| 211 | of this Software are embedded into an Object form of such source code, you | |
| 212 | may redistribute such embedded portions in such Object form without complying | |
| 213 | with the conditions of Sections 4(a), 4(b) and 4(d) of the License. | |
| 214 | ||
| 215 | In addition, if you combine or link compiled forms of this Software with | |
| 216 | software that is licensed under the GPLv2 ("Combined Software") and if a | |
| 217 | court of competent jurisdiction determines that the patent provision (Section | |
| 218 | 3), the indemnity provision (Section 9) or other Section of the License | |
| 219 | conflicts with the conditions of the GPLv2, you may retroactively and | |
| 220 | prospectively choose to deem waived or otherwise exclude such Section(s) of | |
| 221 | the License, but only in their entirety and only with respect to the Combined | |
| 222 | Software. | |
| 223 | ||
| 224 | ============================================================================== | |
| 225 | Software from third parties included in the LLVM Project: | |
| 226 | ============================================================================== | |
| 227 | The LLVM Project contains third party software which is under different license | |
| 228 | terms. All such code will be identified clearly using at least one of two | |
| 229 | mechanisms: | |
| 230 | 1) It will be in a separate directory tree with its own `LICENSE.txt` or | |
| 231 | `LICENSE` file at the top containing the specific license and restrictions | |
| 232 | which apply to that software, or | |
| 233 | 2) It will contain specific license and restriction terms at the top of every | |
| 234 | file. | |
| 235 | ||
| 236 | ============================================================================== | |
| 237 | Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy): | |
| 238 | ============================================================================== | |
| 239 | ||
| 240 | The compiler_rt library is dual licensed under both the University of Illinois | |
| 241 | "BSD-Like" license and the MIT license. As a user of this code you may choose | |
| 242 | to use it under either license. As a contributor, you agree to allow your code | |
| 243 | to be used under both. | |
| 244 | ||
| 245 | Full text of the relevant licenses is included below. | |
| 246 | ||
| 247 | ============================================================================== | |
| 248 | ||
| 249 | University of Illinois/NCSA | |
| 250 | Open Source License | |
| 251 | ||
| 252 | Copyright (c) 2009-2019 by the contributors listed in CREDITS.TXT | |
| 253 | ||
| 254 | All rights reserved. | |
| 255 | ||
| 256 | Developed by: | |
| 257 | ||
| 258 | LLVM Team | |
| 259 | ||
| 260 | University of Illinois at Urbana-Champaign | |
| 261 | ||
| 262 | http://llvm.org | |
| 263 | ||
| 264 | Permission is hereby granted, free of charge, to any person obtaining a copy of | |
| 265 | this software and associated documentation files (the "Software"), to deal with | |
| 266 | the Software without restriction, including without limitation the rights to | |
| 267 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | |
| 268 | of the Software, and to permit persons to whom the Software is furnished to do | |
| 269 | so, subject to the following conditions: | |
| 270 | ||
| 271 | * Redistributions of source code must retain the above copyright notice, | |
| 272 | this list of conditions and the following disclaimers. | |
| 273 | ||
| 274 | * Redistributions in binary form must reproduce the above copyright notice, | |
| 275 | this list of conditions and the following disclaimers in the | |
| 276 | documentation and/or other materials provided with the distribution. | |
| 277 | ||
| 278 | * Neither the names of the LLVM Team, University of Illinois at | |
| 279 | Urbana-Champaign, nor the names of its contributors may be used to | |
| 280 | endorse or promote products derived from this Software without specific | |
| 281 | prior written permission. | |
| 282 | ||
| 283 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 284 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | |
| 285 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 286 | CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 287 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 288 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE | |
| 289 | SOFTWARE. | |
| 290 | ||
| 291 | ============================================================================== | |
| 292 | ||
| 293 | Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT | |
| 294 | ||
| 295 | Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 296 | of this software and associated documentation files (the "Software"), to deal | |
| 297 | in the Software without restriction, including without limitation the rights | |
| 298 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 299 | copies of the Software, and to permit persons to whom the Software is | |
| 300 | furnished to do so, subject to the following conditions: | |
| 301 | ||
| 302 | The above copyright notice and this permission notice shall be included in | |
| 303 | all copies or substantial portions of the Software. | |
| 304 | ||
| 305 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 306 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 307 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 308 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 309 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 310 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 311 | THE SOFTWARE. |
lib/libtsan/builtins/assembly.h+41-8| ... | ... | @@ -14,7 +14,7 @@ |
| 14 | 14 | #ifndef COMPILERRT_ASSEMBLY_H |
| 15 | 15 | #define COMPILERRT_ASSEMBLY_H |
| 16 | 16 | |
| 17 | #if defined(__linux__) && defined(__CET__) | |
| 17 | #ifdef __CET__ | |
| 18 | 18 | #if __has_include(<cet.h>) |
| 19 | 19 | #include <cet.h> |
| 20 | 20 | #endif |
| ... | ... | @@ -71,19 +71,35 @@ |
| 71 | 71 | |
| 72 | 72 | #endif |
| 73 | 73 | |
| 74 | #if defined(__aarch64__) && defined(__ELF__) && \ | |
| 75 | defined(COMPILER_RT_EXECUTE_ONLY_CODE) | |
| 76 | // The assembler always creates an implicit '.text' section with default flags | |
| 77 | // (SHF_ALLOC | SHF_EXECINSTR), which is incompatible with the execute-only | |
| 78 | // '.text' section we want to create here because of the missing | |
| 79 | // SHF_AARCH64_PURECODE section flag. To solve this, we use 'unique,0' to | |
| 80 | // differentiate the two sections. The output will therefore have two separate | |
| 81 | // sections named '.text', where code will be placed into the execute-only | |
| 82 | // '.text' section, and the implicitly-created one will be empty. | |
| 83 | #define TEXT_SECTION \ | |
| 84 | .section .text,"axy",@progbits,unique,0 | |
| 85 | #else | |
| 86 | #define TEXT_SECTION \ | |
| 87 | .text | |
| 88 | #endif | |
| 89 | ||
| 74 | 90 | #if defined(__arm__) || defined(__aarch64__) || defined(__arm64ec__) |
| 75 | 91 | #define FUNC_ALIGN \ |
| 76 | .text SEPARATOR \ | |
| 77 | 92 | .balign 16 SEPARATOR |
| 78 | 93 | #else |
| 79 | 94 | #define FUNC_ALIGN |
| 80 | 95 | #endif |
| 81 | 96 | |
| 82 | // BTI and PAC gnu property note | |
| 97 | // BTI, PAC, and GCS gnu property note | |
| 83 | 98 | #define NT_GNU_PROPERTY_TYPE_0 5 |
| 84 | 99 | #define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000 |
| 85 | 100 | #define GNU_PROPERTY_AARCH64_FEATURE_1_BTI 1 |
| 86 | 101 | #define GNU_PROPERTY_AARCH64_FEATURE_1_PAC 2 |
| 102 | #define GNU_PROPERTY_AARCH64_FEATURE_1_GCS 4 | |
| 87 | 103 | |
| 88 | 104 | #if defined(__ARM_FEATURE_BTI_DEFAULT) |
| 89 | 105 | #define BTI_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_BTI |
| ... | ... | @@ -97,6 +113,12 @@ |
| 97 | 113 | #define PAC_FLAG 0 |
| 98 | 114 | #endif |
| 99 | 115 | |
| 116 | #if defined(__ARM_FEATURE_GCS_DEFAULT) | |
| 117 | #define GCS_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_GCS | |
| 118 | #else | |
| 119 | #define GCS_FLAG 0 | |
| 120 | #endif | |
| 121 | ||
| 100 | 122 | #define GNU_PROPERTY(type, value) \ |
| 101 | 123 | .pushsection .note.gnu.property, "a" SEPARATOR \ |
| 102 | 124 | .p2align 3 SEPARATOR \ |
| ... | ... | @@ -118,11 +140,12 @@ |
| 118 | 140 | #define BTI_J |
| 119 | 141 | #endif |
| 120 | 142 | |
| 121 | #if (BTI_FLAG | PAC_FLAG) != 0 | |
| 122 | #define GNU_PROPERTY_BTI_PAC \ | |
| 123 | GNU_PROPERTY(GNU_PROPERTY_AARCH64_FEATURE_1_AND, BTI_FLAG | PAC_FLAG) | |
| 143 | #if (BTI_FLAG | PAC_FLAG | GCS_FLAG) != 0 | |
| 144 | #define GNU_PROPERTY_BTI_PAC_GCS \ | |
| 145 | GNU_PROPERTY(GNU_PROPERTY_AARCH64_FEATURE_1_AND, \ | |
| 146 | BTI_FLAG | PAC_FLAG | GCS_FLAG) | |
| 124 | 147 | #else |
| 125 | #define GNU_PROPERTY_BTI_PAC | |
| 148 | #define GNU_PROPERTY_BTI_PAC_GCS | |
| 126 | 149 | #endif |
| 127 | 150 | |
| 128 | 151 | #if defined(__clang__) || defined(__GCC_HAVE_DWARF2_CFI_ASM) |
| ... | ... | @@ -247,6 +270,7 @@ |
| 247 | 270 | #endif |
| 248 | 271 | |
| 249 | 272 | #define DEFINE_COMPILERRT_FUNCTION(name) \ |
| 273 | TEXT_SECTION SEPARATOR \ | |
| 250 | 274 | DEFINE_CODE_STATE \ |
| 251 | 275 | FILE_LEVEL_DIRECTIVE SEPARATOR \ |
| 252 | 276 | .globl FUNC_SYMBOL(SYMBOL_NAME(name)) SEPARATOR \ |
| ... | ... | @@ -256,6 +280,7 @@ |
| 256 | 280 | FUNC_SYMBOL(SYMBOL_NAME(name)): |
| 257 | 281 | |
| 258 | 282 | #define DEFINE_COMPILERRT_THUMB_FUNCTION(name) \ |
| 283 | TEXT_SECTION SEPARATOR \ | |
| 259 | 284 | DEFINE_CODE_STATE \ |
| 260 | 285 | FILE_LEVEL_DIRECTIVE SEPARATOR \ |
| 261 | 286 | .globl FUNC_SYMBOL(SYMBOL_NAME(name)) SEPARATOR \ |
| ... | ... | @@ -265,6 +290,7 @@ |
| 265 | 290 | FUNC_SYMBOL(SYMBOL_NAME(name)): |
| 266 | 291 | |
| 267 | 292 | #define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name) \ |
| 293 | TEXT_SECTION SEPARATOR \ | |
| 268 | 294 | DEFINE_CODE_STATE \ |
| 269 | 295 | FILE_LEVEL_DIRECTIVE SEPARATOR \ |
| 270 | 296 | .globl FUNC_SYMBOL(SYMBOL_NAME(name)) SEPARATOR \ |
| ... | ... | @@ -274,6 +300,7 @@ |
| 274 | 300 | FUNC_SYMBOL(SYMBOL_NAME(name)): |
| 275 | 301 | |
| 276 | 302 | #define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \ |
| 303 | TEXT_SECTION SEPARATOR \ | |
| 277 | 304 | DEFINE_CODE_STATE \ |
| 278 | 305 | .globl FUNC_SYMBOL(name) SEPARATOR \ |
| 279 | 306 | SYMBOL_IS_FUNC(name) SEPARATOR \ |
| ... | ... | @@ -282,6 +309,7 @@ |
| 282 | 309 | FUNC_SYMBOL(name): |
| 283 | 310 | |
| 284 | 311 | #define DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(name) \ |
| 312 | TEXT_SECTION SEPARATOR \ | |
| 285 | 313 | DEFINE_CODE_STATE \ |
| 286 | 314 | FUNC_ALIGN \ |
| 287 | 315 | .globl FUNC_SYMBOL(name) SEPARATOR \ |
| ... | ... | @@ -296,7 +324,7 @@ |
| 296 | 324 | .globl FUNC_SYMBOL(SYMBOL_NAME(name)) SEPARATOR \ |
| 297 | 325 | SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ |
| 298 | 326 | DECLARE_SYMBOL_VISIBILITY(name) SEPARATOR \ |
| 299 | .set FUNC_SYMBOL(SYMBOL_NAME(name)), FUNC_SYMBOL(target) SEPARATOR | |
| 327 | .set FUNC_SYMBOL(SYMBOL_NAME(name)), FUNC_SYMBOL(SYMBOL_NAME(target)) SEPARATOR | |
| 300 | 328 | |
| 301 | 329 | #if defined(__ARM_EABI__) |
| 302 | 330 | #define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name) \ |
| ... | ... | @@ -329,4 +357,9 @@ |
| 329 | 357 | #endif |
| 330 | 358 | #endif |
| 331 | 359 | |
| 360 | #if defined(__ASSEMBLER__) && (defined(__i386__) || defined(__amd64__)) && \ | |
| 361 | !defined(__arm64ec__) | |
| 362 | .att_syntax | |
| 363 | #endif | |
| 364 | ||
| 332 | 365 | #endif // COMPILERRT_ASSEMBLY_H |
lib/libtsan/interception/interception_win.cpp+4| ... | ... | @@ -646,6 +646,7 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { |
| 646 | 646 | case 0xC033: // 33 C0 : xor eax, eax |
| 647 | 647 | case 0xC933: // 33 C9 : xor ecx, ecx |
| 648 | 648 | case 0xD233: // 33 D2 : xor edx, edx |
| 649 | case 0xFF33: // 33 FF : xor edi, edi | |
| 649 | 650 | case 0x9066: // 66 90 : xchg %ax,%ax (Two-byte NOP) |
| 650 | 651 | case 0xDB84: // 84 DB : test bl,bl |
| 651 | 652 | case 0xC084: // 84 C0 : test al,al |
| ... | ... | @@ -764,6 +765,7 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { |
| 764 | 765 | |
| 765 | 766 | switch (0x00FFFFFF & *(u32 *)address) { |
| 766 | 767 | case 0x10b70f: // 0f b7 10 : movzx edx, WORD PTR [rax] |
| 768 | case 0x02b70f: // 0f b7 02 : movzx eax, WORD PTR [rdx] | |
| 767 | 769 | case 0xc00b4d: // 4d 0b c0 : or r8, r8 |
| 768 | 770 | case 0xc03345: // 45 33 c0 : xor r8d, r8d |
| 769 | 771 | case 0xc08548: // 48 85 c0 : test rax, rax |
| ... | ... | @@ -799,6 +801,7 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { |
| 799 | 801 | case 0xc9854d: // 4d 85 c9 : test r9, r9 |
| 800 | 802 | case 0xc98b4c: // 4c 8b c9 : mov r9, rcx |
| 801 | 803 | case 0xd12948: // 48 29 d1 : sub rcx, rdx |
| 804 | case 0xc22b4c: // 4c 2b c2 : sub r8, rdx | |
| 802 | 805 | case 0xca2b48: // 48 2b ca : sub rcx, rdx |
| 803 | 806 | case 0xca3b48: // 48 3b ca : cmp rcx, rdx |
| 804 | 807 | case 0xd12b48: // 48 2b d1 : sub rdx, rcx |
| ... | ... | @@ -813,6 +816,7 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { |
| 813 | 816 | case 0xd9f748: // 48 f7 d9 : neg rcx |
| 814 | 817 | case 0xc03145: // 45 31 c0 : xor r8d,r8d |
| 815 | 818 | case 0xc93145: // 45 31 c9 : xor r9d,r9d |
| 819 | case 0xd23345: // 45 33 d2 : xor r10d, r10d | |
| 816 | 820 | case 0xdb3345: // 45 33 db : xor r11d, r11d |
| 817 | 821 | case 0xc08445: // 45 84 c0 : test r8b,r8b |
| 818 | 822 | case 0xd28445: // 45 84 d2 : test r10b,r10b |
lib/libtsan/sanitizer_common/sanitizer_allocator_primary32.h+1| ... | ... | @@ -288,6 +288,7 @@ class SizeClassAllocator32 { |
| 288 | 288 | uptr ComputeRegionId(uptr mem) const { |
| 289 | 289 | if (SANITIZER_SIGN_EXTENDED_ADDRESSES) |
| 290 | 290 | mem &= (kSpaceSize - 1); |
| 291 | mem -= kSpaceBeg; | |
| 291 | 292 | const uptr res = mem >> kRegionSizeLog; |
| 292 | 293 | CHECK_LT(res, kNumPossibleRegions); |
| 293 | 294 | return res; |
lib/libtsan/sanitizer_common/sanitizer_allocator_primary64.h+18| ... | ... | @@ -113,6 +113,24 @@ class SizeClassAllocator64 { |
| 113 | 113 | // ~(uptr)0. |
| 114 | 114 | void Init(s32 release_to_os_interval_ms, uptr heap_start = 0) { |
| 115 | 115 | uptr TotalSpaceSize = kSpaceSize + AdditionalSize(); |
| 116 | ||
| 117 | uptr MaxAddr = GetMaxUserVirtualAddress(); | |
| 118 | // VReport does not call the sanitizer allocator. | |
| 119 | VReport(3, "Max user virtual address: 0x%zx\n", MaxAddr); | |
| 120 | VReport(3, "Total space size for primary allocator: 0x%zx\n", | |
| 121 | TotalSpaceSize); | |
| 122 | // TODO: revise the check if we ever configure sanitizers to deliberately | |
| 123 | // map beyond the 2**48 barrier (note that Linux pretends the VMA is | |
| 124 | // limited to 48-bit for backwards compatibility, but allows apps to | |
| 125 | // explicitly specify an address beyond that). | |
| 126 | if (heap_start + TotalSpaceSize >= MaxAddr) { | |
| 127 | // We can't easily adjust the requested heap size, because kSpaceSize is | |
| 128 | // const (for optimization) and used throughout the code. | |
| 129 | VReport(0, "Error: heap size %zx exceeds max user virtual address %zx\n", | |
| 130 | TotalSpaceSize, MaxAddr); | |
| 131 | VReport( | |
| 132 | 0, "Try using a kernel that allows a larger virtual address space\n"); | |
| 133 | } | |
| 116 | 134 | PremappedHeap = heap_start != 0; |
| 117 | 135 | if (PremappedHeap) { |
| 118 | 136 | CHECK(!kUsingConstantSpaceBeg); |
lib/libtsan/sanitizer_common/sanitizer_common.h+15-2| ... | ... | @@ -78,8 +78,8 @@ uptr GetMmapGranularity(); |
| 78 | 78 | uptr GetMaxVirtualAddress(); |
| 79 | 79 | uptr GetMaxUserVirtualAddress(); |
| 80 | 80 | // Threads |
| 81 | tid_t GetTid(); | |
| 82 | int TgKill(pid_t pid, tid_t tid, int sig); | |
| 81 | ThreadID GetTid(); | |
| 82 | int TgKill(pid_t pid, ThreadID tid, int sig); | |
| 83 | 83 | uptr GetThreadSelf(); |
| 84 | 84 | void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, |
| 85 | 85 | uptr *stack_bottom); |
| ... | ... | @@ -390,6 +390,9 @@ void ReportDeadlySignal(const SignalContext &sig, u32 tid, |
| 390 | 390 | void SetAlternateSignalStack(); |
| 391 | 391 | void UnsetAlternateSignalStack(); |
| 392 | 392 | |
| 393 | bool IsSignalHandlerFromSanitizer(int signum); | |
| 394 | bool SetSignalHandlerFromSanitizer(int signum, bool new_state); | |
| 395 | ||
| 393 | 396 | // Construct a one-line string: |
| 394 | 397 | // SUMMARY: SanitizerToolName: error_message |
| 395 | 398 | // and pass it to __sanitizer_report_error_summary. |
| ... | ... | @@ -484,6 +487,13 @@ inline uptr Log2(uptr x) { |
| 484 | 487 | return LeastSignificantSetBitIndex(x); |
| 485 | 488 | } |
| 486 | 489 | |
| 490 | inline bool IntervalsAreSeparate(uptr start1, uptr end1, uptr start2, | |
| 491 | uptr end2) { | |
| 492 | CHECK_LE(start1, end1); | |
| 493 | CHECK_LE(start2, end2); | |
| 494 | return (end1 < start2) || (end2 < start1); | |
| 495 | } | |
| 496 | ||
| 487 | 497 | // Don't use std::min, std::max or std::swap, to minimize dependency |
| 488 | 498 | // on libstdc++. |
| 489 | 499 | template <class T> |
| ... | ... | @@ -734,6 +744,7 @@ enum ModuleArch { |
| 734 | 744 | kModuleArchARMV7S, |
| 735 | 745 | kModuleArchARMV7K, |
| 736 | 746 | kModuleArchARM64, |
| 747 | kModuleArchARM64E, | |
| 737 | 748 | kModuleArchLoongArch64, |
| 738 | 749 | kModuleArchRISCV64, |
| 739 | 750 | kModuleArchHexagon |
| ... | ... | @@ -807,6 +818,8 @@ inline const char *ModuleArchToString(ModuleArch arch) { |
| 807 | 818 | return "armv7k"; |
| 808 | 819 | case kModuleArchARM64: |
| 809 | 820 | return "arm64"; |
| 821 | case kModuleArchARM64E: | |
| 822 | return "arm64e"; | |
| 810 | 823 | case kModuleArchLoongArch64: |
| 811 | 824 | return "loongarch64"; |
| 812 | 825 | case kModuleArchRISCV64: |
lib/libtsan/sanitizer_common/sanitizer_common_interceptors.inc+30-4| ... | ... | @@ -1285,8 +1285,34 @@ INTERCEPTOR(int, puts, char *s) { |
| 1285 | 1285 | #endif |
| 1286 | 1286 | |
| 1287 | 1287 | #if SANITIZER_INTERCEPT_PRCTL |
| 1288 | INTERCEPTOR(int, prctl, int option, unsigned long arg2, unsigned long arg3, | |
| 1289 | unsigned long arg4, unsigned long arg5) { | |
| 1288 | ||
| 1289 | # if defined(__aarch64__) | |
| 1290 | // https://llvm.org/docs/PointerAuth.html | |
| 1291 | // AArch64 is currently the only architecture with full PAC support. | |
| 1292 | // Avoid adding PAC instructions to prevent crashes caused by | |
| 1293 | // prctl(PR_PAC_RESET_KEYS, ...). Since PR_PAC_RESET_KEYS resets the | |
| 1294 | // authentication key, using the old key afterward will lead to a crash. | |
| 1295 | ||
| 1296 | # if defined(__ARM_FEATURE_BTI_DEFAULT) | |
| 1297 | # define BRANCH_PROTECTION_ATTRIBUTE \ | |
| 1298 | __attribute__((target("branch-protection=bti"))) | |
| 1299 | # else | |
| 1300 | # define BRANCH_PROTECTION_ATTRIBUTE \ | |
| 1301 | __attribute__((target("branch-protection=none"))) | |
| 1302 | # endif | |
| 1303 | ||
| 1304 | # define PRCTL_INTERCEPTOR(ret_type, func, ...) \ | |
| 1305 | DEFINE_REAL(ret_type, func, __VA_ARGS__) \ | |
| 1306 | DECLARE_WRAPPER(ret_type, func, __VA_ARGS__) \ | |
| 1307 | extern "C" INTERCEPTOR_ATTRIBUTE BRANCH_PROTECTION_ATTRIBUTE ret_type \ | |
| 1308 | WRAP(func)(__VA_ARGS__) | |
| 1309 | ||
| 1310 | # else | |
| 1311 | # define PRCTL_INTERCEPTOR INTERCEPTOR | |
| 1312 | # endif | |
| 1313 | ||
| 1314 | PRCTL_INTERCEPTOR(int, prctl, int option, unsigned long arg2, | |
| 1315 | unsigned long arg3, unsigned long arg4, unsigned long arg5) { | |
| 1290 | 1316 | void *ctx; |
| 1291 | 1317 | COMMON_INTERCEPTOR_ENTER(ctx, prctl, option, arg2, arg3, arg4, arg5); |
| 1292 | 1318 | static const int PR_SET_NAME = 15; |
| ... | ... | @@ -1300,7 +1326,7 @@ INTERCEPTOR(int, prctl, int option, unsigned long arg2, unsigned long arg3, |
| 1300 | 1326 | static const int PR_SET_SECCOMP = 22; |
| 1301 | 1327 | static const int SECCOMP_MODE_FILTER = 2; |
| 1302 | 1328 | # endif |
| 1303 | if (option == PR_SET_VMA && arg2 == 0UL) { | |
| 1329 | if (option == PR_SET_VMA && arg2 == 0UL && arg5 != 0UL) { | |
| 1304 | 1330 | char *name = (char *)arg5; |
| 1305 | 1331 | COMMON_INTERCEPTOR_READ_RANGE(ctx, name, internal_strlen(name) + 1); |
| 1306 | 1332 | } |
| ... | ... | @@ -1326,7 +1352,7 @@ INTERCEPTOR(int, prctl, int option, unsigned long arg2, unsigned long arg3, |
| 1326 | 1352 | } |
| 1327 | 1353 | return res; |
| 1328 | 1354 | } |
| 1329 | #define INIT_PRCTL COMMON_INTERCEPT_FUNCTION(prctl) | |
| 1355 | # define INIT_PRCTL COMMON_INTERCEPT_FUNCTION(prctl) | |
| 1330 | 1356 | #else |
| 1331 | 1357 | #define INIT_PRCTL |
| 1332 | 1358 | #endif // SANITIZER_INTERCEPT_PRCTL |
lib/libtsan/sanitizer_common/sanitizer_common_interceptors_ioctl.inc+4| ... | ... | @@ -344,12 +344,16 @@ static void ioctl_table_fill() { |
| 344 | 344 | _(SOUND_PCM_WRITE_CHANNELS, WRITE, sizeof(int)); |
| 345 | 345 | _(SOUND_PCM_WRITE_FILTER, WRITE, sizeof(int)); |
| 346 | 346 | _(TCFLSH, NONE, 0); |
| 347 | # if SANITIZER_TERMIOS_IOCTL_CONSTANTS | |
| 347 | 348 | _(TCGETS, WRITE, struct_termios_sz); |
| 349 | # endif | |
| 348 | 350 | _(TCSBRK, NONE, 0); |
| 349 | 351 | _(TCSBRKP, NONE, 0); |
| 352 | # if SANITIZER_TERMIOS_IOCTL_CONSTANTS | |
| 350 | 353 | _(TCSETS, READ, struct_termios_sz); |
| 351 | 354 | _(TCSETSF, READ, struct_termios_sz); |
| 352 | 355 | _(TCSETSW, READ, struct_termios_sz); |
| 356 | # endif | |
| 353 | 357 | _(TCXONC, NONE, 0); |
| 354 | 358 | _(TIOCGLCKTRMIOS, WRITE, struct_termios_sz); |
| 355 | 359 | _(TIOCGSOFTCAR, WRITE, sizeof(int)); |
lib/libtsan/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S+2-1| ... | ... | @@ -5,6 +5,7 @@ |
| 5 | 5 | |
| 6 | 6 | ASM_HIDDEN(COMMON_INTERCEPTOR_SPILL_AREA) |
| 7 | 7 | |
| 8 | TEXT_SECTION | |
| 8 | 9 | .comm _ZN14__interception10real_vforkE,8,8 |
| 9 | 10 | .globl ASM_WRAPPER_NAME(vfork) |
| 10 | 11 | ASM_TYPE_FUNCTION(ASM_WRAPPER_NAME(vfork)) |
| ... | ... | @@ -43,6 +44,6 @@ ASM_SIZE(vfork) |
| 43 | 44 | ASM_INTERCEPTOR_TRAMPOLINE(vfork) |
| 44 | 45 | ASM_TRAMPOLINE_ALIAS(vfork, vfork) |
| 45 | 46 | |
| 46 | GNU_PROPERTY_BTI_PAC | |
| 47 | GNU_PROPERTY_BTI_PAC_GCS | |
| 47 | 48 | |
| 48 | 49 | #endif |
lib/libtsan/sanitizer_common/sanitizer_common_interceptors_vfork_i386.inc.S+2| ... | ... | @@ -2,6 +2,8 @@ |
| 2 | 2 | |
| 3 | 3 | #include "sanitizer_common/sanitizer_asm.h" |
| 4 | 4 | |
| 5 | .att_syntax | |
| 6 | ||
| 5 | 7 | .comm _ZN14__interception10real_vforkE,4,4 |
| 6 | 8 | .globl ASM_WRAPPER_NAME(vfork) |
| 7 | 9 | ASM_TYPE_FUNCTION(ASM_WRAPPER_NAME(vfork)) |
lib/libtsan/sanitizer_common/sanitizer_common_interceptors_vfork_x86_64.inc.S+2| ... | ... | @@ -2,6 +2,8 @@ |
| 2 | 2 | |
| 3 | 3 | #include "sanitizer_common/sanitizer_asm.h" |
| 4 | 4 | |
| 5 | .att_syntax | |
| 6 | ||
| 5 | 7 | .comm _ZN14__interception10real_vforkE,8,8 |
| 6 | 8 | .globl ASM_WRAPPER_NAME(vfork) |
| 7 | 9 | ASM_TYPE_FUNCTION(ASM_WRAPPER_NAME(vfork)) |
lib/libtsan/sanitizer_common/sanitizer_common_syscalls.inc+18| ... | ... | @@ -143,6 +143,12 @@ struct sanitizer_kernel_sockaddr { |
| 143 | 143 | char sa_data[14]; |
| 144 | 144 | }; |
| 145 | 145 | |
| 146 | struct sanitizer_kernel_open_how { | |
| 147 | u64 flags; | |
| 148 | u64 mode; | |
| 149 | u64 resolve; | |
| 150 | }; | |
| 151 | ||
| 146 | 152 | // Real sigset size is always passed as a syscall argument. |
| 147 | 153 | // Declare it "void" to catch sizeof(kernel_sigset_t). |
| 148 | 154 | typedef void kernel_sigset_t; |
| ... | ... | @@ -2843,6 +2849,18 @@ PRE_SYSCALL(openat)(long dfd, const void *filename, long flags, long mode) { |
| 2843 | 2849 | POST_SYSCALL(openat) |
| 2844 | 2850 | (long res, long dfd, const void *filename, long flags, long mode) {} |
| 2845 | 2851 | |
| 2852 | PRE_SYSCALL(openat2)(long dfd, const void* filename, | |
| 2853 | const sanitizer_kernel_open_how* how, uptr howlen) { | |
| 2854 | if (filename) | |
| 2855 | PRE_READ(filename, __sanitizer::internal_strlen((const char*)filename) + 1); | |
| 2856 | ||
| 2857 | if (how) | |
| 2858 | PRE_READ(how, howlen); | |
| 2859 | } | |
| 2860 | ||
| 2861 | POST_SYSCALL(openat2)(long res, long dfd, const void* filename, | |
| 2862 | const sanitizer_kernel_open_how* how, uptr howlen) {} | |
| 2863 | ||
| 2846 | 2864 | PRE_SYSCALL(newfstatat) |
| 2847 | 2865 | (long dfd, const void *filename, void *statbuf, long flag) { |
| 2848 | 2866 | if (filename) |
lib/libtsan/sanitizer_common/sanitizer_coverage_interface.inc deleted-43| ... | ... | @@ -1,43 +0,0 @@ |
| 1 | //===-- sanitizer_coverage_interface.inc ----------------------------------===// | |
| 2 | // | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 6 | // | |
| 7 | //===----------------------------------------------------------------------===// | |
| 8 | // Sanitizer Coverage interface list. | |
| 9 | //===----------------------------------------------------------------------===// | |
| 10 | INTERFACE_FUNCTION(__sanitizer_cov_dump) | |
| 11 | INTERFACE_FUNCTION(__sanitizer_cov_reset) | |
| 12 | INTERFACE_FUNCTION(__sanitizer_dump_coverage) | |
| 13 | INTERFACE_FUNCTION(__sanitizer_dump_trace_pc_guard_coverage) | |
| 14 | INTERFACE_WEAK_FUNCTION(__sancov_default_options) | |
| 15 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp) | |
| 16 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp1) | |
| 17 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp2) | |
| 18 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp4) | |
| 19 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp8) | |
| 20 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp1) | |
| 21 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp2) | |
| 22 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp4) | |
| 23 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp8) | |
| 24 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_div4) | |
| 25 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_div8) | |
| 26 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_gep) | |
| 27 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_guard) | |
| 28 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_guard_init) | |
| 29 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_indir) | |
| 30 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_load1) | |
| 31 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_load2) | |
| 32 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_load4) | |
| 33 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_load8) | |
| 34 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_load16) | |
| 35 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_store1) | |
| 36 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_store2) | |
| 37 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_store4) | |
| 38 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_store8) | |
| 39 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_store16) | |
| 40 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_switch) | |
| 41 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_8bit_counters_init) | |
| 42 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_bool_flag_init) | |
| 43 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_pcs_init) |
lib/libtsan/sanitizer_common/sanitizer_file.cpp+40-12| ... | ... | @@ -36,9 +36,17 @@ void RawWrite(const char *buffer) { |
| 36 | 36 | |
| 37 | 37 | void ReportFile::ReopenIfNecessary() { |
| 38 | 38 | mu->CheckLocked(); |
| 39 | if (fd == kStdoutFd || fd == kStderrFd) return; | |
| 40 | ||
| 41 | 39 | uptr pid = internal_getpid(); |
| 40 | if (fallbackToStderrActive && fd_pid != pid) { | |
| 41 | // If fallbackToStderrActive is set then we fellback to stderr. If this is a | |
| 42 | // new process, mark fd as invalid so we attempt to open again. | |
| 43 | CHECK_EQ(fd, kStderrFd); | |
| 44 | fd = kInvalidFd; | |
| 45 | fallbackToStderrActive = false; | |
| 46 | } | |
| 47 | if (fd == kStdoutFd || fd == kStderrFd) | |
| 48 | return; | |
| 49 | ||
| 42 | 50 | // If in tracer, use the parent's file. |
| 43 | 51 | if (pid == stoptheworld_tracer_pid) |
| 44 | 52 | pid = stoptheworld_tracer_ppid; |
| ... | ... | @@ -48,8 +56,7 @@ void ReportFile::ReopenIfNecessary() { |
| 48 | 56 | // process, close it now. |
| 49 | 57 | if (fd_pid == pid) |
| 50 | 58 | return; |
| 51 | else | |
| 52 | CloseFile(fd); | |
| 59 | CloseFile(fd); | |
| 53 | 60 | } |
| 54 | 61 | |
| 55 | 62 | const char *exe_name = GetProcessName(); |
| ... | ... | @@ -65,18 +72,24 @@ void ReportFile::ReopenIfNecessary() { |
| 65 | 72 | error_t err; |
| 66 | 73 | fd = OpenFile(full_path, WrOnly, &err); |
| 67 | 74 | if (fd == kInvalidFd) { |
| 68 | const char *ErrorMsgPrefix = "ERROR: Can't open file: "; | |
| 75 | bool fallback = common_flags()->log_fallback_to_stderr; | |
| 76 | const char *ErrorMsgPrefix = | |
| 77 | fallback ? "WARNING: Can't open file, falling back to stderr: " | |
| 78 | : "ERROR: Can't open file: "; | |
| 69 | 79 | WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); |
| 70 | 80 | WriteToFile(kStderrFd, full_path, internal_strlen(full_path)); |
| 71 | 81 | char errmsg[100]; |
| 72 | 82 | internal_snprintf(errmsg, sizeof(errmsg), " (reason: %d)\n", err); |
| 73 | 83 | WriteToFile(kStderrFd, errmsg, internal_strlen(errmsg)); |
| 74 | Die(); | |
| 84 | if (!fallback) | |
| 85 | Die(); | |
| 86 | fallbackToStderrActive = true; | |
| 87 | fd = kStderrFd; | |
| 75 | 88 | } |
| 76 | 89 | fd_pid = pid; |
| 77 | 90 | } |
| 78 | 91 | |
| 79 | static void RecursiveCreateParentDirs(char *path) { | |
| 92 | static void RecursiveCreateParentDirs(char *path, fd_t &fd) { | |
| 80 | 93 | if (path[0] == '\0') |
| 81 | 94 | return; |
| 82 | 95 | for (int i = 1; path[i] != '\0'; ++i) { |
| ... | ... | @@ -85,12 +98,19 @@ static void RecursiveCreateParentDirs(char *path) { |
| 85 | 98 | continue; |
| 86 | 99 | path[i] = '\0'; |
| 87 | 100 | if (!DirExists(path) && !CreateDir(path)) { |
| 88 | const char *ErrorMsgPrefix = "ERROR: Can't create directory: "; | |
| 101 | bool fallback = common_flags()->log_fallback_to_stderr; | |
| 102 | const char *ErrorMsgPrefix = | |
| 103 | fallback ? "WARNING: Can't create directory, falling back to stderr: " | |
| 104 | : "ERROR: Can't create directory: "; | |
| 89 | 105 | WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); |
| 90 | 106 | WriteToFile(kStderrFd, path, internal_strlen(path)); |
| 91 | 107 | const char *ErrorMsgSuffix = "\n"; |
| 92 | 108 | WriteToFile(kStderrFd, ErrorMsgSuffix, internal_strlen(ErrorMsgSuffix)); |
| 93 | Die(); | |
| 109 | if (!fallback) | |
| 110 | Die(); | |
| 111 | path[i] = save; | |
| 112 | fd = kStderrFd; | |
| 113 | return; | |
| 94 | 114 | } |
| 95 | 115 | path[i] = save; |
| 96 | 116 | } |
| ... | ... | @@ -108,6 +128,9 @@ static void ParseAndSetPath(const char *pattern, char *dest, |
| 108 | 128 | CHECK(dest); |
| 109 | 129 | CHECK_GE(dest_size, 1); |
| 110 | 130 | dest[0] = '\0'; |
| 131 | // Return empty string if empty string was passed | |
| 132 | if (internal_strlen(pattern) == 0) | |
| 133 | return; | |
| 111 | 134 | uptr next_substr_start_idx = 0; |
| 112 | 135 | for (uptr i = 0; i < internal_strlen(pattern) - 1; i++) { |
| 113 | 136 | if (pattern[i] != '%') |
| ... | ... | @@ -161,12 +184,17 @@ void ReportFile::SetReportPath(const char *path) { |
| 161 | 184 | if (path) { |
| 162 | 185 | uptr len = internal_strlen(path); |
| 163 | 186 | if (len > sizeof(path_prefix) - 100) { |
| 164 | const char *message = "ERROR: Path is too long: "; | |
| 187 | bool fallback = common_flags()->log_fallback_to_stderr; | |
| 188 | const char *message = | |
| 189 | fallback ? "WARNING: Path is too long, falling back to stderr: " | |
| 190 | : "ERROR: Path is too long: "; | |
| 165 | 191 | WriteToFile(kStderrFd, message, internal_strlen(message)); |
| 166 | 192 | WriteToFile(kStderrFd, path, 8); |
| 167 | 193 | message = "...\n"; |
| 168 | 194 | WriteToFile(kStderrFd, message, internal_strlen(message)); |
| 169 | Die(); | |
| 195 | if (!fallback) | |
| 196 | Die(); | |
| 197 | path = "stderr"; | |
| 170 | 198 | } |
| 171 | 199 | } |
| 172 | 200 | |
| ... | ... | @@ -180,7 +208,7 @@ void ReportFile::SetReportPath(const char *path) { |
| 180 | 208 | fd = kStdoutFd; |
| 181 | 209 | } else { |
| 182 | 210 | ParseAndSetPath(path, path_prefix, kMaxPathLength); |
| 183 | RecursiveCreateParentDirs(path_prefix); | |
| 211 | RecursiveCreateParentDirs(path_prefix, fd); | |
| 184 | 212 | } |
| 185 | 213 | } |
| 186 | 214 |
lib/libtsan/sanitizer_common/sanitizer_file.h+3| ... | ... | @@ -43,6 +43,9 @@ struct ReportFile { |
| 43 | 43 | // PID of the process that opened fd. If a fork() occurs, |
| 44 | 44 | // the PID of child will be different from fd_pid. |
| 45 | 45 | uptr fd_pid; |
| 46 | // Set to true if the last attempt to open the logfile failed, perhaps due to | |
| 47 | // permission errors | |
| 48 | bool fallbackToStderrActive = false; | |
| 46 | 49 | |
| 47 | 50 | private: |
| 48 | 51 | void ReopenIfNecessary(); |
lib/libtsan/sanitizer_common/sanitizer_flags.inc+7| ... | ... | @@ -65,6 +65,8 @@ COMMON_FLAG( |
| 65 | 65 | bool, log_to_syslog, (bool)SANITIZER_ANDROID || (bool)SANITIZER_APPLE, |
| 66 | 66 | "Write all sanitizer output to syslog in addition to other means of " |
| 67 | 67 | "logging.") |
| 68 | COMMON_FLAG(bool, log_fallback_to_stderr, false, | |
| 69 | "When set, fallback to stderr if we are unable to open log path.") | |
| 68 | 70 | COMMON_FLAG( |
| 69 | 71 | int, verbosity, 0, |
| 70 | 72 | "Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).") |
| ... | ... | @@ -111,6 +113,11 @@ COMMON_FLAG(HandleSignalMode, handle_sigfpe, kHandleSignalYes, |
| 111 | 113 | COMMON_FLAG(bool, allow_user_segv_handler, true, |
| 112 | 114 | "Deprecated. True has no effect, use handle_sigbus=1. If false, " |
| 113 | 115 | "handle_*=1 will be upgraded to handle_*=2.") |
| 116 | COMMON_FLAG(bool, cloak_sanitizer_signal_handlers, false, | |
| 117 | "If set, signal/sigaction will pretend that sanitizers did not " | |
| 118 | "preinstall any signal handlers. If the user subsequently installs " | |
| 119 | "a signal handler, this will disable cloaking for the respective " | |
| 120 | "signal.") | |
| 114 | 121 | COMMON_FLAG(bool, use_sigaltstack, true, |
| 115 | 122 | "If set, uses alternate stack for signal handling.") |
| 116 | 123 | COMMON_FLAG(bool, detect_deadlocks, true, |
lib/libtsan/sanitizer_common/sanitizer_fuchsia.cpp+30-3| ... | ... | @@ -14,6 +14,7 @@ |
| 14 | 14 | #include "sanitizer_fuchsia.h" |
| 15 | 15 | #if SANITIZER_FUCHSIA |
| 16 | 16 | |
| 17 | # include <limits.h> | |
| 17 | 18 | # include <pthread.h> |
| 18 | 19 | # include <stdlib.h> |
| 19 | 20 | # include <unistd.h> |
| ... | ... | @@ -68,7 +69,7 @@ int internal_dlinfo(void *handle, int request, void *p) { UNIMPLEMENTED(); } |
| 68 | 69 | |
| 69 | 70 | uptr GetThreadSelf() { return reinterpret_cast<uptr>(thrd_current()); } |
| 70 | 71 | |
| 71 | tid_t GetTid() { return GetThreadSelf(); } | |
| 72 | ThreadID GetTid() { return GetThreadSelf(); } | |
| 72 | 73 | |
| 73 | 74 | void Abort() { abort(); } |
| 74 | 75 | |
| ... | ... | @@ -117,11 +118,37 @@ uptr GetMmapGranularity() { return _zx_system_get_page_size(); } |
| 117 | 118 | |
| 118 | 119 | sanitizer_shadow_bounds_t ShadowBounds; |
| 119 | 120 | |
| 121 | // Any sanitizer that utilizes shadow should explicitly call whenever it's | |
| 122 | // appropriate for that sanitizer to reference shadow bounds. For ASan, this is | |
| 123 | // done in `InitializeShadowMemory` and for HWASan, this is done in | |
| 124 | // `InitShadow`. | |
| 120 | 125 | void InitShadowBounds() { ShadowBounds = __sanitizer_shadow_bounds(); } |
| 121 | 126 | |
| 127 | // TODO(leonardchan): It's not immediately clear from a user perspective if | |
| 128 | // `GetMaxUserVirtualAddress` should be called exatly once on runtime startup | |
| 129 | // or can be called multiple times. Currently it looks like most instances of | |
| 130 | // `GetMaxUserVirtualAddress` are meant to be called once, but if someone | |
| 131 | // decides to call this multiple times in the future, we should have a separate | |
| 132 | // function that's ok to call multiple times. Ideally we would just invoke this | |
| 133 | // syscall once. Also for Fuchsia, this syscall technically gets invoked twice | |
| 134 | // since `__sanitizer_shadow_bounds` also invokes this syscall under the hood. | |
| 122 | 135 | uptr GetMaxUserVirtualAddress() { |
| 123 | InitShadowBounds(); | |
| 124 | return ShadowBounds.memory_limit - 1; | |
| 136 | zx_info_vmar_t info; | |
| 137 | zx_status_t status = _zx_object_get_info(_zx_vmar_root_self(), ZX_INFO_VMAR, | |
| 138 | &info, sizeof(info), NULL, NULL); | |
| 139 | CHECK_EQ(status, ZX_OK); | |
| 140 | ||
| 141 | // Find the top of the accessible address space. | |
| 142 | uintptr_t top = info.base + info.len; | |
| 143 | ||
| 144 | // Round it up to a power-of-two size. There may be some pages at | |
| 145 | // the top that can't actually be mapped, but for purposes of the | |
| 146 | // the shadow, we'll pretend they could be. | |
| 147 | int bit = (sizeof(uintptr_t) * CHAR_BIT) - __builtin_clzl(top); | |
| 148 | if (top != (uintptr_t)1 << bit) | |
| 149 | top = (uintptr_t)1 << (bit + 1); | |
| 150 | ||
| 151 | return top - 1; | |
| 125 | 152 | } |
| 126 | 153 | |
| 127 | 154 | uptr GetMaxVirtualAddress() { return GetMaxUserVirtualAddress(); } |
lib/libtsan/sanitizer_common/sanitizer_haiku.cpp+2-2| ... | ... | @@ -231,12 +231,12 @@ uptr internal_execve(const char *filename, char *const argv[], |
| 231 | 231 | } |
| 232 | 232 | |
| 233 | 233 | # if 0 |
| 234 | tid_t GetTid() { | |
| 234 | ThreadID GetTid() { | |
| 235 | 235 | DEFINE__REAL(int, _lwp_self); |
| 236 | 236 | return _REAL(_lwp_self); |
| 237 | 237 | } |
| 238 | 238 | |
| 239 | int TgKill(pid_t pid, tid_t tid, int sig) { | |
| 239 | int TgKill(pid_t pid, ThreadID tid, int sig) { | |
| 240 | 240 | DEFINE__REAL(int, _lwp_kill, int a, int b); |
| 241 | 241 | (void)pid; |
| 242 | 242 | return _REAL(_lwp_kill, tid, sig); |
lib/libtsan/sanitizer_common/sanitizer_internal_defs.h+1-1| ... | ... | @@ -209,7 +209,7 @@ typedef long ssize; |
| 209 | 209 | typedef sptr ssize; |
| 210 | 210 | #endif |
| 211 | 211 | |
| 212 | typedef u64 tid_t; | |
| 212 | typedef u64 ThreadID; | |
| 213 | 213 | |
| 214 | 214 | // ----------- ATTENTION ------------- |
| 215 | 215 | // This header should NOT include any other headers to avoid portability issues. |
lib/libtsan/sanitizer_common/sanitizer_libc.cpp+8| ... | ... | @@ -190,6 +190,14 @@ uptr internal_strlcat(char *dst, const char *src, uptr maxlen) { |
| 190 | 190 | return dstlen + srclen; |
| 191 | 191 | } |
| 192 | 192 | |
| 193 | char* internal_strcat(char* dst, const char* src) { | |
| 194 | uptr len = internal_strlen(dst); | |
| 195 | uptr i; | |
| 196 | for (i = 0; src[i]; i++) dst[len + i] = src[i]; | |
| 197 | dst[len + i] = 0; | |
| 198 | return dst; | |
| 199 | } | |
| 200 | ||
| 193 | 201 | char *internal_strncat(char *dst, const char *src, uptr n) { |
| 194 | 202 | uptr len = internal_strlen(dst); |
| 195 | 203 | uptr i; |
lib/libtsan/sanitizer_common/sanitizer_libc.h+1| ... | ... | @@ -59,6 +59,7 @@ char *internal_strdup(const char *s); |
| 59 | 59 | uptr internal_strlen(const char *s); |
| 60 | 60 | uptr internal_strlcat(char *dst, const char *src, uptr maxlen); |
| 61 | 61 | char *internal_strncat(char *dst, const char *src, uptr n); |
| 62 | char* internal_strcat(char* dst, const char* src); | |
| 62 | 63 | int internal_strncmp(const char *s1, const char *s2, uptr n); |
| 63 | 64 | uptr internal_strlcpy(char *dst, const char *src, uptr maxlen); |
| 64 | 65 | char *internal_strncpy(char *dst, const char *src, uptr n); |
lib/libtsan/sanitizer_common/sanitizer_linux.cpp+15-7| ... | ... | @@ -635,7 +635,7 @@ bool DirExists(const char *path) { |
| 635 | 635 | } |
| 636 | 636 | |
| 637 | 637 | # if !SANITIZER_NETBSD |
| 638 | tid_t GetTid() { | |
| 638 | ThreadID GetTid() { | |
| 639 | 639 | # if SANITIZER_FREEBSD |
| 640 | 640 | long Tid; |
| 641 | 641 | thr_self(&Tid); |
| ... | ... | @@ -649,7 +649,7 @@ tid_t GetTid() { |
| 649 | 649 | # endif |
| 650 | 650 | } |
| 651 | 651 | |
| 652 | int TgKill(pid_t pid, tid_t tid, int sig) { | |
| 652 | int TgKill(pid_t pid, ThreadID tid, int sig) { | |
| 653 | 653 | # if SANITIZER_LINUX |
| 654 | 654 | return internal_syscall(SYSCALL(tgkill), pid, tid, sig); |
| 655 | 655 | # elif SANITIZER_FREEBSD |
| ... | ... | @@ -1091,7 +1091,7 @@ ThreadLister::ThreadLister(pid_t pid) : buffer_(4096) { |
| 1091 | 1091 | } |
| 1092 | 1092 | |
| 1093 | 1093 | ThreadLister::Result ThreadLister::ListThreads( |
| 1094 | InternalMmapVector<tid_t> *threads) { | |
| 1094 | InternalMmapVector<ThreadID> *threads) { | |
| 1095 | 1095 | int descriptor = internal_open(task_path_.data(), O_RDONLY | O_DIRECTORY); |
| 1096 | 1096 | if (internal_iserror(descriptor)) { |
| 1097 | 1097 | Report("Can't open %s for reading.\n", task_path_.data()); |
| ... | ... | @@ -1146,7 +1146,7 @@ ThreadLister::Result ThreadLister::ListThreads( |
| 1146 | 1146 | } |
| 1147 | 1147 | } |
| 1148 | 1148 | |
| 1149 | const char *ThreadLister::LoadStatus(tid_t tid) { | |
| 1149 | const char *ThreadLister::LoadStatus(ThreadID tid) { | |
| 1150 | 1150 | status_path_.clear(); |
| 1151 | 1151 | status_path_.AppendF("%s/%llu/status", task_path_.data(), tid); |
| 1152 | 1152 | auto cleanup = at_scope_exit([&] { |
| ... | ... | @@ -1159,7 +1159,7 @@ const char *ThreadLister::LoadStatus(tid_t tid) { |
| 1159 | 1159 | return buffer_.data(); |
| 1160 | 1160 | } |
| 1161 | 1161 | |
| 1162 | bool ThreadLister::IsAlive(tid_t tid) { | |
| 1162 | bool ThreadLister::IsAlive(ThreadID tid) { | |
| 1163 | 1163 | // /proc/%d/task/%d/status uses same call to detect alive threads as |
| 1164 | 1164 | // proc_task_readdir. See task_state implementation in Linux. |
| 1165 | 1165 | static const char kPrefix[] = "\nPPid:"; |
| ... | ... | @@ -1289,7 +1289,7 @@ uptr GetPageSize() { |
| 1289 | 1289 | |
| 1290 | 1290 | uptr ReadBinaryName(/*out*/ char *buf, uptr buf_len) { |
| 1291 | 1291 | # if SANITIZER_HAIKU |
| 1292 | int cookie = 0; | |
| 1292 | int32 cookie = 0; | |
| 1293 | 1293 | image_info info; |
| 1294 | 1294 | const char *argv0 = "<UNKNOWN>"; |
| 1295 | 1295 | while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) { |
| ... | ... | @@ -1989,7 +1989,10 @@ SignalContext::WriteFlag SignalContext::GetWriteFlag() const { |
| 1989 | 1989 | # elif SANITIZER_NETBSD |
| 1990 | 1990 | uptr err = ucontext->uc_mcontext.__gregs[_REG_ERR]; |
| 1991 | 1991 | # elif SANITIZER_HAIKU |
| 1992 | uptr err = ucontext->uc_mcontext.r13; | |
| 1992 | uptr err = 0; // FIXME: ucontext->uc_mcontext.r13; | |
| 1993 | // The err register was added on the main branch and not | |
| 1994 | // available with the current release. To be reverted later. | |
| 1995 | // https://github.com/haiku/haiku/commit/11adda21aa4e6b24f71a496868a44d7607bc3764 | |
| 1993 | 1996 | # elif SANITIZER_SOLARIS && defined(__i386__) |
| 1994 | 1997 | const int Err = 13; |
| 1995 | 1998 | uptr err = ucontext->uc_mcontext.gregs[Err]; |
| ... | ... | @@ -2619,6 +2622,11 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { |
| 2619 | 2622 | *pc = ucontext->uc_mcontext.mc_eip; |
| 2620 | 2623 | *bp = ucontext->uc_mcontext.mc_ebp; |
| 2621 | 2624 | *sp = ucontext->uc_mcontext.mc_esp; |
| 2625 | # elif SANITIZER_HAIKU | |
| 2626 | ucontext_t *ucontext = (ucontext_t *)context; | |
| 2627 | *pc = ucontext->uc_mcontext.eip; | |
| 2628 | *bp = ucontext->uc_mcontext.ebp; | |
| 2629 | *sp = ucontext->uc_mcontext.esp; | |
| 2622 | 2630 | # else |
| 2623 | 2631 | ucontext_t *ucontext = (ucontext_t *)context; |
| 2624 | 2632 | # if SANITIZER_SOLARIS |
lib/libtsan/sanitizer_common/sanitizer_linux.h+3-3| ... | ... | @@ -108,11 +108,11 @@ class ThreadLister { |
| 108 | 108 | Incomplete, |
| 109 | 109 | Ok, |
| 110 | 110 | }; |
| 111 | Result ListThreads(InternalMmapVector<tid_t> *threads); | |
| 112 | const char *LoadStatus(tid_t tid); | |
| 111 | Result ListThreads(InternalMmapVector<ThreadID> *threads); | |
| 112 | const char *LoadStatus(ThreadID tid); | |
| 113 | 113 | |
| 114 | 114 | private: |
| 115 | bool IsAlive(tid_t tid); | |
| 115 | bool IsAlive(ThreadID tid); | |
| 116 | 116 | |
| 117 | 117 | InternalScopedString task_path_; |
| 118 | 118 | InternalScopedString status_path_; |
lib/libtsan/sanitizer_common/sanitizer_linux_libcdep.cpp+1| ... | ... | @@ -29,6 +29,7 @@ |
| 29 | 29 | # include "sanitizer_solaris.h" |
| 30 | 30 | |
| 31 | 31 | # if SANITIZER_HAIKU |
| 32 | # define _GNU_SOURCE | |
| 32 | 33 | # define _DEFAULT_SOURCE |
| 33 | 34 | # endif |
| 34 | 35 |
lib/libtsan/sanitizer_common/sanitizer_mac.cpp+255-104| ... | ... | @@ -22,6 +22,11 @@ |
| 22 | 22 | # endif |
| 23 | 23 | # include <stdio.h> |
| 24 | 24 | |
| 25 | // Start searching for available memory region past PAGEZERO, which is | |
| 26 | // 4KB on 32-bit and 4GB on 64-bit. | |
| 27 | # define GAP_SEARCH_START_ADDRESS \ | |
| 28 | ((SANITIZER_WORDSIZE == 32) ? 0x000000001000 : 0x000100000000) | |
| 29 | ||
| 25 | 30 | # include "sanitizer_common.h" |
| 26 | 31 | # include "sanitizer_file.h" |
| 27 | 32 | # include "sanitizer_flags.h" |
| ... | ... | @@ -58,9 +63,11 @@ extern char ***_NSGetArgv(void); |
| 58 | 63 | # include <dlfcn.h> // for dladdr() |
| 59 | 64 | # include <errno.h> |
| 60 | 65 | # include <fcntl.h> |
| 66 | # include <inttypes.h> | |
| 61 | 67 | # include <libkern/OSAtomic.h> |
| 62 | 68 | # include <mach-o/dyld.h> |
| 63 | 69 | # include <mach/mach.h> |
| 70 | # include <mach/mach_error.h> | |
| 64 | 71 | # include <mach/mach_time.h> |
| 65 | 72 | # include <mach/vm_statistics.h> |
| 66 | 73 | # include <malloc/malloc.h> |
| ... | ... | @@ -96,8 +103,16 @@ extern "C" { |
| 96 | 103 | natural_t *nesting_depth, |
| 97 | 104 | vm_region_recurse_info_t info, |
| 98 | 105 | mach_msg_type_number_t *infoCnt); |
| 106 | ||
| 107 | extern const void* _dyld_get_shared_cache_range(size_t* length); | |
| 99 | 108 | } |
| 100 | 109 | |
| 110 | # if !SANITIZER_GO | |
| 111 | // Weak symbol no-op when TSan is not linked | |
| 112 | SANITIZER_WEAK_ATTRIBUTE extern void __tsan_set_in_internal_write_call( | |
| 113 | bool value) {} | |
| 114 | # endif | |
| 115 | ||
| 101 | 116 | namespace __sanitizer { |
| 102 | 117 | |
| 103 | 118 | #include "sanitizer_syscall_generic.inc" |
| ... | ... | @@ -168,7 +183,15 @@ uptr internal_read(fd_t fd, void *buf, uptr count) { |
| 168 | 183 | } |
| 169 | 184 | |
| 170 | 185 | uptr internal_write(fd_t fd, const void *buf, uptr count) { |
| 186 | # if SANITIZER_GO | |
| 171 | 187 | return write(fd, buf, count); |
| 188 | # else | |
| 189 | // We need to disable interceptors when writing in TSan | |
| 190 | __tsan_set_in_internal_write_call(true); | |
| 191 | uptr res = write(fd, buf, count); | |
| 192 | __tsan_set_in_internal_write_call(false); | |
| 193 | return res; | |
| 194 | # endif | |
| 172 | 195 | } |
| 173 | 196 | |
| 174 | 197 | uptr internal_stat(const char *path, void *buf) { |
| ... | ... | @@ -258,53 +281,43 @@ int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, |
| 258 | 281 | (size_t)newlen); |
| 259 | 282 | } |
| 260 | 283 | |
| 261 | static fd_t internal_spawn_impl(const char *argv[], const char *envp[], | |
| 262 | pid_t *pid) { | |
| 263 | fd_t primary_fd = kInvalidFd; | |
| 264 | fd_t secondary_fd = kInvalidFd; | |
| 284 | bool internal_spawn(const char* argv[], const char* envp[], pid_t* pid, | |
| 285 | fd_t fd_stdin, fd_t fd_stdout) { | |
| 286 | // NOTE: Caller ensures that fd_stdin and fd_stdout are not 0, 1, or 2, since | |
| 287 | // this can break communication. | |
| 288 | // | |
| 289 | // NOTE: Caller is responsible for closing fd_stdin after the process has | |
| 290 | // died. | |
| 265 | 291 | |
| 292 | int res; | |
| 266 | 293 | auto fd_closer = at_scope_exit([&] { |
| 267 | internal_close(primary_fd); | |
| 268 | internal_close(secondary_fd); | |
| 294 | // NOTE: We intentionally do not close fd_stdin since this can | |
| 295 | // cause us to receive a fatal SIGPIPE if the process dies. | |
| 296 | internal_close(fd_stdout); | |
| 269 | 297 | }); |
| 270 | 298 | |
| 271 | // We need a new pseudoterminal to avoid buffering problems. The 'atos' tool | |
| 272 | // in particular detects when it's talking to a pipe and forgets to flush the | |
| 273 | // output stream after sending a response. | |
| 274 | primary_fd = posix_openpt(O_RDWR); | |
| 275 | if (primary_fd == kInvalidFd) | |
| 276 | return kInvalidFd; | |
| 277 | ||
| 278 | int res = grantpt(primary_fd) || unlockpt(primary_fd); | |
| 279 | if (res != 0) return kInvalidFd; | |
| 280 | ||
| 281 | // Use TIOCPTYGNAME instead of ptsname() to avoid threading problems. | |
| 282 | char secondary_pty_name[128]; | |
| 283 | res = ioctl(primary_fd, TIOCPTYGNAME, secondary_pty_name); | |
| 284 | if (res == -1) return kInvalidFd; | |
| 285 | ||
| 286 | secondary_fd = internal_open(secondary_pty_name, O_RDWR); | |
| 287 | if (secondary_fd == kInvalidFd) | |
| 288 | return kInvalidFd; | |
| 289 | ||
| 290 | 299 | // File descriptor actions |
| 291 | 300 | posix_spawn_file_actions_t acts; |
| 292 | 301 | res = posix_spawn_file_actions_init(&acts); |
| 293 | if (res != 0) return kInvalidFd; | |
| 302 | if (res != 0) | |
| 303 | return false; | |
| 294 | 304 | |
| 295 | 305 | auto acts_cleanup = at_scope_exit([&] { |
| 296 | 306 | posix_spawn_file_actions_destroy(&acts); |
| 297 | 307 | }); |
| 298 | 308 | |
| 299 | res = posix_spawn_file_actions_adddup2(&acts, secondary_fd, STDIN_FILENO) || | |
| 300 | posix_spawn_file_actions_adddup2(&acts, secondary_fd, STDOUT_FILENO) || | |
| 301 | posix_spawn_file_actions_addclose(&acts, secondary_fd); | |
| 302 | if (res != 0) return kInvalidFd; | |
| 309 | res = posix_spawn_file_actions_adddup2(&acts, fd_stdin, STDIN_FILENO) || | |
| 310 | posix_spawn_file_actions_adddup2(&acts, fd_stdout, STDOUT_FILENO) || | |
| 311 | posix_spawn_file_actions_addclose(&acts, fd_stdin) || | |
| 312 | posix_spawn_file_actions_addclose(&acts, fd_stdout); | |
| 313 | if (res != 0) | |
| 314 | return false; | |
| 303 | 315 | |
| 304 | 316 | // Spawn attributes |
| 305 | 317 | posix_spawnattr_t attrs; |
| 306 | 318 | res = posix_spawnattr_init(&attrs); |
| 307 | if (res != 0) return kInvalidFd; | |
| 319 | if (res != 0) | |
| 320 | return false; | |
| 308 | 321 | |
| 309 | 322 | auto attrs_cleanup = at_scope_exit([&] { |
| 310 | 323 | posix_spawnattr_destroy(&attrs); |
| ... | ... | @@ -313,50 +326,17 @@ static fd_t internal_spawn_impl(const char *argv[], const char *envp[], |
| 313 | 326 | // In the spawned process, close all file descriptors that are not explicitly |
| 314 | 327 | // described by the file actions object. This is Darwin-specific extension. |
| 315 | 328 | res = posix_spawnattr_setflags(&attrs, POSIX_SPAWN_CLOEXEC_DEFAULT); |
| 316 | if (res != 0) return kInvalidFd; | |
| 329 | if (res != 0) | |
| 330 | return false; | |
| 317 | 331 | |
| 318 | 332 | // posix_spawn |
| 319 | 333 | char **argv_casted = const_cast<char **>(argv); |
| 320 | 334 | char **envp_casted = const_cast<char **>(envp); |
| 321 | 335 | res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, envp_casted); |
| 322 | if (res != 0) return kInvalidFd; | |
| 323 | ||
| 324 | // Disable echo in the new terminal, disable CR. | |
| 325 | struct termios termflags; | |
| 326 | tcgetattr(primary_fd, &termflags); | |
| 327 | termflags.c_oflag &= ~ONLCR; | |
| 328 | termflags.c_lflag &= ~ECHO; | |
| 329 | tcsetattr(primary_fd, TCSANOW, &termflags); | |
| 330 | ||
| 331 | // On success, do not close primary_fd on scope exit. | |
| 332 | fd_t fd = primary_fd; | |
| 333 | primary_fd = kInvalidFd; | |
| 334 | ||
| 335 | return fd; | |
| 336 | } | |
| 337 | ||
| 338 | fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid) { | |
| 339 | // The client program may close its stdin and/or stdout and/or stderr thus | |
| 340 | // allowing open/posix_openpt to reuse file descriptors 0, 1 or 2. In this | |
| 341 | // case the communication is broken if either the parent or the child tries to | |
| 342 | // close or duplicate these descriptors. We temporarily reserve these | |
| 343 | // descriptors here to prevent this. | |
| 344 | fd_t low_fds[3]; | |
| 345 | size_t count = 0; | |
| 346 | ||
| 347 | for (; count < 3; count++) { | |
| 348 | low_fds[count] = posix_openpt(O_RDWR); | |
| 349 | if (low_fds[count] >= STDERR_FILENO) | |
| 350 | break; | |
| 351 | } | |
| 352 | ||
| 353 | fd_t fd = internal_spawn_impl(argv, envp, pid); | |
| 354 | ||
| 355 | for (; count > 0; count--) { | |
| 356 | internal_close(low_fds[count]); | |
| 357 | } | |
| 336 | if (res != 0) | |
| 337 | return false; | |
| 358 | 338 | |
| 359 | return fd; | |
| 339 | return true; | |
| 360 | 340 | } |
| 361 | 341 | |
| 362 | 342 | uptr internal_rename(const char *oldpath, const char *newpath) { |
| ... | ... | @@ -394,8 +374,8 @@ bool DirExists(const char *path) { |
| 394 | 374 | return S_ISDIR(st.st_mode); |
| 395 | 375 | } |
| 396 | 376 | |
| 397 | tid_t GetTid() { | |
| 398 | tid_t tid; | |
| 377 | ThreadID GetTid() { | |
| 378 | ThreadID tid; | |
| 399 | 379 | pthread_threadid_np(nullptr, &tid); |
| 400 | 380 | return tid; |
| 401 | 381 | } |
| ... | ... | @@ -769,11 +749,17 @@ void internal_join_thread(void *th) { pthread_join((pthread_t)th, 0); } |
| 769 | 749 | static Mutex syslog_lock; |
| 770 | 750 | # endif |
| 771 | 751 | |
| 752 | # if SANITIZER_DRIVERKIT | |
| 753 | # define SANITIZER_OS_LOG os_log | |
| 754 | # else | |
| 755 | # define SANITIZER_OS_LOG os_log_error | |
| 756 | # endif | |
| 757 | ||
| 772 | 758 | void WriteOneLineToSyslog(const char *s) { |
| 773 | 759 | #if !SANITIZER_GO |
| 774 | 760 | syslog_lock.CheckLocked(); |
| 775 | 761 | if (GetMacosAlignedVersion() >= MacosVersion(10, 12)) { |
| 776 | os_log_error(OS_LOG_DEFAULT, "%{public}s", s); | |
| 762 | SANITIZER_OS_LOG(OS_LOG_DEFAULT, "%{public}s", s); | |
| 777 | 763 | } else { |
| 778 | 764 | #pragma clang diagnostic push |
| 779 | 765 | // as_log is deprecated. |
| ... | ... | @@ -837,22 +823,22 @@ void LogMessageOnPrintf(const char *str) { |
| 837 | 823 | |
| 838 | 824 | void LogFullErrorReport(const char *buffer) { |
| 839 | 825 | # if !SANITIZER_GO |
| 840 | // Log with os_log_error. This will make it into the crash log. | |
| 826 | // When logging with os_log_error this will make it into the crash log. | |
| 841 | 827 | if (internal_strncmp(SanitizerToolName, "AddressSanitizer", |
| 842 | 828 | sizeof("AddressSanitizer") - 1) == 0) |
| 843 | os_log_error(OS_LOG_DEFAULT, "Address Sanitizer reported a failure."); | |
| 829 | SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Address Sanitizer reported a failure."); | |
| 844 | 830 | else if (internal_strncmp(SanitizerToolName, "UndefinedBehaviorSanitizer", |
| 845 | 831 | sizeof("UndefinedBehaviorSanitizer") - 1) == 0) |
| 846 | os_log_error(OS_LOG_DEFAULT, | |
| 847 | "Undefined Behavior Sanitizer reported a failure."); | |
| 832 | SANITIZER_OS_LOG(OS_LOG_DEFAULT, | |
| 833 | "Undefined Behavior Sanitizer reported a failure."); | |
| 848 | 834 | else if (internal_strncmp(SanitizerToolName, "ThreadSanitizer", |
| 849 | 835 | sizeof("ThreadSanitizer") - 1) == 0) |
| 850 | os_log_error(OS_LOG_DEFAULT, "Thread Sanitizer reported a failure."); | |
| 836 | SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Thread Sanitizer reported a failure."); | |
| 851 | 837 | else |
| 852 | os_log_error(OS_LOG_DEFAULT, "Sanitizer tool reported a failure."); | |
| 838 | SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Sanitizer tool reported a failure."); | |
| 853 | 839 | |
| 854 | 840 | if (common_flags()->log_to_syslog) |
| 855 | os_log_error(OS_LOG_DEFAULT, "Consult syslog for more information."); | |
| 841 | SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Consult syslog for more information."); | |
| 856 | 842 | |
| 857 | 843 | // Log to syslog. |
| 858 | 844 | // The logging on OS X may call pthread_create so we need the threading |
| ... | ... | @@ -933,7 +919,17 @@ static void DisableMmapExcGuardExceptions() { |
| 933 | 919 | RTLD_DEFAULT, "task_set_exc_guard_behavior"); |
| 934 | 920 | if (set_behavior == nullptr) return; |
| 935 | 921 | const task_exc_guard_behavior_t task_exc_guard_none = 0; |
| 936 | set_behavior(mach_task_self(), task_exc_guard_none); | |
| 922 | kern_return_t res = set_behavior(mach_task_self(), task_exc_guard_none); | |
| 923 | if (res != KERN_SUCCESS) { | |
| 924 | Report( | |
| 925 | "WARN: task_set_exc_guard_behavior returned %d (%s), " | |
| 926 | "mmap may fail unexpectedly.\n", | |
| 927 | res, mach_error_string(res)); | |
| 928 | if (res == KERN_DENIED) | |
| 929 | Report( | |
| 930 | "HINT: Check that task_set_exc_guard_behavior is allowed by " | |
| 931 | "sandbox.\n"); | |
| 932 | } | |
| 937 | 933 | } |
| 938 | 934 | |
| 939 | 935 | static void VerifyInterceptorsWorking(); |
| ... | ... | @@ -1100,6 +1096,67 @@ static void StripEnv() { |
| 1100 | 1096 | } |
| 1101 | 1097 | #endif // SANITIZER_GO |
| 1102 | 1098 | |
| 1099 | // Prints out a consolidated memory map: contiguous regions | |
| 1100 | // are merged together. | |
| 1101 | static void PrintVmmap() { | |
| 1102 | const mach_vm_address_t max_vm_address = GetMaxVirtualAddress() + 1; | |
| 1103 | mach_vm_address_t address = GAP_SEARCH_START_ADDRESS; | |
| 1104 | kern_return_t kr = KERN_SUCCESS; | |
| 1105 | ||
| 1106 | Report("Memory map:\n"); | |
| 1107 | mach_vm_address_t last = 0; | |
| 1108 | mach_vm_address_t lastsz = 0; | |
| 1109 | ||
| 1110 | while (1) { | |
| 1111 | mach_vm_size_t vmsize = 0; | |
| 1112 | natural_t depth = 0; | |
| 1113 | vm_region_submap_short_info_data_64_t vminfo; | |
| 1114 | mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64; | |
| 1115 | kr = mach_vm_region_recurse(mach_task_self(), &address, &vmsize, &depth, | |
| 1116 | (vm_region_info_t)&vminfo, &count); | |
| 1117 | ||
| 1118 | if (kr == KERN_DENIED) { | |
| 1119 | Report( | |
| 1120 | "ERROR: mach_vm_region_recurse got KERN_DENIED when printing memory " | |
| 1121 | "map.\n"); | |
| 1122 | Report( | |
| 1123 | "HINT: Check whether mach_vm_region_recurse is allowed by " | |
| 1124 | "sandbox.\n"); | |
| 1125 | } | |
| 1126 | ||
| 1127 | if (kr == KERN_SUCCESS && address < max_vm_address) { | |
| 1128 | if (last + lastsz == address) { | |
| 1129 | // This region is contiguous with the last; merge together. | |
| 1130 | lastsz += vmsize; | |
| 1131 | } else { | |
| 1132 | if (lastsz) | |
| 1133 | Printf("|| `[%p, %p]` || size=0x%016" PRIx64 " ||\n", (void*)last, | |
| 1134 | (void*)(last + lastsz), lastsz); | |
| 1135 | ||
| 1136 | last = address; | |
| 1137 | lastsz = vmsize; | |
| 1138 | } | |
| 1139 | address += vmsize; | |
| 1140 | } else { | |
| 1141 | // We've reached the end of the memory map. Print the last remaining | |
| 1142 | // region, if there is one. | |
| 1143 | if (lastsz) | |
| 1144 | Printf("|| `[%p, %p]` || size=0x%016" PRIx64 " ||\n", (void*)last, | |
| 1145 | (void*)(last + lastsz), lastsz); | |
| 1146 | ||
| 1147 | break; | |
| 1148 | } | |
| 1149 | } | |
| 1150 | } | |
| 1151 | ||
| 1152 | static void ReportShadowAllocFail(uptr shadow_size_bytes, uptr alignment) { | |
| 1153 | Report( | |
| 1154 | "FATAL: Failed to allocate shadow memory. Tried to allocate %p bytes " | |
| 1155 | "(alignment=%p).\n", | |
| 1156 | (void*)shadow_size_bytes, (void*)alignment); | |
| 1157 | PrintVmmap(); | |
| 1158 | } | |
| 1159 | ||
| 1103 | 1160 | char **GetArgv() { |
| 1104 | 1161 | return *_NSGetArgv(); |
| 1105 | 1162 | } |
| ... | ... | @@ -1207,10 +1264,11 @@ uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale, |
| 1207 | 1264 | if (new_max_vm < max_occupied_addr) { |
| 1208 | 1265 | Report("Unable to find a memory range for dynamic shadow.\n"); |
| 1209 | 1266 | Report( |
| 1210 | "space_size = %p, largest_gap_found = %p, max_occupied_addr = %p, " | |
| 1211 | "new_max_vm = %p\n", | |
| 1212 | (void *)space_size, (void *)largest_gap_found, | |
| 1213 | (void *)max_occupied_addr, (void *)new_max_vm); | |
| 1267 | "\tspace_size = %p\n\tlargest_gap_found = %p\n\tmax_occupied_addr " | |
| 1268 | "= %p\n\tnew_max_vm = %p\n", | |
| 1269 | (void*)space_size, (void*)largest_gap_found, (void*)max_occupied_addr, | |
| 1270 | (void*)new_max_vm); | |
| 1271 | ReportShadowAllocFail(shadow_size_bytes, alignment); | |
| 1214 | 1272 | CHECK(0 && "cannot place shadow"); |
| 1215 | 1273 | } |
| 1216 | 1274 | RestrictMemoryToMaxAddress(new_max_vm); |
| ... | ... | @@ -1221,6 +1279,7 @@ uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale, |
| 1221 | 1279 | nullptr, nullptr); |
| 1222 | 1280 | if (shadow_start == 0) { |
| 1223 | 1281 | Report("Unable to find a memory range after restricting VM.\n"); |
| 1282 | ReportShadowAllocFail(shadow_size_bytes, alignment); | |
| 1224 | 1283 | CHECK(0 && "cannot place shadow after restricting vm"); |
| 1225 | 1284 | } |
| 1226 | 1285 | } |
| ... | ... | @@ -1229,6 +1288,25 @@ uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale, |
| 1229 | 1288 | return shadow_start; |
| 1230 | 1289 | } |
| 1231 | 1290 | |
| 1291 | // Returns a list of ranges which must be covered by shadow memory, | |
| 1292 | // and cannot overlap with any fixed mappings made by a sanitizer. | |
| 1293 | // This can ensure that the sanitizer runtime does not map over | |
| 1294 | // platform-reserved regions. | |
| 1295 | void GetAppReservedRanges(InternalMmapVector<ReservedRange>& ranges) { | |
| 1296 | ranges.clear(); | |
| 1297 | ||
| 1298 | # if SANITIZER_OSX | |
| 1299 | // On macOS, the first 512GB are platform-reserved (some of which | |
| 1300 | // may also be available to applications). | |
| 1301 | ranges.push_back({0x1000UL, 0x8000000000UL}); | |
| 1302 | # endif | |
| 1303 | ||
| 1304 | VReport(2, "App ranges:\n"); | |
| 1305 | for (auto& [range_start, range_end] : ranges) { | |
| 1306 | VReport(2, " [%p, %p]\n", range_start, range_end); | |
| 1307 | } | |
| 1308 | } | |
| 1309 | ||
| 1232 | 1310 | uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size, |
| 1233 | 1311 | uptr num_aliases, uptr ring_buffer_size) { |
| 1234 | 1312 | CHECK(false && "HWASan aliasing is unimplemented on Mac"); |
| ... | ... | @@ -1236,40 +1314,61 @@ uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size, |
| 1236 | 1314 | } |
| 1237 | 1315 | |
| 1238 | 1316 | uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, |
| 1239 | uptr *largest_gap_found, | |
| 1240 | uptr *max_occupied_addr) { | |
| 1241 | typedef vm_region_submap_short_info_data_64_t RegionInfo; | |
| 1242 | enum { kRegionInfoSize = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 }; | |
| 1243 | // Start searching for available memory region past PAGEZERO, which is | |
| 1244 | // 4KB on 32-bit and 4GB on 64-bit. | |
| 1245 | mach_vm_address_t start_address = | |
| 1246 | (SANITIZER_WORDSIZE == 32) ? 0x000000001000 : 0x000100000000; | |
| 1247 | ||
| 1317 | uptr* largest_gap_found, | |
| 1318 | uptr* max_occupied_addr) { | |
| 1248 | 1319 | const mach_vm_address_t max_vm_address = GetMaxVirtualAddress() + 1; |
| 1249 | mach_vm_address_t address = start_address; | |
| 1250 | mach_vm_address_t free_begin = start_address; | |
| 1320 | mach_vm_address_t address = GAP_SEARCH_START_ADDRESS; | |
| 1321 | mach_vm_address_t free_begin = GAP_SEARCH_START_ADDRESS; | |
| 1322 | ||
| 1323 | // Restrict the search to be after any reserved ranges | |
| 1324 | InternalMmapVector<ReservedRange> app_ranges; | |
| 1325 | GetAppReservedRanges(app_ranges); | |
| 1326 | ||
| 1327 | for (auto& [range_start, range_end] : app_ranges) { | |
| 1328 | address = Max(address, (mach_vm_address_t)range_end); | |
| 1329 | free_begin = Max(free_begin, (mach_vm_address_t)range_end); | |
| 1330 | } | |
| 1331 | ||
| 1251 | 1332 | kern_return_t kr = KERN_SUCCESS; |
| 1252 | 1333 | if (largest_gap_found) *largest_gap_found = 0; |
| 1253 | 1334 | if (max_occupied_addr) *max_occupied_addr = 0; |
| 1254 | 1335 | while (kr == KERN_SUCCESS) { |
| 1255 | 1336 | mach_vm_size_t vmsize = 0; |
| 1256 | 1337 | natural_t depth = 0; |
| 1257 | RegionInfo vminfo; | |
| 1258 | mach_msg_type_number_t count = kRegionInfoSize; | |
| 1338 | vm_region_submap_short_info_data_64_t vminfo; | |
| 1339 | mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64; | |
| 1259 | 1340 | kr = mach_vm_region_recurse(mach_task_self(), &address, &vmsize, &depth, |
| 1260 | 1341 | (vm_region_info_t)&vminfo, &count); |
| 1261 | 1342 | |
| 1262 | // There are cases where going beyond the processes' max vm does | |
| 1263 | // not return KERN_INVALID_ADDRESS so we check for going beyond that | |
| 1264 | // max address as well. | |
| 1265 | if (kr == KERN_INVALID_ADDRESS || address > max_vm_address) { | |
| 1343 | if (kr == KERN_SUCCESS) { | |
| 1344 | // There are cases where going beyond the processes' max vm does | |
| 1345 | // not return KERN_INVALID_ADDRESS so we check for going beyond that | |
| 1346 | // max address as well. | |
| 1347 | if (address > max_vm_address) { | |
| 1348 | address = max_vm_address; | |
| 1349 | kr = -1; // break after this iteration. | |
| 1350 | } | |
| 1351 | ||
| 1352 | if (max_occupied_addr) | |
| 1353 | *max_occupied_addr = address + vmsize; | |
| 1354 | } else if (kr == KERN_INVALID_ADDRESS) { | |
| 1266 | 1355 | // No more regions beyond "address", consider the gap at the end of VM. |
| 1267 | 1356 | address = max_vm_address; |
| 1268 | vmsize = 0; | |
| 1269 | kr = -1; // break after this iteration. | |
| 1357 | ||
| 1358 | // We will break after this iteration anyway since kr != KERN_SUCCESS | |
| 1359 | } else if (kr == KERN_DENIED) { | |
| 1360 | Report("ERROR: Unable to find a memory range for dynamic shadow.\n"); | |
| 1361 | Report("HINT: Ensure mach_vm_region_recurse is allowed under sandbox.\n"); | |
| 1362 | Die(); | |
| 1270 | 1363 | } else { |
| 1271 | if (max_occupied_addr) *max_occupied_addr = address + vmsize; | |
| 1364 | Report( | |
| 1365 | "WARNING: mach_vm_region_recurse returned unexpected code %d (%s)\n", | |
| 1366 | kr, mach_error_string(kr)); | |
| 1367 | DCHECK(false && "mach_vm_region_recurse returned unexpected code"); | |
| 1368 | break; // address is not valid unless KERN_SUCCESS, therefore we must not | |
| 1369 | // use it. | |
| 1272 | 1370 | } |
| 1371 | ||
| 1273 | 1372 | if (free_begin != address) { |
| 1274 | 1373 | // We found a free region [free_begin..address-1]. |
| 1275 | 1374 | uptr gap_start = RoundUpTo((uptr)free_begin + left_padding, alignment); |
| ... | ... | @@ -1292,6 +1391,58 @@ uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, |
| 1292 | 1391 | return 0; |
| 1293 | 1392 | } |
| 1294 | 1393 | |
| 1394 | // This function (when used during initialization when there is | |
| 1395 | // only a single thread), can be used to verify that a range | |
| 1396 | // of memory hasn't already been mapped, and won't be mapped | |
| 1397 | // later in the shared cache. | |
| 1398 | // | |
| 1399 | // If the syscall mach_vm_region_recurse fails (due to sandbox), | |
| 1400 | // we assume that the memory is not mapped so that execution can continue. | |
| 1401 | // | |
| 1402 | // NOTE: range_end is inclusive | |
| 1403 | // | |
| 1404 | // WARNING: This function must NOT allocate memory, since it is | |
| 1405 | // used in InitializeShadowMemory between where we search for | |
| 1406 | // space for shadow and where we actually allocate it. | |
| 1407 | bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { | |
| 1408 | mach_vm_size_t vmsize = 0; | |
| 1409 | natural_t depth = 0; | |
| 1410 | vm_region_submap_short_info_data_64_t vminfo; | |
| 1411 | mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64; | |
| 1412 | mach_vm_address_t address = range_start; | |
| 1413 | ||
| 1414 | // First, check if the range is already mapped. | |
| 1415 | kern_return_t kr = | |
| 1416 | mach_vm_region_recurse(mach_task_self(), &address, &vmsize, &depth, | |
| 1417 | (vm_region_info_t)&vminfo, &count); | |
| 1418 | ||
| 1419 | if (kr == KERN_DENIED) { | |
| 1420 | Report( | |
| 1421 | "WARN: mach_vm_region_recurse returned KERN_DENIED when checking " | |
| 1422 | "whether an address is mapped.\n"); | |
| 1423 | Report("HINT: Is mach_vm_region_recurse allowed by sandbox?\n"); | |
| 1424 | } | |
| 1425 | ||
| 1426 | if (kr == KERN_SUCCESS && !IntervalsAreSeparate(address, address + vmsize - 1, | |
| 1427 | range_start, range_end)) { | |
| 1428 | // Overlaps with already-mapped memory | |
| 1429 | return false; | |
| 1430 | } | |
| 1431 | ||
| 1432 | size_t cacheLength; | |
| 1433 | uptr cacheStart = (uptr)_dyld_get_shared_cache_range(&cacheLength); | |
| 1434 | ||
| 1435 | if (cacheStart && | |
| 1436 | !IntervalsAreSeparate(cacheStart, cacheStart + cacheLength - 1, | |
| 1437 | range_start, range_end)) { | |
| 1438 | // Overlaps with shared cache region | |
| 1439 | return false; | |
| 1440 | } | |
| 1441 | ||
| 1442 | // We believe this address is available. | |
| 1443 | return true; | |
| 1444 | } | |
| 1445 | ||
| 1295 | 1446 | // FIXME implement on this platform. |
| 1296 | 1447 | void GetMemoryProfile(fill_profile_f cb, uptr *stats) {} |
| 1297 | 1448 |
lib/libtsan/sanitizer_common/sanitizer_mac.h+5| ... | ... | @@ -58,8 +58,13 @@ struct DarwinKernelVersion : VersionBase<DarwinKernelVersion> { |
| 58 | 58 | DarwinKernelVersion(u16 major, u16 minor) : VersionBase(major, minor) {} |
| 59 | 59 | }; |
| 60 | 60 | |
| 61 | struct ReservedRange { | |
| 62 | uptr beg, end; | |
| 63 | }; | |
| 64 | ||
| 61 | 65 | MacosVersion GetMacosAlignedVersion(); |
| 62 | 66 | DarwinKernelVersion GetDarwinKernelVersion(); |
| 67 | void GetAppReservedRanges(InternalMmapVector<ReservedRange>& ranges); | |
| 63 | 68 | |
| 64 | 69 | char **GetEnviron(); |
| 65 | 70 |
lib/libtsan/sanitizer_common/sanitizer_netbsd.cpp+2-2| ... | ... | @@ -229,12 +229,12 @@ uptr internal_execve(const char *filename, char *const argv[], |
| 229 | 229 | return _sys_execve(filename, argv, envp); |
| 230 | 230 | } |
| 231 | 231 | |
| 232 | tid_t GetTid() { | |
| 232 | ThreadID GetTid() { | |
| 233 | 233 | DEFINE__REAL(int, _lwp_self); |
| 234 | 234 | return _REAL(_lwp_self); |
| 235 | 235 | } |
| 236 | 236 | |
| 237 | int TgKill(pid_t pid, tid_t tid, int sig) { | |
| 237 | int TgKill(pid_t pid, ThreadID tid, int sig) { | |
| 238 | 238 | DEFINE__REAL(int, _lwp_kill, int a, int b); |
| 239 | 239 | (void)pid; |
| 240 | 240 | return _REAL(_lwp_kill, tid, sig); |
lib/libtsan/sanitizer_common/sanitizer_platform.h+27-1| ... | ... | @@ -319,7 +319,11 @@ |
| 319 | 319 | #endif |
| 320 | 320 | |
| 321 | 321 | // The first address that can be returned by mmap. |
| 322 | #define SANITIZER_MMAP_BEGIN 0 | |
| 322 | #if SANITIZER_AIX && SANITIZER_WORDSIZE == 64 | |
| 323 | # define SANITIZER_MMAP_BEGIN 0x0a00'0000'0000'0000ULL | |
| 324 | #else | |
| 325 | # define SANITIZER_MMAP_BEGIN 0 | |
| 326 | #endif | |
| 323 | 327 | |
| 324 | 328 | // The range of addresses which can be returned my mmap. |
| 325 | 329 | // FIXME: this value should be different on different platforms. Larger values |
| ... | ... | @@ -482,4 +486,26 @@ |
| 482 | 486 | # define SANITIZER_START_BACKGROUND_THREAD_IN_ASAN_INTERNAL 0 |
| 483 | 487 | #endif |
| 484 | 488 | |
| 489 | #if SANITIZER_LINUX | |
| 490 | # if SANITIZER_GLIBC | |
| 491 | // Workaround for | |
| 492 | // glibc/commit/3d3572f59059e2b19b8541ea648a6172136ec42e | |
| 493 | // Linux: Keep termios ioctl constants strictly internal | |
| 494 | # if __GLIBC_PREREQ(2, 41) | |
| 495 | # define SANITIZER_TERMIOS_IOCTL_CONSTANTS 0 | |
| 496 | # else | |
| 497 | # define SANITIZER_TERMIOS_IOCTL_CONSTANTS 1 | |
| 498 | # endif | |
| 499 | # else | |
| 500 | # define SANITIZER_TERMIOS_IOCTL_CONSTANTS 1 | |
| 501 | # endif | |
| 502 | #endif | |
| 503 | ||
| 504 | #if SANITIZER_APPLE && SANITIZER_WORDSIZE == 64 | |
| 505 | // MTE uses the lower half of the top byte. | |
| 506 | # define STRIP_MTE_TAG(addr) ((addr) & ~((uptr)0x0f << 56)) | |
| 507 | #else | |
| 508 | # define STRIP_MTE_TAG(addr) (addr) | |
| 509 | #endif | |
| 510 | ||
| 485 | 511 | #endif // SANITIZER_PLATFORM_H |
lib/libtsan/sanitizer_common/sanitizer_platform_interceptors.h+5-4| ... | ... | @@ -167,7 +167,7 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment, |
| 167 | 167 | |
| 168 | 168 | #define SANITIZER_INTERCEPT_STRLEN SI_NOT_FUCHSIA |
| 169 | 169 | #define SANITIZER_INTERCEPT_STRNLEN (SI_NOT_MAC && SI_NOT_FUCHSIA) |
| 170 | #define SANITIZER_INTERCEPT_STRCMP (SI_NOT_FUCHSIA && SI_NOT_AIX) | |
| 170 | #define SANITIZER_INTERCEPT_STRCMP SI_NOT_FUCHSIA | |
| 171 | 171 | #define SANITIZER_INTERCEPT_STRSTR SI_NOT_FUCHSIA |
| 172 | 172 | #define SANITIZER_INTERCEPT_STRCASESTR (SI_POSIX && SI_NOT_AIX) |
| 173 | 173 | #define SANITIZER_INTERCEPT_STRTOK SI_NOT_FUCHSIA |
| ... | ... | @@ -179,8 +179,8 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment, |
| 179 | 179 | #define SANITIZER_INTERCEPT_TEXTDOMAIN SI_LINUX_NOT_ANDROID || SI_SOLARIS |
| 180 | 180 | #define SANITIZER_INTERCEPT_STRCASECMP SI_POSIX |
| 181 | 181 | #define SANITIZER_INTERCEPT_MEMSET 1 |
| 182 | #define SANITIZER_INTERCEPT_MEMMOVE SI_NOT_AIX | |
| 183 | #define SANITIZER_INTERCEPT_MEMCPY SI_NOT_AIX | |
| 182 | #define SANITIZER_INTERCEPT_MEMMOVE 1 | |
| 183 | #define SANITIZER_INTERCEPT_MEMCPY 1 | |
| 184 | 184 | #define SANITIZER_INTERCEPT_MEMCMP SI_NOT_FUCHSIA |
| 185 | 185 | #define SANITIZER_INTERCEPT_BCMP \ |
| 186 | 186 | SANITIZER_INTERCEPT_MEMCMP && \ |
| ... | ... | @@ -551,7 +551,8 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment, |
| 551 | 551 | #define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC && !SI_NETBSD) |
| 552 | 552 | #define SANITIZER_INTERCEPT_MCHECK_MPROBE SI_LINUX_NOT_ANDROID |
| 553 | 553 | #define SANITIZER_INTERCEPT_WCSLEN 1 |
| 554 | #define SANITIZER_INTERCEPT_WCSCAT SI_POSIX | |
| 554 | #define SANITIZER_INTERCEPT_WCSNLEN 1 | |
| 555 | #define SANITIZER_INTERCEPT_WCSCAT (SI_POSIX || SI_WINDOWS) | |
| 555 | 556 | #define SANITIZER_INTERCEPT_WCSDUP SI_POSIX |
| 556 | 557 | #define SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION (!SI_WINDOWS && SI_NOT_FUCHSIA) |
| 557 | 558 | #define SANITIZER_INTERCEPT_BSD_SIGNAL SI_ANDROID |
lib/libtsan/sanitizer_common/sanitizer_platform_limits_posix.cpp+4-4| ... | ... | @@ -779,16 +779,16 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); |
| 779 | 779 | unsigned IOCTL_SOUND_PCM_WRITE_FILTER = SOUND_PCM_WRITE_FILTER; |
| 780 | 780 | #endif // SOUND_VERSION |
| 781 | 781 | unsigned IOCTL_TCFLSH = TCFLSH; |
| 782 | unsigned IOCTL_TCGETA = TCGETA; | |
| 782 | # if SANITIZER_TERMIOS_IOCTL_CONSTANTS | |
| 783 | 783 | unsigned IOCTL_TCGETS = TCGETS; |
| 784 | # endif | |
| 784 | 785 | unsigned IOCTL_TCSBRK = TCSBRK; |
| 785 | 786 | unsigned IOCTL_TCSBRKP = TCSBRKP; |
| 786 | unsigned IOCTL_TCSETA = TCSETA; | |
| 787 | unsigned IOCTL_TCSETAF = TCSETAF; | |
| 788 | unsigned IOCTL_TCSETAW = TCSETAW; | |
| 787 | # if SANITIZER_TERMIOS_IOCTL_CONSTANTS | |
| 789 | 788 | unsigned IOCTL_TCSETS = TCSETS; |
| 790 | 789 | unsigned IOCTL_TCSETSF = TCSETSF; |
| 791 | 790 | unsigned IOCTL_TCSETSW = TCSETSW; |
| 791 | # endif | |
| 792 | 792 | unsigned IOCTL_TCXONC = TCXONC; |
| 793 | 793 | unsigned IOCTL_TIOCGLCKTRMIOS = TIOCGLCKTRMIOS; |
| 794 | 794 | unsigned IOCTL_TIOCGSOFTCAR = TIOCGSOFTCAR; |
lib/libtsan/sanitizer_common/sanitizer_platform_limits_posix.h+32-6| ... | ... | @@ -32,6 +32,8 @@ |
| 32 | 32 | # elif SANITIZER_GLIBC || SANITIZER_ANDROID |
| 33 | 33 | # define SANITIZER_HAS_STAT64 1 |
| 34 | 34 | # define SANITIZER_HAS_STATFS64 1 |
| 35 | # elif SANITIZER_HAIKU | |
| 36 | # include <stdint.h> | |
| 35 | 37 | # endif |
| 36 | 38 | |
| 37 | 39 | # if defined(__sparc__) |
| ... | ... | @@ -102,6 +104,8 @@ const unsigned struct_kernel_stat_sz = SANITIZER_ANDROID |
| 102 | 104 | ? FIRST_32_SECOND_64(104, 128) |
| 103 | 105 | # if defined(_ABIN32) && _MIPS_SIM == _ABIN32 |
| 104 | 106 | : FIRST_32_SECOND_64(176, 216); |
| 107 | # elif SANITIZER_MUSL | |
| 108 | : FIRST_32_SECOND_64(160, 208); | |
| 105 | 109 | # else |
| 106 | 110 | : FIRST_32_SECOND_64(160, 216); |
| 107 | 111 | # endif |
| ... | ... | @@ -476,6 +480,30 @@ struct __sanitizer_cmsghdr { |
| 476 | 480 | int cmsg_level; |
| 477 | 481 | int cmsg_type; |
| 478 | 482 | }; |
| 483 | # elif SANITIZER_MUSL | |
| 484 | struct __sanitizer_msghdr { | |
| 485 | void *msg_name; | |
| 486 | unsigned msg_namelen; | |
| 487 | struct __sanitizer_iovec *msg_iov; | |
| 488 | int msg_iovlen; | |
| 489 | # if SANITIZER_WORDSIZE == 64 | |
| 490 | int __pad1; | |
| 491 | # endif | |
| 492 | void *msg_control; | |
| 493 | unsigned msg_controllen; | |
| 494 | # if SANITIZER_WORDSIZE == 64 | |
| 495 | int __pad2; | |
| 496 | # endif | |
| 497 | int msg_flags; | |
| 498 | }; | |
| 499 | struct __sanitizer_cmsghdr { | |
| 500 | unsigned cmsg_len; | |
| 501 | # if SANITIZER_WORDSIZE == 64 | |
| 502 | int __pad1; | |
| 503 | # endif | |
| 504 | int cmsg_level; | |
| 505 | int cmsg_type; | |
| 506 | }; | |
| 479 | 507 | # else |
| 480 | 508 | // In POSIX, int msg_iovlen; socklen_t msg_controllen; socklen_t cmsg_len; but |
| 481 | 509 | // many implementations don't conform to the standard. |
| ... | ... | @@ -603,7 +631,7 @@ typedef unsigned long __sanitizer_sigset_t; |
| 603 | 631 | # elif SANITIZER_APPLE |
| 604 | 632 | typedef unsigned __sanitizer_sigset_t; |
| 605 | 633 | # elif SANITIZER_HAIKU |
| 606 | typedef unsigned long __sanitizer_sigset_t; | |
| 634 | typedef uint64_t __sanitizer_sigset_t; | |
| 607 | 635 | # elif SANITIZER_LINUX |
| 608 | 636 | struct __sanitizer_sigset_t { |
| 609 | 637 | // The size is determined by looking at sizeof of real sigset_t on linux. |
| ... | ... | @@ -1312,16 +1340,14 @@ extern unsigned IOCTL_SNDCTL_COPR_SENDMSG; |
| 1312 | 1340 | extern unsigned IOCTL_SNDCTL_COPR_WCODE; |
| 1313 | 1341 | extern unsigned IOCTL_SNDCTL_COPR_WDATA; |
| 1314 | 1342 | extern unsigned IOCTL_TCFLSH; |
| 1315 | extern unsigned IOCTL_TCGETA; | |
| 1316 | extern unsigned IOCTL_TCGETS; | |
| 1317 | 1343 | extern unsigned IOCTL_TCSBRK; |
| 1318 | 1344 | extern unsigned IOCTL_TCSBRKP; |
| 1319 | extern unsigned IOCTL_TCSETA; | |
| 1320 | extern unsigned IOCTL_TCSETAF; | |
| 1321 | extern unsigned IOCTL_TCSETAW; | |
| 1345 | # if SANITIZER_TERMIOS_IOCTL_CONSTANTS | |
| 1346 | extern unsigned IOCTL_TCGETS; | |
| 1322 | 1347 | extern unsigned IOCTL_TCSETS; |
| 1323 | 1348 | extern unsigned IOCTL_TCSETSF; |
| 1324 | 1349 | extern unsigned IOCTL_TCSETSW; |
| 1350 | # endif | |
| 1325 | 1351 | extern unsigned IOCTL_TCXONC; |
| 1326 | 1352 | extern unsigned IOCTL_TIOCGLCKTRMIOS; |
| 1327 | 1353 | extern unsigned IOCTL_TIOCGSOFTCAR; |
lib/libtsan/sanitizer_common/sanitizer_posix.cpp+3-12| ... | ... | @@ -225,17 +225,9 @@ void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) { |
| 225 | 225 | return (void *)p; |
| 226 | 226 | } |
| 227 | 227 | |
| 228 | static inline bool IntervalsAreSeparate(uptr start1, uptr end1, | |
| 229 | uptr start2, uptr end2) { | |
| 230 | CHECK(start1 <= end1); | |
| 231 | CHECK(start2 <= end2); | |
| 232 | return (end1 < start2) || (end2 < start1); | |
| 233 | } | |
| 234 | ||
| 228 | # if !SANITIZER_APPLE | |
| 235 | 229 | // FIXME: this is thread-unsafe, but should not cause problems most of the time. |
| 236 | // When the shadow is mapped only a single thread usually exists (plus maybe | |
| 237 | // several worker threads on Mac, which aren't expected to map big chunks of | |
| 238 | // memory). | |
| 230 | // When the shadow is mapped only a single thread usually exists | |
| 239 | 231 | bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { |
| 240 | 232 | MemoryMappingLayout proc_maps(/*cache_enabled*/true); |
| 241 | 233 | if (proc_maps.Error()) |
| ... | ... | @@ -251,7 +243,6 @@ bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { |
| 251 | 243 | return true; |
| 252 | 244 | } |
| 253 | 245 | |
| 254 | #if !SANITIZER_APPLE | |
| 255 | 246 | void DumpProcessMap() { |
| 256 | 247 | MemoryMappingLayout proc_maps(/*cache_enabled*/true); |
| 257 | 248 | const sptr kBufSize = 4095; |
| ... | ... | @@ -265,7 +256,7 @@ void DumpProcessMap() { |
| 265 | 256 | Report("End of process memory map.\n"); |
| 266 | 257 | UnmapOrDie(filename, kBufSize); |
| 267 | 258 | } |
| 268 | #endif | |
| 259 | # endif | |
| 269 | 260 | |
| 270 | 261 | const char *GetPwd() { |
| 271 | 262 | return GetEnv("PWD"); |
lib/libtsan/sanitizer_common/sanitizer_posix.h+2-1| ... | ... | @@ -67,7 +67,8 @@ uptr internal_ptrace(int request, int pid, void *addr, void *data); |
| 67 | 67 | uptr internal_waitpid(int pid, int *status, int options); |
| 68 | 68 | |
| 69 | 69 | int internal_fork(); |
| 70 | fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid); | |
| 70 | bool internal_spawn(const char* argv[], const char* envp[], pid_t* pid, | |
| 71 | fd_t fd_stdin, fd_t fd_stdout); | |
| 71 | 72 | |
| 72 | 73 | int internal_sysctl(const int *name, unsigned int namelen, void *oldp, |
| 73 | 74 | uptr *oldlenp, const void *newp, uptr newlen); |
lib/libtsan/sanitizer_common/sanitizer_posix_libcdep.cpp+19| ... | ... | @@ -47,6 +47,8 @@ typedef void (*sa_sigaction_t)(int, siginfo_t *, void *); |
| 47 | 47 | |
| 48 | 48 | namespace __sanitizer { |
| 49 | 49 | |
| 50 | [[maybe_unused]] static atomic_uint8_t signal_handler_is_from_sanitizer[64]; | |
| 51 | ||
| 50 | 52 | u32 GetUid() { |
| 51 | 53 | return getuid(); |
| 52 | 54 | } |
| ... | ... | @@ -210,6 +212,20 @@ void UnsetAlternateSignalStack() { |
| 210 | 212 | UnmapOrDie(oldstack.ss_sp, oldstack.ss_size); |
| 211 | 213 | } |
| 212 | 214 | |
| 215 | bool IsSignalHandlerFromSanitizer(int signum) { | |
| 216 | return atomic_load(&signal_handler_is_from_sanitizer[signum], | |
| 217 | memory_order_relaxed); | |
| 218 | } | |
| 219 | ||
| 220 | bool SetSignalHandlerFromSanitizer(int signum, bool new_state) { | |
| 221 | if (signum < 0 || static_cast<unsigned>(signum) >= | |
| 222 | ARRAY_SIZE(signal_handler_is_from_sanitizer)) | |
| 223 | return false; | |
| 224 | ||
| 225 | return atomic_exchange(&signal_handler_is_from_sanitizer[signum], new_state, | |
| 226 | memory_order_relaxed); | |
| 227 | } | |
| 228 | ||
| 213 | 229 | static void MaybeInstallSigaction(int signum, |
| 214 | 230 | SignalHandlerType handler) { |
| 215 | 231 | if (GetHandleSignalMode(signum) == kHandleSignalNo) return; |
| ... | ... | @@ -223,6 +239,9 @@ static void MaybeInstallSigaction(int signum, |
| 223 | 239 | if (common_flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK; |
| 224 | 240 | CHECK_EQ(0, internal_sigaction(signum, &sigact, nullptr)); |
| 225 | 241 | VReport(1, "Installed the sigaction for signal %d\n", signum); |
| 242 | ||
| 243 | if (common_flags()->cloak_sanitizer_signal_handlers) | |
| 244 | SetSignalHandlerFromSanitizer(signum, true); | |
| 226 | 245 | } |
| 227 | 246 | |
| 228 | 247 | void InstallDeadlySignalHandlers(SignalHandlerType handler) { |
lib/libtsan/sanitizer_common/sanitizer_procmaps_mac.cpp+102-37| ... | ... | @@ -20,18 +20,21 @@ |
| 20 | 20 | #include <mach/mach.h> |
| 21 | 21 | |
| 22 | 22 | // These are not available in older macOS SDKs. |
| 23 | #ifndef CPU_SUBTYPE_X86_64_H | |
| 24 | #define CPU_SUBTYPE_X86_64_H ((cpu_subtype_t)8) /* Haswell */ | |
| 25 | #endif | |
| 26 | #ifndef CPU_SUBTYPE_ARM_V7S | |
| 27 | #define CPU_SUBTYPE_ARM_V7S ((cpu_subtype_t)11) /* Swift */ | |
| 28 | #endif | |
| 29 | #ifndef CPU_SUBTYPE_ARM_V7K | |
| 30 | #define CPU_SUBTYPE_ARM_V7K ((cpu_subtype_t)12) | |
| 31 | #endif | |
| 32 | #ifndef CPU_TYPE_ARM64 | |
| 33 | #define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) | |
| 34 | #endif | |
| 23 | # ifndef CPU_SUBTYPE_X86_64_H | |
| 24 | # define CPU_SUBTYPE_X86_64_H ((cpu_subtype_t)8) /* Haswell */ | |
| 25 | # endif | |
| 26 | # ifndef CPU_SUBTYPE_ARM_V7S | |
| 27 | # define CPU_SUBTYPE_ARM_V7S ((cpu_subtype_t)11) /* Swift */ | |
| 28 | # endif | |
| 29 | # ifndef CPU_SUBTYPE_ARM_V7K | |
| 30 | # define CPU_SUBTYPE_ARM_V7K ((cpu_subtype_t)12) | |
| 31 | # endif | |
| 32 | # ifndef CPU_TYPE_ARM64 | |
| 33 | # define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) | |
| 34 | # endif | |
| 35 | # ifndef CPU_SUBTYPE_ARM64E | |
| 36 | # define CPU_SUBTYPE_ARM64E ((cpu_subtype_t)2) | |
| 37 | # endif | |
| 35 | 38 | |
| 36 | 39 | namespace __sanitizer { |
| 37 | 40 | |
| ... | ... | @@ -42,7 +45,6 @@ struct MemoryMappedSegmentData { |
| 42 | 45 | const char *current_load_cmd_addr; |
| 43 | 46 | u32 lc_type; |
| 44 | 47 | uptr base_virt_addr; |
| 45 | uptr addr_mask; | |
| 46 | 48 | }; |
| 47 | 49 | |
| 48 | 50 | template <typename Section> |
| ... | ... | @@ -51,12 +53,62 @@ static void NextSectionLoad(LoadedModule *module, MemoryMappedSegmentData *data, |
| 51 | 53 | const Section *sc = (const Section *)data->current_load_cmd_addr; |
| 52 | 54 | data->current_load_cmd_addr += sizeof(Section); |
| 53 | 55 | |
| 54 | uptr sec_start = (sc->addr & data->addr_mask) + data->base_virt_addr; | |
| 56 | uptr sec_start = sc->addr + data->base_virt_addr; | |
| 55 | 57 | uptr sec_end = sec_start + sc->size; |
| 56 | 58 | module->addAddressRange(sec_start, sec_end, /*executable=*/false, isWritable, |
| 57 | 59 | sc->sectname); |
| 58 | 60 | } |
| 59 | 61 | |
| 62 | static bool VerifyMemoryMapping(MemoryMappingLayout* mapping) { | |
| 63 | InternalMmapVector<LoadedModule> modules; | |
| 64 | modules.reserve(128); // matches DumpProcessMap | |
| 65 | mapping->DumpListOfModules(&modules); | |
| 66 | ||
| 67 | InternalMmapVector<LoadedModule::AddressRange> segments; | |
| 68 | for (uptr i = 0; i < modules.size(); ++i) { | |
| 69 | for (auto& range : modules[i].ranges()) { | |
| 70 | if (range.beg == range.end) | |
| 71 | continue; | |
| 72 | segments.push_back(range); | |
| 73 | } | |
| 74 | } | |
| 75 | ||
| 76 | // Verify that none of the segments overlap: | |
| 77 | // 1. Sort the segments by the start address | |
| 78 | // 2. Check that every segment starts after the previous one ends. | |
| 79 | Sort(segments.data(), segments.size(), | |
| 80 | [](LoadedModule::AddressRange& a, LoadedModule::AddressRange& b) { | |
| 81 | return a.beg < b.beg; | |
| 82 | }); | |
| 83 | ||
| 84 | // To avoid spam, we only print the report message once-per-process. | |
| 85 | static bool invalid_module_map_reported = false; | |
| 86 | bool well_formed = true; | |
| 87 | ||
| 88 | for (size_t i = 1; i < segments.size(); i++) { | |
| 89 | uptr cur_start = segments[i].beg; | |
| 90 | uptr prev_end = segments[i - 1].end; | |
| 91 | if (cur_start < prev_end) { | |
| 92 | well_formed = false; | |
| 93 | VReport(2, "Overlapping mappings: %s start = %p, %s end = %p\n", | |
| 94 | segments[i].name, (void*)cur_start, segments[i - 1].name, | |
| 95 | (void*)prev_end); | |
| 96 | if (!invalid_module_map_reported) { | |
| 97 | Report( | |
| 98 | "WARN: Invalid dyld module map detected. This is most likely a bug " | |
| 99 | "in the sanitizer.\n"); | |
| 100 | Report("WARN: Backtraces may be unreliable.\n"); | |
| 101 | invalid_module_map_reported = true; | |
| 102 | } | |
| 103 | } | |
| 104 | } | |
| 105 | ||
| 106 | for (auto& m : modules) m.clear(); | |
| 107 | ||
| 108 | mapping->Reset(); | |
| 109 | return well_formed; | |
| 110 | } | |
| 111 | ||
| 60 | 112 | void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { |
| 61 | 113 | // Don't iterate over sections when the caller hasn't set up the |
| 62 | 114 | // data pointer, when there are no sections, or when the segment |
| ... | ... | @@ -82,6 +134,7 @@ void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { |
| 82 | 134 | |
| 83 | 135 | MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) { |
| 84 | 136 | Reset(); |
| 137 | VerifyMemoryMapping(this); | |
| 85 | 138 | } |
| 86 | 139 | |
| 87 | 140 | MemoryMappingLayout::~MemoryMappingLayout() { |
| ... | ... | @@ -123,7 +176,7 @@ void MemoryMappingLayout::Reset() { |
| 123 | 176 | // The dyld load address should be unchanged throughout process execution, |
| 124 | 177 | // and it is expensive to compute once many libraries have been loaded, |
| 125 | 178 | // so cache it here and do not reset. |
| 126 | static mach_header *dyld_hdr = 0; | |
| 179 | static const mach_header* dyld_hdr = 0; | |
| 127 | 180 | static const char kDyldPath[] = "/usr/lib/dyld"; |
| 128 | 181 | static const int kDyldImageIdx = -1; |
| 129 | 182 | |
| ... | ... | @@ -187,17 +240,22 @@ typedef struct dyld_shared_cache_dylib_text_info |
| 187 | 240 | |
| 188 | 241 | extern bool _dyld_get_shared_cache_uuid(uuid_t uuid); |
| 189 | 242 | extern const void *_dyld_get_shared_cache_range(size_t *length); |
| 243 | extern intptr_t _dyld_get_image_slide(const struct mach_header* mh); | |
| 190 | 244 | extern int dyld_shared_cache_iterate_text( |
| 191 | 245 | const uuid_t cacheUuid, |
| 192 | 246 | void (^callback)(const dyld_shared_cache_dylib_text_info *info)); |
| 247 | SANITIZER_WEAK_IMPORT const struct mach_header* _dyld_get_dyld_header(void); | |
| 193 | 248 | } // extern "C" |
| 194 | 249 | |
| 195 | static mach_header *GetDyldImageHeaderViaSharedCache() { | |
| 250 | static const mach_header* GetDyldImageHeaderViaSharedCache() { | |
| 196 | 251 | uuid_t uuid; |
| 197 | 252 | bool hasCache = _dyld_get_shared_cache_uuid(uuid); |
| 198 | 253 | if (!hasCache) |
| 199 | 254 | return nullptr; |
| 200 | 255 | |
| 256 | if (&_dyld_get_dyld_header != nullptr) | |
| 257 | return _dyld_get_dyld_header(); | |
| 258 | ||
| 201 | 259 | size_t cacheLength; |
| 202 | 260 | __block uptr cacheStart = (uptr)_dyld_get_shared_cache_range(&cacheLength); |
| 203 | 261 | CHECK(cacheStart && cacheLength); |
| ... | ... | @@ -255,23 +313,21 @@ static bool NextSegmentLoad(MemoryMappedSegment *segment, |
| 255 | 313 | layout_data->current_load_cmd_count--; |
| 256 | 314 | if (((const load_command *)lc)->cmd == kLCSegment) { |
| 257 | 315 | const SegmentCommand* sc = (const SegmentCommand *)lc; |
| 258 | uptr base_virt_addr, addr_mask; | |
| 259 | if (layout_data->current_image == kDyldImageIdx) { | |
| 260 | base_virt_addr = (uptr)get_dyld_hdr(); | |
| 261 | // vmaddr is masked with 0xfffff because on macOS versions < 10.12, | |
| 262 | // it contains an absolute address rather than an offset for dyld. | |
| 263 | // To make matters even more complicated, this absolute address | |
| 264 | // isn't actually the absolute segment address, but the offset portion | |
| 265 | // of the address is accurate when combined with the dyld base address, | |
| 266 | // and the mask will give just this offset. | |
| 267 | addr_mask = 0xfffff; | |
| 268 | } else { | |
| 316 | if (internal_strcmp(sc->segname, "__LINKEDIT") == 0) { | |
| 317 | // The LINKEDIT sections are for internal linker use, and may alias | |
| 318 | // with the LINKEDIT section for other modules. (If we included them, | |
| 319 | // our memory map would contain overlappping sections.) | |
| 320 | return false; | |
| 321 | } | |
| 322 | ||
| 323 | uptr base_virt_addr; | |
| 324 | if (layout_data->current_image == kDyldImageIdx) | |
| 325 | base_virt_addr = (uptr)_dyld_get_image_slide(get_dyld_hdr()); | |
| 326 | else | |
| 269 | 327 | base_virt_addr = |
| 270 | 328 | (uptr)_dyld_get_image_vmaddr_slide(layout_data->current_image); |
| 271 | addr_mask = ~0; | |
| 272 | } | |
| 273 | 329 | |
| 274 | segment->start = (sc->vmaddr & addr_mask) + base_virt_addr; | |
| 330 | segment->start = sc->vmaddr + base_virt_addr; | |
| 275 | 331 | segment->end = segment->start + sc->vmsize; |
| 276 | 332 | // Most callers don't need section information, so only fill this struct |
| 277 | 333 | // when required. |
| ... | ... | @@ -281,9 +337,9 @@ static bool NextSegmentLoad(MemoryMappedSegment *segment, |
| 281 | 337 | (const char *)lc + sizeof(SegmentCommand); |
| 282 | 338 | seg_data->lc_type = kLCSegment; |
| 283 | 339 | seg_data->base_virt_addr = base_virt_addr; |
| 284 | seg_data->addr_mask = addr_mask; | |
| 285 | 340 | internal_strncpy(seg_data->name, sc->segname, |
| 286 | 341 | ARRAY_SIZE(seg_data->name)); |
| 342 | seg_data->name[ARRAY_SIZE(seg_data->name) - 1] = 0; | |
| 287 | 343 | } |
| 288 | 344 | |
| 289 | 345 | // Return the initial protection. |
| ... | ... | @@ -297,6 +353,7 @@ static bool NextSegmentLoad(MemoryMappedSegment *segment, |
| 297 | 353 | ? kDyldPath |
| 298 | 354 | : _dyld_get_image_name(layout_data->current_image); |
| 299 | 355 | internal_strncpy(segment->filename, src, segment->filename_size); |
| 356 | segment->filename[segment->filename_size - 1] = 0; | |
| 300 | 357 | } |
| 301 | 358 | segment->arch = layout_data->current_arch; |
| 302 | 359 | internal_memcpy(segment->uuid, layout_data->current_uuid, kModuleUUIDSize); |
| ... | ... | @@ -311,18 +368,26 @@ ModuleArch ModuleArchFromCpuType(cpu_type_t cputype, cpu_subtype_t cpusubtype) { |
| 311 | 368 | case CPU_TYPE_I386: |
| 312 | 369 | return kModuleArchI386; |
| 313 | 370 | case CPU_TYPE_X86_64: |
| 314 | if (cpusubtype == CPU_SUBTYPE_X86_64_ALL) return kModuleArchX86_64; | |
| 315 | if (cpusubtype == CPU_SUBTYPE_X86_64_H) return kModuleArchX86_64H; | |
| 371 | if (cpusubtype == CPU_SUBTYPE_X86_64_ALL) | |
| 372 | return kModuleArchX86_64; | |
| 373 | if (cpusubtype == CPU_SUBTYPE_X86_64_H) | |
| 374 | return kModuleArchX86_64H; | |
| 316 | 375 | CHECK(0 && "Invalid subtype of x86_64"); |
| 317 | 376 | return kModuleArchUnknown; |
| 318 | 377 | case CPU_TYPE_ARM: |
| 319 | if (cpusubtype == CPU_SUBTYPE_ARM_V6) return kModuleArchARMV6; | |
| 320 | if (cpusubtype == CPU_SUBTYPE_ARM_V7) return kModuleArchARMV7; | |
| 321 | if (cpusubtype == CPU_SUBTYPE_ARM_V7S) return kModuleArchARMV7S; | |
| 322 | if (cpusubtype == CPU_SUBTYPE_ARM_V7K) return kModuleArchARMV7K; | |
| 378 | if (cpusubtype == CPU_SUBTYPE_ARM_V6) | |
| 379 | return kModuleArchARMV6; | |
| 380 | if (cpusubtype == CPU_SUBTYPE_ARM_V7) | |
| 381 | return kModuleArchARMV7; | |
| 382 | if (cpusubtype == CPU_SUBTYPE_ARM_V7S) | |
| 383 | return kModuleArchARMV7S; | |
| 384 | if (cpusubtype == CPU_SUBTYPE_ARM_V7K) | |
| 385 | return kModuleArchARMV7K; | |
| 323 | 386 | CHECK(0 && "Invalid subtype of ARM"); |
| 324 | 387 | return kModuleArchUnknown; |
| 325 | 388 | case CPU_TYPE_ARM64: |
| 389 | if (cpusubtype == CPU_SUBTYPE_ARM64E) | |
| 390 | return kModuleArchARM64E; | |
| 326 | 391 | return kModuleArchARM64; |
| 327 | 392 | default: |
| 328 | 393 | CHECK(0 && "Invalid CPU type"); |
lib/libtsan/sanitizer_common/sanitizer_redefine_builtins.h+1-1| ... | ... | @@ -15,7 +15,7 @@ |
| 15 | 15 | # define SANITIZER_REDEFINE_BUILTINS_H |
| 16 | 16 | |
| 17 | 17 | // The asm hack only works with GCC and Clang. |
| 18 | # if !defined(_WIN32) && !defined(_AIX) | |
| 18 | # if !defined(_WIN32) && !defined(_AIX) && !defined(__APPLE__) | |
| 19 | 19 | |
| 20 | 20 | asm(R"( |
| 21 | 21 | .set memcpy, __sanitizer_internal_memcpy |
lib/libtsan/sanitizer_common/sanitizer_signal_interceptors.inc+40-2| ... | ... | @@ -45,6 +45,8 @@ using namespace __sanitizer; |
| 45 | 45 | INTERCEPTOR(uptr, bsd_signal, int signum, uptr handler) { |
| 46 | 46 | SIGNAL_INTERCEPTOR_ENTER(); |
| 47 | 47 | if (GetHandleSignalMode(signum) == kHandleSignalExclusive) return 0; |
| 48 | ||
| 49 | // TODO: support cloak_sanitizer_signal_handlers | |
| 48 | 50 | SIGNAL_INTERCEPTOR_SIGNAL_IMPL(bsd_signal, signum, handler); |
| 49 | 51 | } |
| 50 | 52 | #define INIT_BSD_SIGNAL COMMON_INTERCEPT_FUNCTION(bsd_signal) |
| ... | ... | @@ -56,19 +58,55 @@ INTERCEPTOR(uptr, bsd_signal, int signum, uptr handler) { |
| 56 | 58 | INTERCEPTOR(uptr, signal, int signum, uptr handler) { |
| 57 | 59 | SIGNAL_INTERCEPTOR_ENTER(); |
| 58 | 60 | if (GetHandleSignalMode(signum) == kHandleSignalExclusive) |
| 61 | // The user can neither view nor change the signal handler, regardless of | |
| 62 | // the cloak_sanitizer_signal_handlers setting. This differs from | |
| 63 | // sigaction(). | |
| 59 | 64 | return (uptr) nullptr; |
| 60 | SIGNAL_INTERCEPTOR_SIGNAL_IMPL(signal, signum, handler); | |
| 65 | ||
| 66 | uptr ret = +[](auto signal, int signum, uptr handler) { | |
| 67 | SIGNAL_INTERCEPTOR_SIGNAL_IMPL(signal, signum, handler); | |
| 68 | }(signal, signum, handler); | |
| 69 | ||
| 70 | if (ret != sig_err && SetSignalHandlerFromSanitizer(signum, false)) | |
| 71 | // If the user sets a signal handler, it becomes uncloaked, even if they | |
| 72 | // reuse a sanitizer's signal handler. | |
| 73 | ret = sig_dfl; | |
| 74 | ||
| 75 | return ret; | |
| 61 | 76 | } |
| 62 | 77 | #define INIT_SIGNAL COMMON_INTERCEPT_FUNCTION(signal) |
| 63 | 78 | |
| 64 | 79 | INTERCEPTOR(int, sigaction_symname, int signum, |
| 65 | 80 | const __sanitizer_sigaction *act, __sanitizer_sigaction *oldact) { |
| 66 | 81 | SIGNAL_INTERCEPTOR_ENTER(); |
| 82 | ||
| 67 | 83 | if (GetHandleSignalMode(signum) == kHandleSignalExclusive) { |
| 68 | 84 | if (!oldact) return 0; |
| 69 | 85 | act = nullptr; |
| 86 | // If cloak_sanitizer_signal_handlers=true, the user can neither view nor | |
| 87 | // change the signal handle. | |
| 88 | // If false, the user can view but not change the signal handler. This | |
| 89 | // differs from signal(). | |
| 70 | 90 | } |
| 71 | SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signum, act, oldact); | |
| 91 | ||
| 92 | int ret = +[](int signum, const __sanitizer_sigaction* act, | |
| 93 | __sanitizer_sigaction* oldact) { | |
| 94 | SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signum, act, oldact); | |
| 95 | }(signum, act, oldact); | |
| 96 | ||
| 97 | if (act) { | |
| 98 | if (ret == 0 && SetSignalHandlerFromSanitizer(signum, false)) { | |
| 99 | // If the user sets a signal handler, it becomes uncloaked, even if they | |
| 100 | // reuse a sanitizer's signal handler. | |
| 101 | ||
| 102 | if (oldact) | |
| 103 | oldact->handler = reinterpret_cast<__sanitizer_sighandler_ptr>(sig_dfl); | |
| 104 | } | |
| 105 | } else if (ret == 0 && oldact && IsSignalHandlerFromSanitizer(signum)) { | |
| 106 | oldact->handler = reinterpret_cast<__sanitizer_sighandler_ptr>(sig_dfl); | |
| 107 | } | |
| 108 | ||
| 109 | return ret; | |
| 72 | 110 | } |
| 73 | 111 | #define INIT_SIGACTION COMMON_INTERCEPT_FUNCTION(sigaction_symname) |
| 74 | 112 |
lib/libtsan/sanitizer_common/sanitizer_stoptheworld.h+1-1| ... | ... | @@ -38,7 +38,7 @@ class SuspendedThreadsList { |
| 38 | 38 | } |
| 39 | 39 | |
| 40 | 40 | virtual uptr ThreadCount() const { UNIMPLEMENTED(); } |
| 41 | virtual tid_t GetThreadID(uptr index) const { UNIMPLEMENTED(); } | |
| 41 | virtual ThreadID GetThreadID(uptr index) const { UNIMPLEMENTED(); } | |
| 42 | 42 | |
| 43 | 43 | protected: |
| 44 | 44 | ~SuspendedThreadsList() {} |
lib/libtsan/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp+83-12| ... | ... | @@ -94,17 +94,17 @@ class SuspendedThreadsListLinux final : public SuspendedThreadsList { |
| 94 | 94 | public: |
| 95 | 95 | SuspendedThreadsListLinux() { thread_ids_.reserve(1024); } |
| 96 | 96 | |
| 97 | tid_t GetThreadID(uptr index) const override; | |
| 97 | ThreadID GetThreadID(uptr index) const override; | |
| 98 | 98 | uptr ThreadCount() const override; |
| 99 | bool ContainsTid(tid_t thread_id) const; | |
| 100 | void Append(tid_t tid); | |
| 99 | bool ContainsTid(ThreadID thread_id) const; | |
| 100 | void Append(ThreadID tid); | |
| 101 | 101 | |
| 102 | 102 | PtraceRegistersStatus GetRegistersAndSP(uptr index, |
| 103 | 103 | InternalMmapVector<uptr> *buffer, |
| 104 | 104 | uptr *sp) const override; |
| 105 | 105 | |
| 106 | 106 | private: |
| 107 | InternalMmapVector<tid_t> thread_ids_; | |
| 107 | InternalMmapVector<ThreadID> thread_ids_; | |
| 108 | 108 | }; |
| 109 | 109 | |
| 110 | 110 | // Structure for passing arguments into the tracer thread. |
| ... | ... | @@ -137,10 +137,10 @@ class ThreadSuspender { |
| 137 | 137 | private: |
| 138 | 138 | SuspendedThreadsListLinux suspended_threads_list_; |
| 139 | 139 | pid_t pid_; |
| 140 | bool SuspendThread(tid_t thread_id); | |
| 140 | bool SuspendThread(ThreadID thread_id); | |
| 141 | 141 | }; |
| 142 | 142 | |
| 143 | bool ThreadSuspender::SuspendThread(tid_t tid) { | |
| 143 | bool ThreadSuspender::SuspendThread(ThreadID tid) { | |
| 144 | 144 | int pterrno; |
| 145 | 145 | if (internal_iserror(internal_ptrace(PTRACE_ATTACH, tid, nullptr, nullptr), |
| 146 | 146 | &pterrno)) { |
| ... | ... | @@ -210,7 +210,7 @@ void ThreadSuspender::KillAllThreads() { |
| 210 | 210 | bool ThreadSuspender::SuspendAllThreads() { |
| 211 | 211 | ThreadLister thread_lister(pid_); |
| 212 | 212 | bool retry = true; |
| 213 | InternalMmapVector<tid_t> threads; | |
| 213 | InternalMmapVector<ThreadID> threads; | |
| 214 | 214 | threads.reserve(128); |
| 215 | 215 | for (int i = 0; i < 30 && retry; ++i) { |
| 216 | 216 | retry = false; |
| ... | ... | @@ -226,7 +226,7 @@ bool ThreadSuspender::SuspendAllThreads() { |
| 226 | 226 | case ThreadLister::Ok: |
| 227 | 227 | break; |
| 228 | 228 | } |
| 229 | for (tid_t tid : threads) { | |
| 229 | for (ThreadID tid : threads) { | |
| 230 | 230 | // Are we already attached to this thread? |
| 231 | 231 | // Currently this check takes linear time, however the number of threads |
| 232 | 232 | // is usually small. |
| ... | ... | @@ -403,7 +403,77 @@ struct ScopedSetTracerPID { |
| 403 | 403 | } |
| 404 | 404 | }; |
| 405 | 405 | |
| 406 | // This detects whether ptrace is blocked (e.g., by seccomp), by forking and | |
| 407 | // then attempting ptrace. | |
| 408 | // This separate check is necessary because StopTheWorld() creates a thread | |
| 409 | // with a shared virtual address space and shared TLS, and therefore | |
| 410 | // cannot use waitpid() due to the shared errno. | |
| 411 | static void TestPTrace() { | |
| 412 | # if SANITIZER_SPARC | |
| 413 | // internal_fork() on SPARC actually calls __fork(). We can't safely fork, | |
| 414 | // because it's possible seccomp has been configured to disallow fork() but | |
| 415 | // allow clone(). | |
| 416 | VReport(1, "WARNING: skipping TestPTrace() because this is SPARC\n"); | |
| 417 | VReport(1, | |
| 418 | "If seccomp blocks ptrace, LeakSanitizer may hang without further " | |
| 419 | "notice\n"); | |
| 420 | VReport( | |
| 421 | 1, | |
| 422 | "If seccomp does not block ptrace, you can safely ignore this warning\n"); | |
| 423 | # else | |
| 424 | // Heuristic: only check the first time this is called. This is not always | |
| 425 | // correct (e.g., user manually triggers leak detection, then updates | |
| 426 | // seccomp, then leak detection is triggered again). | |
| 427 | static bool checked = false; | |
| 428 | if (checked) | |
| 429 | return; | |
| 430 | checked = true; | |
| 431 | ||
| 432 | // Hopefully internal_fork() is not too expensive, thanks to copy-on-write. | |
| 433 | // Besides, this is only called the first time. | |
| 434 | // Note that internal_fork() on non-SPARC Linux actually calls | |
| 435 | // SYSCALL(clone); thus, it is reasonable to use it because if seccomp kills | |
| 436 | // TestPTrace(), it would have killed StopTheWorld() anyway. | |
| 437 | int pid = internal_fork(); | |
| 438 | ||
| 439 | if (pid < 0) { | |
| 440 | int rverrno; | |
| 441 | if (internal_iserror(pid, &rverrno)) | |
| 442 | VReport(0, "WARNING: TestPTrace() failed to fork (errno %d)\n", rverrno); | |
| 443 | ||
| 444 | // We don't abort the sanitizer - it's still worth letting the sanitizer | |
| 445 | // try. | |
| 446 | return; | |
| 447 | } | |
| 448 | ||
| 449 | if (pid == 0) { | |
| 450 | // Child subprocess | |
| 451 | ||
| 452 | // TODO: consider checking return value of internal_ptrace, to handle | |
| 453 | // SCMP_ACT_ERRNO. However, be careful not to consume too many | |
| 454 | // resources performing a proper ptrace. | |
| 455 | internal_ptrace(PTRACE_ATTACH, 0, nullptr, nullptr); | |
| 456 | internal__exit(0); | |
| 457 | } else { | |
| 458 | int wstatus; | |
| 459 | internal_waitpid(pid, &wstatus, 0); | |
| 460 | ||
| 461 | // Handle SCMP_ACT_KILL | |
| 462 | if (WIFSIGNALED(wstatus)) { | |
| 463 | VReport(0, | |
| 464 | "WARNING: ptrace appears to be blocked (is seccomp enabled?). " | |
| 465 | "LeakSanitizer may hang.\n"); | |
| 466 | VReport(0, "Child exited with signal %d.\n", WTERMSIG(wstatus)); | |
| 467 | // We don't abort the sanitizer - it's still worth letting the sanitizer | |
| 468 | // try. | |
| 469 | } | |
| 470 | } | |
| 471 | # endif | |
| 472 | } | |
| 473 | ||
| 406 | 474 | void StopTheWorld(StopTheWorldCallback callback, void *argument) { |
| 475 | TestPTrace(); | |
| 476 | ||
| 407 | 477 | StopTheWorldScope in_stoptheworld; |
| 408 | 478 | // Prepare the arguments for TracerThread. |
| 409 | 479 | struct TracerThreadArgument tracer_thread_argument; |
| ... | ... | @@ -457,7 +527,8 @@ void StopTheWorld(StopTheWorldCallback callback, void *argument) { |
| 457 | 527 | internal_prctl(PR_SET_PTRACER, tracer_pid, 0, 0, 0); |
| 458 | 528 | // Allow the tracer thread to start. |
| 459 | 529 | tracer_thread_argument.mutex.Unlock(); |
| 460 | // NOTE: errno is shared between this thread and the tracer thread. | |
| 530 | // NOTE: errno is shared between this thread and the tracer thread | |
| 531 | // (clone was called without CLONE_SETTLS / newtls). | |
| 461 | 532 | // internal_waitpid() may call syscall() which can access/spoil errno, |
| 462 | 533 | // so we can't call it now. Instead we for the tracer thread to finish using |
| 463 | 534 | // the spin loop below. Man page for sched_yield() says "In the Linux |
| ... | ... | @@ -546,7 +617,7 @@ static constexpr uptr kExtraRegs[] = {0}; |
| 546 | 617 | #error "Unsupported architecture" |
| 547 | 618 | #endif // SANITIZER_ANDROID && defined(__arm__) |
| 548 | 619 | |
| 549 | tid_t SuspendedThreadsListLinux::GetThreadID(uptr index) const { | |
| 620 | ThreadID SuspendedThreadsListLinux::GetThreadID(uptr index) const { | |
| 550 | 621 | CHECK_LT(index, thread_ids_.size()); |
| 551 | 622 | return thread_ids_[index]; |
| 552 | 623 | } |
| ... | ... | @@ -555,14 +626,14 @@ uptr SuspendedThreadsListLinux::ThreadCount() const { |
| 555 | 626 | return thread_ids_.size(); |
| 556 | 627 | } |
| 557 | 628 | |
| 558 | bool SuspendedThreadsListLinux::ContainsTid(tid_t thread_id) const { | |
| 629 | bool SuspendedThreadsListLinux::ContainsTid(ThreadID thread_id) const { | |
| 559 | 630 | for (uptr i = 0; i < thread_ids_.size(); i++) { |
| 560 | 631 | if (thread_ids_[i] == thread_id) return true; |
| 561 | 632 | } |
| 562 | 633 | return false; |
| 563 | 634 | } |
| 564 | 635 | |
| 565 | void SuspendedThreadsListLinux::Append(tid_t tid) { | |
| 636 | void SuspendedThreadsListLinux::Append(ThreadID tid) { | |
| 566 | 637 | thread_ids_.push_back(tid); |
| 567 | 638 | } |
| 568 | 639 |
lib/libtsan/sanitizer_common/sanitizer_stoptheworld_mac.cpp+3-3| ... | ... | @@ -23,7 +23,7 @@ |
| 23 | 23 | |
| 24 | 24 | namespace __sanitizer { |
| 25 | 25 | typedef struct { |
| 26 | tid_t tid; | |
| 26 | ThreadID tid; | |
| 27 | 27 | thread_t thread; |
| 28 | 28 | } SuspendedThreadInfo; |
| 29 | 29 | |
| ... | ... | @@ -31,7 +31,7 @@ class SuspendedThreadsListMac final : public SuspendedThreadsList { |
| 31 | 31 | public: |
| 32 | 32 | SuspendedThreadsListMac() = default; |
| 33 | 33 | |
| 34 | tid_t GetThreadID(uptr index) const override; | |
| 34 | ThreadID GetThreadID(uptr index) const override; | |
| 35 | 35 | thread_t GetThread(uptr index) const; |
| 36 | 36 | uptr ThreadCount() const override; |
| 37 | 37 | bool ContainsThread(thread_t thread) const; |
| ... | ... | @@ -111,7 +111,7 @@ typedef x86_thread_state32_t regs_struct; |
| 111 | 111 | #error "Unsupported architecture" |
| 112 | 112 | #endif |
| 113 | 113 | |
| 114 | tid_t SuspendedThreadsListMac::GetThreadID(uptr index) const { | |
| 114 | ThreadID SuspendedThreadsListMac::GetThreadID(uptr index) const { | |
| 115 | 115 | CHECK_LT(index, threads_.size()); |
| 116 | 116 | return threads_[index].tid; |
| 117 | 117 | } |
lib/libtsan/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp+7-7| ... | ... | @@ -52,17 +52,17 @@ class SuspendedThreadsListNetBSD final : public SuspendedThreadsList { |
| 52 | 52 | public: |
| 53 | 53 | SuspendedThreadsListNetBSD() { thread_ids_.reserve(1024); } |
| 54 | 54 | |
| 55 | tid_t GetThreadID(uptr index) const; | |
| 55 | ThreadID GetThreadID(uptr index) const; | |
| 56 | 56 | uptr ThreadCount() const; |
| 57 | bool ContainsTid(tid_t thread_id) const; | |
| 58 | void Append(tid_t tid); | |
| 57 | bool ContainsTid(ThreadID thread_id) const; | |
| 58 | void Append(ThreadID tid); | |
| 59 | 59 | |
| 60 | 60 | PtraceRegistersStatus GetRegistersAndSP(uptr index, |
| 61 | 61 | InternalMmapVector<uptr> *buffer, |
| 62 | 62 | uptr *sp) const; |
| 63 | 63 | |
| 64 | 64 | private: |
| 65 | InternalMmapVector<tid_t> thread_ids_; | |
| 65 | InternalMmapVector<ThreadID> thread_ids_; | |
| 66 | 66 | }; |
| 67 | 67 | |
| 68 | 68 | struct TracerThreadArgument { |
| ... | ... | @@ -313,7 +313,7 @@ void StopTheWorld(StopTheWorldCallback callback, void *argument) { |
| 313 | 313 | } |
| 314 | 314 | } |
| 315 | 315 | |
| 316 | tid_t SuspendedThreadsListNetBSD::GetThreadID(uptr index) const { | |
| 316 | ThreadID SuspendedThreadsListNetBSD::GetThreadID(uptr index) const { | |
| 317 | 317 | CHECK_LT(index, thread_ids_.size()); |
| 318 | 318 | return thread_ids_[index]; |
| 319 | 319 | } |
| ... | ... | @@ -322,7 +322,7 @@ uptr SuspendedThreadsListNetBSD::ThreadCount() const { |
| 322 | 322 | return thread_ids_.size(); |
| 323 | 323 | } |
| 324 | 324 | |
| 325 | bool SuspendedThreadsListNetBSD::ContainsTid(tid_t thread_id) const { | |
| 325 | bool SuspendedThreadsListNetBSD::ContainsTid(ThreadID thread_id) const { | |
| 326 | 326 | for (uptr i = 0; i < thread_ids_.size(); i++) { |
| 327 | 327 | if (thread_ids_[i] == thread_id) |
| 328 | 328 | return true; |
| ... | ... | @@ -330,7 +330,7 @@ bool SuspendedThreadsListNetBSD::ContainsTid(tid_t thread_id) const { |
| 330 | 330 | return false; |
| 331 | 331 | } |
| 332 | 332 | |
| 333 | void SuspendedThreadsListNetBSD::Append(tid_t tid) { | |
| 333 | void SuspendedThreadsListNetBSD::Append(ThreadID tid) { | |
| 334 | 334 | thread_ids_.push_back(tid); |
| 335 | 335 | } |
| 336 | 336 |
lib/libtsan/sanitizer_common/sanitizer_stoptheworld_win.cpp+2-2| ... | ... | @@ -38,7 +38,7 @@ struct SuspendedThreadsListWindows final : public SuspendedThreadsList { |
| 38 | 38 | InternalMmapVector<uptr> *buffer, |
| 39 | 39 | uptr *sp) const override; |
| 40 | 40 | |
| 41 | tid_t GetThreadID(uptr index) const override; | |
| 41 | ThreadID GetThreadID(uptr index) const override; | |
| 42 | 42 | uptr ThreadCount() const override; |
| 43 | 43 | }; |
| 44 | 44 | |
| ... | ... | @@ -68,7 +68,7 @@ PtraceRegistersStatus SuspendedThreadsListWindows::GetRegistersAndSP( |
| 68 | 68 | return REGISTERS_AVAILABLE; |
| 69 | 69 | } |
| 70 | 70 | |
| 71 | tid_t SuspendedThreadsListWindows::GetThreadID(uptr index) const { | |
| 71 | ThreadID SuspendedThreadsListWindows::GetThreadID(uptr index) const { | |
| 72 | 72 | CHECK_LT(index, threadIds.size()); |
| 73 | 73 | return threadIds[index]; |
| 74 | 74 | } |
lib/libtsan/sanitizer_common/sanitizer_symbolizer_internal.h+5-1| ... | ... | @@ -83,7 +83,7 @@ class SymbolizerProcess { |
| 83 | 83 | const char *SendCommand(const char *command); |
| 84 | 84 | |
| 85 | 85 | protected: |
| 86 | ~SymbolizerProcess() {} | |
| 86 | ~SymbolizerProcess(); | |
| 87 | 87 | |
| 88 | 88 | /// The maximum number of arguments required to invoke a tool process. |
| 89 | 89 | static const unsigned kArgVMax = 16; |
| ... | ... | @@ -114,6 +114,10 @@ class SymbolizerProcess { |
| 114 | 114 | fd_t input_fd_; |
| 115 | 115 | fd_t output_fd_; |
| 116 | 116 | |
| 117 | // We hold on to the child's stdin fd (the read end of the pipe) | |
| 118 | // so that when we write to it, we don't get a SIGPIPE | |
| 119 | fd_t child_stdin_fd_; | |
| 120 | ||
| 117 | 121 | InternalMmapVector<char> buffer_; |
| 118 | 122 | |
| 119 | 123 | static const uptr kMaxTimesRestarted = 5; |
lib/libtsan/sanitizer_common/sanitizer_symbolizer_libcdep.cpp+11-1| ... | ... | @@ -476,10 +476,11 @@ const char *LLVMSymbolizer::FormatAndSendCommand(const char *command_prefix, |
| 476 | 476 | return symbolizer_process_->SendCommand(buffer_); |
| 477 | 477 | } |
| 478 | 478 | |
| 479 | SymbolizerProcess::SymbolizerProcess(const char *path, bool use_posix_spawn) | |
| 479 | SymbolizerProcess::SymbolizerProcess(const char* path, bool use_posix_spawn) | |
| 480 | 480 | : path_(path), |
| 481 | 481 | input_fd_(kInvalidFd), |
| 482 | 482 | output_fd_(kInvalidFd), |
| 483 | child_stdin_fd_(kInvalidFd), | |
| 483 | 484 | times_restarted_(0), |
| 484 | 485 | failed_to_start_(false), |
| 485 | 486 | reported_invalid_path_(false), |
| ... | ... | @@ -488,6 +489,11 @@ SymbolizerProcess::SymbolizerProcess(const char *path, bool use_posix_spawn) |
| 488 | 489 | CHECK_NE(path_[0], '\0'); |
| 489 | 490 | } |
| 490 | 491 | |
| 492 | SymbolizerProcess::~SymbolizerProcess() { | |
| 493 | if (child_stdin_fd_ != kInvalidFd) | |
| 494 | CloseFile(child_stdin_fd_); | |
| 495 | } | |
| 496 | ||
| 491 | 497 | static bool IsSameModule(const char *path) { |
| 492 | 498 | if (const char *ProcessName = GetProcessName()) { |
| 493 | 499 | if (const char *SymbolizerName = StripModuleName(path)) { |
| ... | ... | @@ -533,6 +539,10 @@ bool SymbolizerProcess::Restart() { |
| 533 | 539 | CloseFile(input_fd_); |
| 534 | 540 | if (output_fd_ != kInvalidFd) |
| 535 | 541 | CloseFile(output_fd_); |
| 542 | if (child_stdin_fd_ != kInvalidFd) { | |
| 543 | CloseFile(child_stdin_fd_); | |
| 544 | child_stdin_fd_ = kInvalidFd; // Don't free in destructor | |
| 545 | } | |
| 536 | 546 | return StartSymbolizerSubprocess(); |
| 537 | 547 | } |
| 538 | 548 |
lib/libtsan/sanitizer_common/sanitizer_symbolizer_mac.cpp+86-29| ... | ... | @@ -78,13 +78,25 @@ class AtosSymbolizerProcess final : public SymbolizerProcess { |
| 78 | 78 | } |
| 79 | 79 | |
| 80 | 80 | bool ReachedEndOfOutput(const char *buffer, uptr length) const override { |
| 81 | return (length >= 1 && buffer[length - 1] == '\n'); | |
| 81 | if (common_flags()->symbolize_inline_frames) { | |
| 82 | // When running with -i, atos sends two newlines at the end of each | |
| 83 | // address it symbolizes. This indicates the end of the set of frames | |
| 84 | // for a particular address. | |
| 85 | return length >= 2 && buffer[length - 1] == '\n' && | |
| 86 | buffer[length - 2] == '\n'; | |
| 87 | } else { | |
| 88 | // When running without -i, atos only sends a single newline at | |
| 89 | // the end of each address it symbolizes. | |
| 90 | return length >= 1 && buffer[length - 1] == '\n'; | |
| 91 | } | |
| 82 | 92 | } |
| 83 | 93 | |
| 84 | 94 | void GetArgV(const char *path_to_binary, |
| 85 | 95 | const char *(&argv)[kArgVMax]) const override { |
| 86 | 96 | int i = 0; |
| 87 | 97 | argv[i++] = path_to_binary; |
| 98 | if (common_flags()->symbolize_inline_frames) | |
| 99 | argv[i++] = "-i"; | |
| 88 | 100 | argv[i++] = "-p"; |
| 89 | 101 | argv[i++] = &pid_str_[0]; |
| 90 | 102 | if (GetMacosAlignedVersion() == MacosVersion(10, 9)) { |
| ... | ... | @@ -102,12 +114,16 @@ class AtosSymbolizerProcess final : public SymbolizerProcess { |
| 102 | 114 | |
| 103 | 115 | #undef K_ATOS_ENV_VAR |
| 104 | 116 | |
| 105 | static bool ParseCommandOutput(const char *str, uptr addr, char **out_name, | |
| 106 | char **out_module, char **out_file, uptr *line, | |
| 107 | uptr *start_address) { | |
| 117 | // Parses a single frame (one line) from str, and returns the pointer to the | |
| 118 | // next character to parse (i.e. after the newline) if successful. If | |
| 119 | // it fails, returns NULL. | |
| 120 | static const char* ParseCommandOutput(const char* str, uptr addr, | |
| 121 | char** out_name, char** out_module, | |
| 122 | char** out_file, uptr* line, | |
| 123 | uptr* start_address) { | |
| 108 | 124 | // Trim ending newlines. |
| 109 | 125 | char *trim; |
| 110 | ExtractTokenUpToDelimiter(str, "\n", &trim); | |
| 126 | str = ExtractTokenUpToDelimiter(str, "\n", &trim); | |
| 111 | 127 | |
| 112 | 128 | // The line from `atos` is in one of these formats: |
| 113 | 129 | // myfunction (in library.dylib) (sourcefile.c:17) |
| ... | ... | @@ -124,7 +140,7 @@ static bool ParseCommandOutput(const char *str, uptr addr, char **out_name, |
| 124 | 140 | if (rest[0] == '\0') { |
| 125 | 141 | InternalFree(symbol_name); |
| 126 | 142 | InternalFree(trim); |
| 127 | return false; | |
| 143 | return NULL; | |
| 128 | 144 | } |
| 129 | 145 | |
| 130 | 146 | if (internal_strncmp(symbol_name, "0x", 2) != 0) |
| ... | ... | @@ -149,7 +165,7 @@ static bool ParseCommandOutput(const char *str, uptr addr, char **out_name, |
| 149 | 165 | } |
| 150 | 166 | |
| 151 | 167 | InternalFree(trim); |
| 152 | return true; | |
| 168 | return str; | |
| 153 | 169 | } |
| 154 | 170 | |
| 155 | 171 | AtosSymbolizer::AtosSymbolizer(const char *path, LowLevelAllocator *allocator) |
| ... | ... | @@ -161,31 +177,72 @@ bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { |
| 161 | 177 | char command[32]; |
| 162 | 178 | internal_snprintf(command, sizeof(command), "0x%zx\n", addr); |
| 163 | 179 | const char *buf = process_->SendCommand(command); |
| 164 | if (!buf) return false; | |
| 165 | uptr line; | |
| 166 | uptr start_address = AddressInfo::kUnknown; | |
| 167 | if (!ParseCommandOutput(buf, addr, &stack->info.function, &stack->info.module, | |
| 168 | &stack->info.file, &line, &start_address)) { | |
| 169 | Report("WARNING: atos failed to symbolize address \"0x%zx\"\n", addr); | |
| 180 | if (!buf) | |
| 170 | 181 | return false; |
| 171 | } | |
| 172 | stack->info.line = (int)line; | |
| 173 | ||
| 174 | if (start_address == AddressInfo::kUnknown) { | |
| 175 | // Fallback to dladdr() to get function start address if atos doesn't report | |
| 176 | // it. | |
| 177 | Dl_info info; | |
| 178 | int result = dladdr((const void *)addr, &info); | |
| 179 | if (result) | |
| 180 | start_address = reinterpret_cast<uptr>(info.dli_saddr); | |
| 181 | } | |
| 182 | 182 | |
| 183 | // Only assign to `function_offset` if we were able to get the function's | |
| 184 | // start address and we got a sensible `start_address` (dladdr doesn't always | |
| 185 | // ensure that `addr >= sym_addr`). | |
| 186 | if (start_address != AddressInfo::kUnknown && addr >= start_address) { | |
| 187 | stack->info.function_offset = addr - start_address; | |
| 183 | SymbolizedStack* last = stack; | |
| 184 | bool top_frame = true; | |
| 185 | ||
| 186 | // Parse one line of input (i.e. one frame). | |
| 187 | // | |
| 188 | // When symbolize_inline_frames=true, an empty line | |
| 189 | // (i.e. \n at the beginning of a line) indicates that the last | |
| 190 | // frame has been sent. | |
| 191 | // | |
| 192 | // When symbolize_inline_frames=false, the symbolizer will send only | |
| 193 | // one frame (without a empty line), so loop runs exactly once | |
| 194 | // and hits an early `break`. | |
| 195 | while (*buf != '\n') { | |
| 196 | uptr line; | |
| 197 | uptr start_address = AddressInfo::kUnknown; | |
| 198 | ||
| 199 | SymbolizedStack* cur; | |
| 200 | if (top_frame) { | |
| 201 | cur = stack; | |
| 202 | } else { | |
| 203 | cur = SymbolizedStack::New(stack->info.address); | |
| 204 | cur->info.FillModuleInfo(stack->info.module, stack->info.module_offset, | |
| 205 | stack->info.module_arch); | |
| 206 | last->next = cur; | |
| 207 | last = cur; | |
| 208 | } | |
| 209 | ||
| 210 | // Parse one line of input (i.e. one frame) | |
| 211 | // If this succeeds, buf will be updated to point to the first character | |
| 212 | // after the newline. | |
| 213 | buf = ParseCommandOutput(buf, addr, &cur->info.function, &cur->info.module, | |
| 214 | &cur->info.file, &line, &start_address); | |
| 215 | ||
| 216 | // Upon failure, ParseCommandOutput returns NULL. | |
| 217 | if (!buf) { | |
| 218 | Report("WARNING: atos failed to symbolize address \"0x%zx\"\n", addr); | |
| 219 | return false; | |
| 220 | } | |
| 221 | cur->info.line = (int)line; | |
| 222 | ||
| 223 | if (top_frame && start_address == AddressInfo::kUnknown) { | |
| 224 | // Fallback to dladdr() to get function start address if atos doesn't | |
| 225 | // report it. | |
| 226 | Dl_info info; | |
| 227 | int result = dladdr((const void*)addr, &info); | |
| 228 | if (result) | |
| 229 | start_address = reinterpret_cast<uptr>(info.dli_saddr); | |
| 230 | } | |
| 231 | ||
| 232 | // Only assign to `function_offset` if we were able to get the function's | |
| 233 | // start address and we got a sensible `start_address` (dladdr doesn't | |
| 234 | // always ensure that `addr >= sym_addr`). | |
| 235 | if (start_address != AddressInfo::kUnknown && addr >= start_address) { | |
| 236 | cur->info.function_offset = addr - start_address; | |
| 237 | } | |
| 238 | ||
| 239 | // atos only sends one line when inline frames are off | |
| 240 | if (!common_flags()->symbolize_inline_frames) | |
| 241 | break; | |
| 242 | ||
| 243 | top_frame = false; | |
| 188 | 244 | } |
| 245 | ||
| 189 | 246 | return true; |
| 190 | 247 | } |
| 191 | 248 |
lib/libtsan/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp+27-16| ... | ... | @@ -156,30 +156,34 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() { |
| 156 | 156 | Printf("\n"); |
| 157 | 157 | } |
| 158 | 158 | |
| 159 | fd_t infd[2] = {}, outfd[2] = {}; | |
| 160 | if (!CreateTwoHighNumberedPipes(infd, outfd)) { | |
| 161 | Report( | |
| 162 | "WARNING: Can't create a socket pair to start " | |
| 163 | "external symbolizer (errno: %d)\n", | |
| 164 | errno); | |
| 165 | return false; | |
| 166 | } | |
| 167 | ||
| 159 | 168 | if (use_posix_spawn_) { |
| 160 | 169 | # if SANITIZER_APPLE |
| 161 | fd_t fd = internal_spawn(argv, const_cast<const char **>(GetEnvP()), &pid); | |
| 162 | if (fd == kInvalidFd) { | |
| 170 | bool success = internal_spawn(argv, const_cast<const char**>(GetEnvP()), | |
| 171 | &pid, outfd[0], infd[1]); | |
| 172 | if (!success) { | |
| 163 | 173 | Report("WARNING: failed to spawn external symbolizer (errno: %d)\n", |
| 164 | 174 | errno); |
| 175 | internal_close(infd[0]); | |
| 176 | internal_close(outfd[1]); | |
| 165 | 177 | return false; |
| 166 | 178 | } |
| 167 | 179 | |
| 168 | input_fd_ = fd; | |
| 169 | output_fd_ = fd; | |
| 180 | // We intentionally hold on to the read-end so that we don't get a SIGPIPE | |
| 181 | child_stdin_fd_ = outfd[0]; | |
| 182 | ||
| 170 | 183 | # else // SANITIZER_APPLE |
| 171 | 184 | UNIMPLEMENTED(); |
| 172 | 185 | # endif // SANITIZER_APPLE |
| 173 | 186 | } else { |
| 174 | fd_t infd[2] = {}, outfd[2] = {}; | |
| 175 | if (!CreateTwoHighNumberedPipes(infd, outfd)) { | |
| 176 | Report( | |
| 177 | "WARNING: Can't create a socket pair to start " | |
| 178 | "external symbolizer (errno: %d)\n", | |
| 179 | errno); | |
| 180 | return false; | |
| 181 | } | |
| 182 | ||
| 183 | 187 | pid = StartSubprocess(path_, argv, GetEnvP(), /* stdin */ outfd[0], |
| 184 | 188 | /* stdout */ infd[1]); |
| 185 | 189 | if (pid < 0) { |
| ... | ... | @@ -187,11 +191,11 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() { |
| 187 | 191 | internal_close(outfd[1]); |
| 188 | 192 | return false; |
| 189 | 193 | } |
| 190 | ||
| 191 | input_fd_ = infd[0]; | |
| 192 | output_fd_ = outfd[1]; | |
| 193 | 194 | } |
| 194 | 195 | |
| 196 | input_fd_ = infd[0]; | |
| 197 | output_fd_ = outfd[1]; | |
| 198 | ||
| 195 | 199 | CHECK_GT(pid, 0); |
| 196 | 200 | |
| 197 | 201 | // Check that symbolizer subprocess started successfully. |
| ... | ... | @@ -505,6 +509,13 @@ static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list, |
| 505 | 509 | } |
| 506 | 510 | |
| 507 | 511 | # if SANITIZER_APPLE |
| 512 | if (list->empty()) { | |
| 513 | Report( | |
| 514 | "WARN: No external symbolizers found. Symbols may be missing or " | |
| 515 | "unreliable.\n"); | |
| 516 | Report( | |
| 517 | "HINT: Is PATH set? Does sandbox allow file-read of /usr/bin/atos?\n"); | |
| 518 | } | |
| 508 | 519 | VReport(2, "Using dladdr symbolizer.\n"); |
| 509 | 520 | list->push_back(new (*allocator) DlAddrSymbolizer()); |
| 510 | 521 | # endif // SANITIZER_APPLE |
lib/libtsan/sanitizer_common/sanitizer_thread_registry.cpp+5-4| ... | ... | @@ -80,7 +80,7 @@ void ThreadContextBase::SetFinished() { |
| 80 | 80 | OnFinished(); |
| 81 | 81 | } |
| 82 | 82 | |
| 83 | void ThreadContextBase::SetStarted(tid_t _os_id, ThreadType _thread_type, | |
| 83 | void ThreadContextBase::SetStarted(ThreadID _os_id, ThreadType _thread_type, | |
| 84 | 84 | void *arg) { |
| 85 | 85 | status = ThreadStatusRunning; |
| 86 | 86 | os_id = _os_id; |
| ... | ... | @@ -228,7 +228,8 @@ static bool FindThreadContextByOsIdCallback(ThreadContextBase *tctx, |
| 228 | 228 | tctx->status != ThreadStatusDead); |
| 229 | 229 | } |
| 230 | 230 | |
| 231 | ThreadContextBase *ThreadRegistry::FindThreadContextByOsIDLocked(tid_t os_id) { | |
| 231 | ThreadContextBase *ThreadRegistry::FindThreadContextByOsIDLocked( | |
| 232 | ThreadID os_id) { | |
| 232 | 233 | return FindThreadContextLocked(FindThreadContextByOsIdCallback, |
| 233 | 234 | (void *)os_id); |
| 234 | 235 | } |
| ... | ... | @@ -322,8 +323,8 @@ ThreadStatus ThreadRegistry::FinishThread(u32 tid) { |
| 322 | 323 | return prev_status; |
| 323 | 324 | } |
| 324 | 325 | |
| 325 | void ThreadRegistry::StartThread(u32 tid, tid_t os_id, ThreadType thread_type, | |
| 326 | void *arg) { | |
| 326 | void ThreadRegistry::StartThread(u32 tid, ThreadID os_id, | |
| 327 | ThreadType thread_type, void *arg) { | |
| 327 | 328 | ThreadRegistryLock l(this); |
| 328 | 329 | running_threads_++; |
| 329 | 330 | ThreadContextBase *tctx = threads_[tid]; |
lib/libtsan/sanitizer_common/sanitizer_thread_registry.h+4-4| ... | ... | @@ -43,7 +43,7 @@ class ThreadContextBase { |
| 43 | 43 | const u32 tid; // Thread ID. Main thread should have tid = 0. |
| 44 | 44 | u64 unique_id; // Unique thread ID. |
| 45 | 45 | u32 reuse_count; // Number of times this tid was reused. |
| 46 | tid_t os_id; // PID (used for reporting). | |
| 46 | ThreadID os_id; // PID (used for reporting). | |
| 47 | 47 | uptr user_id; // Some opaque user thread id (e.g. pthread_t). |
| 48 | 48 | char name[64]; // As annotated by user. |
| 49 | 49 | |
| ... | ... | @@ -62,7 +62,7 @@ class ThreadContextBase { |
| 62 | 62 | void SetDead(); |
| 63 | 63 | void SetJoined(void *arg); |
| 64 | 64 | void SetFinished(); |
| 65 | void SetStarted(tid_t _os_id, ThreadType _thread_type, void *arg); | |
| 65 | void SetStarted(ThreadID _os_id, ThreadType _thread_type, void *arg); | |
| 66 | 66 | void SetCreated(uptr _user_id, u64 _unique_id, bool _detached, |
| 67 | 67 | u32 _parent_tid, u32 _stack_tid, void *arg); |
| 68 | 68 | void Reset(); |
| ... | ... | @@ -126,7 +126,7 @@ class SANITIZER_MUTEX ThreadRegistry { |
| 126 | 126 | // is found. |
| 127 | 127 | ThreadContextBase *FindThreadContextLocked(FindThreadCallback cb, |
| 128 | 128 | void *arg); |
| 129 | ThreadContextBase *FindThreadContextByOsIDLocked(tid_t os_id); | |
| 129 | ThreadContextBase *FindThreadContextByOsIDLocked(ThreadID os_id); | |
| 130 | 130 | |
| 131 | 131 | void SetThreadName(u32 tid, const char *name); |
| 132 | 132 | void SetThreadNameByUserId(uptr user_id, const char *name); |
| ... | ... | @@ -134,7 +134,7 @@ class SANITIZER_MUTEX ThreadRegistry { |
| 134 | 134 | void JoinThread(u32 tid, void *arg); |
| 135 | 135 | // Finishes thread and returns previous status. |
| 136 | 136 | ThreadStatus FinishThread(u32 tid); |
| 137 | void StartThread(u32 tid, tid_t os_id, ThreadType thread_type, void *arg); | |
| 137 | void StartThread(u32 tid, ThreadID os_id, ThreadType thread_type, void *arg); | |
| 138 | 138 | u32 ConsumeThreadUserId(uptr user_id); |
| 139 | 139 | void SetThreadUserId(u32 tid, uptr user_id); |
| 140 | 140 |
lib/libtsan/sanitizer_common/sanitizer_win.cpp+1-3| ... | ... | @@ -108,9 +108,7 @@ int internal_dlinfo(void *handle, int request, void *p) { |
| 108 | 108 | |
| 109 | 109 | // In contrast to POSIX, on Windows GetCurrentThreadId() |
| 110 | 110 | // returns a system-unique identifier. |
| 111 | tid_t GetTid() { | |
| 112 | return GetCurrentThreadId(); | |
| 113 | } | |
| 111 | ThreadID GetTid() { return GetCurrentThreadId(); } | |
| 114 | 112 | |
| 115 | 113 | uptr GetThreadSelf() { |
| 116 | 114 | return GetTid(); |
lib/libtsan/tsan_debugging.cpp+2-2| ... | ... | @@ -165,7 +165,7 @@ int __tsan_get_report_mutex(void *report, uptr idx, uptr *mutex_id, void **addr, |
| 165 | 165 | } |
| 166 | 166 | |
| 167 | 167 | SANITIZER_INTERFACE_ATTRIBUTE |
| 168 | int __tsan_get_report_thread(void *report, uptr idx, int *tid, tid_t *os_id, | |
| 168 | int __tsan_get_report_thread(void *report, uptr idx, int *tid, ThreadID *os_id, | |
| 169 | 169 | int *running, const char **name, int *parent_tid, |
| 170 | 170 | void **trace, uptr trace_size) { |
| 171 | 171 | const ReportDesc *rep = (ReportDesc *)report; |
| ... | ... | @@ -242,7 +242,7 @@ const char *__tsan_locate_address(uptr addr, char *name, uptr name_size, |
| 242 | 242 | |
| 243 | 243 | SANITIZER_INTERFACE_ATTRIBUTE |
| 244 | 244 | int __tsan_get_alloc_stack(uptr addr, uptr *trace, uptr size, int *thread_id, |
| 245 | tid_t *os_id) { | |
| 245 | ThreadID *os_id) { | |
| 246 | 246 | MBlock *b = 0; |
| 247 | 247 | Allocator *a = allocator(); |
| 248 | 248 | if (a->PointerIsMine((void *)addr)) { |
lib/libtsan/tsan_flags.cpp+37| ... | ... | @@ -20,6 +20,43 @@ |
| 20 | 20 | #include "tsan_rtl.h" |
| 21 | 21 | #include "ubsan/ubsan_flags.h" |
| 22 | 22 | |
| 23 | #if SANITIZER_APPLE && !SANITIZER_GO | |
| 24 | namespace __sanitizer { | |
| 25 | ||
| 26 | template <> | |
| 27 | inline bool FlagHandler<LockDuringWriteSetting>::Parse(const char *value) { | |
| 28 | if (internal_strcmp(value, "on") == 0) { | |
| 29 | *t_ = kLockDuringAllWrites; | |
| 30 | return true; | |
| 31 | } | |
| 32 | if (internal_strcmp(value, "disable_for_current_process") == 0) { | |
| 33 | *t_ = kNoLockDuringWritesCurrentProcess; | |
| 34 | return true; | |
| 35 | } | |
| 36 | if (internal_strcmp(value, "disable_for_all_processes") == 0) { | |
| 37 | *t_ = kNoLockDuringWritesAllProcesses; | |
| 38 | return true; | |
| 39 | } | |
| 40 | Printf("ERROR: Invalid value for signal handler option: '%s'\n", value); | |
| 41 | return false; | |
| 42 | } | |
| 43 | ||
| 44 | template <> | |
| 45 | inline bool FlagHandler<LockDuringWriteSetting>::Format(char *buffer, | |
| 46 | uptr size) { | |
| 47 | switch (*t_) { | |
| 48 | case kLockDuringAllWrites: | |
| 49 | return FormatString(buffer, size, "on"); | |
| 50 | case kNoLockDuringWritesCurrentProcess: | |
| 51 | return FormatString(buffer, size, "disable_for_current_process"); | |
| 52 | case kNoLockDuringWritesAllProcesses: | |
| 53 | return FormatString(buffer, size, "disable_for_all_processes"); | |
| 54 | } | |
| 55 | } | |
| 56 | ||
| 57 | } // namespace __sanitizer | |
| 58 | #endif // SANITIZER_APPLE && !SANITIZER_GO | |
| 59 | ||
| 23 | 60 | namespace __tsan { |
| 24 | 61 | |
| 25 | 62 | // Can be overriden in frontend. |
lib/libtsan/tsan_flags.h+8| ... | ... | @@ -16,6 +16,14 @@ |
| 16 | 16 | #include "sanitizer_common/sanitizer_flags.h" |
| 17 | 17 | #include "sanitizer_common/sanitizer_deadlock_detector_interface.h" |
| 18 | 18 | |
| 19 | #if SANITIZER_APPLE && !SANITIZER_GO | |
| 20 | enum LockDuringWriteSetting { | |
| 21 | kLockDuringAllWrites, | |
| 22 | kNoLockDuringWritesCurrentProcess, | |
| 23 | kNoLockDuringWritesAllProcesses, | |
| 24 | }; | |
| 25 | #endif | |
| 26 | ||
| 19 | 27 | namespace __tsan { |
| 20 | 28 | |
| 21 | 29 | struct Flags : DDFlags { |
lib/libtsan/tsan_flags.inc+12| ... | ... | @@ -80,3 +80,15 @@ TSAN_FLAG(bool, shared_ptr_interceptor, true, |
| 80 | 80 | TSAN_FLAG(bool, print_full_thread_history, false, |
| 81 | 81 | "If set, prints thread creation stacks for the threads involved in " |
| 82 | 82 | "the report and their ancestors up to the main thread.") |
| 83 | ||
| 84 | #if SANITIZER_APPLE && !SANITIZER_GO | |
| 85 | TSAN_FLAG(LockDuringWriteSetting, lock_during_write, kLockDuringAllWrites, | |
| 86 | "Determines whether to obtain a lock while writing logs or error " | |
| 87 | "reports. " | |
| 88 | "\"on\" - [default] lock during all writes. " | |
| 89 | "\"disable_for_current_process\" - don't lock during all writes in " | |
| 90 | "the current process, but do lock for all writes in child " | |
| 91 | "processes." | |
| 92 | "\"disable_for_all_processes\" - don't lock during all writes in " | |
| 93 | "the current process and it's children processes.") | |
| 94 | #endif |
lib/libtsan/tsan_interceptors.h+9-1| ... | ... | @@ -1,6 +1,9 @@ |
| 1 | 1 | #ifndef TSAN_INTERCEPTORS_H |
| 2 | 2 | #define TSAN_INTERCEPTORS_H |
| 3 | 3 | |
| 4 | #if SANITIZER_APPLE && !SANITIZER_GO | |
| 5 | # include "sanitizer_common/sanitizer_mac.h" | |
| 6 | #endif | |
| 4 | 7 | #include "sanitizer_common/sanitizer_stacktrace.h" |
| 5 | 8 | #include "tsan_rtl.h" |
| 6 | 9 | |
| ... | ... | @@ -43,7 +46,12 @@ inline bool in_symbolizer() { |
| 43 | 46 | #endif |
| 44 | 47 | |
| 45 | 48 | inline bool MustIgnoreInterceptor(ThreadState *thr) { |
| 46 | return !thr->is_inited || thr->ignore_interceptors || thr->in_ignored_lib; | |
| 49 | return !thr->is_inited || thr->ignore_interceptors || thr->in_ignored_lib | |
| 50 | #if SANITIZER_APPLE && !SANITIZER_GO | |
| 51 | || (flags()->lock_during_write != kLockDuringAllWrites && | |
| 52 | thr->in_internal_write_call) | |
| 53 | #endif | |
| 54 | ; | |
| 47 | 55 | } |
| 48 | 56 | |
| 49 | 57 | } // namespace __tsan |
lib/libtsan/tsan_interceptors_mac.cpp+19| ... | ... | @@ -281,6 +281,25 @@ TSAN_INTERCEPTOR(void, os_unfair_lock_lock, os_unfair_lock_t lock) { |
| 281 | 281 | Acquire(thr, pc, (uptr)lock); |
| 282 | 282 | } |
| 283 | 283 | |
| 284 | // os_unfair_lock_lock_with_flags was introduced in macOS 15 | |
| 285 | # if defined(__MAC_15_0) || defined(__IPHONE_18_0) || defined(__TVOS_18_0) || \ | |
| 286 | defined(__VISIONOS_2_0) || defined(__WATCHOS_11_0) | |
| 287 | # pragma clang diagnostic push | |
| 288 | # pragma clang diagnostic ignored "-Wunguarded-availability-new" | |
| 289 | // We're just intercepting this - if it doesn't exist on the platform, then the | |
| 290 | // process shouldn't have called it in the first place. | |
| 291 | TSAN_INTERCEPTOR(void, os_unfair_lock_lock_with_flags, os_unfair_lock_t lock, | |
| 292 | os_unfair_lock_flags_t flags) { | |
| 293 | if (!cur_thread()->is_inited || cur_thread()->is_dead) { | |
| 294 | return REAL(os_unfair_lock_lock_with_flags)(lock, flags); | |
| 295 | } | |
| 296 | SCOPED_TSAN_INTERCEPTOR(os_unfair_lock_lock_with_flags, lock, flags); | |
| 297 | REAL(os_unfair_lock_lock_with_flags)(lock, flags); | |
| 298 | Acquire(thr, pc, (uptr)lock); | |
| 299 | } | |
| 300 | # pragma clang diagnostic pop | |
| 301 | # endif | |
| 302 | ||
| 284 | 303 | TSAN_INTERCEPTOR(void, os_unfair_lock_lock_with_options, os_unfair_lock_t lock, |
| 285 | 304 | u32 options) { |
| 286 | 305 | if (!cur_thread()->is_inited || cur_thread()->is_dead) { |
lib/libtsan/tsan_interceptors_posix.cpp+78-32| ... | ... | @@ -22,6 +22,7 @@ |
| 22 | 22 | #include "sanitizer_common/sanitizer_internal_defs.h" |
| 23 | 23 | #include "sanitizer_common/sanitizer_libc.h" |
| 24 | 24 | #include "sanitizer_common/sanitizer_linux.h" |
| 25 | #include "sanitizer_common/sanitizer_placement_new.h" | |
| 25 | 26 | #include "sanitizer_common/sanitizer_platform_interceptors.h" |
| 26 | 27 | #include "sanitizer_common/sanitizer_platform_limits_netbsd.h" |
| 27 | 28 | #include "sanitizer_common/sanitizer_platform_limits_posix.h" |
| ... | ... | @@ -30,6 +31,9 @@ |
| 30 | 31 | #include "sanitizer_common/sanitizer_tls_get_addr.h" |
| 31 | 32 | #include "sanitizer_common/sanitizer_vector.h" |
| 32 | 33 | #include "tsan_fd.h" |
| 34 | #if SANITIZER_APPLE && !SANITIZER_GO | |
| 35 | # include "tsan_flags.h" | |
| 36 | #endif | |
| 33 | 37 | #include "tsan_interceptors.h" |
| 34 | 38 | #include "tsan_interface.h" |
| 35 | 39 | #include "tsan_mman.h" |
| ... | ... | @@ -78,17 +82,6 @@ struct ucontext_t { |
| 78 | 82 | }; |
| 79 | 83 | #endif |
| 80 | 84 | |
| 81 | #if defined(__x86_64__) || defined(__mips__) || SANITIZER_PPC64V1 || \ | |
| 82 | defined(__s390x__) | |
| 83 | #define PTHREAD_ABI_BASE "GLIBC_2.3.2" | |
| 84 | #elif defined(__aarch64__) || SANITIZER_PPC64V2 | |
| 85 | #define PTHREAD_ABI_BASE "GLIBC_2.17" | |
| 86 | #elif SANITIZER_LOONGARCH64 | |
| 87 | #define PTHREAD_ABI_BASE "GLIBC_2.36" | |
| 88 | #elif SANITIZER_RISCV64 | |
| 89 | # define PTHREAD_ABI_BASE "GLIBC_2.27" | |
| 90 | #endif | |
| 91 | ||
| 92 | 85 | extern "C" int pthread_attr_init(void *attr); |
| 93 | 86 | extern "C" int pthread_attr_destroy(void *attr); |
| 94 | 87 | DECLARE_REAL(int, pthread_attr_getdetachstate, void *, void *) |
| ... | ... | @@ -340,11 +333,6 @@ void ScopedInterceptor::DisableIgnoresImpl() { |
| 340 | 333 | } |
| 341 | 334 | |
| 342 | 335 | #define TSAN_INTERCEPT(func) INTERCEPT_FUNCTION(func) |
| 343 | #if SANITIZER_FREEBSD || SANITIZER_NETBSD | |
| 344 | # define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION(func) | |
| 345 | #else | |
| 346 | # define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION_VER(func, ver) | |
| 347 | #endif | |
| 348 | 336 | #if SANITIZER_FREEBSD |
| 349 | 337 | # define TSAN_MAYBE_INTERCEPT_FREEBSD_ALIAS(func) \ |
| 350 | 338 | INTERCEPT_FUNCTION(_pthread_##func) |
| ... | ... | @@ -1145,6 +1133,22 @@ TSAN_INTERCEPTOR(int, pthread_create, |
| 1145 | 1133 | |
| 1146 | 1134 | TSAN_INTERCEPTOR(int, pthread_join, void *th, void **ret) { |
| 1147 | 1135 | SCOPED_INTERCEPTOR_RAW(pthread_join, th, ret); |
| 1136 | #if SANITIZER_ANDROID | |
| 1137 | { | |
| 1138 | // In Bionic, if the target thread has already exited when pthread_detach is | |
| 1139 | // called, pthread_detach will call pthread_join internally to clean it up. | |
| 1140 | // In that case, the thread has already been consumed by the pthread_detach | |
| 1141 | // interceptor. | |
| 1142 | Tid tid = ctx->thread_registry.FindThread( | |
| 1143 | [](ThreadContextBase* tctx, void* arg) { | |
| 1144 | return tctx->user_id == (uptr)arg; | |
| 1145 | }, | |
| 1146 | th); | |
| 1147 | if (tid == kInvalidTid) { | |
| 1148 | return REAL(pthread_join)(th, ret); | |
| 1149 | } | |
| 1150 | } | |
| 1151 | #endif | |
| 1148 | 1152 | Tid tid = ThreadConsumeTid(thr, pc, (uptr)th); |
| 1149 | 1153 | ThreadIgnoreBegin(thr, pc); |
| 1150 | 1154 | int res = BLOCK_REAL(pthread_join)(th, ret); |
| ... | ... | @@ -1664,6 +1668,14 @@ TSAN_INTERCEPTOR(int, pthread_barrier_wait, void *b) { |
| 1664 | 1668 | |
| 1665 | 1669 | TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) { |
| 1666 | 1670 | SCOPED_INTERCEPTOR_RAW(pthread_once, o, f); |
| 1671 | #if SANITIZER_APPLE && !SANITIZER_GO | |
| 1672 | if (flags()->lock_during_write != kLockDuringAllWrites && | |
| 1673 | cur_thread_init()->in_internal_write_call) { | |
| 1674 | // This is needed to make it through process launch without hanging | |
| 1675 | f(); | |
| 1676 | return 0; | |
| 1677 | } | |
| 1678 | #endif | |
| 1667 | 1679 | if (o == 0 || f == 0) |
| 1668 | 1680 | return errno_EINVAL; |
| 1669 | 1681 | atomic_uint32_t *a; |
| ... | ... | @@ -2141,13 +2153,29 @@ static void ReportErrnoSpoiling(ThreadState *thr, uptr pc, int sig) { |
| 2141 | 2153 | // StackTrace::GetNestInstructionPc(pc) is used because return address is |
| 2142 | 2154 | // expected, OutputReport() will undo this. |
| 2143 | 2155 | ObtainCurrentStack(thr, StackTrace::GetNextInstructionPc(pc), &stack); |
| 2144 | ThreadRegistryLock l(&ctx->thread_registry); | |
| 2145 | ScopedReport rep(ReportTypeErrnoInSignal); | |
| 2146 | rep.SetSigNum(sig); | |
| 2147 | if (!IsFiredSuppression(ctx, ReportTypeErrnoInSignal, stack)) { | |
| 2148 | rep.AddStack(stack, true); | |
| 2149 | OutputReport(thr, rep); | |
| 2156 | // Use alloca, because malloc during signal handling deadlocks | |
| 2157 | ScopedReport *rep = (ScopedReport *)__builtin_alloca(sizeof(ScopedReport)); | |
| 2158 | bool suppressed; | |
| 2159 | // Take a new scope as Apple platforms require the below locks released | |
| 2160 | // before symbolizing in order to avoid a deadlock | |
| 2161 | { | |
| 2162 | ThreadRegistryLock l(&ctx->thread_registry); | |
| 2163 | new (rep) ScopedReport(ReportTypeErrnoInSignal); | |
| 2164 | rep->SetSigNum(sig); | |
| 2165 | suppressed = IsFiredSuppression(ctx, ReportTypeErrnoInSignal, stack); | |
| 2166 | if (!suppressed) | |
| 2167 | rep->AddStack(stack, true); | |
| 2168 | #if SANITIZER_APPLE | |
| 2169 | } // Close this scope to release the locks before writing report | |
| 2170 | #endif | |
| 2171 | if (!suppressed) | |
| 2172 | OutputReport(thr, *rep); | |
| 2173 | ||
| 2174 | // Need to manually destroy this because we used placement new to allocate | |
| 2175 | rep->~ScopedReport(); | |
| 2176 | #if !SANITIZER_APPLE | |
| 2150 | 2177 | } |
| 2178 | #endif | |
| 2151 | 2179 | } |
| 2152 | 2180 | |
| 2153 | 2181 | static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire, |
| ... | ... | @@ -2411,7 +2439,11 @@ TSAN_INTERCEPTOR(int, vfork, int fake) { |
| 2411 | 2439 | } |
| 2412 | 2440 | #endif |
| 2413 | 2441 | |
| 2414 | #if SANITIZER_LINUX | |
| 2442 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | |
| 2443 | // Bionic's pthread_create internally calls clone. When the CLONE_THREAD flag is | |
| 2444 | // set, clone does not create a new process but a new thread. This is a | |
| 2445 | // workaround for Android. Disabling the interception of clone solves the | |
| 2446 | // problem in most scenarios. | |
| 2415 | 2447 | TSAN_INTERCEPTOR(int, clone, int (*fn)(void *), void *stack, int flags, |
| 2416 | 2448 | void *arg, int *parent_tid, void *tls, pid_t *child_tid) { |
| 2417 | 2449 | SCOPED_INTERCEPTOR_RAW(clone, fn, stack, flags, arg, parent_tid, tls, |
| ... | ... | @@ -2888,12 +2920,12 @@ TSAN_INTERCEPTOR(void, _lwp_exit) { |
| 2888 | 2920 | #endif |
| 2889 | 2921 | |
| 2890 | 2922 | #if SANITIZER_FREEBSD |
| 2891 | TSAN_INTERCEPTOR(void, thr_exit, tid_t *state) { | |
| 2923 | TSAN_INTERCEPTOR(void, thr_exit, ThreadID *state) { | |
| 2892 | 2924 | SCOPED_TSAN_INTERCEPTOR(thr_exit, state); |
| 2893 | 2925 | DestroyThreadState(); |
| 2894 | 2926 | REAL(thr_exit(state)); |
| 2895 | 2927 | } |
| 2896 | #define TSAN_MAYBE_INTERCEPT_THR_EXIT TSAN_INTERCEPT(thr_exit) | |
| 2928 | # define TSAN_MAYBE_INTERCEPT_THR_EXIT TSAN_INTERCEPT(thr_exit) | |
| 2897 | 2929 | #else |
| 2898 | 2930 | #define TSAN_MAYBE_INTERCEPT_THR_EXIT |
| 2899 | 2931 | #endif |
| ... | ... | @@ -3024,12 +3056,26 @@ void InitializeInterceptors() { |
| 3024 | 3056 | TSAN_INTERCEPT(pthread_timedjoin_np); |
| 3025 | 3057 | #endif |
| 3026 | 3058 | |
| 3027 | TSAN_INTERCEPT_VER(pthread_cond_init, PTHREAD_ABI_BASE); | |
| 3028 | TSAN_INTERCEPT_VER(pthread_cond_signal, PTHREAD_ABI_BASE); | |
| 3029 | TSAN_INTERCEPT_VER(pthread_cond_broadcast, PTHREAD_ABI_BASE); | |
| 3030 | TSAN_INTERCEPT_VER(pthread_cond_wait, PTHREAD_ABI_BASE); | |
| 3031 | TSAN_INTERCEPT_VER(pthread_cond_timedwait, PTHREAD_ABI_BASE); | |
| 3032 | TSAN_INTERCEPT_VER(pthread_cond_destroy, PTHREAD_ABI_BASE); | |
| 3059 | // In glibc versions older than 2.36, dlsym(RTLD_NEXT, "pthread_cond_init") | |
| 3060 | // may return an outdated symbol (max(2.2,base_version)) if the port was | |
| 3061 | // introduced before 2.3.2 (when the new pthread_cond_t was introduced). | |
| 3062 | #if SANITIZER_GLIBC && !__GLIBC_PREREQ(2, 36) && \ | |
| 3063 | (defined(__x86_64__) || defined(__mips__) || SANITIZER_PPC64V1 || \ | |
| 3064 | defined(__s390x__)) | |
| 3065 | INTERCEPT_FUNCTION_VER(pthread_cond_init, "GLIBC_2.3.2"); | |
| 3066 | INTERCEPT_FUNCTION_VER(pthread_cond_signal, "GLIBC_2.3.2"); | |
| 3067 | INTERCEPT_FUNCTION_VER(pthread_cond_broadcast, "GLIBC_2.3.2"); | |
| 3068 | INTERCEPT_FUNCTION_VER(pthread_cond_wait, "GLIBC_2.3.2"); | |
| 3069 | INTERCEPT_FUNCTION_VER(pthread_cond_timedwait, "GLIBC_2.3.2"); | |
| 3070 | INTERCEPT_FUNCTION_VER(pthread_cond_destroy, "GLIBC_2.3.2"); | |
| 3071 | #else | |
| 3072 | INTERCEPT_FUNCTION(pthread_cond_init); | |
| 3073 | INTERCEPT_FUNCTION(pthread_cond_signal); | |
| 3074 | INTERCEPT_FUNCTION(pthread_cond_broadcast); | |
| 3075 | INTERCEPT_FUNCTION(pthread_cond_wait); | |
| 3076 | INTERCEPT_FUNCTION(pthread_cond_timedwait); | |
| 3077 | INTERCEPT_FUNCTION(pthread_cond_destroy); | |
| 3078 | #endif | |
| 3033 | 3079 | |
| 3034 | 3080 | TSAN_MAYBE_PTHREAD_COND_CLOCKWAIT; |
| 3035 | 3081 | |
| ... | ... | @@ -3120,7 +3166,7 @@ void InitializeInterceptors() { |
| 3120 | 3166 | |
| 3121 | 3167 | TSAN_INTERCEPT(fork); |
| 3122 | 3168 | TSAN_INTERCEPT(vfork); |
| 3123 | #if SANITIZER_LINUX | |
| 3169 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | |
| 3124 | 3170 | TSAN_INTERCEPT(clone); |
| 3125 | 3171 | #endif |
| 3126 | 3172 | #if !SANITIZER_ANDROID |
lib/libtsan/tsan_interface.h+3-3| ... | ... | @@ -16,7 +16,7 @@ |
| 16 | 16 | #define TSAN_INTERFACE_H |
| 17 | 17 | |
| 18 | 18 | #include <sanitizer_common/sanitizer_internal_defs.h> |
| 19 | using __sanitizer::tid_t; | |
| 19 | using __sanitizer::ThreadID; | |
| 20 | 20 | using __sanitizer::uptr; |
| 21 | 21 | |
| 22 | 22 | // This header should NOT include any other headers. |
| ... | ... | @@ -175,7 +175,7 @@ int __tsan_get_report_mutex(void *report, uptr idx, uptr *mutex_id, void **addr, |
| 175 | 175 | |
| 176 | 176 | // Returns information about threads included in the report. |
| 177 | 177 | SANITIZER_INTERFACE_ATTRIBUTE |
| 178 | int __tsan_get_report_thread(void *report, uptr idx, int *tid, tid_t *os_id, | |
| 178 | int __tsan_get_report_thread(void *report, uptr idx, int *tid, ThreadID *os_id, | |
| 179 | 179 | int *running, const char **name, int *parent_tid, |
| 180 | 180 | void **trace, uptr trace_size); |
| 181 | 181 | |
| ... | ... | @@ -192,7 +192,7 @@ const char *__tsan_locate_address(uptr addr, char *name, uptr name_size, |
| 192 | 192 | // Returns the allocation stack for a heap pointer. |
| 193 | 193 | SANITIZER_INTERFACE_ATTRIBUTE |
| 194 | 194 | int __tsan_get_alloc_stack(uptr addr, uptr *trace, uptr size, int *thread_id, |
| 195 | tid_t *os_id); | |
| 195 | ThreadID *os_id); | |
| 196 | 196 | |
| 197 | 197 | #endif // SANITIZER_GO |
| 198 | 198 |
lib/libtsan/tsan_interface_ann.cpp+23-9| ... | ... | @@ -437,16 +437,30 @@ void __tsan_mutex_post_divert(void *addr, unsigned flagz) { |
| 437 | 437 | } |
| 438 | 438 | |
| 439 | 439 | static void ReportMutexHeldWrongContext(ThreadState *thr, uptr pc) { |
| 440 | ThreadRegistryLock l(&ctx->thread_registry); | |
| 441 | ScopedReport rep(ReportTypeMutexHeldWrongContext); | |
| 442 | for (uptr i = 0; i < thr->mset.Size(); ++i) { | |
| 443 | MutexSet::Desc desc = thr->mset.Get(i); | |
| 444 | rep.AddMutex(desc.addr, desc.stack_id); | |
| 440 | // Use alloca, because malloc during signal handling deadlocks | |
| 441 | ScopedReport *rep = (ScopedReport *)__builtin_alloca(sizeof(ScopedReport)); | |
| 442 | // Take a new scope as Apple platforms require the below locks released | |
| 443 | // before symbolizing in order to avoid a deadlock | |
| 444 | { | |
| 445 | ThreadRegistryLock l(&ctx->thread_registry); | |
| 446 | new (rep) ScopedReport(ReportTypeMutexHeldWrongContext); | |
| 447 | for (uptr i = 0; i < thr->mset.Size(); ++i) { | |
| 448 | MutexSet::Desc desc = thr->mset.Get(i); | |
| 449 | rep->AddMutex(desc.addr, desc.stack_id); | |
| 450 | } | |
| 451 | VarSizeStackTrace trace; | |
| 452 | ObtainCurrentStack(thr, pc, &trace); | |
| 453 | rep->AddStack(trace, true); | |
| 454 | #if SANITIZER_APPLE | |
| 455 | } // Close this scope to release the locks | |
| 456 | #endif | |
| 457 | OutputReport(thr, *rep); | |
| 458 | ||
| 459 | // Need to manually destroy this because we used placement new to allocate | |
| 460 | rep->~ScopedReport(); | |
| 461 | #if !SANITIZER_APPLE | |
| 445 | 462 | } |
| 446 | VarSizeStackTrace trace; | |
| 447 | ObtainCurrentStack(thr, pc, &trace); | |
| 448 | rep.AddStack(trace, true); | |
| 449 | OutputReport(thr, rep); | |
| 463 | #endif | |
| 450 | 464 | } |
| 451 | 465 | |
| 452 | 466 | INTERFACE_ATTRIBUTE |
lib/libtsan/tsan_mman.cpp+18-4| ... | ... | @@ -182,10 +182,24 @@ static void SignalUnsafeCall(ThreadState *thr, uptr pc) { |
| 182 | 182 | ObtainCurrentStack(thr, pc, &stack); |
| 183 | 183 | if (IsFiredSuppression(ctx, ReportTypeSignalUnsafe, stack)) |
| 184 | 184 | return; |
| 185 | ThreadRegistryLock l(&ctx->thread_registry); | |
| 186 | ScopedReport rep(ReportTypeSignalUnsafe); | |
| 187 | rep.AddStack(stack, true); | |
| 188 | OutputReport(thr, rep); | |
| 185 | // Use alloca, because malloc during signal handling deadlocks | |
| 186 | ScopedReport *rep = (ScopedReport *)__builtin_alloca(sizeof(ScopedReport)); | |
| 187 | // Take a new scope as Apple platforms require the below locks released | |
| 188 | // before symbolizing in order to avoid a deadlock | |
| 189 | { | |
| 190 | ThreadRegistryLock l(&ctx->thread_registry); | |
| 191 | new (rep) ScopedReport(ReportTypeSignalUnsafe); | |
| 192 | rep->AddStack(stack, true); | |
| 193 | #if SANITIZER_APPLE | |
| 194 | } // Close this scope to release the locks | |
| 195 | #endif | |
| 196 | OutputReport(thr, *rep); | |
| 197 | ||
| 198 | // Need to manually destroy this because we used placement new to allocate | |
| 199 | rep->~ScopedReport(); | |
| 200 | #if !SANITIZER_APPLE | |
| 201 | } | |
| 202 | #endif | |
| 189 | 203 | } |
| 190 | 204 | |
| 191 | 205 |
lib/libtsan/tsan_platform.h+44-7| ... | ... | @@ -681,6 +681,32 @@ struct MappingGoMips64_47 { |
| 681 | 681 | static const uptr kShadowAdd = 0x200000000000ull; |
| 682 | 682 | }; |
| 683 | 683 | |
| 684 | /* Go on linux/riscv64 (39-bit VMA) | |
| 685 | 0000 0001 0000 - 000f 0000 0000: executable and heap (60 GiB) | |
| 686 | 000f 0000 0000 - 0010 0000 0000: - | |
| 687 | 0010 0000 0000 - 0030 0000 0000: shadow - 128 GiB ( ~ 2 * app) | |
| 688 | 0030 0000 0000 - 0038 0000 0000: metainfo - 32 GiB ( ~ 0.5 * app) | |
| 689 | 0038 0000 0000 - 0040 0000 0000: - | |
| 690 | */ | |
| 691 | struct MappingGoRiscv64_39 { | |
| 692 | static const uptr kMetaShadowBeg = 0x003000000000ull; | |
| 693 | static const uptr kMetaShadowEnd = 0x003800000000ull; | |
| 694 | static const uptr kShadowBeg = 0x001000000000ull; | |
| 695 | static const uptr kShadowEnd = 0x003000000000ull; | |
| 696 | static const uptr kLoAppMemBeg = 0x000000010000ull; | |
| 697 | static const uptr kLoAppMemEnd = 0x000f00000000ull; | |
| 698 | static const uptr kMidAppMemBeg = 0; | |
| 699 | static const uptr kMidAppMemEnd = 0; | |
| 700 | static const uptr kHiAppMemBeg = 0; | |
| 701 | static const uptr kHiAppMemEnd = 0; | |
| 702 | static const uptr kHeapMemBeg = 0; | |
| 703 | static const uptr kHeapMemEnd = 0; | |
| 704 | static const uptr kVdsoBeg = 0; | |
| 705 | static const uptr kShadowMsk = 0; | |
| 706 | static const uptr kShadowXor = 0; | |
| 707 | static const uptr kShadowAdd = 0x001000000000ull; | |
| 708 | }; | |
| 709 | ||
| 684 | 710 | /* Go on linux/riscv64 (48-bit VMA) |
| 685 | 711 | 0000 0001 0000 - 00e0 0000 0000: executable and heap (896 GiB) |
| 686 | 712 | 00e0 0000 0000 - 2000 0000 0000: - |
| ... | ... | @@ -689,13 +715,13 @@ struct MappingGoMips64_47 { |
| 689 | 715 | 3000 0000 0000 - 3100 0000 0000: metainfo - 1 TiB ( ~ 1 * app) |
| 690 | 716 | 3100 0000 0000 - 8000 0000 0000: - |
| 691 | 717 | */ |
| 692 | struct MappingGoRiscv64 { | |
| 718 | struct MappingGoRiscv64_48 { | |
| 693 | 719 | static const uptr kMetaShadowBeg = 0x300000000000ull; |
| 694 | 720 | static const uptr kMetaShadowEnd = 0x310000000000ull; |
| 695 | 721 | static const uptr kShadowBeg = 0x200000000000ull; |
| 696 | 722 | static const uptr kShadowEnd = 0x240000000000ull; |
| 697 | 723 | static const uptr kLoAppMemBeg = 0x000000010000ull; |
| 698 | static const uptr kLoAppMemEnd = 0x000e00000000ull; | |
| 724 | static const uptr kLoAppMemEnd = 0x00e000000000ull; | |
| 699 | 725 | static const uptr kMidAppMemBeg = 0; |
| 700 | 726 | static const uptr kMidAppMemEnd = 0; |
| 701 | 727 | static const uptr kHiAppMemBeg = 0; |
| ... | ... | @@ -756,7 +782,12 @@ ALWAYS_INLINE auto SelectMapping(Arg arg) { |
| 756 | 782 | # elif defined(__loongarch_lp64) |
| 757 | 783 | return Func::template Apply<MappingGoLoongArch64_47>(arg); |
| 758 | 784 | # elif SANITIZER_RISCV64 |
| 759 | return Func::template Apply<MappingGoRiscv64>(arg); | |
| 785 | switch (vmaSize) { | |
| 786 | case 39: | |
| 787 | return Func::template Apply<MappingGoRiscv64_39>(arg); | |
| 788 | case 48: | |
| 789 | return Func::template Apply<MappingGoRiscv64_48>(arg); | |
| 790 | } | |
| 760 | 791 | # elif SANITIZER_WINDOWS |
| 761 | 792 | return Func::template Apply<MappingGoWindows>(arg); |
| 762 | 793 | # else |
| ... | ... | @@ -827,7 +858,8 @@ void ForEachMapping() { |
| 827 | 858 | Func::template Apply<MappingGoAarch64>(); |
| 828 | 859 | Func::template Apply<MappingGoLoongArch64_47>(); |
| 829 | 860 | Func::template Apply<MappingGoMips64_47>(); |
| 830 | Func::template Apply<MappingGoRiscv64>(); | |
| 861 | Func::template Apply<MappingGoRiscv64_39>(); | |
| 862 | Func::template Apply<MappingGoRiscv64_48>(); | |
| 831 | 863 | Func::template Apply<MappingGoS390x>(); |
| 832 | 864 | } |
| 833 | 865 | |
| ... | ... | @@ -926,7 +958,9 @@ struct IsAppMemImpl { |
| 926 | 958 | }; |
| 927 | 959 | |
| 928 | 960 | ALWAYS_INLINE |
| 929 | bool IsAppMem(uptr mem) { return SelectMapping<IsAppMemImpl>(mem); } | |
| 961 | bool IsAppMem(uptr mem) { | |
| 962 | return SelectMapping<IsAppMemImpl>(STRIP_MTE_TAG(mem)); | |
| 963 | } | |
| 930 | 964 | |
| 931 | 965 | struct IsShadowMemImpl { |
| 932 | 966 | template <typename Mapping> |
| ... | ... | @@ -965,7 +999,8 @@ struct MemToShadowImpl { |
| 965 | 999 | |
| 966 | 1000 | ALWAYS_INLINE |
| 967 | 1001 | RawShadow *MemToShadow(uptr x) { |
| 968 | return reinterpret_cast<RawShadow *>(SelectMapping<MemToShadowImpl>(x)); | |
| 1002 | return reinterpret_cast<RawShadow*>( | |
| 1003 | SelectMapping<MemToShadowImpl>(STRIP_MTE_TAG(x))); | |
| 969 | 1004 | } |
| 970 | 1005 | |
| 971 | 1006 | struct MemToMetaImpl { |
| ... | ... | @@ -979,7 +1014,9 @@ struct MemToMetaImpl { |
| 979 | 1014 | }; |
| 980 | 1015 | |
| 981 | 1016 | ALWAYS_INLINE |
| 982 | u32 *MemToMeta(uptr x) { return SelectMapping<MemToMetaImpl>(x); } | |
| 1017 | u32* MemToMeta(uptr x) { | |
| 1018 | return SelectMapping<MemToMetaImpl>(STRIP_MTE_TAG(x)); | |
| 1019 | } | |
| 983 | 1020 | |
| 984 | 1021 | struct ShadowToMemImpl { |
| 985 | 1022 | template <typename Mapping> |
lib/libtsan/tsan_platform_linux.cpp+42-14| ... | ... | @@ -393,9 +393,9 @@ void InitializePlatformEarly() { |
| 393 | 393 | Die(); |
| 394 | 394 | } |
| 395 | 395 | # else |
| 396 | if (vmaSize != 48) { | |
| 396 | if (vmaSize != 39 && vmaSize != 48) { | |
| 397 | 397 | Printf("FATAL: ThreadSanitizer: unsupported VMA range\n"); |
| 398 | Printf("FATAL: Found %zd - Supported 48\n", vmaSize); | |
| 398 | Printf("FATAL: Found %zd - Supported 39 and 48\n", vmaSize); | |
| 399 | 399 | Die(); |
| 400 | 400 | } |
| 401 | 401 | # endif |
| ... | ... | @@ -415,7 +415,7 @@ void InitializePlatform() { |
| 415 | 415 | // is not compiled with -pie. |
| 416 | 416 | #if !SANITIZER_GO |
| 417 | 417 | { |
| 418 | # if SANITIZER_LINUX && (defined(__aarch64__) || defined(__loongarch_lp64)) | |
| 418 | # if INIT_LONGJMP_XOR_KEY | |
| 419 | 419 | // Initialize the xor key used in {sig}{set,long}jump. |
| 420 | 420 | InitializeLongjmpXorKey(); |
| 421 | 421 | # endif |
| ... | ... | @@ -486,8 +486,20 @@ int ExtractRecvmsgFDs(void *msgp, int *fds, int nfd) { |
| 486 | 486 | |
| 487 | 487 | // Reverse operation of libc stack pointer mangling |
| 488 | 488 | static uptr UnmangleLongJmpSp(uptr mangled_sp) { |
| 489 | #if defined(__x86_64__) | |
| 490 | # if SANITIZER_LINUX | |
| 489 | # if SANITIZER_ANDROID && INIT_LONGJMP_XOR_KEY | |
| 490 | if (longjmp_xor_key == 0) { | |
| 491 | // bionic libc initialization process: __libc_init_globals -> | |
| 492 | // __libc_init_vdso (calls strcmp) -> __libc_init_setjmp_cookie. strcmp is | |
| 493 | // intercepted by TSan, so during TSan initialization the setjmp_cookie | |
| 494 | // remains uninitialized. On Android, longjmp_xor_key must be set on first | |
| 495 | // use. | |
| 496 | InitializeLongjmpXorKey(); | |
| 497 | CHECK_NE(longjmp_xor_key, 0); | |
| 498 | } | |
| 499 | # endif | |
| 500 | ||
| 501 | # if defined(__x86_64__) | |
| 502 | # if SANITIZER_LINUX | |
| 491 | 503 | // Reverse of: |
| 492 | 504 | // xor %fs:0x30, %rsi |
| 493 | 505 | // rol $0x11, %rsi |
| ... | ... | @@ -542,13 +554,23 @@ static uptr UnmangleLongJmpSp(uptr mangled_sp) { |
| 542 | 554 | # else |
| 543 | 555 | # define LONG_JMP_SP_ENV_SLOT 2 |
| 544 | 556 | # endif |
| 545 | #elif SANITIZER_LINUX | |
| 546 | # ifdef __aarch64__ | |
| 547 | # define LONG_JMP_SP_ENV_SLOT 13 | |
| 548 | # elif defined(__loongarch__) | |
| 549 | # define LONG_JMP_SP_ENV_SLOT 1 | |
| 550 | # elif defined(__mips64) | |
| 551 | # define LONG_JMP_SP_ENV_SLOT 1 | |
| 557 | # elif SANITIZER_ANDROID | |
| 558 | # ifdef __aarch64__ | |
| 559 | # define LONG_JMP_SP_ENV_SLOT 3 | |
| 560 | # elif SANITIZER_RISCV64 | |
| 561 | # define LONG_JMP_SP_ENV_SLOT 3 | |
| 562 | # elif defined(__x86_64__) | |
| 563 | # define LONG_JMP_SP_ENV_SLOT 6 | |
| 564 | # else | |
| 565 | # error unsupported | |
| 566 | # endif | |
| 567 | # elif SANITIZER_LINUX | |
| 568 | # ifdef __aarch64__ | |
| 569 | # define LONG_JMP_SP_ENV_SLOT 13 | |
| 570 | # elif defined(__loongarch__) | |
| 571 | # define LONG_JMP_SP_ENV_SLOT 1 | |
| 572 | # elif defined(__mips64) | |
| 573 | # define LONG_JMP_SP_ENV_SLOT 1 | |
| 552 | 574 | # elif SANITIZER_RISCV64 |
| 553 | 575 | # define LONG_JMP_SP_ENV_SLOT 13 |
| 554 | 576 | # elif defined(__s390x__) |
| ... | ... | @@ -556,7 +578,7 @@ static uptr UnmangleLongJmpSp(uptr mangled_sp) { |
| 556 | 578 | # else |
| 557 | 579 | # define LONG_JMP_SP_ENV_SLOT 6 |
| 558 | 580 | # endif |
| 559 | #endif | |
| 581 | # endif | |
| 560 | 582 | |
| 561 | 583 | uptr ExtractLongJmpSp(uptr *env) { |
| 562 | 584 | uptr mangled_sp = env[LONG_JMP_SP_ENV_SLOT]; |
| ... | ... | @@ -653,7 +675,13 @@ ThreadState *cur_thread() { |
| 653 | 675 | } |
| 654 | 676 | CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &oldset, nullptr)); |
| 655 | 677 | } |
| 656 | return thr; | |
| 678 | ||
| 679 | // Skia calls mallopt(M_THREAD_DISABLE_MEM_INIT, 1), which sets the least | |
| 680 | // significant bit of TLS_SLOT_SANITIZER to 1. Scudo allocator uses this bit | |
| 681 | // as a flag to disable memory initialization. This is a workaround to get the | |
| 682 | // correct ThreadState pointer. | |
| 683 | uptr addr = reinterpret_cast<uptr>(thr); | |
| 684 | return reinterpret_cast<ThreadState*>(addr & ~1ULL); | |
| 657 | 685 | } |
| 658 | 686 | |
| 659 | 687 | void set_cur_thread(ThreadState *thr) { |
lib/libtsan/tsan_platform_mac.cpp+16-3| ... | ... | @@ -226,9 +226,20 @@ static void ThreadTerminateCallback(uptr thread) { |
| 226 | 226 | void InitializePlatformEarly() { |
| 227 | 227 | # if !SANITIZER_GO && SANITIZER_IOS |
| 228 | 228 | uptr max_vm = GetMaxUserVirtualAddress() + 1; |
| 229 | if (max_vm != HiAppMemEnd()) { | |
| 230 | Printf("ThreadSanitizer: unsupported vm address limit %p, expected %p.\n", | |
| 231 | (void *)max_vm, (void *)HiAppMemEnd()); | |
| 229 | if (max_vm < HiAppMemEnd()) { | |
| 230 | Report( | |
| 231 | "ThreadSanitizer: Unsupported virtual memory layout:\n\tVM address " | |
| 232 | "limit = %p\n\tExpected %p.\n", | |
| 233 | (void*)max_vm, (void*)HiAppMemEnd()); | |
| 234 | Die(); | |
| 235 | } | |
| 236 | // In some configurations, the max_vm is expanded, but much of this space is | |
| 237 | // already mapped. TSAN will not work in this configuration. | |
| 238 | if (!MemoryRangeIsAvailable(HiAppMemEnd() - 1, HiAppMemEnd() - 1)) { | |
| 239 | Report( | |
| 240 | "ThreadSanitizer: Unsupported virtual memory layout: Address %p is " | |
| 241 | "already mapped.\n", | |
| 242 | (void*)(HiAppMemEnd() - 1)); | |
| 232 | 243 | Die(); |
| 233 | 244 | } |
| 234 | 245 | #endif |
| ... | ... | @@ -248,7 +259,9 @@ void InitializePlatform() { |
| 248 | 259 | |
| 249 | 260 | ThreadEventCallbacks callbacks = { |
| 250 | 261 | .create = ThreadCreateCallback, |
| 262 | .start = nullptr, | |
| 251 | 263 | .terminate = ThreadTerminateCallback, |
| 264 | .destroy = nullptr, | |
| 252 | 265 | }; |
| 253 | 266 | InstallPthreadIntrospectionHook(callbacks); |
| 254 | 267 | #endif |
lib/libtsan/tsan_report.h+14-1| ... | ... | @@ -12,6 +12,8 @@ |
| 12 | 12 | #ifndef TSAN_REPORT_H |
| 13 | 13 | #define TSAN_REPORT_H |
| 14 | 14 | |
| 15 | #include "sanitizer_common/sanitizer_internal_defs.h" | |
| 16 | #include "sanitizer_common/sanitizer_stacktrace.h" | |
| 15 | 17 | #include "sanitizer_common/sanitizer_symbolizer.h" |
| 16 | 18 | #include "sanitizer_common/sanitizer_thread_registry.h" |
| 17 | 19 | #include "sanitizer_common/sanitizer_vector.h" |
| ... | ... | @@ -56,6 +58,7 @@ struct ReportMop { |
| 56 | 58 | bool atomic; |
| 57 | 59 | uptr external_tag; |
| 58 | 60 | Vector<ReportMopMutex> mset; |
| 61 | StackTrace stack_trace; | |
| 59 | 62 | ReportStack *stack; |
| 60 | 63 | |
| 61 | 64 | ReportMop(); |
| ... | ... | @@ -79,25 +82,34 @@ struct ReportLocation { |
| 79 | 82 | int fd = 0; |
| 80 | 83 | bool fd_closed = false; |
| 81 | 84 | bool suppressable = false; |
| 85 | StackID stack_id = 0; | |
| 82 | 86 | ReportStack *stack = nullptr; |
| 83 | 87 | }; |
| 84 | 88 | |
| 85 | 89 | struct ReportThread { |
| 86 | 90 | Tid id; |
| 87 | tid_t os_id; | |
| 91 | ThreadID os_id; | |
| 88 | 92 | bool running; |
| 89 | 93 | ThreadType thread_type; |
| 90 | 94 | char *name; |
| 91 | 95 | Tid parent_tid; |
| 96 | StackID stack_id; | |
| 92 | 97 | ReportStack *stack; |
| 98 | bool suppressable; | |
| 93 | 99 | }; |
| 94 | 100 | |
| 95 | 101 | struct ReportMutex { |
| 96 | 102 | int id; |
| 97 | 103 | uptr addr; |
| 104 | StackID stack_id; | |
| 98 | 105 | ReportStack *stack; |
| 99 | 106 | }; |
| 100 | 107 | |
| 108 | struct AddedLocationAddr { | |
| 109 | uptr addr; | |
| 110 | usize locs_idx; | |
| 111 | }; | |
| 112 | ||
| 101 | 113 | class ReportDesc { |
| 102 | 114 | public: |
| 103 | 115 | ReportType typ; |
| ... | ... | @@ -105,6 +117,7 @@ class ReportDesc { |
| 105 | 117 | Vector<ReportStack*> stacks; |
| 106 | 118 | Vector<ReportMop*> mops; |
| 107 | 119 | Vector<ReportLocation*> locs; |
| 120 | Vector<AddedLocationAddr> added_location_addrs; | |
| 108 | 121 | Vector<ReportMutex*> mutexes; |
| 109 | 122 | Vector<ReportThread*> threads; |
| 110 | 123 | Vector<Tid> unique_tids; |
lib/libtsan/tsan_rtl.cpp+14| ... | ... | @@ -40,6 +40,13 @@ SANITIZER_WEAK_DEFAULT_IMPL |
| 40 | 40 | void __tsan_test_only_on_fork() {} |
| 41 | 41 | #endif |
| 42 | 42 | |
| 43 | #if SANITIZER_APPLE && !SANITIZER_GO | |
| 44 | // Override weak symbol from sanitizer_common | |
| 45 | extern void __tsan_set_in_internal_write_call(bool value) { | |
| 46 | __tsan::cur_thread_init()->in_internal_write_call = value; | |
| 47 | } | |
| 48 | #endif | |
| 49 | ||
| 43 | 50 | namespace __tsan { |
| 44 | 51 | |
| 45 | 52 | #if !SANITIZER_GO |
| ... | ... | @@ -893,6 +900,13 @@ void ForkChildAfter(ThreadState* thr, uptr pc, bool start_thread) { |
| 893 | 900 | ThreadIgnoreBegin(thr, pc); |
| 894 | 901 | ThreadIgnoreSyncBegin(thr, pc); |
| 895 | 902 | } |
| 903 | ||
| 904 | # if SANITIZER_APPLE && !SANITIZER_GO | |
| 905 | // This flag can have inheritance disabled - we are the child so act | |
| 906 | // accordingly | |
| 907 | if (flags()->lock_during_write == kNoLockDuringWritesCurrentProcess) | |
| 908 | flags()->lock_during_write = kLockDuringAllWrites; | |
| 909 | # endif | |
| 896 | 910 | } |
| 897 | 911 | #endif |
| 898 | 912 |
lib/libtsan/tsan_rtl.h+7-2| ... | ... | @@ -236,6 +236,10 @@ struct alignas(SANITIZER_CACHE_LINE_SIZE) ThreadState { |
| 236 | 236 | |
| 237 | 237 | const ReportDesc *current_report; |
| 238 | 238 | |
| 239 | #if SANITIZER_APPLE && !SANITIZER_GO | |
| 240 | bool in_internal_write_call; | |
| 241 | #endif | |
| 242 | ||
| 239 | 243 | explicit ThreadState(Tid tid); |
| 240 | 244 | }; |
| 241 | 245 | |
| ... | ... | @@ -420,6 +424,7 @@ class ScopedReportBase { |
| 420 | 424 | void AddSleep(StackID stack_id); |
| 421 | 425 | void SetCount(int count); |
| 422 | 426 | void SetSigNum(int sig); |
| 427 | void SymbolizeStackElems(void); | |
| 423 | 428 | |
| 424 | 429 | const ReportDesc *GetReport() const; |
| 425 | 430 | |
| ... | ... | @@ -498,7 +503,7 @@ void ForkChildAfter(ThreadState *thr, uptr pc, bool start_thread); |
| 498 | 503 | |
| 499 | 504 | void ReportRace(ThreadState *thr, RawShadow *shadow_mem, Shadow cur, Shadow old, |
| 500 | 505 | AccessType typ); |
| 501 | bool OutputReport(ThreadState *thr, const ScopedReport &srep); | |
| 506 | bool OutputReport(ThreadState *thr, ScopedReport &srep); | |
| 502 | 507 | bool IsFiredSuppression(Context *ctx, ReportType type, StackTrace trace); |
| 503 | 508 | bool IsExpectedReport(uptr addr, uptr size); |
| 504 | 509 | |
| ... | ... | @@ -559,7 +564,7 @@ void ThreadIgnoreSyncBegin(ThreadState *thr, uptr pc); |
| 559 | 564 | void ThreadIgnoreSyncEnd(ThreadState *thr); |
| 560 | 565 | |
| 561 | 566 | Tid ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached); |
| 562 | void ThreadStart(ThreadState *thr, Tid tid, tid_t os_id, | |
| 567 | void ThreadStart(ThreadState *thr, Tid tid, ThreadID os_id, | |
| 563 | 568 | ThreadType thread_type); |
| 564 | 569 | void ThreadFinish(ThreadState *thr); |
| 565 | 570 | Tid ThreadConsumeTid(ThreadState *thr, uptr pc, uptr uid); |
lib/libtsan/tsan_rtl_aarch64.S+3-5| ... | ... | @@ -4,10 +4,8 @@ |
| 4 | 4 | #include "sanitizer_common/sanitizer_asm.h" |
| 5 | 5 | #include "builtins/assembly.h" |
| 6 | 6 | |
| 7 | #if !defined(__APPLE__) | |
| 8 | .section .text | |
| 9 | #else | |
| 10 | .section __TEXT,__text | |
| 7 | TEXT_SECTION | |
| 8 | #if defined(__APPLE__) | |
| 11 | 9 | .align 3 |
| 12 | 10 | #endif |
| 13 | 11 | |
| ... | ... | @@ -222,6 +220,6 @@ ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(__sigsetjmp)) |
| 222 | 220 | |
| 223 | 221 | NO_EXEC_STACK_DIRECTIVE |
| 224 | 222 | |
| 225 | GNU_PROPERTY_BTI_PAC | |
| 223 | GNU_PROPERTY_BTI_PAC_GCS | |
| 226 | 224 | |
| 227 | 225 | #endif |
lib/libtsan/tsan_rtl_access.cpp+8-3| ... | ... | @@ -419,6 +419,11 @@ NOINLINE void TraceRestartMemoryAccess(ThreadState* thr, uptr pc, uptr addr, |
| 419 | 419 | |
| 420 | 420 | ALWAYS_INLINE USED void MemoryAccess(ThreadState* thr, uptr pc, uptr addr, |
| 421 | 421 | uptr size, AccessType typ) { |
| 422 | #if SANITIZER_APPLE && !SANITIZER_GO | |
| 423 | // Swift symbolizer can be intercepted and deadlock without this | |
| 424 | if (thr->in_symbolizer) | |
| 425 | return; | |
| 426 | #endif | |
| 422 | 427 | RawShadow* shadow_mem = MemToShadow(addr); |
| 423 | 428 | UNUSED char memBuf[4][64]; |
| 424 | 429 | DPrintf2("#%d: Access: %d@%d %p/%zd typ=0x%x {%s, %s, %s, %s}\n", thr->tid, |
| ... | ... | @@ -684,7 +689,7 @@ void MemoryAccessRangeT(ThreadState* thr, uptr pc, uptr addr, uptr size) { |
| 684 | 689 | DCHECK(IsAppMem(addr + size - 1)); |
| 685 | 690 | } |
| 686 | 691 | if (!IsShadowMem(shadow_mem)) { |
| 687 | Printf("Bad shadow start addr: %p (%p)\n", shadow_mem, (void*)addr); | |
| 692 | Printf("Bad shadow start addr: %p (%p)\n", (void*)shadow_mem, (void*)addr); | |
| 688 | 693 | DCHECK(IsShadowMem(shadow_mem)); |
| 689 | 694 | } |
| 690 | 695 | |
| ... | ... | @@ -693,12 +698,12 @@ void MemoryAccessRangeT(ThreadState* thr, uptr pc, uptr addr, uptr size) { |
| 693 | 698 | RawShadow* shadow_mem_end = |
| 694 | 699 | shadow_mem + rounded_size / kShadowCell * kShadowCnt; |
| 695 | 700 | if (!IsShadowMem(shadow_mem_end - 1)) { |
| 696 | Printf("Bad shadow end addr: %p (%p)\n", shadow_mem_end - 1, | |
| 701 | Printf("Bad shadow end addr: %p (%p)\n", (void*)(shadow_mem_end - 1), | |
| 697 | 702 | (void*)(addr + size - 1)); |
| 698 | 703 | Printf( |
| 699 | 704 | "Shadow start addr (ok): %p (%p); size: 0x%zx; rounded_size: 0x%zx; " |
| 700 | 705 | "kShadowMultiplier: %zx\n", |
| 701 | shadow_mem, (void*)addr, size, rounded_size, kShadowMultiplier); | |
| 706 | (void*)shadow_mem, (void*)addr, size, rounded_size, kShadowMultiplier); | |
| 702 | 707 | DCHECK(IsShadowMem(shadow_mem_end - 1)); |
| 703 | 708 | } |
| 704 | 709 | #endif |
lib/libtsan/tsan_rtl_amd64.S+2| ... | ... | @@ -3,6 +3,8 @@ |
| 3 | 3 | |
| 4 | 4 | #include "sanitizer_common/sanitizer_asm.h" |
| 5 | 5 | |
| 6 | .att_syntax | |
| 7 | ||
| 6 | 8 | #if !defined(__APPLE__) |
| 7 | 9 | .section .text |
| 8 | 10 | #else |
lib/libtsan/tsan_rtl_mutex.cpp+94-49| ... | ... | @@ -11,14 +11,15 @@ |
| 11 | 11 | //===----------------------------------------------------------------------===// |
| 12 | 12 | |
| 13 | 13 | #include <sanitizer_common/sanitizer_deadlock_detector_interface.h> |
| 14 | #include <sanitizer_common/sanitizer_placement_new.h> | |
| 14 | 15 | #include <sanitizer_common/sanitizer_stackdepot.h> |
| 15 | 16 | |
| 16 | #include "tsan_rtl.h" | |
| 17 | 17 | #include "tsan_flags.h" |
| 18 | #include "tsan_sync.h" | |
| 18 | #include "tsan_platform.h" | |
| 19 | 19 | #include "tsan_report.h" |
| 20 | #include "tsan_rtl.h" | |
| 20 | 21 | #include "tsan_symbolize.h" |
| 21 | #include "tsan_platform.h" | |
| 22 | #include "tsan_sync.h" | |
| 22 | 23 | |
| 23 | 24 | namespace __tsan { |
| 24 | 25 | |
| ... | ... | @@ -55,14 +56,28 @@ static void ReportMutexMisuse(ThreadState *thr, uptr pc, ReportType typ, |
| 55 | 56 | return; |
| 56 | 57 | if (!ShouldReport(thr, typ)) |
| 57 | 58 | return; |
| 58 | ThreadRegistryLock l(&ctx->thread_registry); | |
| 59 | ScopedReport rep(typ); | |
| 60 | rep.AddMutex(addr, creation_stack_id); | |
| 61 | VarSizeStackTrace trace; | |
| 62 | ObtainCurrentStack(thr, pc, &trace); | |
| 63 | rep.AddStack(trace, true); | |
| 64 | rep.AddLocation(addr, 1); | |
| 65 | OutputReport(thr, rep); | |
| 59 | // Use alloca, because malloc during signal handling deadlocks | |
| 60 | ScopedReport *rep = (ScopedReport *)__builtin_alloca(sizeof(ScopedReport)); | |
| 61 | // Take a new scope as Apple platforms require the below locks released | |
| 62 | // before symbolizing in order to avoid a deadlock | |
| 63 | { | |
| 64 | ThreadRegistryLock l(&ctx->thread_registry); | |
| 65 | new (rep) ScopedReport(typ); | |
| 66 | rep->AddMutex(addr, creation_stack_id); | |
| 67 | VarSizeStackTrace trace; | |
| 68 | ObtainCurrentStack(thr, pc, &trace); | |
| 69 | rep->AddStack(trace, true); | |
| 70 | rep->AddLocation(addr, 1); | |
| 71 | #if SANITIZER_APPLE | |
| 72 | } // Close this scope to release the locks | |
| 73 | #endif | |
| 74 | OutputReport(thr, *rep); | |
| 75 | ||
| 76 | // Need to manually destroy this because we used placement new to allocate | |
| 77 | rep->~ScopedReport(); | |
| 78 | #if !SANITIZER_APPLE | |
| 79 | } | |
| 80 | #endif | |
| 66 | 81 | } |
| 67 | 82 | |
| 68 | 83 | static void RecordMutexLock(ThreadState *thr, uptr pc, uptr addr, |
| ... | ... | @@ -528,51 +543,81 @@ void AfterSleep(ThreadState *thr, uptr pc) { |
| 528 | 543 | void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) { |
| 529 | 544 | if (r == 0 || !ShouldReport(thr, ReportTypeDeadlock)) |
| 530 | 545 | return; |
| 531 | ThreadRegistryLock l(&ctx->thread_registry); | |
| 532 | ScopedReport rep(ReportTypeDeadlock); | |
| 533 | for (int i = 0; i < r->n; i++) { | |
| 534 | rep.AddMutex(r->loop[i].mtx_ctx0, r->loop[i].stk[0]); | |
| 535 | rep.AddUniqueTid((int)r->loop[i].thr_ctx); | |
| 536 | rep.AddThread((int)r->loop[i].thr_ctx); | |
| 537 | } | |
| 538 | uptr dummy_pc = 0x42; | |
| 539 | for (int i = 0; i < r->n; i++) { | |
| 540 | for (int j = 0; j < (flags()->second_deadlock_stack ? 2 : 1); j++) { | |
| 541 | u32 stk = r->loop[i].stk[j]; | |
| 542 | if (stk && stk != kInvalidStackID) { | |
| 543 | rep.AddStack(StackDepotGet(stk), true); | |
| 544 | } else { | |
| 545 | // Sometimes we fail to extract the stack trace (FIXME: investigate), | |
| 546 | // but we should still produce some stack trace in the report. | |
| 547 | rep.AddStack(StackTrace(&dummy_pc, 1), true); | |
| 546 | // Use alloca, because malloc during signal handling deadlocks | |
| 547 | ScopedReport *rep = (ScopedReport *)__builtin_alloca(sizeof(ScopedReport)); | |
| 548 | // Take a new scope as Apple platforms require the below locks released | |
| 549 | // before symbolizing in order to avoid a deadlock | |
| 550 | { | |
| 551 | ThreadRegistryLock l(&ctx->thread_registry); | |
| 552 | new (rep) ScopedReport(ReportTypeDeadlock); | |
| 553 | for (int i = 0; i < r->n; i++) { | |
| 554 | rep->AddMutex(r->loop[i].mtx_ctx0, r->loop[i].stk[0]); | |
| 555 | rep->AddUniqueTid((int)r->loop[i].thr_ctx); | |
| 556 | rep->AddThread((int)r->loop[i].thr_ctx); | |
| 557 | } | |
| 558 | uptr dummy_pc = 0x42; | |
| 559 | for (int i = 0; i < r->n; i++) { | |
| 560 | for (int j = 0; j < (flags()->second_deadlock_stack ? 2 : 1); j++) { | |
| 561 | u32 stk = r->loop[i].stk[j]; | |
| 562 | StackTrace stack; | |
| 563 | if (stk && stk != kInvalidStackID) { | |
| 564 | stack = StackDepotGet(stk); | |
| 565 | } else { | |
| 566 | // Sometimes we fail to extract the stack trace (FIXME: investigate), | |
| 567 | // but we should still produce some stack trace in the report. | |
| 568 | stack = StackTrace(&dummy_pc, 1); | |
| 569 | } | |
| 570 | rep->AddStack(stack, true); | |
| 548 | 571 | } |
| 549 | 572 | } |
| 573 | #if SANITIZER_APPLE | |
| 574 | } // Close this scope to release the locks | |
| 575 | #endif | |
| 576 | OutputReport(thr, *rep); | |
| 577 | ||
| 578 | // Need to manually destroy this because we used placement new to allocate | |
| 579 | rep->~ScopedReport(); | |
| 580 | #if !SANITIZER_APPLE | |
| 550 | 581 | } |
| 551 | OutputReport(thr, rep); | |
| 582 | #endif | |
| 552 | 583 | } |
| 553 | 584 | |
| 554 | 585 | void ReportDestroyLocked(ThreadState *thr, uptr pc, uptr addr, |
| 555 | 586 | FastState last_lock, StackID creation_stack_id) { |
| 556 | // We need to lock the slot during RestoreStack because it protects | |
| 557 | // the slot journal. | |
| 558 | Lock slot_lock(&ctx->slots[static_cast<uptr>(last_lock.sid())].mtx); | |
| 559 | ThreadRegistryLock l0(&ctx->thread_registry); | |
| 560 | Lock slots_lock(&ctx->slot_mtx); | |
| 561 | ScopedReport rep(ReportTypeMutexDestroyLocked); | |
| 562 | rep.AddMutex(addr, creation_stack_id); | |
| 563 | VarSizeStackTrace trace; | |
| 564 | ObtainCurrentStack(thr, pc, &trace); | |
| 565 | rep.AddStack(trace, true); | |
| 566 | ||
| 567 | Tid tid; | |
| 568 | DynamicMutexSet mset; | |
| 569 | uptr tag; | |
| 570 | if (!RestoreStack(EventType::kLock, last_lock.sid(), last_lock.epoch(), addr, | |
| 571 | 0, kAccessWrite, &tid, &trace, mset, &tag)) | |
| 572 | return; | |
| 573 | rep.AddStack(trace, true); | |
| 574 | rep.AddLocation(addr, 1); | |
| 575 | OutputReport(thr, rep); | |
| 587 | // Use alloca, because malloc during signal handling deadlocks | |
| 588 | ScopedReport *rep = (ScopedReport *)__builtin_alloca(sizeof(ScopedReport)); | |
| 589 | // Take a new scope as Apple platforms require the below locks released | |
| 590 | // before symbolizing in order to avoid a deadlock | |
| 591 | { | |
| 592 | // We need to lock the slot during RestoreStack because it protects | |
| 593 | // the slot journal. | |
| 594 | Lock slot_lock(&ctx->slots[static_cast<uptr>(last_lock.sid())].mtx); | |
| 595 | ThreadRegistryLock l0(&ctx->thread_registry); | |
| 596 | Lock slots_lock(&ctx->slot_mtx); | |
| 597 | new (rep) ScopedReport(ReportTypeMutexDestroyLocked); | |
| 598 | rep->AddMutex(addr, creation_stack_id); | |
| 599 | VarSizeStackTrace trace; | |
| 600 | ObtainCurrentStack(thr, pc, &trace); | |
| 601 | rep->AddStack(trace, true); | |
| 602 | ||
| 603 | Tid tid; | |
| 604 | DynamicMutexSet mset; | |
| 605 | uptr tag; | |
| 606 | if (!RestoreStack(EventType::kLock, last_lock.sid(), last_lock.epoch(), | |
| 607 | addr, 0, kAccessWrite, &tid, &trace, mset, &tag)) | |
| 608 | return; | |
| 609 | rep->AddStack(trace, true); | |
| 610 | rep->AddLocation(addr, 1); | |
| 611 | #if SANITIZER_APPLE | |
| 612 | } // Close this scope to release the locks | |
| 613 | #endif | |
| 614 | OutputReport(thr, *rep); | |
| 615 | ||
| 616 | // Need to manually destroy this because we used placement new to allocate | |
| 617 | rep->~ScopedReport(); | |
| 618 | #if !SANITIZER_APPLE | |
| 619 | } | |
| 620 | #endif | |
| 576 | 621 | } |
| 577 | 622 | |
| 578 | 623 | } // namespace __tsan |
lib/libtsan/tsan_rtl_report.cpp+132-65| ... | ... | @@ -11,10 +11,12 @@ |
| 11 | 11 | //===----------------------------------------------------------------------===// |
| 12 | 12 | |
| 13 | 13 | #include "sanitizer_common/sanitizer_common.h" |
| 14 | #include "sanitizer_common/sanitizer_internal_defs.h" | |
| 14 | 15 | #include "sanitizer_common/sanitizer_libc.h" |
| 15 | 16 | #include "sanitizer_common/sanitizer_placement_new.h" |
| 16 | 17 | #include "sanitizer_common/sanitizer_stackdepot.h" |
| 17 | 18 | #include "sanitizer_common/sanitizer_stacktrace.h" |
| 19 | #include "tsan_defs.h" | |
| 18 | 20 | #include "tsan_fd.h" |
| 19 | 21 | #include "tsan_flags.h" |
| 20 | 22 | #include "tsan_mman.h" |
| ... | ... | @@ -109,7 +111,13 @@ static ReportStack *SymbolizeStack(StackTrace trace) { |
| 109 | 111 | // instruction. |
| 110 | 112 | if ((pc & kExternalPCBit) == 0) |
| 111 | 113 | pc1 = StackTrace::GetPreviousInstructionPc(pc); |
| 112 | SymbolizedStack *ent = SymbolizeCode(pc1); | |
| 114 | SymbolizedStack* ent = SymbolizeCode(pc1, si == trace.size - 1); | |
| 115 | #if SANITIZER_GO | |
| 116 | if (ent == nullptr) { | |
| 117 | // Go might have 0 frames for this PC (wrapper frames aren't reported). | |
| 118 | continue; | |
| 119 | } | |
| 120 | #endif | |
| 113 | 121 | CHECK_NE(ent, 0); |
| 114 | 122 | SymbolizedStack *last = ent; |
| 115 | 123 | while (last->next) { |
| ... | ... | @@ -187,10 +195,8 @@ void ScopedReportBase::AddMemoryAccess(uptr addr, uptr external_tag, Shadow s, |
| 187 | 195 | mop->size = size; |
| 188 | 196 | mop->write = !(typ & kAccessRead); |
| 189 | 197 | mop->atomic = typ & kAccessAtomic; |
| 190 | mop->stack = SymbolizeStack(stack); | |
| 191 | 198 | mop->external_tag = external_tag; |
| 192 | if (mop->stack) | |
| 193 | mop->stack->suppressable = true; | |
| 199 | mop->stack_trace = stack; | |
| 194 | 200 | for (uptr i = 0; i < mset->Size(); i++) { |
| 195 | 201 | MutexSet::Desc d = mset->Get(i); |
| 196 | 202 | int id = this->AddMutex(d.addr, d.stack_id); |
| ... | ... | @@ -199,6 +205,56 @@ void ScopedReportBase::AddMemoryAccess(uptr addr, uptr external_tag, Shadow s, |
| 199 | 205 | } |
| 200 | 206 | } |
| 201 | 207 | |
| 208 | void ScopedReportBase::SymbolizeStackElems() { | |
| 209 | // symbolize memory ops | |
| 210 | for (usize i = 0, size = rep_->mops.Size(); i < size; i++) { | |
| 211 | ReportMop *mop = rep_->mops[i]; | |
| 212 | mop->stack = SymbolizeStack(mop->stack_trace); | |
| 213 | if (mop->stack) | |
| 214 | mop->stack->suppressable = true; | |
| 215 | } | |
| 216 | ||
| 217 | // symbolize locations | |
| 218 | for (usize i = 0, size = rep_->locs.Size(); i < size; i++) { | |
| 219 | // added locations have a NULL placeholder - don't dereference them | |
| 220 | if (ReportLocation *loc = rep_->locs[i]) | |
| 221 | loc->stack = SymbolizeStackId(loc->stack_id); | |
| 222 | } | |
| 223 | ||
| 224 | // symbolize any added locations | |
| 225 | for (usize i = 0, size = rep_->added_location_addrs.Size(); i < size; i++) { | |
| 226 | AddedLocationAddr *added_loc = &rep_->added_location_addrs[i]; | |
| 227 | if (ReportLocation *loc = SymbolizeData(added_loc->addr)) { | |
| 228 | loc->suppressable = true; | |
| 229 | rep_->locs[added_loc->locs_idx] = loc; | |
| 230 | } | |
| 231 | } | |
| 232 | ||
| 233 | // Filter out any added location placeholders that could not be symbolized | |
| 234 | usize j = 0; | |
| 235 | for (usize i = 0, size = rep_->locs.Size(); i < size; i++) { | |
| 236 | if (rep_->locs[i] != nullptr) { | |
| 237 | rep_->locs[j] = rep_->locs[i]; | |
| 238 | j++; | |
| 239 | } | |
| 240 | } | |
| 241 | rep_->locs.Resize(j); | |
| 242 | ||
| 243 | // symbolize threads | |
| 244 | for (usize i = 0, size = rep_->threads.Size(); i < size; i++) { | |
| 245 | ReportThread *rt = rep_->threads[i]; | |
| 246 | rt->stack = SymbolizeStackId(rt->stack_id); | |
| 247 | if (rt->stack) | |
| 248 | rt->stack->suppressable = rt->suppressable; | |
| 249 | } | |
| 250 | ||
| 251 | // symbolize mutexes | |
| 252 | for (usize i = 0, size = rep_->mutexes.Size(); i < size; i++) { | |
| 253 | ReportMutex *rm = rep_->mutexes[i]; | |
| 254 | rm->stack = SymbolizeStackId(rm->stack_id); | |
| 255 | } | |
| 256 | } | |
| 257 | ||
| 202 | 258 | void ScopedReportBase::AddUniqueTid(Tid unique_tid) { |
| 203 | 259 | rep_->unique_tids.PushBack(unique_tid); |
| 204 | 260 | } |
| ... | ... | @@ -216,10 +272,8 @@ void ScopedReportBase::AddThread(const ThreadContext *tctx, bool suppressable) { |
| 216 | 272 | rt->name = internal_strdup(tctx->name); |
| 217 | 273 | rt->parent_tid = tctx->parent_tid; |
| 218 | 274 | rt->thread_type = tctx->thread_type; |
| 219 | rt->stack = 0; | |
| 220 | rt->stack = SymbolizeStackId(tctx->creation_stack_id); | |
| 221 | if (rt->stack) | |
| 222 | rt->stack->suppressable = suppressable; | |
| 275 | rt->stack_id = tctx->creation_stack_id; | |
| 276 | rt->suppressable = suppressable; | |
| 223 | 277 | } |
| 224 | 278 | |
| 225 | 279 | #if !SANITIZER_GO |
| ... | ... | @@ -270,7 +324,7 @@ int ScopedReportBase::AddMutex(uptr addr, StackID creation_stack_id) { |
| 270 | 324 | rep_->mutexes.PushBack(rm); |
| 271 | 325 | rm->id = rep_->mutexes.Size() - 1; |
| 272 | 326 | rm->addr = addr; |
| 273 | rm->stack = SymbolizeStackId(creation_stack_id); | |
| 327 | rm->stack_id = creation_stack_id; | |
| 274 | 328 | return rm->id; |
| 275 | 329 | } |
| 276 | 330 | |
| ... | ... | @@ -288,7 +342,7 @@ void ScopedReportBase::AddLocation(uptr addr, uptr size) { |
| 288 | 342 | loc->fd_closed = closed; |
| 289 | 343 | loc->fd = fd; |
| 290 | 344 | loc->tid = creat_tid; |
| 291 | loc->stack = SymbolizeStackId(creat_stack); | |
| 345 | loc->stack_id = creat_stack; | |
| 292 | 346 | rep_->locs.PushBack(loc); |
| 293 | 347 | AddThread(creat_tid); |
| 294 | 348 | return; |
| ... | ... | @@ -310,7 +364,7 @@ void ScopedReportBase::AddLocation(uptr addr, uptr size) { |
| 310 | 364 | loc->heap_chunk_size = b->siz; |
| 311 | 365 | loc->external_tag = b->tag; |
| 312 | 366 | loc->tid = b->tid; |
| 313 | loc->stack = SymbolizeStackId(b->stk); | |
| 367 | loc->stack_id = b->stk; | |
| 314 | 368 | rep_->locs.PushBack(loc); |
| 315 | 369 | AddThread(b->tid); |
| 316 | 370 | return; |
| ... | ... | @@ -324,11 +378,8 @@ void ScopedReportBase::AddLocation(uptr addr, uptr size) { |
| 324 | 378 | AddThread(tctx); |
| 325 | 379 | } |
| 326 | 380 | #endif |
| 327 | if (ReportLocation *loc = SymbolizeData(addr)) { | |
| 328 | loc->suppressable = true; | |
| 329 | rep_->locs.PushBack(loc); | |
| 330 | return; | |
| 331 | } | |
| 381 | rep_->added_location_addrs.PushBack({addr, rep_->locs.Size()}); | |
| 382 | rep_->locs.PushBack(nullptr); | |
| 332 | 383 | } |
| 333 | 384 | |
| 334 | 385 | #if !SANITIZER_GO |
| ... | ... | @@ -628,11 +679,12 @@ static bool HandleRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2]) { |
| 628 | 679 | return false; |
| 629 | 680 | } |
| 630 | 681 | |
| 631 | bool OutputReport(ThreadState *thr, const ScopedReport &srep) { | |
| 682 | bool OutputReport(ThreadState *thr, ScopedReport &srep) { | |
| 632 | 683 | // These should have been checked in ShouldReport. |
| 633 | 684 | // It's too late to check them here, we have already taken locks. |
| 634 | 685 | CHECK(flags()->report_bugs); |
| 635 | 686 | CHECK(!thr->suppress_reports); |
| 687 | srep.SymbolizeStackElems(); | |
| 636 | 688 | atomic_store_relaxed(&ctx->last_symbolize_time_ns, NanoTime()); |
| 637 | 689 | const ReportDesc *rep = srep.GetReport(); |
| 638 | 690 | CHECK_EQ(thr->current_report, nullptr); |
| ... | ... | @@ -761,65 +813,80 @@ void ReportRace(ThreadState *thr, RawShadow *shadow_mem, Shadow cur, Shadow old, |
| 761 | 813 | DynamicMutexSet mset1; |
| 762 | 814 | MutexSet *mset[kMop] = {&thr->mset, mset1}; |
| 763 | 815 | |
| 764 | // We need to lock the slot during RestoreStack because it protects | |
| 765 | // the slot journal. | |
| 766 | Lock slot_lock(&ctx->slots[static_cast<uptr>(s[1].sid())].mtx); | |
| 767 | ThreadRegistryLock l0(&ctx->thread_registry); | |
| 768 | Lock slots_lock(&ctx->slot_mtx); | |
| 769 | if (SpuriousRace(old)) | |
| 770 | return; | |
| 771 | if (!RestoreStack(EventType::kAccessExt, s[1].sid(), s[1].epoch(), addr1, | |
| 772 | size1, typ1, &tids[1], &traces[1], mset[1], &tags[1])) { | |
| 773 | StoreShadow(&ctx->last_spurious_race, old.raw()); | |
| 774 | return; | |
| 775 | } | |
| 816 | // Use alloca, because malloc during signal handling deadlocks | |
| 817 | ScopedReport *rep = (ScopedReport *)__builtin_alloca(sizeof(ScopedReport)); | |
| 818 | // Take a new scope as Apple platforms require the below locks released | |
| 819 | // before symbolizing in order to avoid a deadlock | |
| 820 | { | |
| 821 | // We need to lock the slot during RestoreStack because it protects | |
| 822 | // the slot journal. | |
| 823 | Lock slot_lock(&ctx->slots[static_cast<uptr>(s[1].sid())].mtx); | |
| 824 | ThreadRegistryLock l0(&ctx->thread_registry); | |
| 825 | Lock slots_lock(&ctx->slot_mtx); | |
| 826 | if (SpuriousRace(old)) | |
| 827 | return; | |
| 828 | if (!RestoreStack(EventType::kAccessExt, s[1].sid(), s[1].epoch(), addr1, | |
| 829 | size1, typ1, &tids[1], &traces[1], mset[1], &tags[1])) { | |
| 830 | StoreShadow(&ctx->last_spurious_race, old.raw()); | |
| 831 | return; | |
| 832 | } | |
| 776 | 833 | |
| 777 | if (IsFiredSuppression(ctx, rep_typ, traces[1])) | |
| 778 | return; | |
| 834 | if (IsFiredSuppression(ctx, rep_typ, traces[1])) | |
| 835 | return; | |
| 779 | 836 | |
| 780 | if (HandleRacyStacks(thr, traces)) | |
| 781 | return; | |
| 837 | if (HandleRacyStacks(thr, traces)) | |
| 838 | return; | |
| 782 | 839 | |
| 783 | // If any of the accesses has a tag, treat this as an "external" race. | |
| 784 | uptr tag = kExternalTagNone; | |
| 785 | for (uptr i = 0; i < kMop; i++) { | |
| 786 | if (tags[i] != kExternalTagNone) { | |
| 787 | rep_typ = ReportTypeExternalRace; | |
| 788 | tag = tags[i]; | |
| 789 | break; | |
| 840 | // If any of the accesses has a tag, treat this as an "external" race. | |
| 841 | uptr tag = kExternalTagNone; | |
| 842 | for (uptr i = 0; i < kMop; i++) { | |
| 843 | if (tags[i] != kExternalTagNone) { | |
| 844 | rep_typ = ReportTypeExternalRace; | |
| 845 | tag = tags[i]; | |
| 846 | break; | |
| 847 | } | |
| 790 | 848 | } |
| 791 | } | |
| 792 | 849 | |
| 793 | ScopedReport rep(rep_typ, tag); | |
| 794 | for (uptr i = 0; i < kMop; i++) | |
| 795 | rep.AddMemoryAccess(addr, tags[i], s[i], tids[i], traces[i], mset[i]); | |
| 850 | new (rep) ScopedReport(rep_typ, tag); | |
| 851 | for (uptr i = 0; i < kMop; i++) | |
| 852 | rep->AddMemoryAccess(addr, tags[i], s[i], tids[i], traces[i], mset[i]); | |
| 796 | 853 | |
| 797 | for (uptr i = 0; i < kMop; i++) { | |
| 798 | ThreadContext *tctx = static_cast<ThreadContext *>( | |
| 799 | ctx->thread_registry.GetThreadLocked(tids[i])); | |
| 800 | rep.AddThread(tctx); | |
| 801 | } | |
| 854 | for (uptr i = 0; i < kMop; i++) { | |
| 855 | ThreadContext *tctx = static_cast<ThreadContext *>( | |
| 856 | ctx->thread_registry.GetThreadLocked(tids[i])); | |
| 857 | rep->AddThread(tctx); | |
| 858 | } | |
| 802 | 859 | |
| 803 | rep.AddLocation(addr_min, addr_max - addr_min); | |
| 804 | ||
| 805 | if (flags()->print_full_thread_history) { | |
| 806 | const ReportDesc *rep_desc = rep.GetReport(); | |
| 807 | for (uptr i = 0; i < rep_desc->threads.Size(); i++) { | |
| 808 | Tid parent_tid = rep_desc->threads[i]->parent_tid; | |
| 809 | if (parent_tid == kMainTid || parent_tid == kInvalidTid) | |
| 810 | continue; | |
| 811 | ThreadContext *parent_tctx = static_cast<ThreadContext *>( | |
| 812 | ctx->thread_registry.GetThreadLocked(parent_tid)); | |
| 813 | rep.AddThread(parent_tctx); | |
| 860 | rep->AddLocation(addr_min, addr_max - addr_min); | |
| 861 | ||
| 862 | if (flags()->print_full_thread_history) { | |
| 863 | const ReportDesc *rep_desc = rep->GetReport(); | |
| 864 | for (uptr i = 0; i < rep_desc->threads.Size(); i++) { | |
| 865 | Tid parent_tid = rep_desc->threads[i]->parent_tid; | |
| 866 | if (parent_tid == kMainTid || parent_tid == kInvalidTid) | |
| 867 | continue; | |
| 868 | ThreadContext *parent_tctx = static_cast<ThreadContext *>( | |
| 869 | ctx->thread_registry.GetThreadLocked(parent_tid)); | |
| 870 | rep->AddThread(parent_tctx); | |
| 871 | } | |
| 814 | 872 | } |
| 815 | } | |
| 816 | 873 | |
| 817 | 874 | #if !SANITIZER_GO |
| 818 | if (!((typ0 | typ1) & kAccessFree) && | |
| 819 | s[1].epoch() <= thr->last_sleep_clock.Get(s[1].sid())) | |
| 820 | rep.AddSleep(thr->last_sleep_stack_id); | |
| 875 | if (!((typ0 | typ1) & kAccessFree) && | |
| 876 | s[1].epoch() <= thr->last_sleep_clock.Get(s[1].sid())) | |
| 877 | rep->AddSleep(thr->last_sleep_stack_id); | |
| 878 | #endif | |
| 879 | ||
| 880 | #if SANITIZER_APPLE | |
| 881 | } // Close this scope to release the locks | |
| 882 | #endif | |
| 883 | OutputReport(thr, *rep); | |
| 884 | ||
| 885 | // Need to manually destroy this because we used placement new to allocate | |
| 886 | rep->~ScopedReport(); | |
| 887 | #if !SANITIZER_APPLE | |
| 888 | } | |
| 821 | 889 | #endif |
| 822 | OutputReport(thr, rep); | |
| 823 | 890 | } |
| 824 | 891 | |
| 825 | 892 | void PrintCurrentStack(ThreadState *thr, uptr pc) { |
lib/libtsan/tsan_rtl_thread.cpp+31-9| ... | ... | @@ -88,15 +88,33 @@ void ThreadFinalize(ThreadState *thr) { |
| 88 | 88 | #if !SANITIZER_GO |
| 89 | 89 | if (!ShouldReport(thr, ReportTypeThreadLeak)) |
| 90 | 90 | return; |
| 91 | ThreadRegistryLock l(&ctx->thread_registry); | |
| 92 | 91 | Vector<ThreadLeak> leaks; |
| 93 | ctx->thread_registry.RunCallbackForEachThreadLocked(CollectThreadLeaks, | |
| 94 | &leaks); | |
| 92 | { | |
| 93 | ThreadRegistryLock l(&ctx->thread_registry); | |
| 94 | ctx->thread_registry.RunCallbackForEachThreadLocked(CollectThreadLeaks, | |
| 95 | &leaks); | |
| 96 | } | |
| 97 | ||
| 95 | 98 | for (uptr i = 0; i < leaks.Size(); i++) { |
| 96 | ScopedReport rep(ReportTypeThreadLeak); | |
| 97 | rep.AddThread(leaks[i].tctx, true); | |
| 98 | rep.SetCount(leaks[i].count); | |
| 99 | OutputReport(thr, rep); | |
| 99 | // Use alloca, because malloc during signal handling deadlocks | |
| 100 | ScopedReport *rep = (ScopedReport *)__builtin_alloca(sizeof(ScopedReport)); | |
| 101 | // Take a new scope as Apple platforms require the below locks released | |
| 102 | // before symbolizing in order to avoid a deadlock | |
| 103 | { | |
| 104 | ThreadRegistryLock l(&ctx->thread_registry); | |
| 105 | new (rep) ScopedReport(ReportTypeThreadLeak); | |
| 106 | rep->AddThread(leaks[i].tctx, true); | |
| 107 | rep->SetCount(leaks[i].count); | |
| 108 | # if SANITIZER_APPLE | |
| 109 | } // Close this scope to release the locks | |
| 110 | # endif | |
| 111 | OutputReport(thr, *rep); | |
| 112 | ||
| 113 | // Need to manually destroy this because we used placement new to allocate | |
| 114 | rep->~ScopedReport(); | |
| 115 | # if !SANITIZER_APPLE | |
| 116 | } | |
| 117 | # endif | |
| 100 | 118 | } |
| 101 | 119 | #endif |
| 102 | 120 | } |
| ... | ... | @@ -149,7 +167,7 @@ struct OnStartedArgs { |
| 149 | 167 | uptr tls_size; |
| 150 | 168 | }; |
| 151 | 169 | |
| 152 | void ThreadStart(ThreadState *thr, Tid tid, tid_t os_id, | |
| 170 | void ThreadStart(ThreadState *thr, Tid tid, ThreadID os_id, | |
| 153 | 171 | ThreadType thread_type) { |
| 154 | 172 | ctx->thread_registry.StartThread(tid, os_id, thread_type, thr); |
| 155 | 173 | if (!thr->ignore_sync) { |
| ... | ... | @@ -188,10 +206,14 @@ void ThreadStart(ThreadState *thr, Tid tid, tid_t os_id, |
| 188 | 206 | } |
| 189 | 207 | #endif |
| 190 | 208 | |
| 191 | #if !SANITIZER_GO | |
| 209 | #if !SANITIZER_GO && !SANITIZER_ANDROID | |
| 192 | 210 | // Don't imitate stack/TLS writes for the main thread, |
| 193 | 211 | // because its initialization is synchronized with all |
| 194 | 212 | // subsequent threads anyway. |
| 213 | // Because thr is created by MmapOrDie, the thr object | |
| 214 | // is not in tls, the pointer to the thr object is in | |
| 215 | // TLS_SLOT_SANITIZER slot. So skip this check on | |
| 216 | // Android platform. | |
| 195 | 217 | if (tid != kMainTid) { |
| 196 | 218 | if (stk_addr && stk_size) { |
| 197 | 219 | const uptr pc = StackTrace::GetNextInstructionPc( |
lib/libtsan/tsan_symbolize.cpp+1-1| ... | ... | @@ -79,7 +79,7 @@ static void AddFrame(void *ctx, const char *function_name, const char *file, |
| 79 | 79 | info->column = column; |
| 80 | 80 | } |
| 81 | 81 | |
| 82 | SymbolizedStack *SymbolizeCode(uptr addr) { | |
| 82 | SymbolizedStack* SymbolizeCode(uptr addr, bool leaf) { | |
| 83 | 83 | // Check if PC comes from non-native land. |
| 84 | 84 | if (addr & kExternalPCBit) { |
| 85 | 85 | SymbolizedStackBuilder ssb = {nullptr, nullptr, addr}; |
lib/libtsan/tsan_symbolize.h+1-1| ... | ... | @@ -19,7 +19,7 @@ namespace __tsan { |
| 19 | 19 | |
| 20 | 20 | void EnterSymbolizer(); |
| 21 | 21 | void ExitSymbolizer(); |
| 22 | SymbolizedStack *SymbolizeCode(uptr addr); | |
| 22 | SymbolizedStack* SymbolizeCode(uptr addr, bool leaf); | |
| 23 | 23 | ReportLocation *SymbolizeData(uptr addr); |
| 24 | 24 | void SymbolizeFlush(); |
| 25 | 25 |
lib/libtsan/tsan_trace.h+1-1| ... | ... | @@ -190,7 +190,7 @@ struct Trace { |
| 190 | 190 | Mutex mtx; |
| 191 | 191 | IList<TraceHeader, &TraceHeader::trace_parts, TracePart> parts; |
| 192 | 192 | // First node non-queued into ctx->trace_part_recycle. |
| 193 | TracePart* local_head; | |
| 193 | TracePart* local_head = nullptr; | |
| 194 | 194 | // Final position in the last part for finished threads. |
| 195 | 195 | Event* final_pos = nullptr; |
| 196 | 196 | // Number of trace parts allocated on behalf of this trace specifically. |