From dc93a2ec88abd5c7148c261a5938b84fa3b36521 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Wed, 19 Jun 2024 23:56:26 -0700 Subject: [PATCH 1/5] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20ch?= =?UTF-8?q?anges=20to=20main=20this=20commit=20is=20based=20on?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.5-bogner [skip ci] --- .../clang-reorder-fields/tool/CMakeLists.txt | 3 + .../tool/ClangReorderFields.cpp | 313 ++++++++++++++---- 2 files changed, 259 insertions(+), 57 deletions(-) diff --git a/clang-tools-extra/clang-reorder-fields/tool/CMakeLists.txt b/clang-tools-extra/clang-reorder-fields/tool/CMakeLists.txt index b414f4f4da99f..682d893aba65c 100644 --- a/clang-tools-extra/clang-reorder-fields/tool/CMakeLists.txt +++ b/clang-tools-extra/clang-reorder-fields/tool/CMakeLists.txt @@ -4,8 +4,11 @@ add_clang_tool(clang-reorder-fields clang_target_link_libraries(clang-reorder-fields PRIVATE + clangAST + clangASTMatchers clangBasic clangFrontend + clangLex clangRewrite clangSerialization clangTooling diff --git a/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp b/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp index 5b77ee7b5738c..bd322d2a08134 100644 --- a/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp +++ b/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp @@ -1,93 +1,292 @@ -//===-- tools/extra/clang-reorder-fields/tool/ClangReorderFields.cpp -*- C++ -*-===// +//===---- ClangLLVMRename.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 // //===----------------------------------------------------------------------===// -/// -/// \file -/// This file contains the implementation of clang-reorder-fields tool -/// +// +// This is a refactoring tool to rename variables so that they start with a +// lowercase letter. This tool is intended to be used to rename variables in +// LLVM codebase in which variable names start with an uppercase letter at +// the moment. +// +// Usage: +// clang-llmv-rename ... +// +// ... specify the paths of files in the CMake source tree. This +// path is looked up in the compile command database. Here is how to build +// the tool and apply that to all files under "lld" directory. +// +// $ git clone https://github.com/llvm/llvm-project.git +// $ mkdir llvm-project/build +// $ cd llvm-project/build +// $ cmake -GNinja -DCMAKE_BUILD_TYPE=Release \ +// -DLLVM_ENABLE_PROJECTS='clang-tools-extra;lld' \ +// -DCMAKE_EXPORT_COMPILE_COMMANDS=On \ +// ../llvm +// $ ninja +// $ bin/clang-llvm-rename ../lld/**/*.{cpp,h} +// +// For each variable in given files, the tool first check whether the +// variable's definition is in one of given files or not, and rename it if +// and only if it can find a definition of the variable. If the tool cannot +// modify a definition of a variable, it doesn't rename it, in order to keep +// a program compiles. +// +// Note that this tool is not perfect; it doesn't resolve or even detect +// name conflicts caused by renaming. You may need to rename variables +// before using this tool so that your program is free from name conflicts +// due to lowercase/uppercase renaming. +// //===----------------------------------------------------------------------===// -#include "../ReorderFieldsAction.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/DiagnosticOptions.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/LangOptions.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Basic/SourceManager.h" +#include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Lex/Lexer.h" #include "clang/Rewrite/Core/Rewriter.h" #include "clang/Tooling/CommonOptionsParser.h" +#include "clang/Tooling/Execution.h" #include "clang/Tooling/Refactoring.h" +#include "clang/Tooling/Refactoring/AtomicChange.h" #include "clang/Tooling/Tooling.h" -#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" -#include -#include -#include +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Signals.h" -using namespace llvm; using namespace clang; +using namespace clang::ast_matchers; +using namespace clang::tooling; +using namespace llvm; -cl::OptionCategory ClangReorderFieldsCategory("clang-reorder-fields options"); +namespace { +class RenameCallback : public MatchFinder::MatchCallback { +public: + RenameCallback( + std::map &FileToReplacements, + ArrayRef Paths) + : FileToReplacements(FileToReplacements) { + for (StringRef S : Paths) + InputFiles.insert(canonicalizePath(S)); + } -static cl::opt - RecordName("record-name", cl::Required, - cl::desc("The name of the struct/class."), - cl::cat(ClangReorderFieldsCategory)); + // This function is called for each AST pattern matche. + void run(const MatchFinder::MatchResult &Result) override { + SourceManager &SM = *Result.SourceManager; -static cl::list FieldsOrder("fields-order", cl::CommaSeparated, - cl::OneOrMore, - cl::desc("The desired fields order."), - cl::cat(ClangReorderFieldsCategory)); + if (auto *D = Result.Nodes.getNodeAs("VarDecl")) { + if (isa(D)) + return; + if (isGlobalConst(D)) + return; + convert(SM, D->getLocation(), D->getName()); + return; + } -static cl::opt Inplace("i", cl::desc("Overwrite edited files."), - cl::cat(ClangReorderFieldsCategory)); + if (auto *D = Result.Nodes.getNodeAs("ParmVarDecl")) { + if (auto *Fn = + dyn_cast_or_null(D->getParentFunctionOrMethod())) + if (Fn->isImplicit()) + return; + convert(SM, D->getLocation(), ""); + return; + } -const char Usage[] = "A tool to reorder fields in C/C++ structs/classes.\n"; + if (auto *D = Result.Nodes.getNodeAs("FieldDecl")) { + convert(SM, D->getLocation(), ""); + return; + } -int main(int argc, const char **argv) { - auto ExpectedParser = tooling::CommonOptionsParser::create( - argc, argv, ClangReorderFieldsCategory, cl::OneOrMore, Usage); - if (!ExpectedParser) { - llvm::errs() << ExpectedParser.takeError(); - return 1; + if (auto *D = Result.Nodes.getNodeAs("DeclRefExpr")) { + if (!isInGivenFiles(SM, D->getFoundDecl()->getLocation())) + return; + if (isa(D->getDecl()) || + isa(D->getDecl())) + return; + if (auto *Decl = dyn_cast(D->getFoundDecl())) + if (isGlobalConst(Decl)) + return; + if (D->getDecl()->getName().empty()) + return; + convert(SM, D->getLocation(), ""); + return; + } + + if (auto *D = Result.Nodes.getNodeAs("MemberExpr")) { + if (!isInGivenFiles(SM, D->getFoundDecl()->getLocation())) + return; + if (D->getMemberDecl()->getName().empty()) + return; + convert(SM, D->getMemberLoc(), D->getMemberDecl()->getName()); + return; + } + + if (auto *D = + Result.Nodes.getNodeAs("CXXCtorInitializer")) { + if (!isInGivenFiles(SM, D->getMemberLocation())) + return; + convert(SM, D->getSourceLocation(), D->getMember()->getName()); + } + + if (auto *D = Result.Nodes.getNodeAs( + "CXXDependentScopeMemberExpr")) { + if (!isInGivenFiles(SM, D->getMemberLoc())) + return; + + SourceLocation Loc = D->getBeginLoc(); + int Len = Lexer::MeasureTokenLength(Loc, SM, LangOptions()); + std::string Name = std::string(SM.getCharacterData(Loc), Len); + if (Name == "ELFT" || Name == "RelTy") + return; + + convert(SM, D->getMemberLoc(), + D->getMemberNameInfo().getName().getAsString()); + } } - tooling::CommonOptionsParser &OP = ExpectedParser.get(); + // Setup an AST matcher. + void registerMatchers(MatchFinder &M) { + M.addMatcher(varDecl(isExpansionInMainFile()).bind("VarDecl"), this); + M.addMatcher(parmVarDecl(isExpansionInMainFile()).bind("ParmVarDecl"), + this); + M.addMatcher(fieldDecl(isExpansionInMainFile()).bind("FieldDecl"), this); + M.addMatcher(declRefExpr(isExpansionInMainFile()).bind("DeclRefExpr"), + this); + M.addMatcher(memberExpr(isExpansionInMainFile()).bind("MemberExpr"), this); + M.addMatcher(cxxCtorInitializer().bind("CXXCtorInitializer"), this); + M.addMatcher(cxxDependentScopeMemberExpr(isExpansionInMainFile()) + .bind("CXXDependentScopeMemberExpr"), + this); + } - auto Files = OP.getSourcePathList(); - tooling::RefactoringTool Tool(OP.getCompilations(), Files); +private: + // Returns true if a given source location is in an input file. + bool isInGivenFiles(SourceManager &SM, SourceLocation Loc) { + std::string Path = canonicalizePath(SM.getFilename(SM.getSpellingLoc(Loc))); + return InputFiles.count(Path); + } - reorder_fields::ReorderFieldsAction Action(RecordName, FieldsOrder, - Tool.getReplacements()); + // Returns true if D is a global variable whose name looks like + // ALL_UPPERCASE_NAME. + bool isGlobalConst(const VarDecl *D) { + return !D->isLocalVarDeclOrParm() && + D->getName().find_first_not_of( + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_") == StringRef::npos; + } - auto Factory = tooling::newFrontendActionFactory(&Action); + // Renames an identifier so that it starts with a lowercase letter. + void convert(SourceManager &SM, SourceLocation Loc, StringRef MustMatch) { + if (!Loc.isValid()) + return; - if (Inplace) - return Tool.runAndSave(Factory.get()); + SourceLocation SpellingLoc = SM.getSpellingLoc(Loc); + if (!SM.isInMainFile(SpellingLoc)) + return; - int ExitCode = Tool.run(Factory.get()); - LangOptions DefaultLangOptions; - IntrusiveRefCntPtr DiagOpts(new DiagnosticOptions()); - TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts); - DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr(new DiagnosticIDs()), &*DiagOpts, - &DiagnosticPrinter, false); + int Len = Lexer::MeasureTokenLength(SpellingLoc, SM, LangOptions()); + std::string OldName = std::string(SM.getCharacterData(SpellingLoc), Len); - auto &FileMgr = Tool.getFiles(); - SourceManager Sources(Diagnostics, FileMgr); - Rewriter Rewrite(Sources, DefaultLangOptions); - Tool.applyAllReplacements(Rewrite); + if (!MustMatch.empty() && OldName != MustMatch) + return; - for (const auto &File : Files) { - auto Entry = llvm::cantFail(FileMgr.getFileRef(File)); - const auto ID = Sources.getOrCreateFileID(Entry, SrcMgr::C_User); - Rewrite.getEditBuffer(ID).write(outs()); + std::string NewName = tolower(OldName); + tooling::Replacement Repl(SM, SpellingLoc, OldName.size(), NewName); + if (!Repl.getFilePath().empty()) + consumeError(FileToReplacements[Repl.getFilePath().str()].add(Repl)); } - return ExitCode; + // Returns a new identifier name for a given identifier. Basically, a new + // name is differnet only at the first character, but for some identifiers + // such as all capital ones, there are special renaming rules. + std::string tolower(StringRef S) { + // This is a list of special renaming rule. + std::string Ret = StringSwitch(S) + .Case("MBOrErr", "mbOrErr") + .Case("CGProfile", "cgProfile") + .Case("IS", "isec") + .Case("ISAddr", "isecAddr") + .Case("ISLoc", "isecLoc") + .Case("ISLimit", "isecLimit") + .Case("prevISLimit", "prevIsecLimit") + .Case("TSBase", "tsBase") + .Case("TSLimit", "tsLimit") + .Case("Static", "isStatic") + .Case("Pic", "isPic") + .Case("Main", "mainPart") + .Case("Class", "eqClass") + .Default(""); + if (!Ret.empty()) + return Ret; + + // If a new name would be a reserved word, don't rename. + for (StringRef S2 : {"new", "case", "default"}) + if (S.lower() == S2) + return std::string(S); + + // Convert all-uppercase names to all-smallcase. + if (S.find_first_not_of("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") == + StringRef::npos) + return S.lower(); + + // They are converted to lowercase names. + for (StringRef S2 : {"MBRef", "EFlags", "EKind", "EMachine", "OSec", "MBs"}) + if (S == S2) + return S2.lower(); + + // If an identifier starts with one of the folloiwng prefixes, the + // prefix will be converted to lowercase. + for (StringRef Prefix : {"LTO", "ARM", "PPC", "RISCV", "LMA", "VMA", "ELF", + "ISD", "ABI", "LHS", "RHS", "VFP", "DTP", "OPT_"}) + if (S.starts_with(Prefix)) + return (Prefix.lower() + S.substr(Prefix.size())).str(); + + // Otherwise, lowercase the first character. + Ret = S.str(); + Ret[0] = std::tolower(Ret[0]); + return Ret; + } + + // Removes "../" and make a resulting path absolute. + std::string canonicalizePath(StringRef Path) { + SmallString<128> S = Path; + sys::fs::make_absolute(S); + sys::path::remove_dots(S, /*remove_dot_dot=*/true); + return std::string(S); + } + + std::map &FileToReplacements; + StringSet<> InputFiles; +}; +} // end anonymous namespace + +// Set up the command line options +static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); +static cl::OptionCategory ToolTemplateCategory("tool-template options"); + +int main(int argc, const char **argv) { + sys::PrintStackTraceOnErrorSignal(argv[0]); + + auto ExpectedParser = + tooling::CommonOptionsParser::create(argc, argv, ToolTemplateCategory); + if (!ExpectedParser) + return 0; + tooling::CommonOptionsParser &OptParser = ExpectedParser.get(); + + const std::vector &Files = OptParser.getSourcePathList(); + tooling::RefactoringTool Tool(OptParser.getCompilations(), Files); + + RenameCallback Callback(Tool.getReplacements(), Files); + MatchFinder Finder; + Callback.registerMatchers(Finder); + + std::unique_ptr Factory = + tooling::newFrontendActionFactory(&Finder); + return Tool.runAndSave(Factory.get()); } From 54357a77702361abf1044d1ee5d0dee3e4fa407c Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Thu, 20 Jun 2024 00:23:01 -0700 Subject: [PATCH 2/5] more Created using spr 1.3.5-bogner --- compiler-rt/lib/nsan/nsan.cpp | 59 ++++++------ compiler-rt/lib/nsan/nsan_flags.cpp | 2 - compiler-rt/lib/nsan/nsan_stats.cpp | 107 ++++++++++----------- compiler-rt/lib/nsan/nsan_stats.h | 43 +++++---- compiler-rt/lib/nsan/nsan_suppressions.cpp | 48 +++++---- 5 files changed, 124 insertions(+), 135 deletions(-) diff --git a/compiler-rt/lib/nsan/nsan.cpp b/compiler-rt/lib/nsan/nsan.cpp index ece1130f73d14..fd5390e20a029 100644 --- a/compiler-rt/lib/nsan/nsan.cpp +++ b/compiler-rt/lib/nsan/nsan.cpp @@ -71,7 +71,6 @@ __nsan_set_value_unknown(const u8 *addr, uptr size) { internal_memset((void *)getShadowTypeAddrFor(addr), 0, size); } -namespace __nsan { const char *FTInfo::kCppTypeName = "float"; const char *FTInfo::kCppTypeName = "double"; @@ -177,8 +176,6 @@ template T max(T a, T b) { return a < b ? b : a; } } // end anonymous namespace -} // end namespace __nsan - void __sanitizer::BufferedStackTrace::UnwindImpl(uptr pc, uptr bp, void *context, bool request_fast, @@ -189,7 +186,7 @@ void __sanitizer::BufferedStackTrace::UnwindImpl(uptr pc, uptr bp, extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_print_accumulated_stats() { if (nsan_stats) - nsan_stats->print(); + nsan_stats->Print(); } static void NsanAtexit() { @@ -228,18 +225,18 @@ __nsan_get_shadow_ptr_for_longdouble_store(u8 *store_addr, uptr n) { return getShadowPtrForStore(store_addr, n); } -template static bool isValidShadowType(const u8 *shadow_type) { +template static bool IsValidShadowType(const u8 *shadow_type) { return __builtin_memcmp(shadow_type, FTInfo::kTypePattern, sizeof(FT)) == 0; } -template static bool isZero(const T *ptr) { +template static bool IsZero(const T *ptr) { constexpr const char kZeros[kSize] = {}; // Zero initialized. return __builtin_memcmp(ptr, kZeros, kSize) == 0; } -template static bool isUnknownShadowType(const u8 *shadow_type) { - return isZero::kTypePattern)>(shadow_type); +template static bool IsUnknownShadowType(const u8 *shadow_type) { + return IsZero::kTypePattern)>(shadow_type); } // The three folowing functions check that the address stores a complete @@ -249,21 +246,21 @@ template static const u8 *getShadowPtrForLoad(const u8 *load_addr, uptr n) { const u8 *const shadow_type = getShadowTypeAddrFor(load_addr); for (uptr i = 0; i < n; ++i) { - if (!isValidShadowType(shadow_type + i * sizeof(FT))) { + if (!IsValidShadowType(shadow_type + i * sizeof(FT))) { // If loadtracking stats are enabled, log loads with invalid types // (tampered with through type punning). if (flags().enable_loadtracking_stats) { - if (isUnknownShadowType(shadow_type + i * sizeof(FT))) { + if (IsUnknownShadowType(shadow_type + i * sizeof(FT))) { // Warn only if the value is non-zero. Zero is special because // applications typically initialize large buffers to zero in an // untyped way. - if (!isZero(load_addr)) { + if (!IsZero(load_addr)) { GET_CALLER_PC_BP; - nsan_stats->addUnknownLoadTrackingEvent(pc, bp); + nsan_stats->AddUnknownLoadTrackingEvent(pc, bp); } } else { GET_CALLER_PC_BP; - nsan_stats->addInvalidLoadTrackingEvent(pc, bp); + nsan_stats->AddInvalidLoadTrackingEvent(pc, bp); } } return nullptr; @@ -442,7 +439,7 @@ int32_t checkFT(const FT value, ShadowFT Shadow, CheckTypeT CheckType, // want to avoid having to move the computation of `largest` before the // absolute value check when this branch is not taken. const InternalFT largest = max(ftAbs(check_value), ftAbs(check_shadow)); - nsan_stats->addCheck(CheckType, pc, bp, abs_err / largest); + nsan_stats->AddCheck(CheckType, pc, bp, abs_err / largest); } // Note: writing the comparison that way ensures that when `abs_err` is Nan @@ -534,7 +531,7 @@ int32_t checkFT(const FT value, ShadowFT Shadow, CheckTypeT CheckType, if (flags().enable_warning_stats) { GET_CALLER_PC_BP; - nsan_stats->addWarning(CheckType, pc, bp, abs_err / largest); + nsan_stats->AddWarning(CheckType, pc, bp, abs_err / largest); } if (flags().halt_on_error) { @@ -565,10 +562,10 @@ __nsan_internal_check_longdouble_q(long double value, __float128 shadow, return checkFT(value, shadow, static_cast(check_type), check_arg); } -static const char *getTruthValueName(bool v) { return v ? "true" : "false"; } +static const char *GetTruthValueName(bool v) { return v ? "true" : "false"; } // This uses the same values as CmpInst::Predicate. -static const char *getPredicateName(int v) { +static const char *GetPredicateName(int v) { switch (v) { case 0: return "(false)"; @@ -618,21 +615,19 @@ void fCmpFailFT(const FT Lhs, const FT Rhs, ShadowFT LhsShadow, } GET_CALLER_PC_BP; - BufferedStackTrace Stack; - Stack.Unwind(pc, bp, nullptr, false); + BufferedStackTrace stack; + stack.Unwind(pc, bp, nullptr, false); - if (GetSuppressionForStack(&Stack, CheckKind::Fcmp)) { + if (GetSuppressionForStack(&stack, CheckKind::Fcmp)) { // FIXME: optionally print. return; } - if (flags().enable_warning_stats) { - nsan_stats->addWarning(CheckTypeT::kFcmp, pc, bp, 0.0); - } + if (flags().enable_warning_stats) + nsan_stats->AddWarning(CheckTypeT::kFcmp, pc, bp, 0.0); - if (flags().disable_warnings) { + if (flags().disable_warnings) return; - } // FIXME: ideally we would print the shadow value as FP128. Right now because // we truncate to long double we can sometimes see stuff like: @@ -640,7 +635,7 @@ void fCmpFailFT(const FT Lhs, const FT Rhs, ShadowFT LhsShadow, using ValuePrinter = FTPrinter; using ShadowPrinter = FTPrinter; Decorator D; - const char *const PredicateName = getPredicateName(Predicate); + const char *const PredicateName = GetPredicateName(Predicate); Printf("%s", D.Warning()); Printf("WARNING: NumericalStabilitySanitizer: floating-point comparison " "results depend on precision\n" @@ -651,20 +646,20 @@ void fCmpFailFT(const FT Lhs, const FT Rhs, ShadowFT LhsShadow, "%s", // Native, decimal. FTInfo::kCppTypeName, ValuePrinter::dec(Lhs).Buffer, PredicateName, - ValuePrinter::dec(Rhs).Buffer, getTruthValueName(result), + ValuePrinter::dec(Rhs).Buffer, GetTruthValueName(result), // Shadow, decimal FTInfo::kCppTypeName, ShadowPrinter::dec(LhsShadow).Buffer, PredicateName, ShadowPrinter::dec(RhsShadow).Buffer, - getTruthValueName(ShadowResult), + GetTruthValueName(ShadowResult), // Native, hex. FTInfo::kCppTypeName, ValuePrinter::hex(Lhs).Buffer, PredicateName, - ValuePrinter::hex(Rhs).Buffer, getTruthValueName(result), + ValuePrinter::hex(Rhs).Buffer, GetTruthValueName(result), // Shadow, hex FTInfo::kCppTypeName, ShadowPrinter::hex(LhsShadow).Buffer, PredicateName, ShadowPrinter::hex(RhsShadow).Buffer, - getTruthValueName(ShadowResult), D.End()); + GetTruthValueName(ShadowResult), D.End()); Printf("%s", D.Default()); - Stack.Print(); + stack.Print(); if (flags().halt_on_error) { Printf("Exiting\n"); Die(); @@ -799,7 +794,7 @@ extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_init() { InitializeInterceptors(); - initializeStats(); + InitializeStats(); if (flags().print_stats_on_exit) Atexit(NsanAtexit); diff --git a/compiler-rt/lib/nsan/nsan_flags.cpp b/compiler-rt/lib/nsan/nsan_flags.cpp index 2c7764653a22d..94e3a187c8e6c 100644 --- a/compiler-rt/lib/nsan/nsan_flags.cpp +++ b/compiler-rt/lib/nsan/nsan_flags.cpp @@ -18,11 +18,9 @@ using namespace __sanitizer; using namespace __nsan; -namespace __nsan { SANITIZER_INTERFACE_WEAK_DEF(const char *, __nsan_default_options, void) { return ""; } -} // namespace __nsan Flags __nsan::flags_data; diff --git a/compiler-rt/lib/nsan/nsan_stats.cpp b/compiler-rt/lib/nsan/nsan_stats.cpp index f23a72e3ba2a8..d188df1b1f70b 100644 --- a/compiler-rt/lib/nsan/nsan_stats.cpp +++ b/compiler-rt/lib/nsan/nsan_stats.cpp @@ -22,72 +22,73 @@ #include #include -namespace __nsan { - using namespace __sanitizer; +using namespace __nsan; Stats::Stats() { - CheckAndWarnings.Initialize(0); + check_and_warnings.Initialize(0); TrackedLoads.Initialize(0); } Stats::~Stats() { Printf("deleting nsan stats\n"); } -static uptr key(CheckTypeT CheckType, u32 StackId) { +static uptr Key(CheckTypeT CheckType, u32 StackId) { return static_cast(CheckType) + StackId * static_cast(CheckTypeT::kMaxCheckType); } template -void UpdateEntry(CheckTypeT CheckTy, uptr PC, uptr BP, MapT *Map, - VectorT *Vector, Mutex *Mutex, Fn F) { +static void UpdateEntry(CheckTypeT check_ty, uptr pc, uptr bp, MapT *map, + VectorT *vector, Mutex *mutex, Fn F) { BufferedStackTrace Stack; - Stack.Unwind(PC, BP, nullptr, false); - u32 StackId = StackDepotPut(Stack); - typename MapT::Handle Handle(Map, key(CheckTy, StackId)); - Lock L(Mutex); + Stack.Unwind(pc, bp, nullptr, false); + u32 stack_id = StackDepotPut(Stack); + typename MapT::Handle Handle(map, Key(check_ty, stack_id)); + Lock L(mutex); if (Handle.created()) { - typename VectorT::value_type Entry; - Entry.StackId = StackId; - Entry.CheckTy = CheckTy; - F(Entry); - Vector->push_back(Entry); + typename VectorT::value_type entry; + entry.stack_id = stack_id; + entry.check_ty = check_ty; + F(entry); + vector->push_back(entry); } else { - auto &Entry = (*Vector)[*Handle]; - F(Entry); + auto &entry = (*vector)[*Handle]; + F(entry); } } -void Stats::addCheck(CheckTypeT CheckTy, uptr PC, uptr BP, double RelErr) { - UpdateEntry(CheckTy, PC, BP, &CheckAndWarningsMap, &CheckAndWarnings, - &CheckAndWarningsMutex, [RelErr](CheckAndWarningsValue &Entry) { - ++Entry.NumChecks; - if (RelErr > Entry.MaxRelativeError) { - Entry.MaxRelativeError = RelErr; +void Stats::AddCheck(CheckTypeT check_ty, uptr pc, uptr bp, double rel_err) { + UpdateEntry(check_ty, pc, bp, &CheckAndWarningsMap, &check_and_warnings, + &check_and_warning_mutex, + [rel_err](CheckAndWarningsValue &entry) { + ++entry.num_checks; + if (rel_err > entry.max_relative_err) { + entry.max_relative_err = rel_err; } }); } -void Stats::addWarning(CheckTypeT CheckTy, uptr PC, uptr BP, double RelErr) { - UpdateEntry(CheckTy, PC, BP, &CheckAndWarningsMap, &CheckAndWarnings, - &CheckAndWarningsMutex, [RelErr](CheckAndWarningsValue &Entry) { - ++Entry.NumWarnings; - if (RelErr > Entry.MaxRelativeError) { - Entry.MaxRelativeError = RelErr; +void Stats::AddWarning(CheckTypeT check_ty, uptr pc, uptr bp, double rel_err) { + UpdateEntry(check_ty, pc, bp, &CheckAndWarningsMap, &check_and_warnings, + &check_and_warning_mutex, + [rel_err](CheckAndWarningsValue &entry) { + ++entry.num_warnings; + if (rel_err > entry.max_relative_err) { + entry.max_relative_err = rel_err; } }); } -void Stats::addInvalidLoadTrackingEvent(uptr PC, uptr BP) { - UpdateEntry(CheckTypeT::kLoad, PC, BP, &LoadTrackingMap, &TrackedLoads, +void Stats::AddInvalidLoadTrackingEvent(uptr pc, uptr bp) { + UpdateEntry(CheckTypeT::kLoad, pc, bp, &LoadTrackingMap, &TrackedLoads, &TrackedLoadsMutex, - [](LoadTrackingValue &Entry) { ++Entry.NumInvalid; }); + [](LoadTrackingValue &entry) { ++entry.num_invalid; }); } -void Stats::addUnknownLoadTrackingEvent(uptr PC, uptr BP) { - UpdateEntry(CheckTypeT::kLoad, PC, BP, &LoadTrackingMap, &TrackedLoads, +void Stats::AddUnknownLoadTrackingEvent(uptr pc, uptr bp) { + UpdateEntry(CheckTypeT::kLoad, pc, bp, &LoadTrackingMap, &TrackedLoads, &TrackedLoadsMutex, - [](LoadTrackingValue &Entry) { ++Entry.NumUnknown; }); + [](LoadTrackingValue &entry) { ++entry.num_unknown; }); } static const char *CheckTypeDisplay(CheckTypeT CheckType) { @@ -115,20 +116,20 @@ static const char *CheckTypeDisplay(CheckTypeT CheckType) { return ""; } -void Stats::print() const { +void Stats::Print() const { { - Lock L(&CheckAndWarningsMutex); - for (const auto &Entry : CheckAndWarnings) { - Printf("warned %llu times out of %llu %s checks ", Entry.NumWarnings, - Entry.NumChecks, CheckTypeDisplay(Entry.CheckTy)); - if (Entry.NumWarnings > 0) { + Lock L(&check_and_warning_mutex); + for (const auto &entry : check_and_warnings) { + Printf("warned %llu times out of %llu %s checks ", entry.num_warnings, + entry.num_checks, CheckTypeDisplay(entry.check_ty)); + if (entry.num_warnings > 0) { char RelErrBuf[64]; snprintf(RelErrBuf, sizeof(RelErrBuf) - 1, "%f", - Entry.MaxRelativeError * 100.0); + entry.max_relative_err * 100.0); Printf("(max relative error: %s%%) ", RelErrBuf); } Printf("at:\n"); - StackDepotGet(Entry.StackId).Print(); + StackDepotGet(entry.stack_id).Print(); } } @@ -136,12 +137,12 @@ void Stats::print() const { Lock L(&TrackedLoadsMutex); u64 TotalInvalidLoadTracking = 0; u64 TotalUnknownLoadTracking = 0; - for (const auto &Entry : TrackedLoads) { - TotalInvalidLoadTracking += Entry.NumInvalid; - TotalUnknownLoadTracking += Entry.NumUnknown; - Printf("invalid/unknown type for %llu/%llu loads at:\n", Entry.NumInvalid, - Entry.NumUnknown); - StackDepotGet(Entry.StackId).Print(); + for (const auto &entry : TrackedLoads) { + TotalInvalidLoadTracking += entry.num_invalid; + TotalUnknownLoadTracking += entry.num_unknown; + Printf("invalid/unknown type for %llu/%llu loads at:\n", + entry.num_invalid, entry.num_unknown); + StackDepotGet(entry.stack_id).Print(); } Printf( "There were %llu/%llu floating-point loads where the shadow type was " @@ -150,9 +151,7 @@ void Stats::print() const { } } -alignas(64) static char StatsPlaceholder[sizeof(Stats)]; -Stats *nsan_stats = nullptr; - -void initializeStats() { nsan_stats = new (StatsPlaceholder) Stats(); } +alignas(64) static char stats_placeholder[sizeof(Stats)]; +Stats *__nsan::nsan_stats = nullptr; -} // namespace __nsan +void __nsan::InitializeStats() { nsan_stats = new (stats_placeholder) Stats(); } diff --git a/compiler-rt/lib/nsan/nsan_stats.h b/compiler-rt/lib/nsan/nsan_stats.h index 7e8c7bb7bf12d..d1c7e0115e7ae 100644 --- a/compiler-rt/lib/nsan/nsan_stats.h +++ b/compiler-rt/lib/nsan/nsan_stats.h @@ -40,52 +40,53 @@ class Stats { ~Stats(); // Signal that we checked the instruction at the given address. - void addCheck(CheckTypeT CheckType, __sanitizer::uptr PC, - __sanitizer::uptr BP, double RelErr); + void AddCheck(CheckTypeT check_ty, __sanitizer::uptr pc, __sanitizer::uptr bp, + double rel_err); // Signal that we warned for the instruction at the given address. - void addWarning(CheckTypeT CheckType, __sanitizer::uptr PC, - __sanitizer::uptr BP, double RelErr); + void AddWarning(CheckTypeT check_ty, __sanitizer::uptr pc, + __sanitizer::uptr bp, double rel_err); // Signal that we detected a floating-point load where the shadow type was // invalid. - void addInvalidLoadTrackingEvent(__sanitizer::uptr PC, __sanitizer::uptr BP); + void AddInvalidLoadTrackingEvent(__sanitizer::uptr pc, __sanitizer::uptr bp); // Signal that we detected a floating-point load where the shadow type was // unknown but the value was nonzero. - void addUnknownLoadTrackingEvent(__sanitizer::uptr PC, __sanitizer::uptr BP); + void AddUnknownLoadTrackingEvent(__sanitizer::uptr pc, __sanitizer::uptr bp); - void print() const; + void Print() const; private: using IndexMap = __sanitizer::AddrHashMap<__sanitizer::uptr, 11>; struct CheckAndWarningsValue { - CheckTypeT CheckTy; - __sanitizer::u32 StackId = 0; - __sanitizer::u64 NumChecks = 0; - __sanitizer::u64 NumWarnings = 0; + CheckTypeT check_ty; + __sanitizer::u32 stack_id = 0; + __sanitizer::u64 num_checks = 0; + __sanitizer::u64 num_warnings = 0; // This is a bitcasted double. Doubles have the nice idea to be ordered as // ints. - double MaxRelativeError = 0; + double max_relative_err = 0; }; - // Maps key(CheckType, StackId) to indices in CheckAndWarnings. + // Map Key(check_ty, StackId) to indices in CheckAndWarnings. IndexMap CheckAndWarningsMap; - __sanitizer::InternalMmapVectorNoCtor CheckAndWarnings; - mutable __sanitizer::Mutex CheckAndWarningsMutex; + __sanitizer::InternalMmapVectorNoCtor + check_and_warnings; + mutable __sanitizer::Mutex check_and_warning_mutex; struct LoadTrackingValue { - CheckTypeT CheckTy; - __sanitizer::u32 StackId = 0; - __sanitizer::u64 NumInvalid = 0; - __sanitizer::u64 NumUnknown = 0; + CheckTypeT check_ty; + __sanitizer::u32 stack_id = 0; + __sanitizer::u64 num_invalid = 0; + __sanitizer::u64 num_unknown = 0; }; - // Maps key(CheckTypeT::kLoad, StackId) to indices in TrackedLoads. + // Map Key(CheckTypeT::kLoad, StackId) to indices in TrackedLoads. IndexMap LoadTrackingMap; __sanitizer::InternalMmapVectorNoCtor TrackedLoads; mutable __sanitizer::Mutex TrackedLoadsMutex; }; extern Stats *nsan_stats; -void initializeStats(); +void InitializeStats(); } // namespace __nsan diff --git a/compiler-rt/lib/nsan/nsan_suppressions.cpp b/compiler-rt/lib/nsan/nsan_suppressions.cpp index 12dd8708c37e7..c4d438e090e05 100644 --- a/compiler-rt/lib/nsan/nsan_suppressions.cpp +++ b/compiler-rt/lib/nsan/nsan_suppressions.cpp @@ -7,55 +7,52 @@ //===----------------------------------------------------------------------===// #include "nsan_suppressions.h" - +#include "nsan_flags.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_stacktrace.h" #include "sanitizer_common/sanitizer_symbolizer.h" -#include "nsan_flags.h" - -// Can be overriden in frontend. -SANITIZER_WEAK_DEFAULT_IMPL -const char *__nsan_default_suppressions() { return 0; } - -namespace __nsan { +using namespace __sanitizer; +using namespace __nsan; -const char *const kSuppressionFcmp = "fcmp"; -const char *const kSuppressionConsistency = "consistency"; +SANITIZER_INTERFACE_WEAK_DEF(const char *, __nsan_default_suppressions, void) { + return 0; +} -using namespace __sanitizer; +const char kSuppressionFcmp[] = "fcmp"; +const char kSuppressionConsistency[] = "consistency"; -alignas(64) static char suppressionPlaceholder[sizeof(SuppressionContext)]; -static SuppressionContext *suppressionCtx = nullptr; +alignas(64) static char suppression_placeholder[sizeof(SuppressionContext)]; +static SuppressionContext *suppression_ctx; // The order should match the enum CheckKind. static const char *kSuppressionTypes[] = {kSuppressionFcmp, kSuppressionConsistency}; -void InitializeSuppressions() { - CHECK_EQ(nullptr, suppressionCtx); - suppressionCtx = new (suppressionPlaceholder) +void __nsan::InitializeSuppressions() { + CHECK_EQ(nullptr, suppression_ctx); + suppression_ctx = new (suppression_placeholder) SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); - suppressionCtx->ParseFromFile(flags().suppressions); - suppressionCtx->Parse(__nsan_default_suppressions()); + suppression_ctx->ParseFromFile(flags().suppressions); + suppression_ctx->Parse(__nsan_default_suppressions()); } -static Suppression *GetSuppressionForAddr(uptr addr, const char *supprType) { +static Suppression *GetSuppressionForAddr(uptr addr, const char *suppr_type) { Suppression *s = nullptr; // Suppress by module name. - SuppressionContext *suppressions = suppressionCtx; + SuppressionContext *suppressions = suppression_ctx; if (const char *moduleName = Symbolizer::GetOrInit()->GetModuleNameForPc(addr)) { - if (suppressions->Match(moduleName, supprType, &s)) + if (suppressions->Match(moduleName, suppr_type, &s)) return s; } // Suppress by file or function name. SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(addr); for (SymbolizedStack *cur = frames; cur; cur = cur->next) { - if (suppressions->Match(cur->info.function, supprType, &s) || - suppressions->Match(cur->info.file, supprType, &s)) { + if (suppressions->Match(cur->info.function, suppr_type, &s) || + suppressions->Match(cur->info.file, suppr_type, &s)) { break; } } @@ -63,7 +60,8 @@ static Suppression *GetSuppressionForAddr(uptr addr, const char *supprType) { return s; } -Suppression *GetSuppressionForStack(const StackTrace *stack, CheckKind k) { +Suppression *__nsan::GetSuppressionForStack(const StackTrace *stack, + CheckKind k) { for (uptr i = 0, e = stack->size; i < e; i++) { Suppression *s = GetSuppressionForAddr( StackTrace::GetPreviousInstructionPc(stack->trace[i]), @@ -73,5 +71,3 @@ Suppression *GetSuppressionForStack(const StackTrace *stack, CheckKind k) { } return nullptr; } - -} // end namespace __nsan From 45e30df51a89e5c17e1b0ff6175bba336899e9ef Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Thu, 20 Jun 2024 00:29:30 -0700 Subject: [PATCH 3/5] more Created using spr 1.3.5-bogner --- compiler-rt/lib/nsan/nsan.cpp | 2 +- compiler-rt/lib/nsan/nsan.h | 50 ++++++++++----------- compiler-rt/lib/nsan/nsan_interceptors.cpp | 24 +++++----- compiler-rt/lib/nsan/tests/NSanUnitTest.cpp | 48 ++++++++++---------- 4 files changed, 62 insertions(+), 62 deletions(-) diff --git a/compiler-rt/lib/nsan/nsan.cpp b/compiler-rt/lib/nsan/nsan.cpp index fd5390e20a029..0c72f798a2dca 100644 --- a/compiler-rt/lib/nsan/nsan.cpp +++ b/compiler-rt/lib/nsan/nsan.cpp @@ -471,7 +471,7 @@ int32_t checkFT(const FT value, ShadowFT Shadow, CheckTypeT CheckType, log2l(static_cast(abs_err / largest / Eps))); } char UlpErrBuf[128] = ""; - const double ShadowUlpDiff = getULPDiff(check_value, check_shadow); + const double ShadowUlpDiff = GetULPDiff(check_value, check_shadow); if (ShadowUlpDiff != kMaxULPDiff) { // This is the ULP diff in the internal domain. The user actually cares // about that in the original domain. diff --git a/compiler-rt/lib/nsan/nsan.h b/compiler-rt/lib/nsan/nsan.h index 510d68b9fef02..1b57e916700f6 100644 --- a/compiler-rt/lib/nsan/nsan.h +++ b/compiler-rt/lib/nsan/nsan.h @@ -164,60 +164,60 @@ template <> struct FTInfo<__float128> { constexpr double kMaxULPDiff = INFINITY; // Helper for getULPDiff that works on bit representations. -template double getULPDiffBits(BT V1Bits, BT V2Bits) { +template double GetULPDiffBits(BT v1_bits, BT v2_bits) { // If the integer representations of two same-sign floats are subtracted then // the absolute value of the result is equal to one plus the number of // representable floats between them. - return V1Bits >= V2Bits ? V1Bits - V2Bits : V2Bits - V1Bits; + return v1_bits >= v2_bits ? v1_bits - v2_bits : v2_bits - v1_bits; } -// Returns the the number of floating point values between V1 and V2, capped to +// Returns the the number of floating point values between v1 and v2, capped to // u64max. Return 0 for (-0.0,0.0). -template double getULPDiff(FT V1, FT V2) { - if (V1 == V2) { +template double GetULPDiff(FT v1, FT v2) { + if (v1 == v2) { return 0; // Typically, -0.0 and 0.0 } using BT = typename FTInfo::orig_bits_type; static_assert(sizeof(FT) == sizeof(BT), "not implemented"); static_assert(sizeof(BT) <= 64, "not implemented"); - BT V1Bits; - __builtin_memcpy(&V1Bits, &V1, sizeof(BT)); - BT V2Bits; - __builtin_memcpy(&V2Bits, &V2, sizeof(BT)); + BT v1_bits; + __builtin_memcpy(&v1_bits, &v1, sizeof(BT)); + BT v2_bits; + __builtin_memcpy(&v2_bits, &v2, sizeof(BT)); // Check whether the signs differ. IEEE-754 float types always store the sign // in the most significant bit. NaNs and infinities are handled by the calling // code. constexpr BT kSignMask = BT{1} << (CHAR_BIT * sizeof(BT) - 1); - if ((V1Bits ^ V2Bits) & kSignMask) { + if ((v1_bits ^ v2_bits) & kSignMask) { // Signs differ. We can get the ULPs as `getULPDiff(negative_number, -0.0) // + getULPDiff(0.0, positive_number)`. - if (V1Bits & kSignMask) { - return getULPDiffBits(V1Bits, kSignMask) + - getULPDiffBits(0, V2Bits); + if (v1_bits & kSignMask) { + return GetULPDiffBits(v1_bits, kSignMask) + + GetULPDiffBits(0, v2_bits); } else { - return getULPDiffBits(V2Bits, kSignMask) + - getULPDiffBits(0, V1Bits); + return GetULPDiffBits(v2_bits, kSignMask) + + GetULPDiffBits(0, v1_bits); } } - return getULPDiffBits(V1Bits, V2Bits); + return GetULPDiffBits(v1_bits, v2_bits); } // FIXME: This needs mor work: Because there is no 80-bit integer type, we have // to go through __uint128_t. Therefore the assumptions about the sign bit do // not hold. -template <> inline double getULPDiff(long double V1, long double V2) { +template <> inline double GetULPDiff(long double v1, long double v2) { using BT = __uint128_t; - BT V1Bits = 0; - __builtin_memcpy(&V1Bits, &V1, sizeof(long double)); - BT V2Bits = 0; - __builtin_memcpy(&V2Bits, &V2, sizeof(long double)); - if ((V1Bits ^ V2Bits) & (BT{1} << (CHAR_BIT * sizeof(BT) - 1))) - return (V1 == V2) ? __sanitizer::u64{0} : kMaxULPDiff; // Signs differ. + BT v1_bits = 0; + __builtin_memcpy(&v1_bits, &v1, sizeof(long double)); + BT v2_bits = 0; + __builtin_memcpy(&v2_bits, &v2, sizeof(long double)); + if ((v1_bits ^ v2_bits) & (BT{1} << (CHAR_BIT * sizeof(BT) - 1))) + return v1 == v2 ? __sanitizer::u64{0} : kMaxULPDiff; // Signs differ. // If the integer representations of two same-sign floats are subtracted then // the absolute value of the result is equal to one plus the number of // representable floats between them. - BT Diff = V1Bits >= V2Bits ? V1Bits - V2Bits : V2Bits - V1Bits; - return Diff >= kMaxULPDiff ? kMaxULPDiff : Diff; + BT diff = v1_bits >= v2_bits ? v1_bits - v2_bits : v2_bits - v1_bits; + return diff >= kMaxULPDiff ? kMaxULPDiff : diff; } } // end namespace __nsan diff --git a/compiler-rt/lib/nsan/nsan_interceptors.cpp b/compiler-rt/lib/nsan/nsan_interceptors.cpp index 77ae3e8ac352a..fc5cbe39f5413 100644 --- a/compiler-rt/lib/nsan/nsan_interceptors.cpp +++ b/compiler-rt/lib/nsan/nsan_interceptors.cpp @@ -31,11 +31,11 @@ using __nsan::nsan_initialized; static constexpr uptr kEarlyAllocBufSize = 16384; static uptr AllocatedBytes; -static char EarlyAllocBuf[kEarlyAllocBufSize]; +static char early_alloc_buf[kEarlyAllocBufSize]; -static bool isInEarlyAllocBuf(const void *Ptr) { - return ((uptr)Ptr >= (uptr)EarlyAllocBuf && - ((uptr)Ptr - (uptr)EarlyAllocBuf) < sizeof(EarlyAllocBuf)); +static bool isInEarlyAllocBuf(const void *ptr) { + return ((uptr)ptr >= (uptr)early_alloc_buf && + ((uptr)ptr - (uptr)early_alloc_buf) < sizeof(early_alloc_buf)); } static u8 *toU8Ptr(wchar_t *ptr) { return reinterpret_cast(ptr); } @@ -49,25 +49,25 @@ template T min(T a, T b) { return a < b ? a : b; } // Handle allocation requests early (before all interceptors are setup). dlsym, // for example, calls calloc. static void *HandleEarlyAlloc(uptr size) { - void *Mem = (void *)&EarlyAllocBuf[AllocatedBytes]; + void *Mem = (void *)&early_alloc_buf[AllocatedBytes]; AllocatedBytes += size; CHECK_LT(AllocatedBytes, kEarlyAllocBufSize); return Mem; } -INTERCEPTOR(void *, memset, void *dst, int V, uptr size) { +INTERCEPTOR(void *, memset, void *dst, int v, uptr size) { // NOTE: This guard is needed because nsan's initialization code might call // memset. if (!nsan_initialized && REAL(memset) == nullptr) - return internal_memset(dst, V, size); + return internal_memset(dst, v, size); - void *res = REAL(memset)(dst, V, size); + void *res = REAL(memset)(dst, v, size); __nsan_set_value_unknown(static_cast(dst), size); return res; } -INTERCEPTOR(wchar_t *, wmemset, wchar_t *dst, wchar_t V, uptr size) { - wchar_t *res = REAL(wmemset)(dst, V, size); +INTERCEPTOR(wchar_t *, wmemset, wchar_t *dst, wchar_t v, uptr size) { + wchar_t *res = REAL(wmemset)(dst, v, size); __nsan_set_value_unknown(toU8Ptr(dst), sizeof(wchar_t) * size); return res; } @@ -123,8 +123,8 @@ INTERCEPTOR(void *, malloc, uptr size) { return res; } -INTERCEPTOR(void *, realloc, void *Ptr, uptr size) { - void *res = REAL(realloc)(Ptr, size); +INTERCEPTOR(void *, realloc, void *ptr, uptr size) { + void *res = REAL(realloc)(ptr, size); // FIXME: We might want to copy the types from the original allocation // (although that would require that we know its size). if (res) diff --git a/compiler-rt/lib/nsan/tests/NSanUnitTest.cpp b/compiler-rt/lib/nsan/tests/NSanUnitTest.cpp index 3c6b505aaf7a1..d121292c36682 100644 --- a/compiler-rt/lib/nsan/tests/NSanUnitTest.cpp +++ b/compiler-rt/lib/nsan/tests/NSanUnitTest.cpp @@ -14,41 +14,41 @@ namespace __nsan { template void TestFT() { // Basic local tests anchored at 0.0. - ASSERT_EQ(getULPDiff(0.0, 0.0), 0); - ASSERT_EQ(getULPDiff(-0.0, 0.0), 0); - ASSERT_EQ(getULPDiff(next(-0.0, -1.0), 0.0), 1); - ASSERT_EQ(getULPDiff(next(0.0, 1.0), -0.0), 1); - ASSERT_EQ(getULPDiff(next(-0.0, -1.0), next(0.0, 1.0)), 2); + ASSERT_EQ(GetULPDiff(0.0, 0.0), 0); + ASSERT_EQ(GetULPDiff(-0.0, 0.0), 0); + ASSERT_EQ(GetULPDiff(next(-0.0, -1.0), 0.0), 1); + ASSERT_EQ(GetULPDiff(next(0.0, 1.0), -0.0), 1); + ASSERT_EQ(GetULPDiff(next(-0.0, -1.0), next(0.0, 1.0)), 2); // Basic local tests anchored at 2.0. - ASSERT_EQ(getULPDiff(next(2.0, 1.0), 2.0), 1); - ASSERT_EQ(getULPDiff(next(2.0, 3.0), 2.0), 1); - ASSERT_EQ(getULPDiff(next(2.0, 1.0), next(2.0, 3.0)), 2); + ASSERT_EQ(GetULPDiff(next(2.0, 1.0), 2.0), 1); + ASSERT_EQ(GetULPDiff(next(2.0, 3.0), 2.0), 1); + ASSERT_EQ(GetULPDiff(next(2.0, 1.0), next(2.0, 3.0)), 2); - ASSERT_NE(getULPDiff(-0.01, 0.01), kMaxULPDiff); + ASSERT_NE(GetULPDiff(-0.01, 0.01), kMaxULPDiff); // Basic local tests anchored at a random number. const FT X = 4863.5123; const FT To = 2 * X; FT Y = X; - ASSERT_EQ(getULPDiff(X, Y), 0); - ASSERT_EQ(getULPDiff(-X, -Y), 0); + ASSERT_EQ(GetULPDiff(X, Y), 0); + ASSERT_EQ(GetULPDiff(-X, -Y), 0); Y = next(Y, To); - ASSERT_EQ(getULPDiff(X, Y), 1); - ASSERT_EQ(getULPDiff(-X, -Y), 1); + ASSERT_EQ(GetULPDiff(X, Y), 1); + ASSERT_EQ(GetULPDiff(-X, -Y), 1); Y = next(Y, To); - ASSERT_EQ(getULPDiff(X, Y), 2); - ASSERT_EQ(getULPDiff(-X, -Y), 2); + ASSERT_EQ(GetULPDiff(X, Y), 2); + ASSERT_EQ(GetULPDiff(-X, -Y), 2); Y = next(Y, To); - ASSERT_EQ(getULPDiff(X, Y), 3); - ASSERT_EQ(getULPDiff(-X, -Y), 3); + ASSERT_EQ(GetULPDiff(X, Y), 3); + ASSERT_EQ(GetULPDiff(-X, -Y), 3); // Values with larger differences. static constexpr const __sanitizer::u64 MantissaSize = __sanitizer::u64{1} << FTInfo::kMantissaBits; - ASSERT_EQ(getULPDiff(1.0, next(2.0, 1.0)), MantissaSize - 1); - ASSERT_EQ(getULPDiff(1.0, 2.0), MantissaSize); - ASSERT_EQ(getULPDiff(1.0, next(2.0, 3.0)), MantissaSize + 1); - ASSERT_EQ(getULPDiff(1.0, 3.0), (3 * MantissaSize) / 2); + ASSERT_EQ(GetULPDiff(1.0, next(2.0, 1.0)), MantissaSize - 1); + ASSERT_EQ(GetULPDiff(1.0, 2.0), MantissaSize); + ASSERT_EQ(GetULPDiff(1.0, next(2.0, 3.0)), MantissaSize + 1); + ASSERT_EQ(GetULPDiff(1.0, 3.0), (3 * MantissaSize) / 2); } TEST(NSanTest, Float) { TestFT(); } @@ -59,9 +59,9 @@ TEST(NSanTest, Double) { TEST(NSanTest, Float128) { // Very basic tests. FIXME: improve when we have nextafter<__float128>. - ASSERT_EQ(getULPDiff<__float128>(0.0, 0.0), 0); - ASSERT_EQ(getULPDiff<__float128>(-0.0, 0.0), 0); - ASSERT_NE(getULPDiff<__float128>(-0.01, 0.01), kMaxULPDiff); + ASSERT_EQ(GetULPDiff<__float128>(0.0, 0.0), 0); + ASSERT_EQ(GetULPDiff<__float128>(-0.0, 0.0), 0); + ASSERT_NE(GetULPDiff<__float128>(-0.01, 0.01), kMaxULPDiff); } } // end namespace __nsan From adeb6b9616f5ca9a72b965aea2c9b2db00459ff2 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Thu, 20 Jun 2024 00:42:45 -0700 Subject: [PATCH 4/5] more Created using spr 1.3.5-bogner --- compiler-rt/lib/nsan/nsan.cpp | 66 +++++++++++----------- compiler-rt/lib/nsan/nsan.h | 12 ++-- compiler-rt/lib/nsan/nsan_interceptors.cpp | 26 ++++----- 3 files changed, 49 insertions(+), 55 deletions(-) diff --git a/compiler-rt/lib/nsan/nsan.cpp b/compiler-rt/lib/nsan/nsan.cpp index 0c72f798a2dca..f7b2ce2048290 100644 --- a/compiler-rt/lib/nsan/nsan.cpp +++ b/compiler-rt/lib/nsan/nsan.cpp @@ -51,16 +51,16 @@ using namespace __sanitizer; using namespace __nsan; -static constexpr const int kMaxVectorWidth = 8; +constexpr int kMaxVectorWidth = 8; // When copying application memory, we also copy its shadow and shadow type. // FIXME: We could provide fixed-size versions that would nicely // vectorize for known sizes. extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_copy_values(const u8 *daddr, const u8 *saddr, uptr size) { - internal_memmove((void *)getShadowTypeAddrFor(daddr), - getShadowTypeAddrFor(saddr), size); - internal_memmove((void *)getShadowAddrFor(daddr), getShadowAddrFor(saddr), + internal_memmove((void *)GetShadowTypeAddrFor(daddr), + GetShadowTypeAddrFor(saddr), size); + internal_memmove((void *)GetShadowAddrFor(daddr), GetShadowAddrFor(saddr), size * kShadowScale); } @@ -68,7 +68,7 @@ __nsan_copy_values(const u8 *daddr, const u8 *saddr, uptr size) { // vectorize for known sizes. extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_set_value_unknown(const u8 *addr, uptr size) { - internal_memset((void *)getShadowTypeAddrFor(addr), 0, size); + internal_memset((void *)GetShadowTypeAddrFor(addr), 0, size); } @@ -83,25 +83,27 @@ const char FTInfo::kTypePattern[sizeof(long double)]; // Helper for __nsan_dump_shadow_mem: Reads the value at address `ptr`, // identified by its type id. -template __float128 readShadowInternal(const u8 *ptr) { +template +static __float128 ReadShadowInternal(const u8 *ptr) { ShadowFT Shadow; __builtin_memcpy(&Shadow, ptr, sizeof(Shadow)); return Shadow; } -__float128 readShadow(const u8 *ptr, const char ShadowTypeId) { +static __float128 ReadShadow(const u8 *ptr, const char ShadowTypeId) { switch (ShadowTypeId) { case 'd': - return readShadowInternal(ptr); + return ReadShadowInternal(ptr); case 'l': - return readShadowInternal(ptr); + return ReadShadowInternal(ptr); case 'q': - return readShadowInternal<__float128>(ptr); + return ReadShadowInternal<__float128>(ptr); default: return 0.0; } } +namespace { class Decorator : public __sanitizer::SanitizerCommonDecorator { public: Decorator() : SanitizerCommonDecorator() {} @@ -110,8 +112,6 @@ class Decorator : public __sanitizer::SanitizerCommonDecorator { const char *End() { return Default(); } }; -namespace { - // Workaround for the fact that Printf() does not support floats. struct PrintBuffer { char Buffer[64]; @@ -202,12 +202,12 @@ static void NsanAtexit() { // We have to have 3 versions because we need to know which type we are storing // since we are setting the type shadow memory. template static u8 *getShadowPtrForStore(u8 *store_addr, uptr n) { - unsigned char *shadow_type = getShadowTypeAddrFor(store_addr); + unsigned char *shadow_type = GetShadowTypeAddrFor(store_addr); for (uptr i = 0; i < n; ++i) { __builtin_memcpy(shadow_type + i * sizeof(FT), FTInfo::kTypePattern, sizeof(FTInfo::kTypePattern)); } - return getShadowAddrFor(store_addr); + return GetShadowAddrFor(store_addr); } extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8 * @@ -244,7 +244,7 @@ template static bool IsUnknownShadowType(const u8 *shadow_type) { // They return nullptr if the type of the value is unknown or incomplete. template static const u8 *getShadowPtrForLoad(const u8 *load_addr, uptr n) { - const u8 *const shadow_type = getShadowTypeAddrFor(load_addr); + const u8 *const shadow_type = GetShadowTypeAddrFor(load_addr); for (uptr i = 0; i < n; ++i) { if (!IsValidShadowType(shadow_type + i * sizeof(FT))) { // If loadtracking stats are enabled, log loads with invalid types @@ -266,7 +266,7 @@ static const u8 *getShadowPtrForLoad(const u8 *load_addr, uptr n) { return nullptr; } } - return getShadowAddrFor(load_addr); + return GetShadowAddrFor(load_addr); } extern "C" SANITIZER_INTERFACE_ATTRIBUTE const u8 * @@ -288,14 +288,14 @@ __nsan_get_shadow_ptr_for_longdouble_load(const u8 *load_addr, uptr n) { // opaque. extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8 * __nsan_internal_get_raw_shadow_ptr(const u8 *addr) { - return getShadowAddrFor(const_cast(addr)); + return GetShadowAddrFor(const_cast(addr)); } // Returns the raw shadow type pointer. The returned pointer should be // considered opaque. extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8 * __nsan_internal_get_raw_shadow_type_ptr(const u8 *addr) { - return reinterpret_cast(getShadowTypeAddrFor(const_cast(addr))); + return reinterpret_cast(GetShadowTypeAddrFor(const_cast(addr))); } static ValueType getValueType(u8 c) { return static_cast(c & 0x3); } @@ -322,8 +322,8 @@ static bool checkValueConsistency(const u8 *shadow_type) { extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_dump_shadow_mem(const u8 *addr, size_t size_bytes, size_t bytes_per_line, size_t shadow_value_type_ids) { - const u8 *const shadow_type = getShadowTypeAddrFor(addr); - const u8 *const shadow = getShadowAddrFor(addr); + const u8 *const shadow_type = GetShadowTypeAddrFor(addr); + const u8 *const shadow = GetShadowAddrFor(addr); constexpr int kMaxNumDecodedValues = 16; __float128 decoded_values[kMaxNumDecodedValues]; @@ -356,7 +356,7 @@ __nsan_dump_shadow_mem(const u8 *addr, size_t size_bytes, size_t bytes_per_line, printf("f%x ", pos); if (LastPos == sizeof(float) - 1) { decoded_values[num_decoded_values] = - readShadow(shadow + kShadowScale * (Offset + 1 - sizeof(float)), + ReadShadow(shadow + kShadowScale * (Offset + 1 - sizeof(float)), static_cast(shadow_value_type_ids & 0xff)); ++num_decoded_values; } @@ -364,7 +364,7 @@ __nsan_dump_shadow_mem(const u8 *addr, size_t size_bytes, size_t bytes_per_line, case kDoubleValueType: printf("d%x ", pos); if (LastPos == sizeof(double) - 1) { - decoded_values[num_decoded_values] = readShadow( + decoded_values[num_decoded_values] = ReadShadow( shadow + kShadowScale * (Offset + 1 - sizeof(double)), static_cast((shadow_value_type_ids >> 8) & 0xff)); ++num_decoded_values; @@ -373,7 +373,7 @@ __nsan_dump_shadow_mem(const u8 *addr, size_t size_bytes, size_t bytes_per_line, case kFp80ValueType: printf("l%x ", pos); if (LastPos == sizeof(long double) - 1) { - decoded_values[num_decoded_values] = readShadow( + decoded_values[num_decoded_values] = ReadShadow( shadow + kShadowScale * (Offset + 1 - sizeof(long double)), static_cast((shadow_value_type_ids >> 16) & 0xff)); ++num_decoded_values; @@ -470,17 +470,17 @@ int32_t checkFT(const FT value, ShadowFT Shadow, CheckTypeT CheckType, static_cast(100.0 * abs_err / largest), log2l(static_cast(abs_err / largest / Eps))); } - char UlpErrBuf[128] = ""; - const double ShadowUlpDiff = GetULPDiff(check_value, check_shadow); - if (ShadowUlpDiff != kMaxULPDiff) { + char ulp_err_buf[128] = ""; + const double shadow_ulp_diff = GetULPDiff(check_value, check_shadow); + if (shadow_ulp_diff != kMaxULPDiff) { // This is the ULP diff in the internal domain. The user actually cares // about that in the original domain. - const double UlpDiff = - ShadowUlpDiff / (u64{1} << (FTInfo::kMantissaBits - - FTInfo::kMantissaBits)); - snprintf(UlpErrBuf, sizeof(UlpErrBuf) - 1, - "(%.0f ULPs == %.1f digits == %.1f bits)", UlpDiff, - log10(UlpDiff), log2(UlpDiff)); + const double ulp_diff = + shadow_ulp_diff / (u64{1} << (FTInfo::kMantissaBits - + FTInfo::kMantissaBits)); + snprintf(ulp_err_buf, sizeof(ulp_err_buf) - 1, + "(%.0f ULPs == %.1f digits == %.1f bits)", ulp_diff, + log10(ulp_diff), log2(ulp_diff)); } Printf("WARNING: NumericalStabilitySanitizer: inconsistent shadow results"); switch (CheckType) { @@ -525,7 +525,7 @@ int32_t checkFT(const FT value, ShadowFT Shadow, CheckTypeT CheckType, ShadowPrinter::dec(Shadow).Buffer, ShadowPrinter::hex(Shadow).Buffer, FTInfo::kCppTypeName, ValuePrinter::dec(Shadow).Buffer, ValuePrinter::hex(Shadow).Buffer, RelErrBuf, - ValuePrinter::hex(abs_err).Buffer, UlpErrBuf); + ValuePrinter::hex(abs_err).Buffer, ulp_err_buf); stack.Print(); } diff --git a/compiler-rt/lib/nsan/nsan.h b/compiler-rt/lib/nsan/nsan.h index 1b57e916700f6..896e5379dfc37 100644 --- a/compiler-rt/lib/nsan/nsan.h +++ b/compiler-rt/lib/nsan/nsan.h @@ -58,25 +58,25 @@ void InitializeInterceptors(); // See notes in nsan_platform. // printf-free (see comment in nsan_interceptors.cc). -inline u8 *getShadowAddrFor(u8 *Ptr) { +inline u8 *GetShadowAddrFor(u8 *Ptr) { uptr AppOffset = ((uptr)Ptr) & ShadowMask(); return (u8 *)(AppOffset * kShadowScale + ShadowAddr()); } // printf-free (see comment in nsan_interceptors.cc). -inline const u8 *getShadowAddrFor(const u8 *Ptr) { - return getShadowAddrFor(const_cast(Ptr)); +inline const u8 *GetShadowAddrFor(const u8 *Ptr) { + return GetShadowAddrFor(const_cast(Ptr)); } // printf-free (see comment in nsan_interceptors.cc). -inline u8 *getShadowTypeAddrFor(u8 *Ptr) { +inline u8 *GetShadowTypeAddrFor(u8 *Ptr) { uptr AppOffset = ((uptr)Ptr) & ShadowMask(); return (u8 *)(AppOffset + TypesAddr()); } // printf-free (see comment in nsan_interceptors.cc). -inline const u8 *getShadowTypeAddrFor(const u8 *Ptr) { - return getShadowTypeAddrFor(const_cast(Ptr)); +inline const u8 *GetShadowTypeAddrFor(const u8 *Ptr) { + return GetShadowTypeAddrFor(const_cast(Ptr)); } // Information about value types and their shadow counterparts. diff --git a/compiler-rt/lib/nsan/nsan_interceptors.cpp b/compiler-rt/lib/nsan/nsan_interceptors.cpp index fc5cbe39f5413..61ea85e83dbb2 100644 --- a/compiler-rt/lib/nsan/nsan_interceptors.cpp +++ b/compiler-rt/lib/nsan/nsan_interceptors.cpp @@ -29,8 +29,8 @@ using namespace __sanitizer; using __nsan::nsan_init_is_running; using __nsan::nsan_initialized; -static constexpr uptr kEarlyAllocBufSize = 16384; -static uptr AllocatedBytes; +constexpr uptr kEarlyAllocBufSize = 16384; +static uptr allocated_bytes; static char early_alloc_buf[kEarlyAllocBufSize]; static bool isInEarlyAllocBuf(const void *ptr) { @@ -38,20 +38,14 @@ static bool isInEarlyAllocBuf(const void *ptr) { ((uptr)ptr - (uptr)early_alloc_buf) < sizeof(early_alloc_buf)); } -static u8 *toU8Ptr(wchar_t *ptr) { return reinterpret_cast(ptr); } - -static const u8 *toU8Ptr(const wchar_t *ptr) { - return reinterpret_cast(ptr); -} - template T min(T a, T b) { return a < b ? a : b; } // Handle allocation requests early (before all interceptors are setup). dlsym, // for example, calls calloc. static void *HandleEarlyAlloc(uptr size) { - void *Mem = (void *)&early_alloc_buf[AllocatedBytes]; - AllocatedBytes += size; - CHECK_LT(AllocatedBytes, kEarlyAllocBufSize); + void *Mem = (void *)&early_alloc_buf[allocated_bytes]; + allocated_bytes += size; + CHECK_LT(allocated_bytes, kEarlyAllocBufSize); return Mem; } @@ -68,7 +62,7 @@ INTERCEPTOR(void *, memset, void *dst, int v, uptr size) { INTERCEPTOR(wchar_t *, wmemset, wchar_t *dst, wchar_t v, uptr size) { wchar_t *res = REAL(wmemset)(dst, v, size); - __nsan_set_value_unknown(toU8Ptr(dst), sizeof(wchar_t) * size); + __nsan_set_value_unknown((u8 *)dst, sizeof(wchar_t) * size); return res; } @@ -86,7 +80,7 @@ INTERCEPTOR(void *, memmove, void *dst, const void *src, uptr size) { INTERCEPTOR(wchar_t *, wmemmove, wchar_t *dst, const wchar_t *src, uptr size) { wchar_t *res = REAL(wmemmove)(dst, src, size); - __nsan_copy_values(toU8Ptr(dst), toU8Ptr(src), sizeof(wchar_t) * size); + __nsan_copy_values((u8 *)dst, (const u8 *)src, sizeof(wchar_t) * size); return res; } @@ -107,7 +101,7 @@ INTERCEPTOR(void *, memcpy, void *dst, const void *src, uptr size) { INTERCEPTOR(wchar_t *, wmemcpy, wchar_t *dst, const wchar_t *src, uptr size) { wchar_t *res = REAL(wmemcpy)(dst, src, size); - __nsan_copy_values(toU8Ptr(dst), toU8Ptr(src), sizeof(wchar_t) * size); + __nsan_copy_values((u8 *)dst, (const u8 *)src, sizeof(wchar_t) * size); return res; } @@ -227,8 +221,8 @@ static void nsanCopyZeroTerminated(char *dst, const char *src, uptr n) { } static void nsanWCopyZeroTerminated(wchar_t *dst, const wchar_t *src, uptr n) { - __nsan_copy_values(toU8Ptr(dst), toU8Ptr(src), sizeof(wchar_t) * n); - __nsan_set_value_unknown(toU8Ptr(dst + n), sizeof(wchar_t)); + __nsan_copy_values((u8 *)dst, (const u8 *)(src), sizeof(wchar_t) * n); + __nsan_set_value_unknown((u8 *)(dst + n), sizeof(wchar_t)); } INTERCEPTOR(char *, strdup, const char *S) { From 2dea1f78be93d5a03b7b70f6564503bd16008c9b Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Thu, 20 Jun 2024 00:45:46 -0700 Subject: [PATCH 5/5] rebase Created using spr 1.3.5-bogner --- compiler-rt/lib/nsan/nsan_interceptors.cpp | 40 +++++++++++----------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/compiler-rt/lib/nsan/nsan_interceptors.cpp b/compiler-rt/lib/nsan/nsan_interceptors.cpp index 61ea85e83dbb2..68127f169ee46 100644 --- a/compiler-rt/lib/nsan/nsan_interceptors.cpp +++ b/compiler-rt/lib/nsan/nsan_interceptors.cpp @@ -154,15 +154,15 @@ INTERCEPTOR(void *, valloc, uptr size) { return res; } -INTERCEPTOR(void *, memalign, uptr Alignment, uptr size) { - void *const res = REAL(memalign)(Alignment, size); +INTERCEPTOR(void *, memalign, uptr align, uptr size) { + void *const res = REAL(memalign)(align, size); if (res) __nsan_set_value_unknown(static_cast(res), size); return res; } -INTERCEPTOR(void *, __libc_memalign, uptr Alignment, uptr size) { - void *const res = REAL(__libc_memalign)(Alignment, size); +INTERCEPTOR(void *, __libc_memalign, uptr align, uptr size) { + void *const res = REAL(__libc_memalign)(align, size); if (res) __nsan_set_value_unknown(static_cast(res), size); return res; @@ -175,30 +175,30 @@ INTERCEPTOR(void *, pvalloc, uptr size) { return res; } -INTERCEPTOR(void *, aligned_alloc, uptr Alignment, uptr size) { - void *const res = REAL(aligned_alloc)(Alignment, size); +INTERCEPTOR(void *, aligned_alloc, uptr align, uptr size) { + void *const res = REAL(aligned_alloc)(align, size); if (res) __nsan_set_value_unknown(static_cast(res), size); return res; } -INTERCEPTOR(int, posix_memalign, void **Memptr, uptr Alignment, uptr size) { - int res = REAL(posix_memalign)(Memptr, Alignment, size); - if (res == 0 && *Memptr) - __nsan_set_value_unknown(static_cast(*Memptr), size); +INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr size) { + int res = REAL(posix_memalign)(memptr, align, size); + if (res == 0 && *memptr) + __nsan_set_value_unknown(static_cast(*memptr), size); return res; } -INTERCEPTOR(char *, strfry, char *S) { - const auto Len = internal_strlen(S); - char *res = REAL(strfry)(S); +INTERCEPTOR(char *, strfry, char *s) { + const auto Len = internal_strlen(s); + char *res = REAL(strfry)(s); if (res) - __nsan_set_value_unknown(reinterpret_cast(S), Len); + __nsan_set_value_unknown(reinterpret_cast(s), Len); return res; } -INTERCEPTOR(char *, strsep, char **Stringp, const char *Delim) { - char *OrigStringp = REAL(strsep)(Stringp, Delim); +INTERCEPTOR(char *, strsep, char **Stringp, const char *delim) { + char *OrigStringp = REAL(strsep)(Stringp, delim); if (Stringp != nullptr) { // The previous character has been overwritten with a '\0' char. __nsan_set_value_unknown(reinterpret_cast(*Stringp) - 1, 1); @@ -206,12 +206,12 @@ INTERCEPTOR(char *, strsep, char **Stringp, const char *Delim) { return OrigStringp; } -INTERCEPTOR(char *, strtok, char *Str, const char *Delim) { +INTERCEPTOR(char *, strtok, char *str, const char *delim) { // This is overly conservative, but the probability that modern code is using // strtok on double data is essentially zero anyway. - if (Str) - __nsan_set_value_unknown(reinterpret_cast(Str), internal_strlen(Str)); - return REAL(strtok)(Str, Delim); + if (str) + __nsan_set_value_unknown(reinterpret_cast(str), internal_strlen(str)); + return REAL(strtok)(str, delim); } static void nsanCopyZeroTerminated(char *dst, const char *src, uptr n) {