diff options
author | nkozlovskiy <nmk@ydb.tech> | 2023-10-11 19:11:46 +0300 |
---|---|---|
committer | nkozlovskiy <nmk@ydb.tech> | 2023-10-11 19:33:28 +0300 |
commit | 61b3971447e473726d6cdb23fc298e457b4d973c (patch) | |
tree | e2a2a864bb7717f7ae6138f6a3194a254dd2c7bb /contrib/libs/clang14-rt/lib/msan | |
parent | a674dc57d88d43c2e8e90a6084d5d2c988e0402c (diff) | |
download | ydb-61b3971447e473726d6cdb23fc298e457b4d973c.tar.gz |
add sanitizers dependencies
Diffstat (limited to 'contrib/libs/clang14-rt/lib/msan')
21 files changed, 5492 insertions, 0 deletions
diff --git a/contrib/libs/clang14-rt/lib/msan/.yandex_meta/licenses.list.txt b/contrib/libs/clang14-rt/lib/msan/.yandex_meta/licenses.list.txt new file mode 100644 index 0000000000..591a53066f --- /dev/null +++ b/contrib/libs/clang14-rt/lib/msan/.yandex_meta/licenses.list.txt @@ -0,0 +1,366 @@ +====================Apache-2.0==================== + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +====================Apache-2.0 WITH LLVM-exception==================== +---- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + + +====================Apache-2.0 WITH LLVM-exception==================== +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. + + +====================Apache-2.0 WITH LLVM-exception==================== +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + + +====================Apache-2.0 WITH LLVM-exception==================== +The LLVM Project is under the Apache License v2.0 with LLVM Exceptions: + + +====================Apache-2.0 WITH LLVM-exception==================== +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +|* See https://llvm.org/LICENSE.txt for license information. + + +====================Apache-2.0 WITH LLVM-exception==================== +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + + +====================COPYRIGHT==================== + InitCache(c); + TransferBatch *b = allocator->AllocateBatch(&stats_, this, class_id); + if (UNLIKELY(!b)) + + +====================COPYRIGHT==================== +Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT + + +====================COPYRIGHT==================== +Copyright (c) 2009-2019 by the contributors listed in CREDITS.TXT + + +====================File: CREDITS.TXT==================== +This file is a partial list of people who have contributed to the LLVM/CompilerRT +project. If you have contributed a patch or made some other contribution to +LLVM/CompilerRT, please submit a patch to this file to add yourself, and it will be +done! + +The list is sorted by surname and formatted to allow easy grepping and +beautification by scripts. The fields are: name (N), email (E), web-address +(W), PGP key ID and fingerprint (P), description (D), and snail-mail address +(S). + +N: Craig van Vliet +E: cvanvliet@auroraux.org +W: http://www.auroraux.org +D: Code style and Readability fixes. + +N: Edward O'Callaghan +E: eocallaghan@auroraux.org +W: http://www.auroraux.org +D: CMake'ify Compiler-RT build system +D: Maintain Solaris & AuroraUX ports of Compiler-RT + +N: Howard Hinnant +E: hhinnant@apple.com +D: Architect and primary author of compiler-rt + +N: Guan-Hong Liu +E: koviankevin@hotmail.com +D: IEEE Quad-precision functions + +N: Joerg Sonnenberger +E: joerg@NetBSD.org +D: Maintains NetBSD port. + +N: Matt Thomas +E: matt@NetBSD.org +D: ARM improvements. + + +====================MIT==================== +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +====================NCSA==================== +Compiler-RT is open source software. You may freely distribute it under the +terms of the license agreement found in LICENSE.txt. + + +====================NCSA==================== +Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy): + + +====================NCSA==================== +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + + +====================NCSA==================== +University of Illinois/NCSA +Open Source License + + +====================NCSA AND MIT==================== +The compiler_rt library is dual licensed under both the University of Illinois +"BSD-Like" license and the MIT license. As a user of this code you may choose +to use it under either license. As a contributor, you agree to allow your code +to be used under both. + +Full text of the relevant licenses is included below. diff --git a/contrib/libs/clang14-rt/lib/msan/msan.cpp b/contrib/libs/clang14-rt/lib/msan/msan.cpp new file mode 100644 index 0000000000..c554a830e7 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/msan/msan.cpp @@ -0,0 +1,736 @@ +//===-- msan.cpp ----------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of MemorySanitizer. +// +// MemorySanitizer runtime. +//===----------------------------------------------------------------------===// + +#include "msan.h" +#include "msan_chained_origin_depot.h" +#include "msan_origin.h" +#include "msan_report.h" +#include "msan_thread.h" +#include "msan_poisoning.h" +#include "sanitizer_common/sanitizer_atomic.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_flags.h" +#include "sanitizer_common/sanitizer_flag_parser.h" +#include "sanitizer_common/sanitizer_libc.h" +#include "sanitizer_common/sanitizer_procmaps.h" +#include "sanitizer_common/sanitizer_stacktrace.h" +#include "sanitizer_common/sanitizer_symbolizer.h" +#include "sanitizer_common/sanitizer_stackdepot.h" +#include "ubsan/ubsan_flags.h" +#include "ubsan/ubsan_init.h" + +// ACHTUNG! No system header includes in this file. + +using namespace __sanitizer; + +// Globals. +static THREADLOCAL int msan_expect_umr = 0; +static THREADLOCAL int msan_expected_umr_found = 0; + +// Function argument shadow. Each argument starts at the next available 8-byte +// aligned address. +SANITIZER_INTERFACE_ATTRIBUTE +THREADLOCAL u64 __msan_param_tls[kMsanParamTlsSize / sizeof(u64)]; + +// Function argument origin. Each argument starts at the same offset as the +// corresponding shadow in (__msan_param_tls). Slightly weird, but changing this +// would break compatibility with older prebuilt binaries. +SANITIZER_INTERFACE_ATTRIBUTE +THREADLOCAL u32 __msan_param_origin_tls[kMsanParamTlsSize / sizeof(u32)]; + +SANITIZER_INTERFACE_ATTRIBUTE +THREADLOCAL u64 __msan_retval_tls[kMsanRetvalTlsSize / sizeof(u64)]; + +SANITIZER_INTERFACE_ATTRIBUTE +THREADLOCAL u32 __msan_retval_origin_tls; + +SANITIZER_INTERFACE_ATTRIBUTE +ALIGNED(16) THREADLOCAL u64 __msan_va_arg_tls[kMsanParamTlsSize / sizeof(u64)]; + +SANITIZER_INTERFACE_ATTRIBUTE +ALIGNED(16) +THREADLOCAL u32 __msan_va_arg_origin_tls[kMsanParamTlsSize / sizeof(u32)]; + +SANITIZER_INTERFACE_ATTRIBUTE +THREADLOCAL u64 __msan_va_arg_overflow_size_tls; + +SANITIZER_INTERFACE_ATTRIBUTE +THREADLOCAL u32 __msan_origin_tls; + +static THREADLOCAL int is_in_symbolizer; + +extern "C" SANITIZER_WEAK_ATTRIBUTE const int __msan_track_origins; + +int __msan_get_track_origins() { + return &__msan_track_origins ? __msan_track_origins : 0; +} + +extern "C" SANITIZER_WEAK_ATTRIBUTE const int __msan_keep_going; + +namespace __msan { + +void EnterSymbolizer() { ++is_in_symbolizer; } +void ExitSymbolizer() { --is_in_symbolizer; } +bool IsInSymbolizer() { return is_in_symbolizer; } + +static Flags msan_flags; + +Flags *flags() { + return &msan_flags; +} + +int msan_inited = 0; +bool msan_init_is_running; + +int msan_report_count = 0; + +// Array of stack origins. +// FIXME: make it resizable. +static const uptr kNumStackOriginDescrs = 1024 * 1024; +static const char *StackOriginDescr[kNumStackOriginDescrs]; +static uptr StackOriginPC[kNumStackOriginDescrs]; +static atomic_uint32_t NumStackOriginDescrs; + +void Flags::SetDefaults() { +#define MSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; +#include "msan_flags.inc" +#undef MSAN_FLAG +} + +// keep_going is an old name for halt_on_error, +// and it has inverse meaning. +class FlagHandlerKeepGoing final : public FlagHandlerBase { + bool *halt_on_error_; + + public: + explicit FlagHandlerKeepGoing(bool *halt_on_error) + : halt_on_error_(halt_on_error) {} + bool Parse(const char *value) final { + bool tmp; + FlagHandler<bool> h(&tmp); + if (!h.Parse(value)) return false; + *halt_on_error_ = !tmp; + return true; + } + bool Format(char *buffer, uptr size) final { + const char *keep_going_str = (*halt_on_error_) ? "false" : "true"; + return FormatString(buffer, size, keep_going_str); + } +}; + +static void RegisterMsanFlags(FlagParser *parser, Flags *f) { +#define MSAN_FLAG(Type, Name, DefaultValue, Description) \ + RegisterFlag(parser, #Name, Description, &f->Name); +#include "msan_flags.inc" +#undef MSAN_FLAG + + FlagHandlerKeepGoing *fh_keep_going = + new (FlagParser::Alloc) FlagHandlerKeepGoing(&f->halt_on_error); + parser->RegisterHandler("keep_going", fh_keep_going, + "deprecated, use halt_on_error"); +} + +static void InitializeFlags() { + SetCommonFlagsDefaults(); + { + CommonFlags cf; + cf.CopyFrom(*common_flags()); + cf.external_symbolizer_path = GetEnv("MSAN_SYMBOLIZER_PATH"); + cf.malloc_context_size = 20; + cf.handle_ioctl = true; + // FIXME: test and enable. + cf.check_printf = false; + cf.intercept_tls_get_addr = true; + OverrideCommonFlags(cf); + } + + Flags *f = flags(); + f->SetDefaults(); + + FlagParser parser; + RegisterMsanFlags(&parser, f); + RegisterCommonFlags(&parser); + +#if MSAN_CONTAINS_UBSAN + __ubsan::Flags *uf = __ubsan::flags(); + uf->SetDefaults(); + + FlagParser ubsan_parser; + __ubsan::RegisterUbsanFlags(&ubsan_parser, uf); + RegisterCommonFlags(&ubsan_parser); +#endif + + // Override from user-specified string. + parser.ParseString(__msan_default_options()); +#if MSAN_CONTAINS_UBSAN + const char *ubsan_default_options = __ubsan_default_options(); + ubsan_parser.ParseString(ubsan_default_options); +#endif + + parser.ParseStringFromEnv("MSAN_OPTIONS"); +#if MSAN_CONTAINS_UBSAN + ubsan_parser.ParseStringFromEnv("UBSAN_OPTIONS"); +#endif + + InitializeCommonFlags(); + + if (Verbosity()) ReportUnrecognizedFlags(); + + if (common_flags()->help) parser.PrintFlagDescriptions(); + + // Check if deprecated exit_code MSan flag is set. + if (f->exit_code != -1) { + if (Verbosity()) + Printf("MSAN_OPTIONS=exit_code is deprecated! " + "Please use MSAN_OPTIONS=exitcode instead.\n"); + CommonFlags cf; + cf.CopyFrom(*common_flags()); + cf.exitcode = f->exit_code; + OverrideCommonFlags(cf); + } + + // Check flag values: + if (f->origin_history_size < 0 || + f->origin_history_size > Origin::kMaxDepth) { + Printf( + "Origin history size invalid: %d. Must be 0 (unlimited) or in [1, %d] " + "range.\n", + f->origin_history_size, Origin::kMaxDepth); + Die(); + } + // Limiting to kStackDepotMaxUseCount / 2 to avoid overflow in + // StackDepotHandle::inc_use_count_unsafe. + if (f->origin_history_per_stack_limit < 0 || + f->origin_history_per_stack_limit > kStackDepotMaxUseCount / 2) { + Printf( + "Origin per-stack limit invalid: %d. Must be 0 (unlimited) or in [1, " + "%d] range.\n", + f->origin_history_per_stack_limit, kStackDepotMaxUseCount / 2); + Die(); + } + if (f->store_context_size < 1) f->store_context_size = 1; +} + +void PrintWarning(uptr pc, uptr bp) { + PrintWarningWithOrigin(pc, bp, __msan_origin_tls); +} + +void PrintWarningWithOrigin(uptr pc, uptr bp, u32 origin) { + if (msan_expect_umr) { + // Printf("Expected UMR\n"); + __msan_origin_tls = origin; + msan_expected_umr_found = 1; + return; + } + + ++msan_report_count; + + GET_FATAL_STACK_TRACE_PC_BP(pc, bp); + + u32 report_origin = + (__msan_get_track_origins() && Origin::isValidId(origin)) ? origin : 0; + ReportUMR(&stack, report_origin); + + if (__msan_get_track_origins() && !Origin::isValidId(origin)) { + Printf( + " ORIGIN: invalid (%x). Might be a bug in MemorySanitizer origin " + "tracking.\n This could still be a bug in your code, too!\n", + origin); + } +} + +void UnpoisonParam(uptr n) { + internal_memset(__msan_param_tls, 0, n * sizeof(*__msan_param_tls)); +} + +// Backup MSan runtime TLS state. +// Implementation must be async-signal-safe. +// Instances of this class may live on the signal handler stack, and data size +// may be an issue. +void ScopedThreadLocalStateBackup::Backup() { + va_arg_overflow_size_tls = __msan_va_arg_overflow_size_tls; +} + +void ScopedThreadLocalStateBackup::Restore() { + // A lame implementation that only keeps essential state and resets the rest. + __msan_va_arg_overflow_size_tls = va_arg_overflow_size_tls; + + internal_memset(__msan_param_tls, 0, sizeof(__msan_param_tls)); + internal_memset(__msan_retval_tls, 0, sizeof(__msan_retval_tls)); + internal_memset(__msan_va_arg_tls, 0, sizeof(__msan_va_arg_tls)); + internal_memset(__msan_va_arg_origin_tls, 0, + sizeof(__msan_va_arg_origin_tls)); + + if (__msan_get_track_origins()) { + internal_memset(&__msan_retval_origin_tls, 0, + sizeof(__msan_retval_origin_tls)); + internal_memset(__msan_param_origin_tls, 0, + sizeof(__msan_param_origin_tls)); + } +} + +void UnpoisonThreadLocalState() { +} + +const char *GetStackOriginDescr(u32 id, uptr *pc) { + CHECK_LT(id, kNumStackOriginDescrs); + if (pc) *pc = StackOriginPC[id]; + return StackOriginDescr[id]; +} + +u32 ChainOrigin(u32 id, StackTrace *stack) { + MsanThread *t = GetCurrentThread(); + if (t && t->InSignalHandler()) + return id; + + Origin o = Origin::FromRawId(id); + stack->tag = StackTrace::TAG_UNKNOWN; + Origin chained = Origin::CreateChainedOrigin(o, stack); + return chained.raw_id(); +} + +} // namespace __msan + +void __sanitizer::BufferedStackTrace::UnwindImpl( + uptr pc, uptr bp, void *context, bool request_fast, u32 max_depth) { + using namespace __msan; + MsanThread *t = GetCurrentThread(); + if (!t || !StackTrace::WillUseFastUnwind(request_fast)) { + // Block reports from our interceptors during _Unwind_Backtrace. + SymbolizerScope sym_scope; + return Unwind(max_depth, pc, bp, context, t ? t->stack_top() : 0, + t ? t->stack_bottom() : 0, false); + } + if (StackTrace::WillUseFastUnwind(request_fast)) + Unwind(max_depth, pc, bp, nullptr, t->stack_top(), t->stack_bottom(), true); + else + Unwind(max_depth, pc, 0, context, 0, 0, false); +} + +// Interface. + +using namespace __msan; + +#define MSAN_MAYBE_WARNING(type, size) \ + void __msan_maybe_warning_##size(type s, u32 o) { \ + GET_CALLER_PC_BP_SP; \ + (void) sp; \ + if (UNLIKELY(s)) { \ + PrintWarningWithOrigin(pc, bp, o); \ + if (__msan::flags()->halt_on_error) { \ + Printf("Exiting\n"); \ + Die(); \ + } \ + } \ + } + +MSAN_MAYBE_WARNING(u8, 1) +MSAN_MAYBE_WARNING(u16, 2) +MSAN_MAYBE_WARNING(u32, 4) +MSAN_MAYBE_WARNING(u64, 8) + +#define MSAN_MAYBE_STORE_ORIGIN(type, size) \ + void __msan_maybe_store_origin_##size(type s, void *p, u32 o) { \ + if (UNLIKELY(s)) { \ + if (__msan_get_track_origins() > 1) { \ + GET_CALLER_PC_BP_SP; \ + (void) sp; \ + GET_STORE_STACK_TRACE_PC_BP(pc, bp); \ + o = ChainOrigin(o, &stack); \ + } \ + *(u32 *)MEM_TO_ORIGIN((uptr)p & ~3UL) = o; \ + } \ + } + +MSAN_MAYBE_STORE_ORIGIN(u8, 1) +MSAN_MAYBE_STORE_ORIGIN(u16, 2) +MSAN_MAYBE_STORE_ORIGIN(u32, 4) +MSAN_MAYBE_STORE_ORIGIN(u64, 8) + +void __msan_warning() { + GET_CALLER_PC_BP_SP; + (void)sp; + PrintWarning(pc, bp); + if (__msan::flags()->halt_on_error) { + if (__msan::flags()->print_stats) + ReportStats(); + Printf("Exiting\n"); + Die(); + } +} + +void __msan_warning_noreturn() { + GET_CALLER_PC_BP_SP; + (void)sp; + PrintWarning(pc, bp); + if (__msan::flags()->print_stats) + ReportStats(); + Printf("Exiting\n"); + Die(); +} + +void __msan_warning_with_origin(u32 origin) { + GET_CALLER_PC_BP_SP; + (void)sp; + PrintWarningWithOrigin(pc, bp, origin); + if (__msan::flags()->halt_on_error) { + if (__msan::flags()->print_stats) + ReportStats(); + Printf("Exiting\n"); + Die(); + } +} + +void __msan_warning_with_origin_noreturn(u32 origin) { + GET_CALLER_PC_BP_SP; + (void)sp; + PrintWarningWithOrigin(pc, bp, origin); + if (__msan::flags()->print_stats) + ReportStats(); + Printf("Exiting\n"); + Die(); +} + +static void OnStackUnwind(const SignalContext &sig, const void *, + BufferedStackTrace *stack) { + stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp, sig.context, + common_flags()->fast_unwind_on_fatal); +} + +static void MsanOnDeadlySignal(int signo, void *siginfo, void *context) { + HandleDeadlySignal(siginfo, context, GetTid(), &OnStackUnwind, nullptr); +} + +static void CheckUnwind() { + GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME()); + stack.Print(); +} + +void __msan_init() { + CHECK(!msan_init_is_running); + if (msan_inited) return; + msan_init_is_running = 1; + SanitizerToolName = "MemorySanitizer"; + + AvoidCVE_2016_2143(); + + CacheBinaryName(); + InitializeFlags(); + + // Install tool-specific callbacks in sanitizer_common. + SetCheckUnwindCallback(CheckUnwind); + + __sanitizer_set_report_path(common_flags()->log_path); + + InitializeInterceptors(); + CheckASLR(); + InitTlsSize(); + InstallDeadlySignalHandlers(MsanOnDeadlySignal); + InstallAtExitHandler(); // Needs __cxa_atexit interceptor. + + DisableCoreDumperIfNecessary(); + if (StackSizeIsUnlimited()) { + VPrintf(1, "Unlimited stack, doing reexec\n"); + // A reasonably large stack size. It is bigger than the usual 8Mb, because, + // well, the program could have been run with unlimited stack for a reason. + SetStackSizeLimitInBytes(32 * 1024 * 1024); + ReExec(); + } + + __msan_clear_on_return(); + if (__msan_get_track_origins()) + VPrintf(1, "msan_track_origins\n"); + if (!InitShadow(__msan_get_track_origins())) { + Printf("FATAL: MemorySanitizer can not mmap the shadow memory.\n"); + Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n"); + Printf("FATAL: Disabling ASLR is known to cause this error.\n"); + Printf("FATAL: If running under GDB, try " + "'set disable-randomization off'.\n"); + DumpProcessMap(); + Die(); + } + + Symbolizer::GetOrInit()->AddHooks(EnterSymbolizer, ExitSymbolizer); + + InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir); + + MsanTSDInit(MsanTSDDtor); + + MsanAllocatorInit(); + + MsanThread *main_thread = MsanThread::Create(nullptr, nullptr); + SetCurrentThread(main_thread); + main_thread->Init(); + +#if MSAN_CONTAINS_UBSAN + __ubsan::InitAsPlugin(); +#endif + + VPrintf(1, "MemorySanitizer init done\n"); + + msan_init_is_running = 0; + msan_inited = 1; +} + +void __msan_set_keep_going(int keep_going) { + flags()->halt_on_error = !keep_going; +} + +void __msan_set_expect_umr(int expect_umr) { + if (expect_umr) { + msan_expected_umr_found = 0; + } else if (!msan_expected_umr_found) { + GET_CALLER_PC_BP_SP; + (void)sp; + GET_FATAL_STACK_TRACE_PC_BP(pc, bp); + ReportExpectedUMRNotFound(&stack); + Die(); + } + msan_expect_umr = expect_umr; +} + +void __msan_print_shadow(const void *x, uptr size) { + if (!MEM_IS_APP(x)) { + Printf("Not a valid application address: %p\n", x); + return; + } + + DescribeMemoryRange(x, size); +} + +void __msan_dump_shadow(const void *x, uptr size) { + if (!MEM_IS_APP(x)) { + Printf("Not a valid application address: %p\n", x); + return; + } + + unsigned char *s = (unsigned char*)MEM_TO_SHADOW(x); + Printf("%p[%p] ", (void *)s, x); + for (uptr i = 0; i < size; i++) + Printf("%x%x ", s[i] >> 4, s[i] & 0xf); + Printf("\n"); +} + +sptr __msan_test_shadow(const void *x, uptr size) { + if (!MEM_IS_APP(x)) return -1; + unsigned char *s = (unsigned char *)MEM_TO_SHADOW((uptr)x); + if (__sanitizer::mem_is_zero((const char *)s, size)) + return -1; + // Slow path: loop through again to find the location. + for (uptr i = 0; i < size; ++i) + if (s[i]) + return i; + return -1; +} + +void __msan_check_mem_is_initialized(const void *x, uptr size) { + if (!__msan::flags()->report_umrs) return; + sptr offset = __msan_test_shadow(x, size); + if (offset < 0) + return; + + GET_CALLER_PC_BP_SP; + (void)sp; + ReportUMRInsideAddressRange(__func__, x, size, offset); + __msan::PrintWarningWithOrigin(pc, bp, + __msan_get_origin(((const char *)x) + offset)); + if (__msan::flags()->halt_on_error) { + Printf("Exiting\n"); + Die(); + } +} + +int __msan_set_poison_in_malloc(int do_poison) { + int old = flags()->poison_in_malloc; + flags()->poison_in_malloc = do_poison; + return old; +} + +int __msan_has_dynamic_component() { return false; } + +NOINLINE +void __msan_clear_on_return() { + __msan_param_tls[0] = 0; +} + +void __msan_partial_poison(const void* data, void* shadow, uptr size) { + internal_memcpy((void*)MEM_TO_SHADOW((uptr)data), shadow, size); +} + +void __msan_load_unpoisoned(const void *src, uptr size, void *dst) { + internal_memcpy(dst, src, size); + __msan_unpoison(dst, size); +} + +void __msan_set_origin(const void *a, uptr size, u32 origin) { + if (__msan_get_track_origins()) SetOrigin(a, size, origin); +} + +// 'descr' is created at compile time and contains '----' in the beginning. +// When we see descr for the first time we replace '----' with a uniq id +// and set the origin to (id | (31-th bit)). +void __msan_set_alloca_origin(void *a, uptr size, char *descr) { + __msan_set_alloca_origin4(a, size, descr, 0); +} + +void __msan_set_alloca_origin4(void *a, uptr size, char *descr, uptr pc) { + static const u32 dash = '-'; + static const u32 first_timer = + dash + (dash << 8) + (dash << 16) + (dash << 24); + u32 *id_ptr = (u32*)descr; + bool print = false; // internal_strstr(descr + 4, "AllocaTOTest") != 0; + u32 id = *id_ptr; + if (id == first_timer) { + u32 idx = atomic_fetch_add(&NumStackOriginDescrs, 1, memory_order_relaxed); + CHECK_LT(idx, kNumStackOriginDescrs); + StackOriginDescr[idx] = descr + 4; +#if SANITIZER_PPC64V1 + // On PowerPC64 ELFv1, the address of a function actually points to a + // three-doubleword data structure with the first field containing + // the address of the function's code. + if (pc) + pc = *reinterpret_cast<uptr*>(pc); +#endif + StackOriginPC[idx] = pc; + id = Origin::CreateStackOrigin(idx).raw_id(); + *id_ptr = id; + if (print) + Printf("First time: idx=%d id=%d %s 0x%zx \n", idx, id, descr + 4, pc); + } + if (print) + Printf("__msan_set_alloca_origin: descr=%s id=%x\n", descr + 4, id); + __msan_set_origin(a, size, id); +} + +u32 __msan_chain_origin(u32 id) { + GET_CALLER_PC_BP_SP; + (void)sp; + GET_STORE_STACK_TRACE_PC_BP(pc, bp); + return ChainOrigin(id, &stack); +} + +u32 __msan_get_origin(const void *a) { + if (!__msan_get_track_origins()) return 0; + uptr x = (uptr)a; + uptr aligned = x & ~3ULL; + uptr origin_ptr = MEM_TO_ORIGIN(aligned); + return *(u32*)origin_ptr; +} + +int __msan_origin_is_descendant_or_same(u32 this_id, u32 prev_id) { + Origin o = Origin::FromRawId(this_id); + while (o.raw_id() != prev_id && o.isChainedOrigin()) + o = o.getNextChainedOrigin(nullptr); + return o.raw_id() == prev_id; +} + +u32 __msan_get_umr_origin() { + return __msan_origin_tls; +} + +u16 __sanitizer_unaligned_load16(const uu16 *p) { + internal_memcpy(&__msan_retval_tls[0], (void *)MEM_TO_SHADOW((uptr)p), + sizeof(uu16)); + if (__msan_get_track_origins()) + __msan_retval_origin_tls = GetOriginIfPoisoned((uptr)p, sizeof(*p)); + return *p; +} +u32 __sanitizer_unaligned_load32(const uu32 *p) { + internal_memcpy(&__msan_retval_tls[0], (void *)MEM_TO_SHADOW((uptr)p), + sizeof(uu32)); + if (__msan_get_track_origins()) + __msan_retval_origin_tls = GetOriginIfPoisoned((uptr)p, sizeof(*p)); + return *p; +} +u64 __sanitizer_unaligned_load64(const uu64 *p) { + internal_memcpy(&__msan_retval_tls[0], (void *)MEM_TO_SHADOW((uptr)p), + sizeof(uu64)); + if (__msan_get_track_origins()) + __msan_retval_origin_tls = GetOriginIfPoisoned((uptr)p, sizeof(*p)); + return *p; +} +void __sanitizer_unaligned_store16(uu16 *p, u16 x) { + static_assert(sizeof(uu16) == sizeof(u16), "incompatible types"); + u16 s; + internal_memcpy(&s, &__msan_param_tls[1], sizeof(uu16)); + internal_memcpy((void *)MEM_TO_SHADOW((uptr)p), &s, sizeof(uu16)); + if (s && __msan_get_track_origins()) + if (uu32 o = __msan_param_origin_tls[2]) + SetOriginIfPoisoned((uptr)p, (uptr)&s, sizeof(s), o); + *p = x; +} +void __sanitizer_unaligned_store32(uu32 *p, u32 x) { + static_assert(sizeof(uu32) == sizeof(u32), "incompatible types"); + u32 s; + internal_memcpy(&s, &__msan_param_tls[1], sizeof(uu32)); + internal_memcpy((void *)MEM_TO_SHADOW((uptr)p), &s, sizeof(uu32)); + if (s && __msan_get_track_origins()) + if (uu32 o = __msan_param_origin_tls[2]) + SetOriginIfPoisoned((uptr)p, (uptr)&s, sizeof(s), o); + *p = x; +} +void __sanitizer_unaligned_store64(uu64 *p, u64 x) { + u64 s = __msan_param_tls[1]; + *(uu64 *)MEM_TO_SHADOW((uptr)p) = s; + if (s && __msan_get_track_origins()) + if (uu32 o = __msan_param_origin_tls[2]) + SetOriginIfPoisoned((uptr)p, (uptr)&s, sizeof(s), o); + *p = x; +} + +void __msan_set_death_callback(void (*callback)(void)) { + SetUserDieCallback(callback); +} + +void __msan_start_switch_fiber(const void *bottom, uptr size) { + MsanThread *t = GetCurrentThread(); + if (!t) { + VReport(1, "__msan_start_switch_fiber called from unknown thread\n"); + return; + } + t->StartSwitchFiber((uptr)bottom, size); +} + +void __msan_finish_switch_fiber(const void **bottom_old, uptr *size_old) { + MsanThread *t = GetCurrentThread(); + if (!t) { + VReport(1, "__msan_finish_switch_fiber called from unknown thread\n"); + return; + } + t->FinishSwitchFiber((uptr *)bottom_old, (uptr *)size_old); + + internal_memset(__msan_param_tls, 0, sizeof(__msan_param_tls)); + internal_memset(__msan_retval_tls, 0, sizeof(__msan_retval_tls)); + internal_memset(__msan_va_arg_tls, 0, sizeof(__msan_va_arg_tls)); + + if (__msan_get_track_origins()) { + internal_memset(__msan_param_origin_tls, 0, + sizeof(__msan_param_origin_tls)); + internal_memset(&__msan_retval_origin_tls, 0, + sizeof(__msan_retval_origin_tls)); + internal_memset(__msan_va_arg_origin_tls, 0, + sizeof(__msan_va_arg_origin_tls)); + } +} + +SANITIZER_INTERFACE_WEAK_DEF(const char *, __msan_default_options, void) { + return ""; +} + +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_print_stack_trace() { + GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME()); + stack.Print(); +} +} // extern "C" diff --git a/contrib/libs/clang14-rt/lib/msan/msan.h b/contrib/libs/clang14-rt/lib/msan/msan.h new file mode 100644 index 0000000000..4b2cec3175 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/msan/msan.h @@ -0,0 +1,402 @@ +//===-- msan.h --------------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of MemorySanitizer. +// +// Private MSan header. +//===----------------------------------------------------------------------===// + +#ifndef MSAN_H +#define MSAN_H + +#include "sanitizer_common/sanitizer_flags.h" +#include "sanitizer_common/sanitizer_internal_defs.h" +#include "sanitizer_common/sanitizer_stacktrace.h" +#include "msan_interface_internal.h" +#include "msan_flags.h" +#include "ubsan/ubsan_platform.h" + +#ifndef MSAN_REPLACE_OPERATORS_NEW_AND_DELETE +# define MSAN_REPLACE_OPERATORS_NEW_AND_DELETE 1 +#endif + +#ifndef MSAN_CONTAINS_UBSAN +# define MSAN_CONTAINS_UBSAN CAN_SANITIZE_UB +#endif + +struct MappingDesc { + uptr start; + uptr end; + enum Type { + INVALID, APP, SHADOW, ORIGIN + } type; + const char *name; +}; + + +#if SANITIZER_LINUX && defined(__mips64) + +// MIPS64 maps: +// - 0x0000000000-0x0200000000: Program own segments +// - 0xa200000000-0xc000000000: PIE program segments +// - 0xe200000000-0xffffffffff: libraries segments. +const MappingDesc kMemoryLayout[] = { + {0x000000000000ULL, 0x000200000000ULL, MappingDesc::APP, "app-1"}, + {0x000200000000ULL, 0x002200000000ULL, MappingDesc::INVALID, "invalid"}, + {0x002200000000ULL, 0x004000000000ULL, MappingDesc::SHADOW, "shadow-2"}, + {0x004000000000ULL, 0x004200000000ULL, MappingDesc::INVALID, "invalid"}, + {0x004200000000ULL, 0x006000000000ULL, MappingDesc::ORIGIN, "origin-2"}, + {0x006000000000ULL, 0x006200000000ULL, MappingDesc::INVALID, "invalid"}, + {0x006200000000ULL, 0x008000000000ULL, MappingDesc::SHADOW, "shadow-3"}, + {0x008000000000ULL, 0x008200000000ULL, MappingDesc::SHADOW, "shadow-1"}, + {0x008200000000ULL, 0x00a000000000ULL, MappingDesc::ORIGIN, "origin-3"}, + {0x00a000000000ULL, 0x00a200000000ULL, MappingDesc::ORIGIN, "origin-1"}, + {0x00a200000000ULL, 0x00c000000000ULL, MappingDesc::APP, "app-2"}, + {0x00c000000000ULL, 0x00e200000000ULL, MappingDesc::INVALID, "invalid"}, + {0x00e200000000ULL, 0x00ffffffffffULL, MappingDesc::APP, "app-3"}}; + +#define MEM_TO_SHADOW(mem) (((uptr)(mem)) ^ 0x8000000000ULL) +#define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x2000000000ULL) + +#elif SANITIZER_LINUX && defined(__aarch64__) + +// The mapping describes both 39-bits, 42-bits, and 48-bits VMA. AArch64 +// maps: +// - 0x0000000000000-0x0000010000000: 39/42/48-bits program own segments +// - 0x0005500000000-0x0005600000000: 39-bits PIE program segments +// - 0x0007f80000000-0x0007fffffffff: 39-bits libraries segments +// - 0x002aa00000000-0x002ab00000000: 42-bits PIE program segments +// - 0x003ff00000000-0x003ffffffffff: 42-bits libraries segments +// - 0x0aaaaa0000000-0x0aaab00000000: 48-bits PIE program segments +// - 0xffff000000000-0x1000000000000: 48-bits libraries segments +// It is fragmented in multiples segments to increase the memory available +// on 42-bits (12.21% of total VMA available for 42-bits and 13.28 for +// 39 bits). The 48-bits segments only cover the usual PIE/default segments +// plus some more segments (262144GB total, 0.39% total VMA). +const MappingDesc kMemoryLayout[] = { + {0x00000000000ULL, 0x01000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x01000000000ULL, 0x02000000000ULL, MappingDesc::SHADOW, "shadow-2"}, + {0x02000000000ULL, 0x03000000000ULL, MappingDesc::ORIGIN, "origin-2"}, + {0x03000000000ULL, 0x04000000000ULL, MappingDesc::SHADOW, "shadow-1"}, + {0x04000000000ULL, 0x05000000000ULL, MappingDesc::ORIGIN, "origin-1"}, + {0x05000000000ULL, 0x06000000000ULL, MappingDesc::APP, "app-1"}, + {0x06000000000ULL, 0x07000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x07000000000ULL, 0x08000000000ULL, MappingDesc::APP, "app-2"}, + {0x08000000000ULL, 0x09000000000ULL, MappingDesc::INVALID, "invalid"}, + // The mappings below are used only for 42-bits VMA. + {0x09000000000ULL, 0x0A000000000ULL, MappingDesc::SHADOW, "shadow-3"}, + {0x0A000000000ULL, 0x0B000000000ULL, MappingDesc::ORIGIN, "origin-3"}, + {0x0B000000000ULL, 0x0F000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x0F000000000ULL, 0x10000000000ULL, MappingDesc::APP, "app-3"}, + {0x10000000000ULL, 0x11000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x11000000000ULL, 0x12000000000ULL, MappingDesc::APP, "app-4"}, + {0x12000000000ULL, 0x17000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x17000000000ULL, 0x18000000000ULL, MappingDesc::SHADOW, "shadow-4"}, + {0x18000000000ULL, 0x19000000000ULL, MappingDesc::ORIGIN, "origin-4"}, + {0x19000000000ULL, 0x20000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x20000000000ULL, 0x21000000000ULL, MappingDesc::APP, "app-5"}, + {0x21000000000ULL, 0x26000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x26000000000ULL, 0x27000000000ULL, MappingDesc::SHADOW, "shadow-5"}, + {0x27000000000ULL, 0x28000000000ULL, MappingDesc::ORIGIN, "origin-5"}, + {0x28000000000ULL, 0x29000000000ULL, MappingDesc::SHADOW, "shadow-7"}, + {0x29000000000ULL, 0x2A000000000ULL, MappingDesc::ORIGIN, "origin-7"}, + {0x2A000000000ULL, 0x2B000000000ULL, MappingDesc::APP, "app-6"}, + {0x2B000000000ULL, 0x2C000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x2C000000000ULL, 0x2D000000000ULL, MappingDesc::SHADOW, "shadow-6"}, + {0x2D000000000ULL, 0x2E000000000ULL, MappingDesc::ORIGIN, "origin-6"}, + {0x2E000000000ULL, 0x2F000000000ULL, MappingDesc::APP, "app-7"}, + {0x2F000000000ULL, 0x39000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x39000000000ULL, 0x3A000000000ULL, MappingDesc::SHADOW, "shadow-9"}, + {0x3A000000000ULL, 0x3B000000000ULL, MappingDesc::ORIGIN, "origin-9"}, + {0x3B000000000ULL, 0x3C000000000ULL, MappingDesc::APP, "app-8"}, + {0x3C000000000ULL, 0x3D000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x3D000000000ULL, 0x3E000000000ULL, MappingDesc::SHADOW, "shadow-8"}, + {0x3E000000000ULL, 0x3F000000000ULL, MappingDesc::ORIGIN, "origin-8"}, + {0x3F000000000ULL, 0x40000000000ULL, MappingDesc::APP, "app-9"}, + // The mappings below are used only for 48-bits VMA. + // TODO(unknown): 48-bit mapping ony covers the usual PIE, non-PIE + // segments and some more segments totalizing 262144GB of VMA (which cover + // only 0.32% of all 48-bit VMA). Memory availability can be increase by + // adding multiple application segments like 39 and 42 mapping. + {0x0040000000000ULL, 0x0041000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x0041000000000ULL, 0x0042000000000ULL, MappingDesc::APP, "app-10"}, + {0x0042000000000ULL, 0x0047000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x0047000000000ULL, 0x0048000000000ULL, MappingDesc::SHADOW, "shadow-10"}, + {0x0048000000000ULL, 0x0049000000000ULL, MappingDesc::ORIGIN, "origin-10"}, + {0x0049000000000ULL, 0x0050000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x0050000000000ULL, 0x0051000000000ULL, MappingDesc::APP, "app-11"}, + {0x0051000000000ULL, 0x0056000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x0056000000000ULL, 0x0057000000000ULL, MappingDesc::SHADOW, "shadow-11"}, + {0x0057000000000ULL, 0x0058000000000ULL, MappingDesc::ORIGIN, "origin-11"}, + {0x0058000000000ULL, 0x0059000000000ULL, MappingDesc::APP, "app-12"}, + {0x0059000000000ULL, 0x005E000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x005E000000000ULL, 0x005F000000000ULL, MappingDesc::SHADOW, "shadow-12"}, + {0x005F000000000ULL, 0x0060000000000ULL, MappingDesc::ORIGIN, "origin-12"}, + {0x0060000000000ULL, 0x0061000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x0061000000000ULL, 0x0062000000000ULL, MappingDesc::APP, "app-13"}, + {0x0062000000000ULL, 0x0067000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x0067000000000ULL, 0x0068000000000ULL, MappingDesc::SHADOW, "shadow-13"}, + {0x0068000000000ULL, 0x0069000000000ULL, MappingDesc::ORIGIN, "origin-13"}, + {0x0069000000000ULL, 0x0AAAAA0000000ULL, MappingDesc::INVALID, "invalid"}, + {0x0AAAAA0000000ULL, 0x0AAAB00000000ULL, MappingDesc::APP, "app-14"}, + {0x0AAAB00000000ULL, 0x0AACAA0000000ULL, MappingDesc::INVALID, "invalid"}, + {0x0AACAA0000000ULL, 0x0AACB00000000ULL, MappingDesc::SHADOW, "shadow-14"}, + {0x0AACB00000000ULL, 0x0AADAA0000000ULL, MappingDesc::INVALID, "invalid"}, + {0x0AADAA0000000ULL, 0x0AADB00000000ULL, MappingDesc::ORIGIN, "origin-14"}, + {0x0AADB00000000ULL, 0x0FF9F00000000ULL, MappingDesc::INVALID, "invalid"}, + {0x0FF9F00000000ULL, 0x0FFA000000000ULL, MappingDesc::SHADOW, "shadow-15"}, + {0x0FFA000000000ULL, 0x0FFAF00000000ULL, MappingDesc::INVALID, "invalid"}, + {0x0FFAF00000000ULL, 0x0FFB000000000ULL, MappingDesc::ORIGIN, "origin-15"}, + {0x0FFB000000000ULL, 0x0FFFF00000000ULL, MappingDesc::INVALID, "invalid"}, + {0x0FFFF00000000ULL, 0x1000000000000ULL, MappingDesc::APP, "app-15"}, +}; +# define MEM_TO_SHADOW(mem) ((uptr)mem ^ 0x6000000000ULL) +# define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x1000000000ULL) + +#elif SANITIZER_LINUX && SANITIZER_PPC64 +const MappingDesc kMemoryLayout[] = { + {0x000000000000ULL, 0x000200000000ULL, MappingDesc::APP, "low memory"}, + {0x000200000000ULL, 0x080000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x080000000000ULL, 0x180200000000ULL, MappingDesc::SHADOW, "shadow"}, + {0x180200000000ULL, 0x1C0000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x1C0000000000ULL, 0x2C0200000000ULL, MappingDesc::ORIGIN, "origin"}, + {0x2C0200000000ULL, 0x300000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x300000000000ULL, 0x800000000000ULL, MappingDesc::APP, "high memory"}}; + +// Various kernels use different low end ranges but we can combine them into one +// big range. They also use different high end ranges but we can map them all to +// one range. +// Maps low and high app ranges to contiguous space with zero base: +// Low: 0000 0000 0000 - 0001 ffff ffff -> 1000 0000 0000 - 1001 ffff ffff +// High: 3000 0000 0000 - 3fff ffff ffff -> 0000 0000 0000 - 0fff ffff ffff +// High: 4000 0000 0000 - 4fff ffff ffff -> 0000 0000 0000 - 0fff ffff ffff +// High: 7000 0000 0000 - 7fff ffff ffff -> 0000 0000 0000 - 0fff ffff ffff +#define LINEARIZE_MEM(mem) \ + (((uptr)(mem) & ~0xE00000000000ULL) ^ 0x100000000000ULL) +#define MEM_TO_SHADOW(mem) (LINEARIZE_MEM((mem)) + 0x080000000000ULL) +#define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x140000000000ULL) + +#elif SANITIZER_LINUX && SANITIZER_S390_64 +const MappingDesc kMemoryLayout[] = { + {0x000000000000ULL, 0x040000000000ULL, MappingDesc::APP, "low memory"}, + {0x040000000000ULL, 0x080000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x080000000000ULL, 0x180000000000ULL, MappingDesc::SHADOW, "shadow"}, + {0x180000000000ULL, 0x1C0000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x1C0000000000ULL, 0x2C0000000000ULL, MappingDesc::ORIGIN, "origin"}, + {0x2C0000000000ULL, 0x440000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x440000000000ULL, 0x500000000000ULL, MappingDesc::APP, "high memory"}}; + +#define MEM_TO_SHADOW(mem) \ + ((((uptr)(mem)) & ~0xC00000000000ULL) + 0x080000000000ULL) +#define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x140000000000ULL) + +#elif SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 64 + +// Low memory: main binary, MAP_32BIT mappings and modules +// High memory: heap, modules and main thread stack +const MappingDesc kMemoryLayout[] = { + {0x000000000000ULL, 0x010000000000ULL, MappingDesc::APP, "low memory"}, + {0x010000000000ULL, 0x100000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x100000000000ULL, 0x310000000000ULL, MappingDesc::SHADOW, "shadow"}, + {0x310000000000ULL, 0x380000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x380000000000ULL, 0x590000000000ULL, MappingDesc::ORIGIN, "origin"}, + {0x590000000000ULL, 0x600000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x600000000000ULL, 0x800000000000ULL, MappingDesc::APP, "high memory"}}; + +// Maps low and high app ranges to contiguous space with zero base: +// Low: 0000 0000 0000 - 00ff ffff ffff -> 2000 0000 0000 - 20ff ffff ffff +// High: 6000 0000 0000 - 7fff ffff ffff -> 0000 0000 0000 - 1fff ffff ffff +#define LINEARIZE_MEM(mem) \ + (((uptr)(mem) & ~0xc00000000000ULL) ^ 0x200000000000ULL) +#define MEM_TO_SHADOW(mem) (LINEARIZE_MEM((mem)) + 0x100000000000ULL) +#define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x280000000000) + +#elif SANITIZER_NETBSD || (SANITIZER_LINUX && SANITIZER_WORDSIZE == 64) + +#ifdef MSAN_LINUX_X86_64_OLD_MAPPING +// Requires PIE binary and ASLR enabled. +// Main thread stack and DSOs at 0x7f0000000000 (sometimes 0x7e0000000000). +// Heap at 0x600000000000. +const MappingDesc kMemoryLayout[] = { + {0x000000000000ULL, 0x200000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x200000000000ULL, 0x400000000000ULL, MappingDesc::SHADOW, "shadow"}, + {0x400000000000ULL, 0x600000000000ULL, MappingDesc::ORIGIN, "origin"}, + {0x600000000000ULL, 0x800000000000ULL, MappingDesc::APP, "app"}}; + +#define MEM_TO_SHADOW(mem) (((uptr)(mem)) & ~0x400000000000ULL) +#define SHADOW_TO_ORIGIN(mem) (((uptr)(mem)) + 0x200000000000ULL) +#else // MSAN_LINUX_X86_64_OLD_MAPPING +// All of the following configurations are supported. +// ASLR disabled: main executable and DSOs at 0x555550000000 +// PIE and ASLR: main executable and DSOs at 0x7f0000000000 +// non-PIE: main executable below 0x100000000, DSOs at 0x7f0000000000 +// Heap at 0x700000000000. +const MappingDesc kMemoryLayout[] = { + {0x000000000000ULL, 0x010000000000ULL, MappingDesc::APP, "app-1"}, + {0x010000000000ULL, 0x100000000000ULL, MappingDesc::SHADOW, "shadow-2"}, + {0x100000000000ULL, 0x110000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x110000000000ULL, 0x200000000000ULL, MappingDesc::ORIGIN, "origin-2"}, + {0x200000000000ULL, 0x300000000000ULL, MappingDesc::SHADOW, "shadow-3"}, + {0x300000000000ULL, 0x400000000000ULL, MappingDesc::ORIGIN, "origin-3"}, + {0x400000000000ULL, 0x500000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x500000000000ULL, 0x510000000000ULL, MappingDesc::SHADOW, "shadow-1"}, + {0x510000000000ULL, 0x600000000000ULL, MappingDesc::APP, "app-2"}, + {0x600000000000ULL, 0x610000000000ULL, MappingDesc::ORIGIN, "origin-1"}, + {0x610000000000ULL, 0x700000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x700000000000ULL, 0x800000000000ULL, MappingDesc::APP, "app-3"}}; +#define MEM_TO_SHADOW(mem) (((uptr)(mem)) ^ 0x500000000000ULL) +#define SHADOW_TO_ORIGIN(mem) (((uptr)(mem)) + 0x100000000000ULL) +#endif // MSAN_LINUX_X86_64_OLD_MAPPING + +#else +#error "Unsupported platform" +#endif + +const uptr kMemoryLayoutSize = sizeof(kMemoryLayout) / sizeof(kMemoryLayout[0]); + +#define MEM_TO_ORIGIN(mem) (SHADOW_TO_ORIGIN(MEM_TO_SHADOW((mem)))) + +#ifndef __clang__ +__attribute__((optimize("unroll-loops"))) +#endif +inline bool addr_is_type(uptr addr, MappingDesc::Type mapping_type) { +// It is critical for performance that this loop is unrolled (because then it is +// simplified into just a few constant comparisons). +#ifdef __clang__ +#pragma unroll +#endif + for (unsigned i = 0; i < kMemoryLayoutSize; ++i) + if (kMemoryLayout[i].type == mapping_type && + addr >= kMemoryLayout[i].start && addr < kMemoryLayout[i].end) + return true; + return false; +} + +#define MEM_IS_APP(mem) addr_is_type((uptr)(mem), MappingDesc::APP) +#define MEM_IS_SHADOW(mem) addr_is_type((uptr)(mem), MappingDesc::SHADOW) +#define MEM_IS_ORIGIN(mem) addr_is_type((uptr)(mem), MappingDesc::ORIGIN) + +// These constants must be kept in sync with the ones in MemorySanitizer.cpp. +const int kMsanParamTlsSize = 800; +const int kMsanRetvalTlsSize = 800; + +namespace __msan { +extern int msan_inited; +extern bool msan_init_is_running; +extern int msan_report_count; + +bool ProtectRange(uptr beg, uptr end); +bool InitShadow(bool init_origins); +char *GetProcSelfMaps(); +void InitializeInterceptors(); + +void MsanAllocatorInit(); +void MsanDeallocate(StackTrace *stack, void *ptr); + +void *msan_malloc(uptr size, StackTrace *stack); +void *msan_calloc(uptr nmemb, uptr size, StackTrace *stack); +void *msan_realloc(void *ptr, uptr size, StackTrace *stack); +void *msan_reallocarray(void *ptr, uptr nmemb, uptr size, StackTrace *stack); +void *msan_valloc(uptr size, StackTrace *stack); +void *msan_pvalloc(uptr size, StackTrace *stack); +void *msan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack); +void *msan_memalign(uptr alignment, uptr size, StackTrace *stack); +int msan_posix_memalign(void **memptr, uptr alignment, uptr size, + StackTrace *stack); + +void InstallTrapHandler(); +void InstallAtExitHandler(); + +const char *GetStackOriginDescr(u32 id, uptr *pc); + +void EnterSymbolizer(); +void ExitSymbolizer(); +bool IsInSymbolizer(); + +struct SymbolizerScope { + SymbolizerScope() { EnterSymbolizer(); } + ~SymbolizerScope() { ExitSymbolizer(); } +}; + +void PrintWarning(uptr pc, uptr bp); +void PrintWarningWithOrigin(uptr pc, uptr bp, u32 origin); + +// Unpoison first n function arguments. +void UnpoisonParam(uptr n); +void UnpoisonThreadLocalState(); + +// Returns a "chained" origin id, pointing to the given stack trace followed by +// the previous origin id. +u32 ChainOrigin(u32 id, StackTrace *stack); + +const int STACK_TRACE_TAG_POISON = StackTrace::TAG_CUSTOM + 1; + +#define GET_MALLOC_STACK_TRACE \ + BufferedStackTrace stack; \ + if (__msan_get_track_origins() && msan_inited) \ + stack.Unwind(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), \ + nullptr, common_flags()->fast_unwind_on_malloc, \ + common_flags()->malloc_context_size) + +// For platforms which support slow unwinder only, we restrict the store context +// size to 1, basically only storing the current pc. We do this because the slow +// unwinder which is based on libunwind is not async signal safe and causes +// random freezes in forking applications as well as in signal handlers. +#define GET_STORE_STACK_TRACE_PC_BP(pc, bp) \ + BufferedStackTrace stack; \ + if (__msan_get_track_origins() > 1 && msan_inited) { \ + int size = flags()->store_context_size; \ + if (!SANITIZER_CAN_FAST_UNWIND) \ + size = Min(size, 1); \ + stack.Unwind(pc, bp, nullptr, common_flags()->fast_unwind_on_malloc, size);\ + } + +#define GET_STORE_STACK_TRACE \ + GET_STORE_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME()) + +#define GET_FATAL_STACK_TRACE_PC_BP(pc, bp) \ + BufferedStackTrace stack; \ + if (msan_inited) { \ + stack.Unwind(pc, bp, nullptr, common_flags()->fast_unwind_on_fatal); \ + } + +class ScopedThreadLocalStateBackup { + public: + ScopedThreadLocalStateBackup() { Backup(); } + ~ScopedThreadLocalStateBackup() { Restore(); } + void Backup(); + void Restore(); + private: + u64 va_arg_overflow_size_tls; +}; + +void MsanTSDInit(void (*destructor)(void *tsd)); +void *MsanTSDGet(); +void MsanTSDSet(void *tsd); +void MsanTSDDtor(void *tsd); + +} // namespace __msan + +#define MSAN_MALLOC_HOOK(ptr, size) \ + do { \ + if (&__sanitizer_malloc_hook) { \ + UnpoisonParam(2); \ + __sanitizer_malloc_hook(ptr, size); \ + } \ + RunMallocHooks(ptr, size); \ + } while (false) +#define MSAN_FREE_HOOK(ptr) \ + do { \ + if (&__sanitizer_free_hook) { \ + UnpoisonParam(1); \ + __sanitizer_free_hook(ptr); \ + } \ + RunFreeHooks(ptr); \ + } while (false) + +#endif // MSAN_H diff --git a/contrib/libs/clang14-rt/lib/msan/msan_allocator.cpp b/contrib/libs/clang14-rt/lib/msan/msan_allocator.cpp new file mode 100644 index 0000000000..dc006457a5 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/msan/msan_allocator.cpp @@ -0,0 +1,375 @@ +//===-- msan_allocator.cpp -------------------------- ---------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of MemorySanitizer. +// +// MemorySanitizer allocator. +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_allocator.h" +#include "sanitizer_common/sanitizer_allocator_checks.h" +#include "sanitizer_common/sanitizer_allocator_interface.h" +#include "sanitizer_common/sanitizer_allocator_report.h" +#include "sanitizer_common/sanitizer_errno.h" +#include "msan.h" +#include "msan_allocator.h" +#include "msan_origin.h" +#include "msan_thread.h" +#include "msan_poisoning.h" + +namespace __msan { + +struct Metadata { + uptr requested_size; +}; + +struct MsanMapUnmapCallback { + void OnMap(uptr p, uptr size) const {} + void OnUnmap(uptr p, uptr size) const { + __msan_unpoison((void *)p, size); + + // We are about to unmap a chunk of user memory. + // Mark the corresponding shadow memory as not needed. + uptr shadow_p = MEM_TO_SHADOW(p); + ReleaseMemoryPagesToOS(shadow_p, shadow_p + size); + if (__msan_get_track_origins()) { + uptr origin_p = MEM_TO_ORIGIN(p); + ReleaseMemoryPagesToOS(origin_p, origin_p + size); + } + } +}; + +#if defined(__mips64) +static const uptr kMaxAllowedMallocSize = 2UL << 30; + +struct AP32 { + static const uptr kSpaceBeg = 0; + static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; + static const uptr kMetadataSize = sizeof(Metadata); + typedef __sanitizer::CompactSizeClassMap SizeClassMap; + static const uptr kRegionSizeLog = 20; + using AddressSpaceView = LocalAddressSpaceView; + typedef MsanMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; +}; +typedef SizeClassAllocator32<AP32> PrimaryAllocator; +#elif defined(__x86_64__) +#if SANITIZER_NETBSD || \ + (SANITIZER_LINUX && !defined(MSAN_LINUX_X86_64_OLD_MAPPING)) +static const uptr kAllocatorSpace = 0x700000000000ULL; +#else +static const uptr kAllocatorSpace = 0x600000000000ULL; +#endif +static const uptr kMaxAllowedMallocSize = 8UL << 30; + +struct AP64 { // Allocator64 parameters. Deliberately using a short name. + static const uptr kSpaceBeg = kAllocatorSpace; + static const uptr kSpaceSize = 0x40000000000; // 4T. + static const uptr kMetadataSize = sizeof(Metadata); + typedef DefaultSizeClassMap SizeClassMap; + typedef MsanMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; + using AddressSpaceView = LocalAddressSpaceView; +}; + +typedef SizeClassAllocator64<AP64> PrimaryAllocator; + +#elif defined(__powerpc64__) +static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G + +struct AP64 { // Allocator64 parameters. Deliberately using a short name. + static const uptr kSpaceBeg = 0x300000000000; + static const uptr kSpaceSize = 0x020000000000; // 2T. + static const uptr kMetadataSize = sizeof(Metadata); + typedef DefaultSizeClassMap SizeClassMap; + typedef MsanMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; + using AddressSpaceView = LocalAddressSpaceView; +}; + +typedef SizeClassAllocator64<AP64> PrimaryAllocator; +#elif defined(__s390x__) +static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G + +struct AP64 { // Allocator64 parameters. Deliberately using a short name. + static const uptr kSpaceBeg = 0x440000000000; + static const uptr kSpaceSize = 0x020000000000; // 2T. + static const uptr kMetadataSize = sizeof(Metadata); + typedef DefaultSizeClassMap SizeClassMap; + typedef MsanMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; + using AddressSpaceView = LocalAddressSpaceView; +}; + +typedef SizeClassAllocator64<AP64> PrimaryAllocator; +#elif defined(__aarch64__) +static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G + +struct AP32 { + static const uptr kSpaceBeg = 0; + static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; + static const uptr kMetadataSize = sizeof(Metadata); + typedef __sanitizer::CompactSizeClassMap SizeClassMap; + static const uptr kRegionSizeLog = 20; + using AddressSpaceView = LocalAddressSpaceView; + typedef MsanMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; +}; +typedef SizeClassAllocator32<AP32> PrimaryAllocator; +#endif +typedef CombinedAllocator<PrimaryAllocator> Allocator; +typedef Allocator::AllocatorCache AllocatorCache; + +static Allocator allocator; +static AllocatorCache fallback_allocator_cache; +static StaticSpinMutex fallback_mutex; + +static uptr max_malloc_size; + +void MsanAllocatorInit() { + SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null); + allocator.Init(common_flags()->allocator_release_to_os_interval_ms); + if (common_flags()->max_allocation_size_mb) + max_malloc_size = Min(common_flags()->max_allocation_size_mb << 20, + kMaxAllowedMallocSize); + else + max_malloc_size = kMaxAllowedMallocSize; +} + +AllocatorCache *GetAllocatorCache(MsanThreadLocalMallocStorage *ms) { + CHECK(ms); + CHECK_LE(sizeof(AllocatorCache), sizeof(ms->allocator_cache)); + return reinterpret_cast<AllocatorCache *>(ms->allocator_cache); +} + +void MsanThreadLocalMallocStorage::CommitBack() { + allocator.SwallowCache(GetAllocatorCache(this)); +} + +static void *MsanAllocate(StackTrace *stack, uptr size, uptr alignment, + bool zeroise) { + if (size > max_malloc_size) { + if (AllocatorMayReturnNull()) { + Report("WARNING: MemorySanitizer failed to allocate 0x%zx bytes\n", size); + return nullptr; + } + ReportAllocationSizeTooBig(size, max_malloc_size, stack); + } + if (UNLIKELY(IsRssLimitExceeded())) { + if (AllocatorMayReturnNull()) + return nullptr; + ReportRssLimitExceeded(stack); + } + MsanThread *t = GetCurrentThread(); + void *allocated; + if (t) { + AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage()); + allocated = allocator.Allocate(cache, size, alignment); + } else { + SpinMutexLock l(&fallback_mutex); + AllocatorCache *cache = &fallback_allocator_cache; + allocated = allocator.Allocate(cache, size, alignment); + } + if (UNLIKELY(!allocated)) { + SetAllocatorOutOfMemory(); + if (AllocatorMayReturnNull()) + return nullptr; + ReportOutOfMemory(size, stack); + } + Metadata *meta = + reinterpret_cast<Metadata *>(allocator.GetMetaData(allocated)); + meta->requested_size = size; + if (zeroise) { + __msan_clear_and_unpoison(allocated, size); + } else if (flags()->poison_in_malloc) { + __msan_poison(allocated, size); + if (__msan_get_track_origins()) { + stack->tag = StackTrace::TAG_ALLOC; + Origin o = Origin::CreateHeapOrigin(stack); + __msan_set_origin(allocated, size, o.raw_id()); + } + } + MSAN_MALLOC_HOOK(allocated, size); + return allocated; +} + +void MsanDeallocate(StackTrace *stack, void *p) { + CHECK(p); + MSAN_FREE_HOOK(p); + Metadata *meta = reinterpret_cast<Metadata *>(allocator.GetMetaData(p)); + uptr size = meta->requested_size; + meta->requested_size = 0; + // This memory will not be reused by anyone else, so we are free to keep it + // poisoned. + if (flags()->poison_in_free) { + __msan_poison(p, size); + if (__msan_get_track_origins()) { + stack->tag = StackTrace::TAG_DEALLOC; + Origin o = Origin::CreateHeapOrigin(stack); + __msan_set_origin(p, size, o.raw_id()); + } + } + MsanThread *t = GetCurrentThread(); + if (t) { + AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage()); + allocator.Deallocate(cache, p); + } else { + SpinMutexLock l(&fallback_mutex); + AllocatorCache *cache = &fallback_allocator_cache; + allocator.Deallocate(cache, p); + } +} + +static void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size, + uptr alignment) { + Metadata *meta = reinterpret_cast<Metadata*>(allocator.GetMetaData(old_p)); + uptr old_size = meta->requested_size; + uptr actually_allocated_size = allocator.GetActuallyAllocatedSize(old_p); + if (new_size <= actually_allocated_size) { + // We are not reallocating here. + meta->requested_size = new_size; + if (new_size > old_size) { + if (flags()->poison_in_malloc) { + stack->tag = StackTrace::TAG_ALLOC; + PoisonMemory((char *)old_p + old_size, new_size - old_size, stack); + } + } + return old_p; + } + uptr memcpy_size = Min(new_size, old_size); + void *new_p = MsanAllocate(stack, new_size, alignment, false /*zeroise*/); + if (new_p) { + CopyMemory(new_p, old_p, memcpy_size, stack); + MsanDeallocate(stack, old_p); + } + return new_p; +} + +static void *MsanCalloc(StackTrace *stack, uptr nmemb, uptr size) { + if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) { + if (AllocatorMayReturnNull()) + return nullptr; + ReportCallocOverflow(nmemb, size, stack); + } + return MsanAllocate(stack, nmemb * size, sizeof(u64), true); +} + +static uptr AllocationSize(const void *p) { + if (!p) return 0; + const void *beg = allocator.GetBlockBegin(p); + if (beg != p) return 0; + Metadata *b = (Metadata *)allocator.GetMetaData(p); + return b->requested_size; +} + +void *msan_malloc(uptr size, StackTrace *stack) { + return SetErrnoOnNull(MsanAllocate(stack, size, sizeof(u64), false)); +} + +void *msan_calloc(uptr nmemb, uptr size, StackTrace *stack) { + return SetErrnoOnNull(MsanCalloc(stack, nmemb, size)); +} + +void *msan_realloc(void *ptr, uptr size, StackTrace *stack) { + if (!ptr) + return SetErrnoOnNull(MsanAllocate(stack, size, sizeof(u64), false)); + if (size == 0) { + MsanDeallocate(stack, ptr); + return nullptr; + } + return SetErrnoOnNull(MsanReallocate(stack, ptr, size, sizeof(u64))); +} + +void *msan_reallocarray(void *ptr, uptr nmemb, uptr size, StackTrace *stack) { + if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) { + errno = errno_ENOMEM; + if (AllocatorMayReturnNull()) + return nullptr; + ReportReallocArrayOverflow(nmemb, size, stack); + } + return msan_realloc(ptr, nmemb * size, stack); +} + +void *msan_valloc(uptr size, StackTrace *stack) { + return SetErrnoOnNull(MsanAllocate(stack, size, GetPageSizeCached(), false)); +} + +void *msan_pvalloc(uptr size, StackTrace *stack) { + uptr PageSize = GetPageSizeCached(); + if (UNLIKELY(CheckForPvallocOverflow(size, PageSize))) { + errno = errno_ENOMEM; + if (AllocatorMayReturnNull()) + return nullptr; + ReportPvallocOverflow(size, stack); + } + // pvalloc(0) should allocate one page. + size = size ? RoundUpTo(size, PageSize) : PageSize; + return SetErrnoOnNull(MsanAllocate(stack, size, PageSize, false)); +} + +void *msan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack) { + if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(alignment, size))) { + errno = errno_EINVAL; + if (AllocatorMayReturnNull()) + return nullptr; + ReportInvalidAlignedAllocAlignment(size, alignment, stack); + } + return SetErrnoOnNull(MsanAllocate(stack, size, alignment, false)); +} + +void *msan_memalign(uptr alignment, uptr size, StackTrace *stack) { + if (UNLIKELY(!IsPowerOfTwo(alignment))) { + errno = errno_EINVAL; + if (AllocatorMayReturnNull()) + return nullptr; + ReportInvalidAllocationAlignment(alignment, stack); + } + return SetErrnoOnNull(MsanAllocate(stack, size, alignment, false)); +} + +int msan_posix_memalign(void **memptr, uptr alignment, uptr size, + StackTrace *stack) { + if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) { + if (AllocatorMayReturnNull()) + return errno_EINVAL; + ReportInvalidPosixMemalignAlignment(alignment, stack); + } + void *ptr = MsanAllocate(stack, size, alignment, false); + if (UNLIKELY(!ptr)) + // OOM error is already taken care of by MsanAllocate. + return errno_ENOMEM; + CHECK(IsAligned((uptr)ptr, alignment)); + *memptr = ptr; + return 0; +} + +} // namespace __msan + +using namespace __msan; + +uptr __sanitizer_get_current_allocated_bytes() { + uptr stats[AllocatorStatCount]; + allocator.GetStats(stats); + return stats[AllocatorStatAllocated]; +} + +uptr __sanitizer_get_heap_size() { + uptr stats[AllocatorStatCount]; + allocator.GetStats(stats); + return stats[AllocatorStatMapped]; +} + +uptr __sanitizer_get_free_bytes() { return 1; } + +uptr __sanitizer_get_unmapped_bytes() { return 1; } + +uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; } + +int __sanitizer_get_ownership(const void *p) { return AllocationSize(p) != 0; } + +uptr __sanitizer_get_allocated_size(const void *p) { return AllocationSize(p); } diff --git a/contrib/libs/clang14-rt/lib/msan/msan_allocator.h b/contrib/libs/clang14-rt/lib/msan/msan_allocator.h new file mode 100644 index 0000000000..365af4d0c4 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/msan/msan_allocator.h @@ -0,0 +1,31 @@ +//===-- msan_allocator.h ----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of MemorySanitizer. +// +//===----------------------------------------------------------------------===// + +#ifndef MSAN_ALLOCATOR_H +#define MSAN_ALLOCATOR_H + +#include "sanitizer_common/sanitizer_common.h" + +namespace __msan { + +struct MsanThreadLocalMallocStorage { + // Allocator cache contains atomic_uint64_t which must be 8-byte aligned. + ALIGNED(8) uptr allocator_cache[96 * (512 * 8 + 16)]; // Opaque. + void CommitBack(); + + private: + // These objects are allocated via mmap() and are zero-initialized. + MsanThreadLocalMallocStorage() {} +}; + +} // namespace __msan +#endif // MSAN_ALLOCATOR_H diff --git a/contrib/libs/clang14-rt/lib/msan/msan_chained_origin_depot.cpp b/contrib/libs/clang14-rt/lib/msan/msan_chained_origin_depot.cpp new file mode 100644 index 0000000000..49b14131a8 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/msan/msan_chained_origin_depot.cpp @@ -0,0 +1,42 @@ +//===-- msan_chained_origin_depot.cpp -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of MemorySanitizer. +// +// A storage for chained origins. +//===----------------------------------------------------------------------===// + +#include "msan_chained_origin_depot.h" + +#include "sanitizer_common/sanitizer_chained_origin_depot.h" + +namespace __msan { + +static ChainedOriginDepot chainedOriginDepot; + +StackDepotStats ChainedOriginDepotGetStats() { + return chainedOriginDepot.GetStats(); +} + +bool ChainedOriginDepotPut(u32 here_id, u32 prev_id, u32 *new_id) { + return chainedOriginDepot.Put(here_id, prev_id, new_id); +} + +u32 ChainedOriginDepotGet(u32 id, u32 *other) { + return chainedOriginDepot.Get(id, other); +} + +void ChainedOriginDepotLockAll() { + chainedOriginDepot.LockAll(); +} + +void ChainedOriginDepotUnlockAll() { + chainedOriginDepot.UnlockAll(); +} + +} // namespace __msan diff --git a/contrib/libs/clang14-rt/lib/msan/msan_chained_origin_depot.h b/contrib/libs/clang14-rt/lib/msan/msan_chained_origin_depot.h new file mode 100644 index 0000000000..ea51c77a90 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/msan/msan_chained_origin_depot.h @@ -0,0 +1,38 @@ +//===-- msan_chained_origin_depot.h -----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of MemorySanitizer. +// +// A storage for chained origins. +//===----------------------------------------------------------------------===// + +#ifndef MSAN_CHAINED_ORIGIN_DEPOT_H +#define MSAN_CHAINED_ORIGIN_DEPOT_H + +#include "sanitizer_common/sanitizer_common.h" + +namespace __msan { + +// Gets the statistic of the origin chain storage. +StackDepotStats ChainedOriginDepotGetStats(); + +// Stores a chain with StackDepot ID here_id and previous chain ID prev_id. +// If successful, returns true and the new chain id new_id. +// If the same element already exists, returns false and sets new_id to the +// existing ID. +bool ChainedOriginDepotPut(u32 here_id, u32 prev_id, u32 *new_id); + +// Retrieves the stored StackDepot ID for the given origin ID. +u32 ChainedOriginDepotGet(u32 id, u32 *other); + +void ChainedOriginDepotLockAll(); +void ChainedOriginDepotUnlockAll(); + +} // namespace __msan + +#endif // MSAN_CHAINED_ORIGIN_DEPOT_H diff --git a/contrib/libs/clang14-rt/lib/msan/msan_flags.h b/contrib/libs/clang14-rt/lib/msan/msan_flags.h new file mode 100644 index 0000000000..836dbbaa16 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/msan/msan_flags.h @@ -0,0 +1,29 @@ +//===-- msan_flags.h --------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of MemorySanitizer. +// +//===----------------------------------------------------------------------===// +#ifndef MSAN_FLAGS_H +#define MSAN_FLAGS_H + +namespace __msan { + +struct Flags { +#define MSAN_FLAG(Type, Name, DefaultValue, Description) Type Name; +#include "msan_flags.inc" +#undef MSAN_FLAG + + void SetDefaults(); +}; + +Flags *flags(); + +} // namespace __msan + +#endif // MSAN_FLAGS_H diff --git a/contrib/libs/clang14-rt/lib/msan/msan_flags.inc b/contrib/libs/clang14-rt/lib/msan/msan_flags.inc new file mode 100644 index 0000000000..e6a26015a2 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/msan/msan_flags.inc @@ -0,0 +1,34 @@ +//===-- msan_flags.inc ------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// MSan runtime flags. +// +//===----------------------------------------------------------------------===// +#ifndef MSAN_FLAG +# error "Define MSAN_FLAG prior to including this file!" +#endif + +// MSAN_FLAG(Type, Name, DefaultValue, Description) +// See COMMON_FLAG in sanitizer_flags.inc for more details. + +MSAN_FLAG(int, exit_code, -1, + "DEPRECATED. Use exitcode from common flags instead.") +MSAN_FLAG(int, origin_history_size, Origin::kMaxDepth, "") +MSAN_FLAG(int, origin_history_per_stack_limit, 20000, "") +MSAN_FLAG(bool, poison_heap_with_zeroes, false, "") +MSAN_FLAG(bool, poison_stack_with_zeroes, false, "") +MSAN_FLAG(bool, poison_in_malloc, true, "") +MSAN_FLAG(bool, poison_in_free, true, "") +MSAN_FLAG(bool, poison_in_dtor, false, "") +MSAN_FLAG(bool, report_umrs, true, "") +MSAN_FLAG(bool, wrap_signals, true, "") +MSAN_FLAG(bool, print_stats, false, "") +MSAN_FLAG(bool, halt_on_error, !&__msan_keep_going, "") +MSAN_FLAG(bool, atexit, false, "") +MSAN_FLAG(int, store_context_size, 20, + "Like malloc_context_size, but for uninit stores.") diff --git a/contrib/libs/clang14-rt/lib/msan/msan_interceptors.cpp b/contrib/libs/clang14-rt/lib/msan/msan_interceptors.cpp new file mode 100644 index 0000000000..487a27bba9 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/msan/msan_interceptors.cpp @@ -0,0 +1,1745 @@ +//===-- msan_interceptors.cpp ---------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of MemorySanitizer. +// +// Interceptors for standard library functions. +// +// FIXME: move as many interceptors as possible into +// sanitizer_common/sanitizer_common_interceptors.h +//===----------------------------------------------------------------------===// + +#include "interception/interception.h" +#include "msan.h" +#include "msan_chained_origin_depot.h" +#include "msan_origin.h" +#include "msan_poisoning.h" +#include "msan_report.h" +#include "msan_thread.h" +#include "sanitizer_common/sanitizer_allocator.h" +#include "sanitizer_common/sanitizer_allocator_dlsym.h" +#include "sanitizer_common/sanitizer_allocator_interface.h" +#include "sanitizer_common/sanitizer_atomic.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_errno.h" +#include "sanitizer_common/sanitizer_errno_codes.h" +#include "sanitizer_common/sanitizer_glibc_version.h" +#include "sanitizer_common/sanitizer_libc.h" +#include "sanitizer_common/sanitizer_linux.h" +#include "sanitizer_common/sanitizer_platform_limits_netbsd.h" +#include "sanitizer_common/sanitizer_platform_limits_posix.h" +#include "sanitizer_common/sanitizer_stackdepot.h" +#include "sanitizer_common/sanitizer_tls_get_addr.h" +#include "sanitizer_common/sanitizer_vector.h" + +#if SANITIZER_NETBSD +#define fstat __fstat50 +#define gettimeofday __gettimeofday50 +#define getrusage __getrusage50 +#define tzset __tzset50 +#endif + +#include <stdarg.h> +// ACHTUNG! No other system header includes in this file. +// Ideally, we should get rid of stdarg.h as well. + +using namespace __msan; + +using __sanitizer::memory_order; +using __sanitizer::atomic_load; +using __sanitizer::atomic_store; +using __sanitizer::atomic_uintptr_t; + +DECLARE_REAL(SIZE_T, strlen, const char *s) +DECLARE_REAL(SIZE_T, strnlen, const char *s, SIZE_T maxlen) +DECLARE_REAL(void *, memcpy, void *dest, const void *src, uptr n) +DECLARE_REAL(void *, memset, void *dest, int c, uptr n) + +// True if this is a nested interceptor. +static THREADLOCAL int in_interceptor_scope; + +void __msan_scoped_disable_interceptor_checks() { ++in_interceptor_scope; } +void __msan_scoped_enable_interceptor_checks() { --in_interceptor_scope; } + +struct InterceptorScope { + InterceptorScope() { ++in_interceptor_scope; } + ~InterceptorScope() { --in_interceptor_scope; } +}; + +bool IsInInterceptorScope() { + return in_interceptor_scope; +} + +struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> { + static bool UseImpl() { return !msan_inited; } +}; + +#define ENSURE_MSAN_INITED() do { \ + CHECK(!msan_init_is_running); \ + if (!msan_inited) { \ + __msan_init(); \ + } \ +} while (0) + +// Check that [x, x+n) range is unpoisoned. +#define CHECK_UNPOISONED_0(x, n) \ + do { \ + sptr __offset = __msan_test_shadow(x, n); \ + if (__msan::IsInSymbolizer()) break; \ + if (__offset >= 0 && __msan::flags()->report_umrs) { \ + GET_CALLER_PC_BP_SP; \ + (void)sp; \ + ReportUMRInsideAddressRange(__func__, x, n, __offset); \ + __msan::PrintWarningWithOrigin( \ + pc, bp, __msan_get_origin((const char *)x + __offset)); \ + if (__msan::flags()->halt_on_error) { \ + Printf("Exiting\n"); \ + Die(); \ + } \ + } \ + } while (0) + +// Check that [x, x+n) range is unpoisoned unless we are in a nested +// interceptor. +#define CHECK_UNPOISONED(x, n) \ + do { \ + if (!IsInInterceptorScope()) CHECK_UNPOISONED_0(x, n); \ + } while (0) + +#define CHECK_UNPOISONED_STRING_OF_LEN(x, len, n) \ + CHECK_UNPOISONED((x), \ + common_flags()->strict_string_checks ? (len) + 1 : (n) ) + +#define CHECK_UNPOISONED_STRING(x, n) \ + CHECK_UNPOISONED_STRING_OF_LEN((x), internal_strlen(x), (n)) + +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD +INTERCEPTOR(SIZE_T, fread_unlocked, void *ptr, SIZE_T size, SIZE_T nmemb, + void *file) { + ENSURE_MSAN_INITED(); + SIZE_T res = REAL(fread_unlocked)(ptr, size, nmemb, file); + if (res > 0) + __msan_unpoison(ptr, res *size); + return res; +} +#define MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED INTERCEPT_FUNCTION(fread_unlocked) +#else +#define MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED +#endif + +#if !SANITIZER_NETBSD +INTERCEPTOR(void *, mempcpy, void *dest, const void *src, SIZE_T n) { + return (char *)__msan_memcpy(dest, src, n) + n; +} +#define MSAN_MAYBE_INTERCEPT_MEMPCPY INTERCEPT_FUNCTION(mempcpy) +#else +#define MSAN_MAYBE_INTERCEPT_MEMPCPY +#endif + +INTERCEPTOR(void *, memccpy, void *dest, const void *src, int c, SIZE_T n) { + ENSURE_MSAN_INITED(); + void *res = REAL(memccpy)(dest, src, c, n); + CHECK(!res || (res >= dest && res <= (char *)dest + n)); + SIZE_T sz = res ? (char *)res - (char *)dest : n; + CHECK_UNPOISONED(src, sz); + __msan_unpoison(dest, sz); + return res; +} + +INTERCEPTOR(void *, bcopy, const void *src, void *dest, SIZE_T n) { + return __msan_memmove(dest, src, n); +} + +INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) { + GET_MALLOC_STACK_TRACE; + CHECK_NE(memptr, 0); + int res = msan_posix_memalign(memptr, alignment, size, &stack); + if (!res) + __msan_unpoison(memptr, sizeof(*memptr)); + return res; +} + +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD +INTERCEPTOR(void *, memalign, SIZE_T alignment, SIZE_T size) { + GET_MALLOC_STACK_TRACE; + return msan_memalign(alignment, size, &stack); +} +#define MSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign) +#else +#define MSAN_MAYBE_INTERCEPT_MEMALIGN +#endif + +INTERCEPTOR(void *, aligned_alloc, SIZE_T alignment, SIZE_T size) { + GET_MALLOC_STACK_TRACE; + return msan_aligned_alloc(alignment, size, &stack); +} + +#if !SANITIZER_NETBSD +INTERCEPTOR(void *, __libc_memalign, SIZE_T alignment, SIZE_T size) { + GET_MALLOC_STACK_TRACE; + void *ptr = msan_memalign(alignment, size, &stack); + if (ptr) + DTLS_on_libc_memalign(ptr, size); + return ptr; +} +#define MSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN INTERCEPT_FUNCTION(__libc_memalign) +#else +#define MSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN +#endif + +INTERCEPTOR(void *, valloc, SIZE_T size) { + GET_MALLOC_STACK_TRACE; + return msan_valloc(size, &stack); +} + +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD +INTERCEPTOR(void *, pvalloc, SIZE_T size) { + GET_MALLOC_STACK_TRACE; + return msan_pvalloc(size, &stack); +} +#define MSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc) +#else +#define MSAN_MAYBE_INTERCEPT_PVALLOC +#endif + +INTERCEPTOR(void, free, void *ptr) { + if (UNLIKELY(!ptr)) + return; + if (DlsymAlloc::PointerIsMine(ptr)) + return DlsymAlloc::Free(ptr); + GET_MALLOC_STACK_TRACE; + MsanDeallocate(&stack, ptr); +} + +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD +INTERCEPTOR(void, cfree, void *ptr) { + if (UNLIKELY(!ptr)) + return; + if (DlsymAlloc::PointerIsMine(ptr)) + return DlsymAlloc::Free(ptr); + GET_MALLOC_STACK_TRACE; + MsanDeallocate(&stack, ptr); +} +# define MSAN_MAYBE_INTERCEPT_CFREE INTERCEPT_FUNCTION(cfree) +#else +#define MSAN_MAYBE_INTERCEPT_CFREE +#endif + +#if !SANITIZER_NETBSD +INTERCEPTOR(uptr, malloc_usable_size, void *ptr) { + return __sanitizer_get_allocated_size(ptr); +} +#define MSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE \ + INTERCEPT_FUNCTION(malloc_usable_size) +#else +#define MSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE +#endif + +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD +// This function actually returns a struct by value, but we can't unpoison a +// temporary! The following is equivalent on all supported platforms but +// aarch64 (which uses a different register for sret value). We have a test +// to confirm that. +INTERCEPTOR(void, mallinfo, __sanitizer_struct_mallinfo *sret) { +#ifdef __aarch64__ + uptr r8; + asm volatile("mov %0,x8" : "=r" (r8)); + sret = reinterpret_cast<__sanitizer_struct_mallinfo*>(r8); +#endif + REAL(memset)(sret, 0, sizeof(*sret)); + __msan_unpoison(sret, sizeof(*sret)); +} +#define MSAN_MAYBE_INTERCEPT_MALLINFO INTERCEPT_FUNCTION(mallinfo) +#else +#define MSAN_MAYBE_INTERCEPT_MALLINFO +#endif + +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD +INTERCEPTOR(int, mallopt, int cmd, int value) { + return 0; +} +#define MSAN_MAYBE_INTERCEPT_MALLOPT INTERCEPT_FUNCTION(mallopt) +#else +#define MSAN_MAYBE_INTERCEPT_MALLOPT +#endif + +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD +INTERCEPTOR(void, malloc_stats, void) { + // FIXME: implement, but don't call REAL(malloc_stats)! +} +#define MSAN_MAYBE_INTERCEPT_MALLOC_STATS INTERCEPT_FUNCTION(malloc_stats) +#else +#define MSAN_MAYBE_INTERCEPT_MALLOC_STATS +#endif + +INTERCEPTOR(char *, strcpy, char *dest, const char *src) { + ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; + SIZE_T n = internal_strlen(src); + CHECK_UNPOISONED_STRING(src + n, 0); + char *res = REAL(strcpy)(dest, src); + CopyShadowAndOrigin(dest, src, n + 1, &stack); + return res; +} + +INTERCEPTOR(char *, strncpy, char *dest, const char *src, SIZE_T n) { + ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; + SIZE_T copy_size = internal_strnlen(src, n); + if (copy_size < n) + copy_size++; // trailing \0 + char *res = REAL(strncpy)(dest, src, n); + CopyShadowAndOrigin(dest, src, copy_size, &stack); + __msan_unpoison(dest + copy_size, n - copy_size); + return res; +} + +#if !SANITIZER_NETBSD +INTERCEPTOR(char *, stpcpy, char *dest, const char *src) { + ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; + SIZE_T n = internal_strlen(src); + CHECK_UNPOISONED_STRING(src + n, 0); + char *res = REAL(stpcpy)(dest, src); + CopyShadowAndOrigin(dest, src, n + 1, &stack); + return res; +} +#define MSAN_MAYBE_INTERCEPT_STPCPY INTERCEPT_FUNCTION(stpcpy) +#else +#define MSAN_MAYBE_INTERCEPT_STPCPY +#endif + +INTERCEPTOR(char *, strdup, char *src) { + ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; + // On FreeBSD strdup() leverages strlen(). + InterceptorScope interceptor_scope; + SIZE_T n = internal_strlen(src); + CHECK_UNPOISONED_STRING(src + n, 0); + char *res = REAL(strdup)(src); + CopyShadowAndOrigin(res, src, n + 1, &stack); + return res; +} + +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD +INTERCEPTOR(char *, __strdup, char *src) { + ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; + SIZE_T n = internal_strlen(src); + CHECK_UNPOISONED_STRING(src + n, 0); + char *res = REAL(__strdup)(src); + CopyShadowAndOrigin(res, src, n + 1, &stack); + return res; +} +#define MSAN_MAYBE_INTERCEPT___STRDUP INTERCEPT_FUNCTION(__strdup) +#else +#define MSAN_MAYBE_INTERCEPT___STRDUP +#endif + +#if !SANITIZER_NETBSD +INTERCEPTOR(char *, gcvt, double number, SIZE_T ndigit, char *buf) { + ENSURE_MSAN_INITED(); + char *res = REAL(gcvt)(number, ndigit, buf); + SIZE_T n = internal_strlen(buf); + __msan_unpoison(buf, n + 1); + return res; +} +#define MSAN_MAYBE_INTERCEPT_GCVT INTERCEPT_FUNCTION(gcvt) +#else +#define MSAN_MAYBE_INTERCEPT_GCVT +#endif + +INTERCEPTOR(char *, strcat, char *dest, const char *src) { + ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; + SIZE_T src_size = internal_strlen(src); + SIZE_T dest_size = internal_strlen(dest); + CHECK_UNPOISONED_STRING(src + src_size, 0); + CHECK_UNPOISONED_STRING(dest + dest_size, 0); + char *res = REAL(strcat)(dest, src); + CopyShadowAndOrigin(dest + dest_size, src, src_size + 1, &stack); + return res; +} + +INTERCEPTOR(char *, strncat, char *dest, const char *src, SIZE_T n) { + ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; + SIZE_T dest_size = internal_strlen(dest); + SIZE_T copy_size = internal_strnlen(src, n); + CHECK_UNPOISONED_STRING(dest + dest_size, 0); + char *res = REAL(strncat)(dest, src, n); + CopyShadowAndOrigin(dest + dest_size, src, copy_size, &stack); + __msan_unpoison(dest + dest_size + copy_size, 1); // \0 + return res; +} + +// Hack: always pass nptr and endptr as part of __VA_ARGS_ to avoid having to +// deal with empty __VA_ARGS__ in the case of INTERCEPTOR_STRTO. +#define INTERCEPTOR_STRTO_BODY(ret_type, func, ...) \ + ENSURE_MSAN_INITED(); \ + ret_type res = REAL(func)(__VA_ARGS__); \ + __msan_unpoison(endptr, sizeof(*endptr)); \ + return res; + +#define INTERCEPTOR_STRTO(ret_type, func, char_type) \ + INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr) { \ + INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr); \ + } + +#define INTERCEPTOR_STRTO_BASE(ret_type, func, char_type) \ + INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \ + int base) { \ + INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, base); \ + } + +#define INTERCEPTOR_STRTO_LOC(ret_type, func, char_type) \ + INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \ + void *loc) { \ + INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, loc); \ + } + +#define INTERCEPTOR_STRTO_BASE_LOC(ret_type, func, char_type) \ + INTERCEPTOR(ret_type, func, const char_type *nptr, char_type **endptr, \ + int base, void *loc) { \ + INTERCEPTOR_STRTO_BODY(ret_type, func, nptr, endptr, base, loc); \ + } + +#if SANITIZER_NETBSD +#define INTERCEPTORS_STRTO(ret_type, func, char_type) \ + INTERCEPTOR_STRTO(ret_type, func, char_type) \ + INTERCEPTOR_STRTO_LOC(ret_type, func##_l, char_type) + +#define INTERCEPTORS_STRTO_BASE(ret_type, func, char_type) \ + INTERCEPTOR_STRTO_BASE(ret_type, func, char_type) \ + INTERCEPTOR_STRTO_BASE_LOC(ret_type, func##_l, char_type) + +#else +#define INTERCEPTORS_STRTO(ret_type, func, char_type) \ + INTERCEPTOR_STRTO(ret_type, func, char_type) \ + INTERCEPTOR_STRTO_LOC(ret_type, func##_l, char_type) \ + INTERCEPTOR_STRTO_LOC(ret_type, __##func##_l, char_type) \ + INTERCEPTOR_STRTO_LOC(ret_type, __##func##_internal, char_type) + +#define INTERCEPTORS_STRTO_BASE(ret_type, func, char_type) \ + INTERCEPTOR_STRTO_BASE(ret_type, func, char_type) \ + INTERCEPTOR_STRTO_BASE_LOC(ret_type, func##_l, char_type) \ + INTERCEPTOR_STRTO_BASE_LOC(ret_type, __##func##_l, char_type) \ + INTERCEPTOR_STRTO_BASE_LOC(ret_type, __##func##_internal, char_type) +#endif + +INTERCEPTORS_STRTO(double, strtod, char) +INTERCEPTORS_STRTO(float, strtof, char) +INTERCEPTORS_STRTO(long double, strtold, char) +INTERCEPTORS_STRTO_BASE(long, strtol, char) +INTERCEPTORS_STRTO_BASE(long long, strtoll, char) +INTERCEPTORS_STRTO_BASE(unsigned long, strtoul, char) +INTERCEPTORS_STRTO_BASE(unsigned long long, strtoull, char) +INTERCEPTORS_STRTO_BASE(u64, strtouq, char) + +INTERCEPTORS_STRTO(double, wcstod, wchar_t) +INTERCEPTORS_STRTO(float, wcstof, wchar_t) +INTERCEPTORS_STRTO(long double, wcstold, wchar_t) +INTERCEPTORS_STRTO_BASE(long, wcstol, wchar_t) +INTERCEPTORS_STRTO_BASE(long long, wcstoll, wchar_t) +INTERCEPTORS_STRTO_BASE(unsigned long, wcstoul, wchar_t) +INTERCEPTORS_STRTO_BASE(unsigned long long, wcstoull, wchar_t) + +#if SANITIZER_NETBSD +#define INTERCEPT_STRTO(func) \ + INTERCEPT_FUNCTION(func); \ + INTERCEPT_FUNCTION(func##_l); +#else +#define INTERCEPT_STRTO(func) \ + INTERCEPT_FUNCTION(func); \ + INTERCEPT_FUNCTION(func##_l); \ + INTERCEPT_FUNCTION(__##func##_l); \ + INTERCEPT_FUNCTION(__##func##_internal); +#endif + + +// FIXME: support *wprintf in common format interceptors. +INTERCEPTOR(int, vswprintf, void *str, uptr size, void *format, va_list ap) { + ENSURE_MSAN_INITED(); + int res = REAL(vswprintf)(str, size, format, ap); + if (res >= 0) { + __msan_unpoison(str, 4 * (res + 1)); + } + return res; +} + +INTERCEPTOR(int, swprintf, void *str, uptr size, void *format, ...) { + ENSURE_MSAN_INITED(); + va_list ap; + va_start(ap, format); + int res = vswprintf(str, size, format, ap); + va_end(ap); + return res; +} + +#define INTERCEPTOR_STRFTIME_BODY(char_type, ret_type, func, s, ...) \ + ENSURE_MSAN_INITED(); \ + InterceptorScope interceptor_scope; \ + ret_type res = REAL(func)(s, __VA_ARGS__); \ + if (s) __msan_unpoison(s, sizeof(char_type) * (res + 1)); \ + return res; + +INTERCEPTOR(SIZE_T, strftime, char *s, SIZE_T max, const char *format, + __sanitizer_tm *tm) { + INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, strftime, s, max, format, tm); +} + +INTERCEPTOR(SIZE_T, strftime_l, char *s, SIZE_T max, const char *format, + __sanitizer_tm *tm, void *loc) { + INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, strftime_l, s, max, format, tm, loc); +} + +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD +INTERCEPTOR(SIZE_T, __strftime_l, char *s, SIZE_T max, const char *format, + __sanitizer_tm *tm, void *loc) { + INTERCEPTOR_STRFTIME_BODY(char, SIZE_T, __strftime_l, s, max, format, tm, + loc); +} +#define MSAN_MAYBE_INTERCEPT___STRFTIME_L INTERCEPT_FUNCTION(__strftime_l) +#else +#define MSAN_MAYBE_INTERCEPT___STRFTIME_L +#endif + +INTERCEPTOR(SIZE_T, wcsftime, wchar_t *s, SIZE_T max, const wchar_t *format, + __sanitizer_tm *tm) { + INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, wcsftime, s, max, format, tm); +} + +INTERCEPTOR(SIZE_T, wcsftime_l, wchar_t *s, SIZE_T max, const wchar_t *format, + __sanitizer_tm *tm, void *loc) { + INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, wcsftime_l, s, max, format, tm, + loc); +} + +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD +INTERCEPTOR(SIZE_T, __wcsftime_l, wchar_t *s, SIZE_T max, const wchar_t *format, + __sanitizer_tm *tm, void *loc) { + INTERCEPTOR_STRFTIME_BODY(wchar_t, SIZE_T, __wcsftime_l, s, max, format, tm, + loc); +} +#define MSAN_MAYBE_INTERCEPT___WCSFTIME_L INTERCEPT_FUNCTION(__wcsftime_l) +#else +#define MSAN_MAYBE_INTERCEPT___WCSFTIME_L +#endif + +INTERCEPTOR(int, mbtowc, wchar_t *dest, const char *src, SIZE_T n) { + ENSURE_MSAN_INITED(); + int res = REAL(mbtowc)(dest, src, n); + if (res != -1 && dest) __msan_unpoison(dest, sizeof(wchar_t)); + return res; +} + +INTERCEPTOR(SIZE_T, mbrtowc, wchar_t *dest, const char *src, SIZE_T n, + void *ps) { + ENSURE_MSAN_INITED(); + SIZE_T res = REAL(mbrtowc)(dest, src, n, ps); + if (res != (SIZE_T)-1 && dest) __msan_unpoison(dest, sizeof(wchar_t)); + return res; +} + +// wchar_t *wmemcpy(wchar_t *dest, const wchar_t *src, SIZE_T n); +INTERCEPTOR(wchar_t *, wmemcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) { + ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; + wchar_t *res = REAL(wmemcpy)(dest, src, n); + CopyShadowAndOrigin(dest, src, n * sizeof(wchar_t), &stack); + return res; +} + +#if !SANITIZER_NETBSD +INTERCEPTOR(wchar_t *, wmempcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) { + ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; + wchar_t *res = REAL(wmempcpy)(dest, src, n); + CopyShadowAndOrigin(dest, src, n * sizeof(wchar_t), &stack); + return res; +} +#define MSAN_MAYBE_INTERCEPT_WMEMPCPY INTERCEPT_FUNCTION(wmempcpy) +#else +#define MSAN_MAYBE_INTERCEPT_WMEMPCPY +#endif + +INTERCEPTOR(wchar_t *, wmemset, wchar_t *s, wchar_t c, SIZE_T n) { + CHECK(MEM_IS_APP(s)); + ENSURE_MSAN_INITED(); + wchar_t *res = REAL(wmemset)(s, c, n); + __msan_unpoison(s, n * sizeof(wchar_t)); + return res; +} + +INTERCEPTOR(wchar_t *, wmemmove, wchar_t *dest, const wchar_t *src, SIZE_T n) { + ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; + wchar_t *res = REAL(wmemmove)(dest, src, n); + MoveShadowAndOrigin(dest, src, n * sizeof(wchar_t), &stack); + return res; +} + +INTERCEPTOR(int, wcscmp, const wchar_t *s1, const wchar_t *s2) { + ENSURE_MSAN_INITED(); + int res = REAL(wcscmp)(s1, s2); + return res; +} + +INTERCEPTOR(int, gettimeofday, void *tv, void *tz) { + ENSURE_MSAN_INITED(); + int res = REAL(gettimeofday)(tv, tz); + if (tv) + __msan_unpoison(tv, 16); + if (tz) + __msan_unpoison(tz, 8); + return res; +} + +#if !SANITIZER_NETBSD +INTERCEPTOR(char *, fcvt, double x, int a, int *b, int *c) { + ENSURE_MSAN_INITED(); + char *res = REAL(fcvt)(x, a, b, c); + __msan_unpoison(b, sizeof(*b)); + __msan_unpoison(c, sizeof(*c)); + if (res) + __msan_unpoison(res, internal_strlen(res) + 1); + return res; +} +#define MSAN_MAYBE_INTERCEPT_FCVT INTERCEPT_FUNCTION(fcvt) +#else +#define MSAN_MAYBE_INTERCEPT_FCVT +#endif + +INTERCEPTOR(char *, getenv, char *name) { + if (msan_init_is_running) + return REAL(getenv)(name); + ENSURE_MSAN_INITED(); + char *res = REAL(getenv)(name); + if (res) + __msan_unpoison(res, internal_strlen(res) + 1); + return res; +} + +extern char **environ; + +static void UnpoisonEnviron() { + char **envp = environ; + for (; *envp; ++envp) { + __msan_unpoison(envp, sizeof(*envp)); + __msan_unpoison(*envp, internal_strlen(*envp) + 1); + } + // Trailing NULL pointer. + __msan_unpoison(envp, sizeof(*envp)); +} + +INTERCEPTOR(int, setenv, const char *name, const char *value, int overwrite) { + ENSURE_MSAN_INITED(); + CHECK_UNPOISONED_STRING(name, 0); + int res = REAL(setenv)(name, value, overwrite); + if (!res) UnpoisonEnviron(); + return res; +} + +INTERCEPTOR(int, putenv, char *string) { + ENSURE_MSAN_INITED(); + int res = REAL(putenv)(string); + if (!res) UnpoisonEnviron(); + return res; +} + +#define SANITIZER_STAT_LINUX (SANITIZER_LINUX && __GLIBC_PREREQ(2, 33)) +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_STAT_LINUX +INTERCEPTOR(int, fstat, int fd, void *buf) { + ENSURE_MSAN_INITED(); + int res = REAL(fstat)(fd, buf); + if (!res) + __msan_unpoison(buf, __sanitizer::struct_stat_sz); + return res; +} +# define MSAN_MAYBE_INTERCEPT_FSTAT MSAN_INTERCEPT_FUNC(fstat) +#else +#define MSAN_MAYBE_INTERCEPT_FSTAT +#endif + +#if SANITIZER_GLIBC +INTERCEPTOR(int, __fxstat, int magic, int fd, void *buf) { + ENSURE_MSAN_INITED(); + int res = REAL(__fxstat)(magic, fd, buf); + if (!res) + __msan_unpoison(buf, __sanitizer::struct_stat_sz); + return res; +} +# define MSAN_MAYBE_INTERCEPT___FXSTAT MSAN_INTERCEPT_FUNC(__fxstat) +#else +#define MSAN_MAYBE_INTERCEPT___FXSTAT +#endif + +#if SANITIZER_GLIBC +INTERCEPTOR(int, __fxstat64, int magic, int fd, void *buf) { + ENSURE_MSAN_INITED(); + int res = REAL(__fxstat64)(magic, fd, buf); + if (!res) + __msan_unpoison(buf, __sanitizer::struct_stat64_sz); + return res; +} +# define MSAN_MAYBE_INTERCEPT___FXSTAT64 MSAN_INTERCEPT_FUNC(__fxstat64) +#else +# define MSAN_MAYBE_INTERCEPT___FXSTAT64 +#endif + +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_STAT_LINUX +INTERCEPTOR(int, fstatat, int fd, char *pathname, void *buf, int flags) { + ENSURE_MSAN_INITED(); + int res = REAL(fstatat)(fd, pathname, buf, flags); + if (!res) __msan_unpoison(buf, __sanitizer::struct_stat_sz); + return res; +} +# define MSAN_MAYBE_INTERCEPT_FSTATAT MSAN_INTERCEPT_FUNC(fstatat) +#else +# define MSAN_MAYBE_INTERCEPT_FSTATAT +#endif + +#if SANITIZER_GLIBC +INTERCEPTOR(int, __fxstatat, int magic, int fd, char *pathname, void *buf, + int flags) { + ENSURE_MSAN_INITED(); + int res = REAL(__fxstatat)(magic, fd, pathname, buf, flags); + if (!res) __msan_unpoison(buf, __sanitizer::struct_stat_sz); + return res; +} +# define MSAN_MAYBE_INTERCEPT___FXSTATAT MSAN_INTERCEPT_FUNC(__fxstatat) +#else +# define MSAN_MAYBE_INTERCEPT___FXSTATAT +#endif + +#if SANITIZER_GLIBC +INTERCEPTOR(int, __fxstatat64, int magic, int fd, char *pathname, void *buf, + int flags) { + ENSURE_MSAN_INITED(); + int res = REAL(__fxstatat64)(magic, fd, pathname, buf, flags); + if (!res) __msan_unpoison(buf, __sanitizer::struct_stat64_sz); + return res; +} +# define MSAN_MAYBE_INTERCEPT___FXSTATAT64 MSAN_INTERCEPT_FUNC(__fxstatat64) +#else +# define MSAN_MAYBE_INTERCEPT___FXSTATAT64 +#endif + +INTERCEPTOR(int, pipe, int pipefd[2]) { + if (msan_init_is_running) + return REAL(pipe)(pipefd); + ENSURE_MSAN_INITED(); + int res = REAL(pipe)(pipefd); + if (!res) + __msan_unpoison(pipefd, sizeof(int[2])); + return res; +} + +INTERCEPTOR(int, pipe2, int pipefd[2], int flags) { + ENSURE_MSAN_INITED(); + int res = REAL(pipe2)(pipefd, flags); + if (!res) + __msan_unpoison(pipefd, sizeof(int[2])); + return res; +} + +INTERCEPTOR(int, socketpair, int domain, int type, int protocol, int sv[2]) { + ENSURE_MSAN_INITED(); + int res = REAL(socketpair)(domain, type, protocol, sv); + if (!res) + __msan_unpoison(sv, sizeof(int[2])); + return res; +} + +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD +INTERCEPTOR(char *, fgets_unlocked, char *s, int size, void *stream) { + ENSURE_MSAN_INITED(); + char *res = REAL(fgets_unlocked)(s, size, stream); + if (res) + __msan_unpoison(s, internal_strlen(s) + 1); + return res; +} +#define MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED INTERCEPT_FUNCTION(fgets_unlocked) +#else +#define MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED +#endif + +#define INTERCEPTOR_GETRLIMIT_BODY(func, resource, rlim) \ + if (msan_init_is_running) \ + return REAL(getrlimit)(resource, rlim); \ + ENSURE_MSAN_INITED(); \ + int res = REAL(func)(resource, rlim); \ + if (!res) \ + __msan_unpoison(rlim, __sanitizer::struct_rlimit_sz); \ + return res + +INTERCEPTOR(int, getrlimit, int resource, void *rlim) { + INTERCEPTOR_GETRLIMIT_BODY(getrlimit, resource, rlim); +} + +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD +INTERCEPTOR(int, __getrlimit, int resource, void *rlim) { + INTERCEPTOR_GETRLIMIT_BODY(__getrlimit, resource, rlim); +} + +INTERCEPTOR(int, getrlimit64, int resource, void *rlim) { + if (msan_init_is_running) return REAL(getrlimit64)(resource, rlim); + ENSURE_MSAN_INITED(); + int res = REAL(getrlimit64)(resource, rlim); + if (!res) __msan_unpoison(rlim, __sanitizer::struct_rlimit64_sz); + return res; +} + +INTERCEPTOR(int, prlimit, int pid, int resource, void *new_rlimit, + void *old_rlimit) { + if (msan_init_is_running) + return REAL(prlimit)(pid, resource, new_rlimit, old_rlimit); + ENSURE_MSAN_INITED(); + CHECK_UNPOISONED(new_rlimit, __sanitizer::struct_rlimit_sz); + int res = REAL(prlimit)(pid, resource, new_rlimit, old_rlimit); + if (!res) __msan_unpoison(old_rlimit, __sanitizer::struct_rlimit_sz); + return res; +} + +INTERCEPTOR(int, prlimit64, int pid, int resource, void *new_rlimit, + void *old_rlimit) { + if (msan_init_is_running) + return REAL(prlimit64)(pid, resource, new_rlimit, old_rlimit); + ENSURE_MSAN_INITED(); + CHECK_UNPOISONED(new_rlimit, __sanitizer::struct_rlimit64_sz); + int res = REAL(prlimit64)(pid, resource, new_rlimit, old_rlimit); + if (!res) __msan_unpoison(old_rlimit, __sanitizer::struct_rlimit64_sz); + return res; +} + +#define MSAN_MAYBE_INTERCEPT___GETRLIMIT INTERCEPT_FUNCTION(__getrlimit) +#define MSAN_MAYBE_INTERCEPT_GETRLIMIT64 INTERCEPT_FUNCTION(getrlimit64) +#define MSAN_MAYBE_INTERCEPT_PRLIMIT INTERCEPT_FUNCTION(prlimit) +#define MSAN_MAYBE_INTERCEPT_PRLIMIT64 INTERCEPT_FUNCTION(prlimit64) +#else +#define MSAN_MAYBE_INTERCEPT___GETRLIMIT +#define MSAN_MAYBE_INTERCEPT_GETRLIMIT64 +#define MSAN_MAYBE_INTERCEPT_PRLIMIT +#define MSAN_MAYBE_INTERCEPT_PRLIMIT64 +#endif + +INTERCEPTOR(int, gethostname, char *name, SIZE_T len) { + ENSURE_MSAN_INITED(); + int res = REAL(gethostname)(name, len); + if (!res || (res == -1 && errno == errno_ENAMETOOLONG)) { + SIZE_T real_len = internal_strnlen(name, len); + if (real_len < len) + ++real_len; + __msan_unpoison(name, real_len); + } + return res; +} + +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD +INTERCEPTOR(int, epoll_wait, int epfd, void *events, int maxevents, + int timeout) { + ENSURE_MSAN_INITED(); + int res = REAL(epoll_wait)(epfd, events, maxevents, timeout); + if (res > 0) { + __msan_unpoison(events, __sanitizer::struct_epoll_event_sz * res); + } + return res; +} +#define MSAN_MAYBE_INTERCEPT_EPOLL_WAIT INTERCEPT_FUNCTION(epoll_wait) +#else +#define MSAN_MAYBE_INTERCEPT_EPOLL_WAIT +#endif + +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD +INTERCEPTOR(int, epoll_pwait, int epfd, void *events, int maxevents, + int timeout, void *sigmask) { + ENSURE_MSAN_INITED(); + int res = REAL(epoll_pwait)(epfd, events, maxevents, timeout, sigmask); + if (res > 0) { + __msan_unpoison(events, __sanitizer::struct_epoll_event_sz * res); + } + return res; +} +#define MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT INTERCEPT_FUNCTION(epoll_pwait) +#else +#define MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT +#endif + +INTERCEPTOR(void *, calloc, SIZE_T nmemb, SIZE_T size) { + GET_MALLOC_STACK_TRACE; + if (DlsymAlloc::Use()) + return DlsymAlloc::Callocate(nmemb, size); + return msan_calloc(nmemb, size, &stack); +} + +INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) { + if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr)) + return DlsymAlloc::Realloc(ptr, size); + GET_MALLOC_STACK_TRACE; + return msan_realloc(ptr, size, &stack); +} + +INTERCEPTOR(void *, reallocarray, void *ptr, SIZE_T nmemb, SIZE_T size) { + GET_MALLOC_STACK_TRACE; + return msan_reallocarray(ptr, nmemb, size, &stack); +} + +INTERCEPTOR(void *, malloc, SIZE_T size) { + if (DlsymAlloc::Use()) + return DlsymAlloc::Allocate(size); + GET_MALLOC_STACK_TRACE; + return msan_malloc(size, &stack); +} + +void __msan_allocated_memory(const void *data, uptr size) { + if (flags()->poison_in_malloc) { + GET_MALLOC_STACK_TRACE; + stack.tag = STACK_TRACE_TAG_POISON; + PoisonMemory(data, size, &stack); + } +} + +void __msan_copy_shadow(void *dest, const void *src, uptr n) { + GET_STORE_STACK_TRACE; + MoveShadowAndOrigin(dest, src, n, &stack); +} + +void __sanitizer_dtor_callback(const void *data, uptr size) { + if (flags()->poison_in_dtor) { + GET_MALLOC_STACK_TRACE; + stack.tag = STACK_TRACE_TAG_POISON; + PoisonMemory(data, size, &stack); + } +} + +extern "C" void __sanitizer_dtor_callback_fields(const void *data, uptr size) { + if (flags()->poison_in_dtor) { + GET_MALLOC_STACK_TRACE; + stack.tag = STACK_TRACE_TAG_POISON; + PoisonMemory(data, size, &stack); + } +} + +extern "C" void __sanitizer_dtor_callback_vptr(const void *data) { + if (flags()->poison_in_dtor) { + GET_MALLOC_STACK_TRACE; + stack.tag = STACK_TRACE_TAG_POISON; + PoisonMemory(data, sizeof(void *), &stack); + } +} + +template <class Mmap> +static void *mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T length, + int prot, int flags, int fd, OFF64_T offset) { + SIZE_T rounded_length = RoundUpTo(length, GetPageSize()); + void *end_addr = (char *)addr + (rounded_length - 1); + if (addr && (!MEM_IS_APP(addr) || !MEM_IS_APP(end_addr))) { + if (flags & map_fixed) { + errno = errno_EINVAL; + return (void *)-1; + } else { + addr = nullptr; + } + } + void *res = real_mmap(addr, length, prot, flags, fd, offset); + if (res != (void *)-1) { + void *end_res = (char *)res + (rounded_length - 1); + if (MEM_IS_APP(res) && MEM_IS_APP(end_res)) { + __msan_unpoison(res, rounded_length); + } else { + // Application has attempted to map more memory than is supported by + // MSAN. Act as if we ran out of memory. + internal_munmap(res, length); + errno = errno_ENOMEM; + return (void *)-1; + } + } + return res; +} + +INTERCEPTOR(int, getrusage, int who, void *usage) { + ENSURE_MSAN_INITED(); + int res = REAL(getrusage)(who, usage); + if (res == 0) { + __msan_unpoison(usage, __sanitizer::struct_rusage_sz); + } + return res; +} + +class SignalHandlerScope { + public: + SignalHandlerScope() { + if (MsanThread *t = GetCurrentThread()) + t->EnterSignalHandler(); + } + ~SignalHandlerScope() { + if (MsanThread *t = GetCurrentThread()) + t->LeaveSignalHandler(); + } +}; + +// sigactions_mu guarantees atomicity of sigaction() and signal() calls. +// Access to sigactions[] is gone with relaxed atomics to avoid data race with +// the signal handler. +const int kMaxSignals = 1024; +static atomic_uintptr_t sigactions[kMaxSignals]; +static StaticSpinMutex sigactions_mu; + +static void SignalHandler(int signo) { + SignalHandlerScope signal_handler_scope; + ScopedThreadLocalStateBackup stlsb; + UnpoisonParam(1); + + typedef void (*signal_cb)(int x); + signal_cb cb = + (signal_cb)atomic_load(&sigactions[signo], memory_order_relaxed); + cb(signo); +} + +static void SignalAction(int signo, void *si, void *uc) { + SignalHandlerScope signal_handler_scope; + ScopedThreadLocalStateBackup stlsb; + UnpoisonParam(3); + __msan_unpoison(si, sizeof(__sanitizer_sigaction)); + __msan_unpoison(uc, ucontext_t_sz(uc)); + + typedef void (*sigaction_cb)(int, void *, void *); + sigaction_cb cb = + (sigaction_cb)atomic_load(&sigactions[signo], memory_order_relaxed); + cb(signo, si, uc); + CHECK_UNPOISONED(uc, ucontext_t_sz(uc)); +} + +static void read_sigaction(const __sanitizer_sigaction *act) { + CHECK_UNPOISONED(&act->sa_flags, sizeof(act->sa_flags)); + if (act->sa_flags & __sanitizer::sa_siginfo) + CHECK_UNPOISONED(&act->sigaction, sizeof(act->sigaction)); + else + CHECK_UNPOISONED(&act->handler, sizeof(act->handler)); + CHECK_UNPOISONED(&act->sa_mask, sizeof(act->sa_mask)); +} + +extern "C" int pthread_attr_init(void *attr); +extern "C" int pthread_attr_destroy(void *attr); + +static void *MsanThreadStartFunc(void *arg) { + MsanThread *t = (MsanThread *)arg; + SetCurrentThread(t); + t->Init(); + SetSigProcMask(&t->starting_sigset_, nullptr); + return t->ThreadStart(); +} + +INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*), + void * param) { + ENSURE_MSAN_INITED(); // for GetTlsSize() + __sanitizer_pthread_attr_t myattr; + if (!attr) { + pthread_attr_init(&myattr); + attr = &myattr; + } + + AdjustStackSize(attr); + + MsanThread *t = MsanThread::Create(callback, param); + ScopedBlockSignals block(&t->starting_sigset_); + int res = REAL(pthread_create)(th, attr, MsanThreadStartFunc, t); + + if (attr == &myattr) + pthread_attr_destroy(&myattr); + if (!res) { + __msan_unpoison(th, __sanitizer::pthread_t_sz); + } + return res; +} + +INTERCEPTOR(int, pthread_key_create, __sanitizer_pthread_key_t *key, + void (*dtor)(void *value)) { + if (msan_init_is_running) return REAL(pthread_key_create)(key, dtor); + ENSURE_MSAN_INITED(); + int res = REAL(pthread_key_create)(key, dtor); + if (!res && key) + __msan_unpoison(key, sizeof(*key)); + return res; +} + +#if SANITIZER_NETBSD +INTERCEPTOR(int, __libc_thr_keycreate, __sanitizer_pthread_key_t *m, + void (*dtor)(void *value)) +ALIAS(WRAPPER_NAME(pthread_key_create)); +#endif + +INTERCEPTOR(int, pthread_join, void *th, void **retval) { + ENSURE_MSAN_INITED(); + int res = REAL(pthread_join)(th, retval); + if (!res && retval) + __msan_unpoison(retval, sizeof(*retval)); + return res; +} + +DEFINE_REAL_PTHREAD_FUNCTIONS + +extern char *tzname[2]; + +INTERCEPTOR(void, tzset, int fake) { + ENSURE_MSAN_INITED(); + InterceptorScope interceptor_scope; + REAL(tzset)(fake); + if (tzname[0]) + __msan_unpoison(tzname[0], internal_strlen(tzname[0]) + 1); + if (tzname[1]) + __msan_unpoison(tzname[1], internal_strlen(tzname[1]) + 1); + return; +} + +struct MSanAtExitRecord { + void (*func)(void *arg); + void *arg; +}; + +struct InterceptorContext { + Mutex atexit_mu; + Vector<struct MSanAtExitRecord *> AtExitStack; + + InterceptorContext() + : AtExitStack() { + } +}; + +static ALIGNED(64) char interceptor_placeholder[sizeof(InterceptorContext)]; +InterceptorContext *interceptor_ctx() { + return reinterpret_cast<InterceptorContext*>(&interceptor_placeholder[0]); +} + +void MSanAtExitWrapper() { + MSanAtExitRecord *r; + { + Lock l(&interceptor_ctx()->atexit_mu); + + uptr element = interceptor_ctx()->AtExitStack.Size() - 1; + r = interceptor_ctx()->AtExitStack[element]; + interceptor_ctx()->AtExitStack.PopBack(); + } + + UnpoisonParam(1); + ((void(*)())r->func)(); + InternalFree(r); +} + +void MSanCxaAtExitWrapper(void *arg) { + UnpoisonParam(1); + MSanAtExitRecord *r = (MSanAtExitRecord *)arg; + // libc before 2.27 had race which caused occasional double handler execution + // https://sourceware.org/ml/libc-alpha/2017-08/msg01204.html + if (!r->func) + return; + r->func(r->arg); + r->func = nullptr; +} + +static int setup_at_exit_wrapper(void(*f)(), void *arg, void *dso); + +// Unpoison argument shadow for C++ module destructors. +INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, + void *dso_handle) { + if (msan_init_is_running) return REAL(__cxa_atexit)(func, arg, dso_handle); + return setup_at_exit_wrapper((void(*)())func, arg, dso_handle); +} + +// Unpoison argument shadow for C++ module destructors. +INTERCEPTOR(int, atexit, void (*func)()) { + // Avoid calling real atexit as it is unreachable on at least on Linux. + if (msan_init_is_running) + return REAL(__cxa_atexit)((void (*)(void *a))func, 0, 0); + return setup_at_exit_wrapper((void(*)())func, 0, 0); +} + +static int setup_at_exit_wrapper(void(*f)(), void *arg, void *dso) { + ENSURE_MSAN_INITED(); + MSanAtExitRecord *r = + (MSanAtExitRecord *)InternalAlloc(sizeof(MSanAtExitRecord)); + r->func = (void(*)(void *a))f; + r->arg = arg; + int res; + if (!dso) { + // NetBSD does not preserve the 2nd argument if dso is equal to 0 + // Store ctx in a local stack-like structure + + Lock l(&interceptor_ctx()->atexit_mu); + + res = REAL(__cxa_atexit)((void (*)(void *a))MSanAtExitWrapper, 0, 0); + if (!res) { + interceptor_ctx()->AtExitStack.PushBack(r); + } + } else { + res = REAL(__cxa_atexit)(MSanCxaAtExitWrapper, r, dso); + } + return res; +} + +static void BeforeFork() { + StackDepotLockAll(); + ChainedOriginDepotLockAll(); +} + +static void AfterFork() { + ChainedOriginDepotUnlockAll(); + StackDepotUnlockAll(); +} + +INTERCEPTOR(int, fork, void) { + ENSURE_MSAN_INITED(); + BeforeFork(); + int pid = REAL(fork)(); + AfterFork(); + return pid; +} + +// NetBSD ships with openpty(3) in -lutil, that needs to be prebuilt explicitly +// with MSan. +#if SANITIZER_LINUX +INTERCEPTOR(int, openpty, int *aparent, int *aworker, char *name, + const void *termp, const void *winp) { + ENSURE_MSAN_INITED(); + InterceptorScope interceptor_scope; + int res = REAL(openpty)(aparent, aworker, name, termp, winp); + if (!res) { + __msan_unpoison(aparent, sizeof(*aparent)); + __msan_unpoison(aworker, sizeof(*aworker)); + } + return res; +} +#define MSAN_MAYBE_INTERCEPT_OPENPTY INTERCEPT_FUNCTION(openpty) +#else +#define MSAN_MAYBE_INTERCEPT_OPENPTY +#endif + +// NetBSD ships with forkpty(3) in -lutil, that needs to be prebuilt explicitly +// with MSan. +#if SANITIZER_LINUX +INTERCEPTOR(int, forkpty, int *aparent, char *name, const void *termp, + const void *winp) { + ENSURE_MSAN_INITED(); + InterceptorScope interceptor_scope; + int res = REAL(forkpty)(aparent, name, termp, winp); + if (res != -1) + __msan_unpoison(aparent, sizeof(*aparent)); + return res; +} +#define MSAN_MAYBE_INTERCEPT_FORKPTY INTERCEPT_FUNCTION(forkpty) +#else +#define MSAN_MAYBE_INTERCEPT_FORKPTY +#endif + +struct MSanInterceptorContext { + bool in_interceptor_scope; +}; + +namespace __msan { + +int OnExit() { + // FIXME: ask frontend whether we need to return failure. + return 0; +} + +} // namespace __msan + +// A version of CHECK_UNPOISONED using a saved scope value. Used in common +// interceptors. +#define CHECK_UNPOISONED_CTX(ctx, x, n) \ + do { \ + if (!((MSanInterceptorContext *)ctx)->in_interceptor_scope) \ + CHECK_UNPOISONED_0(x, n); \ + } while (0) + +#define MSAN_INTERCEPT_FUNC(name) \ + do { \ + if (!INTERCEPT_FUNCTION(name)) \ + VReport(1, "MemorySanitizer: failed to intercept '%s'\n", #name); \ + } while (0) + +#define MSAN_INTERCEPT_FUNC_VER(name, ver) \ + do { \ + if (!INTERCEPT_FUNCTION_VER(name, ver)) \ + VReport(1, "MemorySanitizer: failed to intercept '%s@@%s'\n", #name, \ + ver); \ + } while (0) +#define MSAN_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver) \ + do { \ + if (!INTERCEPT_FUNCTION_VER(name, ver) && !INTERCEPT_FUNCTION(name)) \ + VReport(1, "MemorySanitizer: failed to intercept '%s@@%s' or '%s'\n", \ + #name, ver, #name); \ + } while (0) + +#define COMMON_INTERCEPT_FUNCTION(name) MSAN_INTERCEPT_FUNC(name) +#define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \ + MSAN_INTERCEPT_FUNC_VER(name, ver) +#define COMMON_INTERCEPT_FUNCTION_VER_UNVERSIONED_FALLBACK(name, ver) \ + MSAN_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver) +#define COMMON_INTERCEPTOR_UNPOISON_PARAM(count) \ + UnpoisonParam(count) +#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \ + __msan_unpoison(ptr, size) +#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \ + CHECK_UNPOISONED_CTX(ctx, ptr, size) +#define COMMON_INTERCEPTOR_INITIALIZE_RANGE(ptr, size) \ + __msan_unpoison(ptr, size) +#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \ + if (msan_init_is_running) \ + return REAL(func)(__VA_ARGS__); \ + ENSURE_MSAN_INITED(); \ + MSanInterceptorContext msan_ctx = {IsInInterceptorScope()}; \ + ctx = (void *)&msan_ctx; \ + (void)ctx; \ + InterceptorScope interceptor_scope; \ + __msan_unpoison(__errno_location(), sizeof(int)); +#define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \ + do { \ + } while (false) +#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \ + do { \ + } while (false) +#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \ + do { \ + } while (false) +#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \ + do { \ + } while (false) +#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \ + do { \ + } while (false) // FIXME +#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \ + do { \ + } while (false) // FIXME +#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name) +#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit() +#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \ + do { \ + link_map *map = GET_LINK_MAP_BY_DLOPEN_HANDLE((handle)); \ + if (filename && map) \ + ForEachMappedRegion(map, __msan_unpoison); \ + } while (false) + +#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!msan_inited) + +#define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \ + if (MsanThread *t = GetCurrentThread()) { \ + *begin = t->tls_begin(); \ + *end = t->tls_end(); \ + } else { \ + *begin = *end = 0; \ + } + +#define COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, c, size) \ + { \ + (void)ctx; \ + return __msan_memset(block, c, size); \ + } +#define COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, to, from, size) \ + { \ + (void)ctx; \ + return __msan_memmove(to, from, size); \ + } +#define COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, to, from, size) \ + { \ + (void)ctx; \ + return __msan_memcpy(to, from, size); \ + } + +#define COMMON_INTERCEPTOR_COPY_STRING(ctx, to, from, size) \ + do { \ + GET_STORE_STACK_TRACE; \ + CopyShadowAndOrigin(to, from, size, &stack); \ + __msan_unpoison(to + size, 1); \ + } while (false) + +#define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags, fd, \ + offset) \ + do { \ + return mmap_interceptor(REAL(mmap), addr, sz, prot, flags, fd, off); \ + } while (false) + +#include "sanitizer_common/sanitizer_platform_interceptors.h" +#include "sanitizer_common/sanitizer_common_interceptors.inc" + +static uptr signal_impl(int signo, uptr cb); +static int sigaction_impl(int signo, const __sanitizer_sigaction *act, + __sanitizer_sigaction *oldact); + +#define SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signo, act, oldact) \ + { return sigaction_impl(signo, act, oldact); } + +#define SIGNAL_INTERCEPTOR_SIGNAL_IMPL(func, signo, handler) \ + { \ + handler = signal_impl(signo, handler); \ + InterceptorScope interceptor_scope; \ + return REAL(func)(signo, handler); \ + } + +#include "sanitizer_common/sanitizer_signal_interceptors.inc" + +static int sigaction_impl(int signo, const __sanitizer_sigaction *act, + __sanitizer_sigaction *oldact) { + ENSURE_MSAN_INITED(); + if (signo <= 0 || signo >= kMaxSignals) { + errno = errno_EINVAL; + return -1; + } + if (act) read_sigaction(act); + int res; + if (flags()->wrap_signals) { + SpinMutexLock lock(&sigactions_mu); + uptr old_cb = atomic_load(&sigactions[signo], memory_order_relaxed); + __sanitizer_sigaction new_act; + __sanitizer_sigaction *pnew_act = act ? &new_act : nullptr; + if (act) { + REAL(memcpy)(pnew_act, act, sizeof(__sanitizer_sigaction)); + uptr cb = (uptr)pnew_act->sigaction; + uptr new_cb = (pnew_act->sa_flags & __sanitizer::sa_siginfo) + ? (uptr)SignalAction + : (uptr)SignalHandler; + if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) { + atomic_store(&sigactions[signo], cb, memory_order_relaxed); + pnew_act->sigaction = (decltype(pnew_act->sigaction))new_cb; + } + } + res = REAL(SIGACTION_SYMNAME)(signo, pnew_act, oldact); + if (res == 0 && oldact) { + uptr cb = (uptr)oldact->sigaction; + if (cb == (uptr)SignalAction || cb == (uptr)SignalHandler) { + oldact->sigaction = (decltype(oldact->sigaction))old_cb; + } + } + } else { + res = REAL(SIGACTION_SYMNAME)(signo, act, oldact); + } + + if (res == 0 && oldact) { + __msan_unpoison(oldact, sizeof(__sanitizer_sigaction)); + } + return res; +} + +static uptr signal_impl(int signo, uptr cb) { + ENSURE_MSAN_INITED(); + if (signo <= 0 || signo >= kMaxSignals) { + errno = errno_EINVAL; + return -1; + } + if (flags()->wrap_signals) { + SpinMutexLock lock(&sigactions_mu); + if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) { + atomic_store(&sigactions[signo], cb, memory_order_relaxed); + cb = (uptr)&SignalHandler; + } + } + return cb; +} + +#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) CHECK_UNPOISONED(p, s) +#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \ + do { \ + } while (false) +#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \ + do { \ + } while (false) +#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) __msan_unpoison(p, s) +#include "sanitizer_common/sanitizer_common_syscalls.inc" +#include "sanitizer_common/sanitizer_syscalls_netbsd.inc" + +struct dlinfo { + char *dli_fname; + void *dli_fbase; + char *dli_sname; + void *dli_saddr; +}; + +INTERCEPTOR(int, dladdr, void *addr, dlinfo *info) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, dladdr, addr, info); + int res = REAL(dladdr)(addr, info); + if (res != 0) { + __msan_unpoison(info, sizeof(*info)); + if (info->dli_fname) + __msan_unpoison(info->dli_fname, internal_strlen(info->dli_fname) + 1); + if (info->dli_sname) + __msan_unpoison(info->dli_sname, internal_strlen(info->dli_sname) + 1); + } + return res; +} + +INTERCEPTOR(char *, dlerror, int fake) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, dlerror, fake); + char *res = REAL(dlerror)(fake); + if (res) + __msan_unpoison(res, internal_strlen(res) + 1); + return res; +} + +typedef int (*dl_iterate_phdr_cb)(__sanitizer_dl_phdr_info *info, SIZE_T size, + void *data); +struct dl_iterate_phdr_data { + dl_iterate_phdr_cb callback; + void *data; +}; + +static int msan_dl_iterate_phdr_cb(__sanitizer_dl_phdr_info *info, SIZE_T size, + void *data) { + if (info) { + __msan_unpoison(info, size); + if (info->dlpi_phdr && info->dlpi_phnum) + __msan_unpoison(info->dlpi_phdr, struct_ElfW_Phdr_sz * info->dlpi_phnum); + if (info->dlpi_name) + __msan_unpoison(info->dlpi_name, internal_strlen(info->dlpi_name) + 1); + } + dl_iterate_phdr_data *cbdata = (dl_iterate_phdr_data *)data; + UnpoisonParam(3); + return cbdata->callback(info, size, cbdata->data); +} + +INTERCEPTOR(void *, shmat, int shmid, const void *shmaddr, int shmflg) { + ENSURE_MSAN_INITED(); + void *p = REAL(shmat)(shmid, shmaddr, shmflg); + if (p != (void *)-1) { + __sanitizer_shmid_ds ds; + int res = REAL(shmctl)(shmid, shmctl_ipc_stat, &ds); + if (!res) { + __msan_unpoison(p, ds.shm_segsz); + } + } + return p; +} + +INTERCEPTOR(int, dl_iterate_phdr, dl_iterate_phdr_cb callback, void *data) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, dl_iterate_phdr, callback, data); + dl_iterate_phdr_data cbdata; + cbdata.callback = callback; + cbdata.data = data; + int res = REAL(dl_iterate_phdr)(msan_dl_iterate_phdr_cb, (void *)&cbdata); + return res; +} + +// wchar_t *wcschr(const wchar_t *wcs, wchar_t wc); +INTERCEPTOR(wchar_t *, wcschr, void *s, wchar_t wc, void *ps) { + ENSURE_MSAN_INITED(); + wchar_t *res = REAL(wcschr)(s, wc, ps); + return res; +} + +// wchar_t *wcscpy(wchar_t *dest, const wchar_t *src); +INTERCEPTOR(wchar_t *, wcscpy, wchar_t *dest, const wchar_t *src) { + ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; + wchar_t *res = REAL(wcscpy)(dest, src); + CopyShadowAndOrigin(dest, src, sizeof(wchar_t) * (internal_wcslen(src) + 1), + &stack); + return res; +} + +INTERCEPTOR(wchar_t *, wcsncpy, wchar_t *dest, const wchar_t *src, SIZE_T n) { + ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; + SIZE_T copy_size = internal_wcsnlen(src, n); + if (copy_size < n) copy_size++; // trailing \0 + wchar_t *res = REAL(wcsncpy)(dest, src, n); + CopyShadowAndOrigin(dest, src, copy_size * sizeof(wchar_t), &stack); + __msan_unpoison(dest + copy_size, (n - copy_size) * sizeof(wchar_t)); + return res; +} + +// These interface functions reside here so that they can use +// REAL(memset), etc. +void __msan_unpoison(const void *a, uptr size) { + if (!MEM_IS_APP(a)) return; + SetShadow(a, size, 0); +} + +void __msan_poison(const void *a, uptr size) { + if (!MEM_IS_APP(a)) return; + SetShadow(a, size, __msan::flags()->poison_heap_with_zeroes ? 0 : -1); +} + +void __msan_poison_stack(void *a, uptr size) { + if (!MEM_IS_APP(a)) return; + SetShadow(a, size, __msan::flags()->poison_stack_with_zeroes ? 0 : -1); +} + +void __msan_unpoison_param(uptr n) { UnpoisonParam(n); } + +void __msan_clear_and_unpoison(void *a, uptr size) { + REAL(memset)(a, 0, size); + SetShadow(a, size, 0); +} + +void *__msan_memcpy(void *dest, const void *src, SIZE_T n) { + if (!msan_inited) return internal_memcpy(dest, src, n); + if (msan_init_is_running || __msan::IsInSymbolizer()) + return REAL(memcpy)(dest, src, n); + ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; + void *res = REAL(memcpy)(dest, src, n); + CopyShadowAndOrigin(dest, src, n, &stack); + return res; +} + +void *__msan_memset(void *s, int c, SIZE_T n) { + if (!msan_inited) return internal_memset(s, c, n); + if (msan_init_is_running) return REAL(memset)(s, c, n); + ENSURE_MSAN_INITED(); + void *res = REAL(memset)(s, c, n); + __msan_unpoison(s, n); + return res; +} + +void *__msan_memmove(void *dest, const void *src, SIZE_T n) { + if (!msan_inited) return internal_memmove(dest, src, n); + if (msan_init_is_running) return REAL(memmove)(dest, src, n); + ENSURE_MSAN_INITED(); + GET_STORE_STACK_TRACE; + void *res = REAL(memmove)(dest, src, n); + MoveShadowAndOrigin(dest, src, n, &stack); + return res; +} + +void __msan_unpoison_string(const char* s) { + if (!MEM_IS_APP(s)) return; + __msan_unpoison(s, internal_strlen(s) + 1); +} + +namespace __msan { + +void InitializeInterceptors() { + static int inited = 0; + CHECK_EQ(inited, 0); + + new(interceptor_ctx()) InterceptorContext(); + + InitializeCommonInterceptors(); + InitializeSignalInterceptors(); + + INTERCEPT_FUNCTION(posix_memalign); + MSAN_MAYBE_INTERCEPT_MEMALIGN; + MSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN; + INTERCEPT_FUNCTION(valloc); + MSAN_MAYBE_INTERCEPT_PVALLOC; + INTERCEPT_FUNCTION(malloc); + INTERCEPT_FUNCTION(calloc); + INTERCEPT_FUNCTION(realloc); + INTERCEPT_FUNCTION(reallocarray); + INTERCEPT_FUNCTION(free); + MSAN_MAYBE_INTERCEPT_CFREE; + MSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE; + MSAN_MAYBE_INTERCEPT_MALLINFO; + MSAN_MAYBE_INTERCEPT_MALLOPT; + MSAN_MAYBE_INTERCEPT_MALLOC_STATS; + INTERCEPT_FUNCTION(fread); + MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED; + INTERCEPT_FUNCTION(memccpy); + MSAN_MAYBE_INTERCEPT_MEMPCPY; + INTERCEPT_FUNCTION(bcopy); + INTERCEPT_FUNCTION(wmemset); + INTERCEPT_FUNCTION(wmemcpy); + MSAN_MAYBE_INTERCEPT_WMEMPCPY; + INTERCEPT_FUNCTION(wmemmove); + INTERCEPT_FUNCTION(strcpy); + MSAN_MAYBE_INTERCEPT_STPCPY; + INTERCEPT_FUNCTION(strdup); + MSAN_MAYBE_INTERCEPT___STRDUP; + INTERCEPT_FUNCTION(strncpy); + MSAN_MAYBE_INTERCEPT_GCVT; + INTERCEPT_FUNCTION(strcat); + INTERCEPT_FUNCTION(strncat); + INTERCEPT_STRTO(strtod); + INTERCEPT_STRTO(strtof); + INTERCEPT_STRTO(strtold); + INTERCEPT_STRTO(strtol); + INTERCEPT_STRTO(strtoul); + INTERCEPT_STRTO(strtoll); + INTERCEPT_STRTO(strtoull); + INTERCEPT_STRTO(strtouq); + INTERCEPT_STRTO(wcstod); + INTERCEPT_STRTO(wcstof); + INTERCEPT_STRTO(wcstold); + INTERCEPT_STRTO(wcstol); + INTERCEPT_STRTO(wcstoul); + INTERCEPT_STRTO(wcstoll); + INTERCEPT_STRTO(wcstoull); +#ifdef SANITIZER_NLDBL_VERSION + INTERCEPT_FUNCTION_VER(vswprintf, SANITIZER_NLDBL_VERSION); + INTERCEPT_FUNCTION_VER(swprintf, SANITIZER_NLDBL_VERSION); +#else + INTERCEPT_FUNCTION(vswprintf); + INTERCEPT_FUNCTION(swprintf); +#endif + INTERCEPT_FUNCTION(strftime); + INTERCEPT_FUNCTION(strftime_l); + MSAN_MAYBE_INTERCEPT___STRFTIME_L; + INTERCEPT_FUNCTION(wcsftime); + INTERCEPT_FUNCTION(wcsftime_l); + MSAN_MAYBE_INTERCEPT___WCSFTIME_L; + INTERCEPT_FUNCTION(mbtowc); + INTERCEPT_FUNCTION(mbrtowc); + INTERCEPT_FUNCTION(wcslen); + INTERCEPT_FUNCTION(wcsnlen); + INTERCEPT_FUNCTION(wcschr); + INTERCEPT_FUNCTION(wcscpy); + INTERCEPT_FUNCTION(wcsncpy); + INTERCEPT_FUNCTION(wcscmp); + INTERCEPT_FUNCTION(getenv); + INTERCEPT_FUNCTION(setenv); + INTERCEPT_FUNCTION(putenv); + INTERCEPT_FUNCTION(gettimeofday); + MSAN_MAYBE_INTERCEPT_FCVT; + MSAN_MAYBE_INTERCEPT_FSTAT; + MSAN_MAYBE_INTERCEPT___FXSTAT; + MSAN_MAYBE_INTERCEPT_FSTATAT; + MSAN_MAYBE_INTERCEPT___FXSTATAT; + MSAN_MAYBE_INTERCEPT___FXSTAT64; + MSAN_MAYBE_INTERCEPT___FXSTATAT64; + INTERCEPT_FUNCTION(pipe); + INTERCEPT_FUNCTION(pipe2); + INTERCEPT_FUNCTION(socketpair); + MSAN_MAYBE_INTERCEPT_FGETS_UNLOCKED; + INTERCEPT_FUNCTION(getrlimit); + MSAN_MAYBE_INTERCEPT___GETRLIMIT; + MSAN_MAYBE_INTERCEPT_GETRLIMIT64; + MSAN_MAYBE_INTERCEPT_PRLIMIT; + MSAN_MAYBE_INTERCEPT_PRLIMIT64; + INTERCEPT_FUNCTION(gethostname); + MSAN_MAYBE_INTERCEPT_EPOLL_WAIT; + MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT; + INTERCEPT_FUNCTION(dladdr); + INTERCEPT_FUNCTION(dlerror); + INTERCEPT_FUNCTION(dl_iterate_phdr); + INTERCEPT_FUNCTION(getrusage); +#if defined(__mips__) + INTERCEPT_FUNCTION_VER(pthread_create, "GLIBC_2.2"); +#else + INTERCEPT_FUNCTION(pthread_create); +#endif + INTERCEPT_FUNCTION(pthread_join); + INTERCEPT_FUNCTION(pthread_key_create); + +#if SANITIZER_NETBSD + INTERCEPT_FUNCTION(__libc_thr_keycreate); +#endif + + INTERCEPT_FUNCTION(pthread_join); + INTERCEPT_FUNCTION(tzset); + INTERCEPT_FUNCTION(atexit); + INTERCEPT_FUNCTION(__cxa_atexit); + INTERCEPT_FUNCTION(shmat); + INTERCEPT_FUNCTION(fork); + MSAN_MAYBE_INTERCEPT_OPENPTY; + MSAN_MAYBE_INTERCEPT_FORKPTY; + + inited = 1; +} +} // namespace __msan diff --git a/contrib/libs/clang14-rt/lib/msan/msan_interface_internal.h b/contrib/libs/clang14-rt/lib/msan/msan_interface_internal.h new file mode 100644 index 0000000000..c72c91c3c1 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/msan/msan_interface_internal.h @@ -0,0 +1,198 @@ +//===-- msan_interface_internal.h -------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of MemorySanitizer. +// +// Private MSan interface header. +//===----------------------------------------------------------------------===// + +#ifndef MSAN_INTERFACE_INTERNAL_H +#define MSAN_INTERFACE_INTERNAL_H + +#include "sanitizer_common/sanitizer_internal_defs.h" + +extern "C" { +// FIXME: document all interface functions. + +SANITIZER_INTERFACE_ATTRIBUTE +int __msan_get_track_origins(); + +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_init(); + +// Print a warning and maybe return. +// This function can die based on common_flags()->exitcode. +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_warning(); + +// Print a warning and die. +// Instrumentation inserts calls to this function when building in "fast" mode +// (i.e. -mllvm -msan-keep-going) +SANITIZER_INTERFACE_ATTRIBUTE __attribute__((noreturn)) +void __msan_warning_noreturn(); + +using __sanitizer::uptr; +using __sanitizer::sptr; +using __sanitizer::uu64; +using __sanitizer::uu32; +using __sanitizer::uu16; +using __sanitizer::u64; +using __sanitizer::u32; +using __sanitizer::u16; +using __sanitizer::u8; + +// Versions of the above which take Origin as a parameter +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_warning_with_origin(u32 origin); +SANITIZER_INTERFACE_ATTRIBUTE __attribute__((noreturn)) void +__msan_warning_with_origin_noreturn(u32 origin); + +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_maybe_warning_1(u8 s, u32 o); +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_maybe_warning_2(u16 s, u32 o); +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_maybe_warning_4(u32 s, u32 o); +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_maybe_warning_8(u64 s, u32 o); + +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_maybe_store_origin_1(u8 s, void *p, u32 o); +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_maybe_store_origin_2(u16 s, void *p, u32 o); +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_maybe_store_origin_4(u32 s, void *p, u32 o); +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_maybe_store_origin_8(u64 s, void *p, u32 o); + +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_unpoison(const void *a, uptr size); +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_unpoison_string(const char *s); +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_unpoison_param(uptr n); +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_clear_and_unpoison(void *a, uptr size); +SANITIZER_INTERFACE_ATTRIBUTE +void* __msan_memcpy(void *dst, const void *src, uptr size); +SANITIZER_INTERFACE_ATTRIBUTE +void* __msan_memset(void *s, int c, uptr n); +SANITIZER_INTERFACE_ATTRIBUTE +void* __msan_memmove(void* dest, const void* src, uptr n); +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_poison(const void *a, uptr size); +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_poison_stack(void *a, uptr size); + +// Copy size bytes from src to dst and unpoison the result. +// Useful to implement unsafe loads. +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_load_unpoisoned(void *src, uptr size, void *dst); + +// Returns the offset of the first (at least partially) poisoned byte, +// or -1 if the whole range is good. +SANITIZER_INTERFACE_ATTRIBUTE +sptr __msan_test_shadow(const void *x, uptr size); + +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_check_mem_is_initialized(const void *x, uptr size); + +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_set_origin(const void *a, uptr size, u32 origin); +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_set_alloca_origin(void *a, uptr size, char *descr); +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_set_alloca_origin4(void *a, uptr size, char *descr, uptr pc); +SANITIZER_INTERFACE_ATTRIBUTE +u32 __msan_chain_origin(u32 id); +SANITIZER_INTERFACE_ATTRIBUTE +u32 __msan_get_origin(const void *a); + +// Test that this_id is a descendant of prev_id (or they are simply equal). +// "descendant" here means that are part of the same chain, created with +// __msan_chain_origin. +SANITIZER_INTERFACE_ATTRIBUTE +int __msan_origin_is_descendant_or_same(u32 this_id, u32 prev_id); + + +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_clear_on_return(); + +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_set_keep_going(int keep_going); + +SANITIZER_INTERFACE_ATTRIBUTE +int __msan_set_poison_in_malloc(int do_poison); + +SANITIZER_INTERFACE_ATTRIBUTE +const char *__msan_default_options(); + +// For testing. +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_set_expect_umr(int expect_umr); +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_print_shadow(const void *x, uptr size); +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_dump_shadow(const void *x, uptr size); +SANITIZER_INTERFACE_ATTRIBUTE +int __msan_has_dynamic_component(); + +// For testing. +SANITIZER_INTERFACE_ATTRIBUTE +u32 __msan_get_umr_origin(); +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_partial_poison(const void* data, void* shadow, uptr size); + +// Tell MSan about newly allocated memory (ex.: custom allocator). +// Memory will be marked uninitialized, with origin at the call site. +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_allocated_memory(const void* data, uptr size); + +// Tell MSan about newly destroyed memory. Memory will be marked +// uninitialized. +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_dtor_callback(const void* data, uptr size); + +SANITIZER_INTERFACE_ATTRIBUTE +u16 __sanitizer_unaligned_load16(const uu16 *p); + +SANITIZER_INTERFACE_ATTRIBUTE +u32 __sanitizer_unaligned_load32(const uu32 *p); + +SANITIZER_INTERFACE_ATTRIBUTE +u64 __sanitizer_unaligned_load64(const uu64 *p); + +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_unaligned_store16(uu16 *p, u16 x); + +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_unaligned_store32(uu32 *p, u32 x); + +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_unaligned_store64(uu64 *p, u64 x); + +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_set_death_callback(void (*callback)(void)); + +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_copy_shadow(void *dst, const void *src, uptr size); + +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_scoped_disable_interceptor_checks(); + +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_scoped_enable_interceptor_checks(); + +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_start_switch_fiber(const void *bottom, uptr size); + +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_finish_switch_fiber(const void **bottom_old, uptr *size_old); +} // extern "C" + +#endif // MSAN_INTERFACE_INTERNAL_H diff --git a/contrib/libs/clang14-rt/lib/msan/msan_linux.cpp b/contrib/libs/clang14-rt/lib/msan/msan_linux.cpp new file mode 100644 index 0000000000..bced00ba24 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/msan/msan_linux.cpp @@ -0,0 +1,261 @@ +//===-- msan_linux.cpp ----------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of MemorySanitizer. +// +// Linux-, NetBSD- and FreeBSD-specific code. +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_platform.h" +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD + +#include "msan.h" +#include "msan_report.h" +#include "msan_thread.h" + +#include <elf.h> +#include <link.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <unistd.h> +#include <unwind.h> +#include <sys/time.h> +#include <sys/resource.h> + +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_procmaps.h" + +namespace __msan { + +void ReportMapRange(const char *descr, uptr beg, uptr size) { + if (size > 0) { + uptr end = beg + size - 1; + VPrintf(1, "%s : 0x%zx - 0x%zx\n", descr, beg, end); + } +} + +static bool CheckMemoryRangeAvailability(uptr beg, uptr size) { + if (size > 0) { + uptr end = beg + size - 1; + if (!MemoryRangeIsAvailable(beg, end)) { + Printf("FATAL: Memory range 0x%zx - 0x%zx is not available.\n", beg, end); + return false; + } + } + return true; +} + +static bool ProtectMemoryRange(uptr beg, uptr size, const char *name) { + if (size > 0) { + void *addr = MmapFixedNoAccess(beg, size, name); + if (beg == 0 && addr) { + // Depending on the kernel configuration, we may not be able to protect + // the page at address zero. + uptr gap = 16 * GetPageSizeCached(); + beg += gap; + size -= gap; + addr = MmapFixedNoAccess(beg, size, name); + } + if ((uptr)addr != beg) { + uptr end = beg + size - 1; + Printf("FATAL: Cannot protect memory range 0x%zx - 0x%zx (%s).\n", beg, + end, name); + return false; + } + } + return true; +} + +static void CheckMemoryLayoutSanity() { + uptr prev_end = 0; + for (unsigned i = 0; i < kMemoryLayoutSize; ++i) { + uptr start = kMemoryLayout[i].start; + uptr end = kMemoryLayout[i].end; + MappingDesc::Type type = kMemoryLayout[i].type; + CHECK_LT(start, end); + CHECK_EQ(prev_end, start); + CHECK(addr_is_type(start, type)); + CHECK(addr_is_type((start + end) / 2, type)); + CHECK(addr_is_type(end - 1, type)); + if (type == MappingDesc::APP) { + uptr addr = start; + CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr))); + CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr))); + CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr))); + + addr = (start + end) / 2; + CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr))); + CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr))); + CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr))); + + addr = end - 1; + CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr))); + CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr))); + CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr))); + } + prev_end = end; + } +} + +bool InitShadow(bool init_origins) { + // Let user know mapping parameters first. + VPrintf(1, "__msan_init %p\n", reinterpret_cast<void *>(&__msan_init)); + for (unsigned i = 0; i < kMemoryLayoutSize; ++i) + VPrintf(1, "%s: %zx - %zx\n", kMemoryLayout[i].name, kMemoryLayout[i].start, + kMemoryLayout[i].end - 1); + + CheckMemoryLayoutSanity(); + + if (!MEM_IS_APP(&__msan_init)) { + Printf("FATAL: Code %p is out of application range. Non-PIE build?\n", + reinterpret_cast<void *>(&__msan_init)); + return false; + } + + const uptr maxVirtualAddress = GetMaxUserVirtualAddress(); + + for (unsigned i = 0; i < kMemoryLayoutSize; ++i) { + uptr start = kMemoryLayout[i].start; + uptr end = kMemoryLayout[i].end; + uptr size = end - start; + MappingDesc::Type type = kMemoryLayout[i].type; + + // Check if the segment should be mapped based on platform constraints. + if (start >= maxVirtualAddress) + continue; + + bool map = type == MappingDesc::SHADOW || + (init_origins && type == MappingDesc::ORIGIN); + bool protect = type == MappingDesc::INVALID || + (!init_origins && type == MappingDesc::ORIGIN); + CHECK(!(map && protect)); + if (!map && !protect) + CHECK(type == MappingDesc::APP); + if (map) { + if (!CheckMemoryRangeAvailability(start, size)) + return false; + if (!MmapFixedSuperNoReserve(start, size, kMemoryLayout[i].name)) + return false; + if (common_flags()->use_madv_dontdump) + DontDumpShadowMemory(start, size); + } + if (protect) { + if (!CheckMemoryRangeAvailability(start, size)) + return false; + if (!ProtectMemoryRange(start, size, kMemoryLayout[i].name)) + return false; + } + } + + return true; +} + +static void MsanAtExit(void) { + if (flags()->print_stats && (flags()->atexit || msan_report_count > 0)) + ReportStats(); + if (msan_report_count > 0) { + ReportAtExitStatistics(); + if (common_flags()->exitcode) + internal__exit(common_flags()->exitcode); + } +} + +void InstallAtExitHandler() { + atexit(MsanAtExit); +} + +// ---------------------- TSD ---------------- {{{1 + +#if SANITIZER_NETBSD +// Thread Static Data cannot be used in early init on NetBSD. +// Reuse the MSan TSD API for compatibility with existing code +// with an alternative implementation. + +static void (*tsd_destructor)(void *tsd) = nullptr; + +struct tsd_key { + tsd_key() : key(nullptr) {} + ~tsd_key() { + CHECK(tsd_destructor); + if (key) + (*tsd_destructor)(key); + } + MsanThread *key; +}; + +static thread_local struct tsd_key key; + +void MsanTSDInit(void (*destructor)(void *tsd)) { + CHECK(!tsd_destructor); + tsd_destructor = destructor; +} + +MsanThread *GetCurrentThread() { + CHECK(tsd_destructor); + return key.key; +} + +void SetCurrentThread(MsanThread *tsd) { + CHECK(tsd_destructor); + CHECK(tsd); + CHECK(!key.key); + key.key = tsd; +} + +void MsanTSDDtor(void *tsd) { + CHECK(tsd_destructor); + CHECK_EQ(key.key, tsd); + key.key = nullptr; + // Make sure that signal handler can not see a stale current thread pointer. + atomic_signal_fence(memory_order_seq_cst); + MsanThread::TSDDtor(tsd); +} +#else +static pthread_key_t tsd_key; +static bool tsd_key_inited = false; + +void MsanTSDInit(void (*destructor)(void *tsd)) { + CHECK(!tsd_key_inited); + tsd_key_inited = true; + CHECK_EQ(0, pthread_key_create(&tsd_key, destructor)); +} + +static THREADLOCAL MsanThread* msan_current_thread; + +MsanThread *GetCurrentThread() { + return msan_current_thread; +} + +void SetCurrentThread(MsanThread *t) { + // Make sure we do not reset the current MsanThread. + CHECK_EQ(0, msan_current_thread); + msan_current_thread = t; + // Make sure that MsanTSDDtor gets called at the end. + CHECK(tsd_key_inited); + pthread_setspecific(tsd_key, (void *)t); +} + +void MsanTSDDtor(void *tsd) { + MsanThread *t = (MsanThread*)tsd; + if (t->destructor_iterations_ > 1) { + t->destructor_iterations_--; + CHECK_EQ(0, pthread_setspecific(tsd_key, tsd)); + return; + } + msan_current_thread = nullptr; + // Make sure that signal handler can not see a stale current thread pointer. + atomic_signal_fence(memory_order_seq_cst); + MsanThread::TSDDtor(tsd); +} +#endif + +} // namespace __msan + +#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD diff --git a/contrib/libs/clang14-rt/lib/msan/msan_new_delete.cpp b/contrib/libs/clang14-rt/lib/msan/msan_new_delete.cpp new file mode 100644 index 0000000000..d4e95c0f65 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/msan/msan_new_delete.cpp @@ -0,0 +1,108 @@ +//===-- msan_new_delete.cpp -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of MemorySanitizer. +// +// Interceptors for operators new and delete. +//===----------------------------------------------------------------------===// + +#include "msan.h" +#include "interception/interception.h" +#include "sanitizer_common/sanitizer_allocator.h" +#include "sanitizer_common/sanitizer_allocator_report.h" + +#if MSAN_REPLACE_OPERATORS_NEW_AND_DELETE + +#include <stddef.h> + +using namespace __msan; + +// Fake std::nothrow_t and std::align_val_t to avoid including <new>. +namespace std { + struct nothrow_t {}; + enum class align_val_t: size_t {}; +} // namespace std + + +// TODO(alekseys): throw std::bad_alloc instead of dying on OOM. +#define OPERATOR_NEW_BODY(nothrow) \ + GET_MALLOC_STACK_TRACE; \ + void *res = msan_malloc(size, &stack);\ + if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\ + return res +#define OPERATOR_NEW_BODY_ALIGN(nothrow) \ + GET_MALLOC_STACK_TRACE;\ + void *res = msan_memalign((uptr)align, size, &stack);\ + if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\ + return res; + +INTERCEPTOR_ATTRIBUTE +void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); } +INTERCEPTOR_ATTRIBUTE +void *operator new[](size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); } +INTERCEPTOR_ATTRIBUTE +void *operator new(size_t size, std::nothrow_t const&) { + OPERATOR_NEW_BODY(true /*nothrow*/); +} +INTERCEPTOR_ATTRIBUTE +void *operator new[](size_t size, std::nothrow_t const&) { + OPERATOR_NEW_BODY(true /*nothrow*/); +} +INTERCEPTOR_ATTRIBUTE +void *operator new(size_t size, std::align_val_t align) +{ OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); } +INTERCEPTOR_ATTRIBUTE +void *operator new[](size_t size, std::align_val_t align) +{ OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); } +INTERCEPTOR_ATTRIBUTE +void *operator new(size_t size, std::align_val_t align, std::nothrow_t const&) +{ OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); } +INTERCEPTOR_ATTRIBUTE +void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&) +{ OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); } + +#define OPERATOR_DELETE_BODY \ + GET_MALLOC_STACK_TRACE; \ + if (ptr) MsanDeallocate(&stack, ptr) + +INTERCEPTOR_ATTRIBUTE +void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete[](void *ptr, std::nothrow_t const&) { + OPERATOR_DELETE_BODY; +} +INTERCEPTOR_ATTRIBUTE +void operator delete(void *ptr, size_t size) NOEXCEPT { OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete[](void *ptr, size_t size) NOEXCEPT +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete(void *ptr, std::align_val_t align) NOEXCEPT +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete(void *ptr, std::align_val_t align, std::nothrow_t const&) +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete[](void *ptr, std::align_val_t align, std::nothrow_t const&) +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete(void *ptr, size_t size, std::align_val_t align) NOEXCEPT +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete[](void *ptr, size_t size, std::align_val_t align) NOEXCEPT +{ OPERATOR_DELETE_BODY; } + + +#endif // MSAN_REPLACE_OPERATORS_NEW_AND_DELETE diff --git a/contrib/libs/clang14-rt/lib/msan/msan_origin.h b/contrib/libs/clang14-rt/lib/msan/msan_origin.h new file mode 100644 index 0000000000..e291f538cb --- /dev/null +++ b/contrib/libs/clang14-rt/lib/msan/msan_origin.h @@ -0,0 +1,168 @@ +//===-- msan_origin.h ----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Origin id utils. +//===----------------------------------------------------------------------===// +#ifndef MSAN_ORIGIN_H +#define MSAN_ORIGIN_H + +#include "sanitizer_common/sanitizer_stackdepot.h" +#include "msan_chained_origin_depot.h" + +namespace __msan { + +// Origin handling. +// +// Origin is a 32-bit identifier that is attached to any uninitialized value in +// the program and describes, more or less exactly, how this memory came to be +// uninitialized. +// +// There are 3 kinds of origin ids: +// 1xxx xxxx xxxx xxxx heap origin id +// 0000 xxxx xxxx xxxx stack origin id +// 0zzz xxxx xxxx xxxx chained origin id +// +// Heap origin id describes a heap memory allocation and contains (in the xxx +// part) a value of StackDepot. +// +// Stack origin id describes a stack memory allocation and contains (in the xxx +// part) an index into StackOriginDescr and StackOriginPC. We don't store a +// stack trace for such origins for performance reasons. +// +// Chained origin id describes an event of storing an uninitialized value to +// memory. The xxx part is a value of ChainedOriginDepot, which is a mapping of +// (stack_id, prev_id) -> id, where +// * stack_id describes the event. +// StackDepot keeps a mapping between those and corresponding stack traces. +// * prev_id is another origin id that describes the earlier part of the +// uninitialized value history. +// Following a chain of prev_id provides the full recorded history of an +// uninitialized value. +// +// This, effectively, defines a tree (or 2 trees, see below) where nodes are +// points in value history marked with origin ids, and edges are events that are +// marked with stack_id. +// +// The "zzz" bits of chained origin id are used to store the length (or depth) +// of the origin chain. + +class Origin { + public: + static bool isValidId(u32 id) { return id != 0 && id != (u32)-1; } + + u32 raw_id() const { return raw_id_; } + bool isHeapOrigin() const { + // 0xxx xxxx xxxx xxxx + return raw_id_ >> kHeapShift == 0; + } + bool isStackOrigin() const { + // 1000 xxxx xxxx xxxx + return (raw_id_ >> kDepthShift) == (1 << kDepthBits); + } + bool isChainedOrigin() const { + // 1zzz xxxx xxxx xxxx, zzz != 000 + return (raw_id_ >> kDepthShift) > (1 << kDepthBits); + } + u32 getChainedId() const { + CHECK(isChainedOrigin()); + return raw_id_ & kChainedIdMask; + } + u32 getStackId() const { + CHECK(isStackOrigin()); + return raw_id_ & kChainedIdMask; + } + u32 getHeapId() const { + CHECK(isHeapOrigin()); + return raw_id_ & kHeapIdMask; + } + + // Returns the next origin in the chain and the current stack trace. + Origin getNextChainedOrigin(StackTrace *stack) const { + CHECK(isChainedOrigin()); + u32 prev_id; + u32 stack_id = ChainedOriginDepotGet(getChainedId(), &prev_id); + if (stack) *stack = StackDepotGet(stack_id); + return Origin(prev_id); + } + + StackTrace getStackTraceForHeapOrigin() const { + return StackDepotGet(getHeapId()); + } + + static Origin CreateStackOrigin(u32 id) { + CHECK((id & kStackIdMask) == id); + return Origin((1 << kHeapShift) | id); + } + + static Origin CreateHeapOrigin(StackTrace *stack) { + u32 stack_id = StackDepotPut(*stack); + CHECK(stack_id); + CHECK((stack_id & kHeapIdMask) == stack_id); + return Origin(stack_id); + } + + static Origin CreateChainedOrigin(Origin prev, StackTrace *stack) { + int depth = prev.isChainedOrigin() ? prev.depth() : 0; + // depth is the length of the chain minus 1. + // origin_history_size of 0 means unlimited depth. + if (flags()->origin_history_size > 0) { + if (depth + 1 >= flags()->origin_history_size) { + return prev; + } else { + ++depth; + CHECK(depth < (1 << kDepthBits)); + } + } + + StackDepotHandle h = StackDepotPut_WithHandle(*stack); + if (!h.valid()) return prev; + + if (flags()->origin_history_per_stack_limit > 0) { + int use_count = h.use_count(); + if (use_count > flags()->origin_history_per_stack_limit) return prev; + } + + u32 chained_id; + bool inserted = ChainedOriginDepotPut(h.id(), prev.raw_id(), &chained_id); + CHECK((chained_id & kChainedIdMask) == chained_id); + + if (inserted && flags()->origin_history_per_stack_limit > 0) + h.inc_use_count_unsafe(); + + return Origin((1 << kHeapShift) | (depth << kDepthShift) | chained_id); + } + + static Origin FromRawId(u32 id) { + return Origin(id); + } + + private: + static const int kDepthBits = 3; + static const int kDepthShift = 32 - kDepthBits - 1; + + static const int kHeapShift = 31; + static const u32 kChainedIdMask = ((u32)-1) >> (32 - kDepthShift); + static const u32 kStackIdMask = ((u32)-1) >> (32 - kDepthShift); + static const u32 kHeapIdMask = ((u32)-1) >> (32 - kHeapShift); + + u32 raw_id_; + + explicit Origin(u32 raw_id) : raw_id_(raw_id) {} + + int depth() const { + CHECK(isChainedOrigin()); + return (raw_id_ >> kDepthShift) & ((1 << kDepthBits) - 1); + } + + public: + static const int kMaxDepth = (1 << kDepthBits) - 1; +}; + +} // namespace __msan + +#endif // MSAN_ORIGIN_H diff --git a/contrib/libs/clang14-rt/lib/msan/msan_poisoning.cpp b/contrib/libs/clang14-rt/lib/msan/msan_poisoning.cpp new file mode 100644 index 0000000000..af01aa69f7 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/msan/msan_poisoning.cpp @@ -0,0 +1,253 @@ +//===-- msan_poisoning.cpp --------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of MemorySanitizer. +// +//===----------------------------------------------------------------------===// + +#include "msan_poisoning.h" + +#include "interception/interception.h" +#include "msan_origin.h" +#include "msan_thread.h" +#include "sanitizer_common/sanitizer_common.h" + +DECLARE_REAL(void *, memset, void *dest, int c, uptr n) +DECLARE_REAL(void *, memcpy, void *dest, const void *src, uptr n) +DECLARE_REAL(void *, memmove, void *dest, const void *src, uptr n) + +namespace __msan { + +u32 GetOriginIfPoisoned(uptr addr, uptr size) { + unsigned char *s = (unsigned char *)MEM_TO_SHADOW(addr); + for (uptr i = 0; i < size; ++i) + if (s[i]) return *(u32 *)SHADOW_TO_ORIGIN(((uptr)s + i) & ~3UL); + return 0; +} + +void SetOriginIfPoisoned(uptr addr, uptr src_shadow, uptr size, + u32 src_origin) { + uptr dst_s = MEM_TO_SHADOW(addr); + uptr src_s = src_shadow; + uptr src_s_end = src_s + size; + + for (; src_s < src_s_end; ++dst_s, ++src_s) + if (*(u8 *)src_s) *(u32 *)SHADOW_TO_ORIGIN(dst_s & ~3UL) = src_origin; +} + +void CopyOrigin(const void *dst, const void *src, uptr size, + StackTrace *stack) { + if (!MEM_IS_APP(dst) || !MEM_IS_APP(src)) return; + + uptr d = (uptr)dst; + uptr beg = d & ~3UL; + // Copy left unaligned origin if that memory is poisoned. + if (beg < d) { + u32 o = GetOriginIfPoisoned((uptr)src, beg + 4 - d); + if (o) { + if (__msan_get_track_origins() > 1) o = ChainOrigin(o, stack); + *(u32 *)MEM_TO_ORIGIN(beg) = o; + } + beg += 4; + } + + uptr end = (d + size) & ~3UL; + // If both ends fall into the same 4-byte slot, we are done. + if (end < beg) return; + + // Copy right unaligned origin if that memory is poisoned. + if (end < d + size) { + u32 o = GetOriginIfPoisoned((uptr)src + (end - d), (d + size) - end); + if (o) { + if (__msan_get_track_origins() > 1) o = ChainOrigin(o, stack); + *(u32 *)MEM_TO_ORIGIN(end) = o; + } + } + + if (beg < end) { + // Align src up. + uptr s = ((uptr)src + 3) & ~3UL; + // FIXME: factor out to msan_copy_origin_aligned + if (__msan_get_track_origins() > 1) { + u32 *src = (u32 *)MEM_TO_ORIGIN(s); + u32 *src_s = (u32 *)MEM_TO_SHADOW(s); + u32 *src_end = (u32 *)MEM_TO_ORIGIN(s + (end - beg)); + u32 *dst = (u32 *)MEM_TO_ORIGIN(beg); + u32 src_o = 0; + u32 dst_o = 0; + for (; src < src_end; ++src, ++src_s, ++dst) { + if (!*src_s) continue; + if (*src != src_o) { + src_o = *src; + dst_o = ChainOrigin(src_o, stack); + } + *dst = dst_o; + } + } else { + REAL(memcpy)((void *)MEM_TO_ORIGIN(beg), (void *)MEM_TO_ORIGIN(s), + end - beg); + } + } +} + +void ReverseCopyOrigin(const void *dst, const void *src, uptr size, + StackTrace *stack) { + if (!MEM_IS_APP(dst) || !MEM_IS_APP(src)) + return; + + uptr d = (uptr)dst; + uptr end = (d + size) & ~3UL; + + // Copy right unaligned origin if that memory is poisoned. + if (end < d + size) { + u32 o = GetOriginIfPoisoned((uptr)src + (end - d), (d + size) - end); + if (o) { + if (__msan_get_track_origins() > 1) + o = ChainOrigin(o, stack); + *(u32 *)MEM_TO_ORIGIN(end) = o; + } + } + + uptr beg = d & ~3UL; + + if (beg + 4 < end) { + // Align src up. + uptr s = ((uptr)src + 3) & ~3UL; + if (__msan_get_track_origins() > 1) { + u32 *src = (u32 *)MEM_TO_ORIGIN(s + end - beg - 4); + u32 *src_s = (u32 *)MEM_TO_SHADOW(s + end - beg - 4); + u32 *src_begin = (u32 *)MEM_TO_ORIGIN(s); + u32 *dst = (u32 *)MEM_TO_ORIGIN(end - 4); + u32 src_o = 0; + u32 dst_o = 0; + for (; src >= src_begin; --src, --src_s, --dst) { + if (!*src_s) + continue; + if (*src != src_o) { + src_o = *src; + dst_o = ChainOrigin(src_o, stack); + } + *dst = dst_o; + } + } else { + REAL(memmove) + ((void *)MEM_TO_ORIGIN(beg), (void *)MEM_TO_ORIGIN(s), end - beg - 4); + } + } + + // Copy left unaligned origin if that memory is poisoned. + if (beg < d) { + u32 o = GetOriginIfPoisoned((uptr)src, beg + 4 - d); + if (o) { + if (__msan_get_track_origins() > 1) + o = ChainOrigin(o, stack); + *(u32 *)MEM_TO_ORIGIN(beg) = o; + } + } +} + +void MoveOrigin(const void *dst, const void *src, uptr size, + StackTrace *stack) { + // If destination origin range overlaps with source origin range, move + // origins by coping origins in a reverse order; otherwise, copy origins in + // a normal order. + uptr src_aligned_beg = reinterpret_cast<uptr>(src) & ~3UL; + uptr src_aligned_end = (reinterpret_cast<uptr>(src) + size) & ~3UL; + uptr dst_aligned_beg = reinterpret_cast<uptr>(dst) & ~3UL; + if (dst_aligned_beg < src_aligned_end && dst_aligned_beg >= src_aligned_beg) + return ReverseCopyOrigin(dst, src, size, stack); + return CopyOrigin(dst, src, size, stack); +} + +void MoveShadowAndOrigin(const void *dst, const void *src, uptr size, + StackTrace *stack) { + if (!MEM_IS_APP(dst)) return; + if (!MEM_IS_APP(src)) return; + if (src == dst) return; + // MoveOrigin transfers origins by refering to their shadows. So we + // need to move origins before moving shadows. + if (__msan_get_track_origins()) + MoveOrigin(dst, src, size, stack); + REAL(memmove)((void *)MEM_TO_SHADOW((uptr)dst), + (void *)MEM_TO_SHADOW((uptr)src), size); +} + +void CopyShadowAndOrigin(const void *dst, const void *src, uptr size, + StackTrace *stack) { + if (!MEM_IS_APP(dst)) return; + if (!MEM_IS_APP(src)) return; + // Because origin's range is slightly larger than app range, memcpy may also + // cause overlapped origin ranges. + REAL(memcpy)((void *)MEM_TO_SHADOW((uptr)dst), + (void *)MEM_TO_SHADOW((uptr)src), size); + if (__msan_get_track_origins()) + MoveOrigin(dst, src, size, stack); +} + +void CopyMemory(void *dst, const void *src, uptr size, StackTrace *stack) { + REAL(memcpy)(dst, src, size); + CopyShadowAndOrigin(dst, src, size, stack); +} + +void SetShadow(const void *ptr, uptr size, u8 value) { + uptr PageSize = GetPageSizeCached(); + uptr shadow_beg = MEM_TO_SHADOW(ptr); + uptr shadow_end = shadow_beg + size; + if (value || + shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) { + REAL(memset)((void *)shadow_beg, value, shadow_end - shadow_beg); + } else { + uptr page_beg = RoundUpTo(shadow_beg, PageSize); + uptr page_end = RoundDownTo(shadow_end, PageSize); + + if (page_beg >= page_end) { + REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg); + } else { + if (page_beg != shadow_beg) { + REAL(memset)((void *)shadow_beg, 0, page_beg - shadow_beg); + } + if (page_end != shadow_end) { + REAL(memset)((void *)page_end, 0, shadow_end - page_end); + } + if (!MmapFixedSuperNoReserve(page_beg, page_end - page_beg)) + Die(); + } + } +} + +void SetOrigin(const void *dst, uptr size, u32 origin) { + // Origin mapping is 4 bytes per 4 bytes of application memory. + // Here we extend the range such that its left and right bounds are both + // 4 byte aligned. + uptr x = MEM_TO_ORIGIN((uptr)dst); + uptr beg = x & ~3UL; // align down. + uptr end = (x + size + 3) & ~3UL; // align up. + u64 origin64 = ((u64)origin << 32) | origin; + // This is like memset, but the value is 32-bit. We unroll by 2 to write + // 64 bits at once. May want to unroll further to get 128-bit stores. + if (beg & 7ULL) { + *(u32 *)beg = origin; + beg += 4; + } + for (uptr addr = beg; addr < (end & ~7UL); addr += 8) *(u64 *)addr = origin64; + if (end & 7ULL) *(u32 *)(end - 4) = origin; +} + +void PoisonMemory(const void *dst, uptr size, StackTrace *stack) { + SetShadow(dst, size, (u8)-1); + + if (__msan_get_track_origins()) { + MsanThread *t = GetCurrentThread(); + if (t && t->InSignalHandler()) + return; + Origin o = Origin::CreateHeapOrigin(stack); + SetOrigin(dst, size, o.raw_id()); + } +} + +} // namespace __msan diff --git a/contrib/libs/clang14-rt/lib/msan/msan_poisoning.h b/contrib/libs/clang14-rt/lib/msan/msan_poisoning.h new file mode 100644 index 0000000000..270f1e2499 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/msan/msan_poisoning.h @@ -0,0 +1,58 @@ +//===-- msan_poisoning.h ----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of MemorySanitizer. +// +//===----------------------------------------------------------------------===// + +#ifndef MSAN_POISONING_H +#define MSAN_POISONING_H + +#include "msan.h" + +namespace __msan { + +// Return origin for the first poisoned byte in the memory range, or 0. +u32 GetOriginIfPoisoned(uptr addr, uptr size); + +// Walk [addr, addr+size) app memory region, copying origin tags from the +// corresponding positions in [src_origin, src_origin+size) where the +// corresponding shadow in [src_shadow, src_shadow+size) is non-zero. +void SetOriginIfPoisoned(uptr addr, uptr src_shadow, uptr size, u32 src_origin); + +// Copy origin from src (app address) to dst (app address), creating chained +// origin ids as necessary, without overriding origin for fully initialized +// quads. +void CopyOrigin(const void *dst, const void *src, uptr size, StackTrace *stack); + +// memmove() shadow and origin. Dst and src are application addresses. +// See CopyOrigin() for the origin copying logic. +void MoveShadowAndOrigin(const void *dst, const void *src, uptr size, + StackTrace *stack); + +// memcpy() shadow and origin. Dst and src are application addresses. +// See CopyOrigin() for the origin copying logic. +void CopyShadowAndOrigin(const void *dst, const void *src, uptr size, + StackTrace *stack); + +// memcpy() app memory, and do "the right thing" to the corresponding shadow and +// origin regions. +void CopyMemory(void *dst, const void *src, uptr size, StackTrace *stack); + +// Fill shadow will value. Ptr is an application address. +void SetShadow(const void *ptr, uptr size, u8 value); + +// Set origin for the memory region. +void SetOrigin(const void *dst, uptr size, u32 origin); + +// Mark memory region uninitialized, with origins. +void PoisonMemory(const void *dst, uptr size, StackTrace *stack); + +} // namespace __msan + +#endif // MSAN_POISONING_H diff --git a/contrib/libs/clang14-rt/lib/msan/msan_report.cpp b/contrib/libs/clang14-rt/lib/msan/msan_report.cpp new file mode 100644 index 0000000000..ff3e38c7db --- /dev/null +++ b/contrib/libs/clang14-rt/lib/msan/msan_report.cpp @@ -0,0 +1,277 @@ +//===-- msan_report.cpp ---------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of MemorySanitizer. +// +// Error reporting. +//===----------------------------------------------------------------------===// + +#include "msan.h" +#include "msan_chained_origin_depot.h" +#include "msan_origin.h" +#include "msan_report.h" +#include "sanitizer_common/sanitizer_allocator_internal.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_flags.h" +#include "sanitizer_common/sanitizer_mutex.h" +#include "sanitizer_common/sanitizer_report_decorator.h" +#include "sanitizer_common/sanitizer_stackdepot.h" +#include "sanitizer_common/sanitizer_symbolizer.h" + +using namespace __sanitizer; + +namespace __msan { + +class Decorator: public __sanitizer::SanitizerCommonDecorator { + public: + Decorator() : SanitizerCommonDecorator() { } + const char *Origin() const { return Magenta(); } + const char *Name() const { return Green(); } +}; + +static void DescribeStackOrigin(const char *so, uptr pc) { + Decorator d; + char *s = internal_strdup(so); + char *sep = internal_strchr(s, '@'); + CHECK(sep); + *sep = '\0'; + Printf("%s", d.Origin()); + Printf( + " %sUninitialized value was created by an allocation of '%s%s%s'" + " in the stack frame of function '%s%s%s'%s\n", + d.Origin(), d.Name(), s, d.Origin(), d.Name(), sep + 1, d.Origin(), + d.Default()); + InternalFree(s); + + if (pc) { + // For some reason function address in LLVM IR is 1 less then the address + // of the first instruction. + pc = StackTrace::GetNextInstructionPc(pc); + StackTrace(&pc, 1).Print(); + } +} + +static void DescribeOrigin(u32 id) { + VPrintf(1, " raw origin id: %d\n", id); + Decorator d; + Origin o = Origin::FromRawId(id); + while (o.isChainedOrigin()) { + StackTrace stack; + o = o.getNextChainedOrigin(&stack); + Printf(" %sUninitialized value was stored to memory at%s\n", d.Origin(), + d.Default()); + stack.Print(); + } + if (o.isStackOrigin()) { + uptr pc; + const char *so = GetStackOriginDescr(o.getStackId(), &pc); + DescribeStackOrigin(so, pc); + } else { + StackTrace stack = o.getStackTraceForHeapOrigin(); + switch (stack.tag) { + case StackTrace::TAG_ALLOC: + Printf(" %sUninitialized value was created by a heap allocation%s\n", + d.Origin(), d.Default()); + break; + case StackTrace::TAG_DEALLOC: + Printf(" %sUninitialized value was created by a heap deallocation%s\n", + d.Origin(), d.Default()); + break; + case STACK_TRACE_TAG_POISON: + Printf(" %sMemory was marked as uninitialized%s\n", d.Origin(), + d.Default()); + break; + default: + Printf(" %sUninitialized value was created%s\n", d.Origin(), + d.Default()); + break; + } + stack.Print(); + } +} + +void ReportUMR(StackTrace *stack, u32 origin) { + if (!__msan::flags()->report_umrs) return; + + ScopedErrorReportLock l; + + Decorator d; + Printf("%s", d.Warning()); + Report("WARNING: MemorySanitizer: use-of-uninitialized-value\n"); + Printf("%s", d.Default()); + stack->Print(); + if (origin) { + DescribeOrigin(origin); + } + ReportErrorSummary("use-of-uninitialized-value", stack); +} + +void ReportExpectedUMRNotFound(StackTrace *stack) { + ScopedErrorReportLock l; + + Printf("WARNING: Expected use of uninitialized value not found\n"); + stack->Print(); +} + +void ReportStats() { + ScopedErrorReportLock l; + + if (__msan_get_track_origins() > 0) { + StackDepotStats stack_depot_stats = StackDepotGetStats(); + // FIXME: we want this at normal exit, too! + // FIXME: but only with verbosity=1 or something + Printf("Unique heap origins: %zu\n", stack_depot_stats.n_uniq_ids); + Printf("Stack depot allocated bytes: %zu\n", stack_depot_stats.allocated); + + StackDepotStats chained_origin_depot_stats = ChainedOriginDepotGetStats(); + Printf("Unique origin histories: %zu\n", + chained_origin_depot_stats.n_uniq_ids); + Printf("History depot allocated bytes: %zu\n", + chained_origin_depot_stats.allocated); + } +} + +void ReportAtExitStatistics() { + ScopedErrorReportLock l; + + if (msan_report_count > 0) { + Decorator d; + Printf("%s", d.Warning()); + Printf("MemorySanitizer: %d warnings reported.\n", msan_report_count); + Printf("%s", d.Default()); + } +} + +class OriginSet { + public: + OriginSet() : next_id_(0) {} + int insert(u32 o) { + // Scan from the end for better locality. + for (int i = next_id_ - 1; i >= 0; --i) + if (origins_[i] == o) return i; + if (next_id_ == kMaxSize_) return OVERFLOW; + int id = next_id_++; + origins_[id] = o; + return id; + } + int size() { return next_id_; } + u32 get(int id) { return origins_[id]; } + static char asChar(int id) { + switch (id) { + case MISSING: + return '.'; + case OVERFLOW: + return '*'; + default: + return 'A' + id; + } + } + static const int OVERFLOW = -1; + static const int MISSING = -2; + + private: + static const int kMaxSize_ = 'Z' - 'A' + 1; + u32 origins_[kMaxSize_]; + int next_id_; +}; + +void DescribeMemoryRange(const void *x, uptr size) { + // Real limits. + uptr start = MEM_TO_SHADOW(x); + uptr end = start + size; + // Scan limits: align start down to 4; align size up to 16. + uptr s = start & ~3UL; + size = end - s; + size = (size + 15) & ~15UL; + uptr e = s + size; + + // Single letter names to origin id mapping. + OriginSet origin_set; + + uptr pos = 0; // Offset from aligned start. + bool with_origins = __msan_get_track_origins(); + // True if there is at least 1 poisoned bit in the last 4-byte group. + bool last_quad_poisoned; + int origin_ids[4]; // Single letter origin ids for the current line. + + Decorator d; + Printf("%s", d.Warning()); + uptr start_x = reinterpret_cast<uptr>(x); + Printf("Shadow map [%p, %p) of [%p, %p), %zu bytes:\n", + reinterpret_cast<void *>(start), reinterpret_cast<void *>(end), + reinterpret_cast<void *>(start_x), + reinterpret_cast<void *>(start_x + end - start), end - start); + Printf("%s", d.Default()); + while (s < e) { + // Line start. + if (pos % 16 == 0) { + for (int i = 0; i < 4; ++i) origin_ids[i] = -1; + Printf("%p[%p]:", reinterpret_cast<void *>(s), + reinterpret_cast<void *>(start_x - start + s)); + } + // Group start. + if (pos % 4 == 0) { + Printf(" "); + last_quad_poisoned = false; + } + // Print shadow byte. + if (s < start || s >= end) { + Printf(".."); + } else { + unsigned char v = *(unsigned char *)s; + if (v) last_quad_poisoned = true; + Printf("%x%x", v >> 4, v & 0xf); + } + // Group end. + if (pos % 4 == 3 && with_origins) { + int id = OriginSet::MISSING; + if (last_quad_poisoned) { + u32 o = *(u32 *)SHADOW_TO_ORIGIN(s - 3); + id = origin_set.insert(o); + } + origin_ids[(pos % 16) / 4] = id; + } + // Line end. + if (pos % 16 == 15) { + if (with_origins) { + Printf(" |"); + for (int i = 0; i < 4; ++i) { + char c = OriginSet::asChar(origin_ids[i]); + Printf("%c", c); + if (i != 3) Printf(" "); + } + Printf("|"); + } + Printf("\n"); + } + size--; + s++; + pos++; + } + + Printf("\n"); + + for (int i = 0; i < origin_set.size(); ++i) { + u32 o = origin_set.get(i); + Printf("Origin %c (origin_id %x):\n", OriginSet::asChar(i), o); + DescribeOrigin(o); + } +} + +void ReportUMRInsideAddressRange(const char *what, const void *start, uptr size, + uptr offset) { + Decorator d; + Printf("%s", d.Warning()); + Printf("%sUninitialized bytes in %s%s%s at offset %zu inside [%p, %zu)%s\n", + d.Warning(), d.Name(), what, d.Warning(), offset, start, size, + d.Default()); + if (__sanitizer::Verbosity()) + DescribeMemoryRange(start, size); +} + +} // namespace __msan diff --git a/contrib/libs/clang14-rt/lib/msan/msan_report.h b/contrib/libs/clang14-rt/lib/msan/msan_report.h new file mode 100644 index 0000000000..0965b8cb68 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/msan/msan_report.h @@ -0,0 +1,33 @@ +//===-- msan_report.h -------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file is a part of MemorySanitizer. MSan-private header for error +/// reporting functions. +/// +//===----------------------------------------------------------------------===// + +#ifndef MSAN_REPORT_H +#define MSAN_REPORT_H + +#include "sanitizer_common/sanitizer_internal_defs.h" +#include "sanitizer_common/sanitizer_stacktrace.h" + +namespace __msan { + +void ReportUMR(StackTrace *stack, u32 origin); +void ReportExpectedUMRNotFound(StackTrace *stack); +void ReportStats(); +void ReportAtExitStatistics(); +void DescribeMemoryRange(const void *x, uptr size); +void ReportUMRInsideAddressRange(const char *what, const void *start, uptr size, + uptr offset); + +} // namespace __msan + +#endif // MSAN_REPORT_H diff --git a/contrib/libs/clang14-rt/lib/msan/msan_thread.cpp b/contrib/libs/clang14-rt/lib/msan/msan_thread.cpp new file mode 100644 index 0000000000..40ad6a5019 --- /dev/null +++ b/contrib/libs/clang14-rt/lib/msan/msan_thread.cpp @@ -0,0 +1,122 @@ + +#include "msan.h" +#include "msan_thread.h" +#include "msan_interface_internal.h" + +#include "sanitizer_common/sanitizer_tls_get_addr.h" + +namespace __msan { + +MsanThread *MsanThread::Create(thread_callback_t start_routine, + void *arg) { + uptr PageSize = GetPageSizeCached(); + uptr size = RoundUpTo(sizeof(MsanThread), PageSize); + MsanThread *thread = (MsanThread*)MmapOrDie(size, __func__); + thread->start_routine_ = start_routine; + thread->arg_ = arg; + thread->destructor_iterations_ = GetPthreadDestructorIterations(); + + return thread; +} + +void MsanThread::SetThreadStackAndTls() { + uptr tls_size = 0; + uptr stack_size = 0; + GetThreadStackAndTls(IsMainThread(), &stack_.bottom, &stack_size, &tls_begin_, + &tls_size); + stack_.top = stack_.bottom + stack_size; + tls_end_ = tls_begin_ + tls_size; + + int local; + CHECK(AddrIsInStack((uptr)&local)); +} + +void MsanThread::ClearShadowForThreadStackAndTLS() { + __msan_unpoison((void *)stack_.bottom, stack_.top - stack_.bottom); + if (tls_begin_ != tls_end_) + __msan_unpoison((void *)tls_begin_, tls_end_ - tls_begin_); + DTLS *dtls = DTLS_Get(); + CHECK_NE(dtls, 0); + ForEachDVT(dtls, [](const DTLS::DTV &dtv, int id) { + __msan_unpoison((void *)(dtv.beg), dtv.size); + }); +} + +void MsanThread::Init() { + SetThreadStackAndTls(); + CHECK(MEM_IS_APP(stack_.bottom)); + CHECK(MEM_IS_APP(stack_.top - 1)); + ClearShadowForThreadStackAndTLS(); +} + +void MsanThread::TSDDtor(void *tsd) { + MsanThread *t = (MsanThread*)tsd; + t->Destroy(); +} + +void MsanThread::Destroy() { + malloc_storage().CommitBack(); + // We also clear the shadow on thread destruction because + // some code may still be executing in later TSD destructors + // and we don't want it to have any poisoned stack. + ClearShadowForThreadStackAndTLS(); + uptr size = RoundUpTo(sizeof(MsanThread), GetPageSizeCached()); + UnmapOrDie(this, size); + DTLS_Destroy(); +} + +thread_return_t MsanThread::ThreadStart() { + if (!start_routine_) { + // start_routine_ == 0 if we're on the main thread or on one of the + // OS X libdispatch worker threads. But nobody is supposed to call + // ThreadStart() for the worker threads. + return 0; + } + + thread_return_t res = start_routine_(arg_); + + return res; +} + +MsanThread::StackBounds MsanThread::GetStackBounds() const { + if (!stack_switching_) + return {stack_.bottom, stack_.top}; + const uptr cur_stack = GET_CURRENT_FRAME(); + // Note: need to check next stack first, because FinishSwitchFiber + // may be in process of overwriting stack_.top/bottom_. But in such case + // we are already on the next stack. + if (cur_stack >= next_stack_.bottom && cur_stack < next_stack_.top) + return {next_stack_.bottom, next_stack_.top}; + return {stack_.bottom, stack_.top}; +} + +uptr MsanThread::stack_top() { return GetStackBounds().top; } + +uptr MsanThread::stack_bottom() { return GetStackBounds().bottom; } + +bool MsanThread::AddrIsInStack(uptr addr) { + const auto bounds = GetStackBounds(); + return addr >= bounds.bottom && addr < bounds.top; +} + +void MsanThread::StartSwitchFiber(uptr bottom, uptr size) { + CHECK(!stack_switching_); + next_stack_.bottom = bottom; + next_stack_.top = bottom + size; + stack_switching_ = true; +} + +void MsanThread::FinishSwitchFiber(uptr *bottom_old, uptr *size_old) { + CHECK(stack_switching_); + if (bottom_old) + *bottom_old = stack_.bottom; + if (size_old) + *size_old = stack_.top - stack_.bottom; + stack_.bottom = next_stack_.bottom; + stack_.top = next_stack_.top; + stack_switching_ = false; + next_stack_.top = 0; + next_stack_.bottom = 0; +} + +} // namespace __msan diff --git a/contrib/libs/clang14-rt/lib/msan/msan_thread.h b/contrib/libs/clang14-rt/lib/msan/msan_thread.h new file mode 100644 index 0000000000..f6ed1534cc --- /dev/null +++ b/contrib/libs/clang14-rt/lib/msan/msan_thread.h @@ -0,0 +1,81 @@ +//===-- msan_thread.h -------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of MemorySanitizer. +// +//===----------------------------------------------------------------------===// + +#ifndef MSAN_THREAD_H +#define MSAN_THREAD_H + +#include "msan_allocator.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_posix.h" +namespace __msan { + +class MsanThread { + public: + static MsanThread *Create(thread_callback_t start_routine, void *arg); + static void TSDDtor(void *tsd); + void Destroy(); + + void Init(); // Should be called from the thread itself. + thread_return_t ThreadStart(); + + uptr stack_top(); + uptr stack_bottom(); + uptr tls_begin() { return tls_begin_; } + uptr tls_end() { return tls_end_; } + bool IsMainThread() { return start_routine_ == nullptr; } + + bool AddrIsInStack(uptr addr); + + bool InSignalHandler() { return in_signal_handler_; } + void EnterSignalHandler() { in_signal_handler_++; } + void LeaveSignalHandler() { in_signal_handler_--; } + + void StartSwitchFiber(uptr bottom, uptr size); + void FinishSwitchFiber(uptr *bottom_old, uptr *size_old); + + MsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; } + + int destructor_iterations_; + __sanitizer_sigset_t starting_sigset_; + + private: + // NOTE: There is no MsanThread constructor. It is allocated + // via mmap() and *must* be valid in zero-initialized state. + void SetThreadStackAndTls(); + void ClearShadowForThreadStackAndTLS(); + struct StackBounds { + uptr bottom; + uptr top; + }; + StackBounds GetStackBounds() const; + thread_callback_t start_routine_; + void *arg_; + + bool stack_switching_; + + StackBounds stack_; + StackBounds next_stack_; + + uptr tls_begin_; + uptr tls_end_; + + unsigned in_signal_handler_; + + MsanThreadLocalMallocStorage malloc_storage_; +}; + +MsanThread *GetCurrentThread(); +void SetCurrentThread(MsanThread *t); + +} // namespace __msan + +#endif // MSAN_THREAD_H diff --git a/contrib/libs/clang14-rt/lib/msan/ya.make b/contrib/libs/clang14-rt/lib/msan/ya.make new file mode 100644 index 0000000000..9b0f0fdf2e --- /dev/null +++ b/contrib/libs/clang14-rt/lib/msan/ya.make @@ -0,0 +1,135 @@ +# Generated by devtools/yamaker. + +INCLUDE(${ARCADIA_ROOT}/build/platform/clang/arch.cmake) + +LIBRARY(clang_rt.msan${CLANG_RT_SUFFIX}) + +LICENSE( + Apache-2.0 AND + Apache-2.0 WITH LLVM-exception AND + MIT AND + NCSA +) + +LICENSE_TEXTS(.yandex_meta/licenses.list.txt) + +OWNER(g:cpp-contrib) + +ADDINCL( + contrib/libs/clang14-rt/lib +) + +NO_COMPILER_WARNINGS() + +NO_UTIL() + +NO_SANITIZE() + +CFLAGS( + -DHAVE_RPC_XDR_H=0 + -DUBSAN_CAN_USE_CXXABI + -fPIE + -fcommon + -ffreestanding + -fno-builtin + -fno-exceptions + -fno-lto + -fno-rtti + -fno-stack-protector + -fomit-frame-pointer + -funwind-tables + -fvisibility=hidden +) + +SRCDIR(contrib/libs/clang14-rt/lib) + +SRCS( + interception/interception_linux.cpp + interception/interception_mac.cpp + interception/interception_type_test.cpp + interception/interception_win.cpp + msan/msan.cpp + msan/msan_allocator.cpp + msan/msan_chained_origin_depot.cpp + msan/msan_interceptors.cpp + msan/msan_linux.cpp + msan/msan_poisoning.cpp + msan/msan_report.cpp + msan/msan_thread.cpp + sanitizer_common/sancov_flags.cpp + sanitizer_common/sanitizer_allocator.cpp + sanitizer_common/sanitizer_allocator_checks.cpp + sanitizer_common/sanitizer_allocator_report.cpp + sanitizer_common/sanitizer_chained_origin_depot.cpp + sanitizer_common/sanitizer_common.cpp + sanitizer_common/sanitizer_common_libcdep.cpp + sanitizer_common/sanitizer_coverage_fuchsia.cpp + sanitizer_common/sanitizer_coverage_libcdep_new.cpp + sanitizer_common/sanitizer_coverage_win_sections.cpp + sanitizer_common/sanitizer_deadlock_detector1.cpp + sanitizer_common/sanitizer_deadlock_detector2.cpp + sanitizer_common/sanitizer_errno.cpp + sanitizer_common/sanitizer_file.cpp + sanitizer_common/sanitizer_flag_parser.cpp + sanitizer_common/sanitizer_flags.cpp + sanitizer_common/sanitizer_fuchsia.cpp + sanitizer_common/sanitizer_libc.cpp + sanitizer_common/sanitizer_libignore.cpp + sanitizer_common/sanitizer_linux.cpp + sanitizer_common/sanitizer_linux_libcdep.cpp + sanitizer_common/sanitizer_linux_s390.cpp + sanitizer_common/sanitizer_mac.cpp + sanitizer_common/sanitizer_mac_libcdep.cpp + sanitizer_common/sanitizer_mutex.cpp + sanitizer_common/sanitizer_netbsd.cpp + sanitizer_common/sanitizer_platform_limits_freebsd.cpp + sanitizer_common/sanitizer_platform_limits_linux.cpp + sanitizer_common/sanitizer_platform_limits_netbsd.cpp + sanitizer_common/sanitizer_platform_limits_posix.cpp + sanitizer_common/sanitizer_platform_limits_solaris.cpp + sanitizer_common/sanitizer_posix.cpp + sanitizer_common/sanitizer_posix_libcdep.cpp + sanitizer_common/sanitizer_printf.cpp + sanitizer_common/sanitizer_procmaps_bsd.cpp + sanitizer_common/sanitizer_procmaps_common.cpp + sanitizer_common/sanitizer_procmaps_fuchsia.cpp + sanitizer_common/sanitizer_procmaps_linux.cpp + sanitizer_common/sanitizer_procmaps_mac.cpp + sanitizer_common/sanitizer_procmaps_solaris.cpp + sanitizer_common/sanitizer_solaris.cpp + sanitizer_common/sanitizer_stack_store.cpp + sanitizer_common/sanitizer_stackdepot.cpp + sanitizer_common/sanitizer_stacktrace.cpp + sanitizer_common/sanitizer_stacktrace_libcdep.cpp + sanitizer_common/sanitizer_stacktrace_printer.cpp + sanitizer_common/sanitizer_stacktrace_sparc.cpp + sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp + sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp + sanitizer_common/sanitizer_stoptheworld_mac.cpp + sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp + sanitizer_common/sanitizer_stoptheworld_win.cpp + sanitizer_common/sanitizer_suppressions.cpp + sanitizer_common/sanitizer_symbolizer.cpp + sanitizer_common/sanitizer_symbolizer_libbacktrace.cpp + sanitizer_common/sanitizer_symbolizer_libcdep.cpp + sanitizer_common/sanitizer_symbolizer_mac.cpp + sanitizer_common/sanitizer_symbolizer_markup.cpp + sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp + sanitizer_common/sanitizer_symbolizer_report.cpp + sanitizer_common/sanitizer_symbolizer_win.cpp + sanitizer_common/sanitizer_termination.cpp + sanitizer_common/sanitizer_thread_registry.cpp + sanitizer_common/sanitizer_tls_get_addr.cpp + sanitizer_common/sanitizer_type_traits.cpp + sanitizer_common/sanitizer_unwind_linux_libcdep.cpp + sanitizer_common/sanitizer_unwind_win.cpp + sanitizer_common/sanitizer_win.cpp + ubsan/ubsan_diag.cpp + ubsan/ubsan_flags.cpp + ubsan/ubsan_handlers.cpp + ubsan/ubsan_init.cpp + ubsan/ubsan_monitor.cpp + ubsan/ubsan_value.cpp +) + +END() |