From a9d790f60c3400cb1cee9af92c0487d0e5aada40 Mon Sep 17 00:00:00 2001 From: "Wu, Yingcong" Date: Tue, 21 May 2024 05:13:04 +0200 Subject: [PATCH 1/3] add improvement --- .../layers/sanitizer/asan_interceptor.cpp | 46 ++++-------- .../layers/sanitizer/asan_interceptor.hpp | 5 -- .../loader/layers/sanitizer/asan_options.hpp | 71 +++++++++++++++++++ .../loader/layers/sanitizer/asan_report.cpp | 45 +++++++----- 4 files changed, 111 insertions(+), 56 deletions(-) create mode 100644 source/loader/layers/sanitizer/asan_options.hpp diff --git a/source/loader/layers/sanitizer/asan_interceptor.cpp b/source/loader/layers/sanitizer/asan_interceptor.cpp index c55d752410..8640883001 100644 --- a/source/loader/layers/sanitizer/asan_interceptor.cpp +++ b/source/loader/layers/sanitizer/asan_interceptor.cpp @@ -12,6 +12,7 @@ */ #include "asan_interceptor.hpp" +#include "asan_options.hpp" #include "asan_quarantine.hpp" #include "asan_report.hpp" #include "asan_shadow_setup.hpp" @@ -144,36 +145,9 @@ ur_result_t enqueueMemSetShadow(ur_context_handle_t Context, } // namespace SanitizerInterceptor::SanitizerInterceptor() { - auto Options = getenv_to_map("UR_LAYER_ASAN_OPTIONS"); - if (!Options.has_value()) { - return; - } - - auto KV = Options->find("debug"); - if (KV != Options->end()) { - auto Value = KV->second.front(); - cl_Debug = Value == "1" || Value == "true" ? 1 : 0; - } - - KV = Options->find("quarantine_size_mb"); - if (KV != Options->end()) { - auto Value = KV->second.front(); - try { - cl_MaxQuarantineSizeMB = std::stoul(Value); - } catch (...) { - die("[ERROR]: \"cl_MaxQuarantineSizeMB\" should be an " - "integer"); - } - } - if (cl_MaxQuarantineSizeMB) { - m_Quarantine = - std::make_unique(cl_MaxQuarantineSizeMB * 1024 * 1024); - } - - KV = Options->find("detect_locals"); - if (KV != Options->end()) { - auto Value = KV->second.front(); - cl_DetectLocals = Value == "1" || Value == "true" ? true : false; + if (Options().MaxQuarantineSizeMB) { + m_Quarantine = std::make_unique( + Options().MaxQuarantineSizeMB * 1024 * 1024); } } @@ -651,7 +625,8 @@ ur_result_t SanitizerInterceptor::prepareLaunch( }; // Write debug - EnqueueWriteGlobal(kSPIR_AsanDebug, &cl_Debug, sizeof(cl_Debug)); + EnqueueWriteGlobal(kSPIR_AsanDebug, &(Options().Debug), + sizeof(Options().Debug)); // Write shadow memory offset for global memory EnqueueWriteGlobal(kSPIR_AsanShadowMemoryGlobalStart, @@ -711,7 +686,7 @@ ur_result_t SanitizerInterceptor::prepareLaunch( }; // Write shadow memory offset for local memory - if (cl_DetectLocals) { + if (Options().DetectLocals) { // CPU needn't this if (DeviceInfo->Type == DeviceType::GPU_PVC) { size_t LocalMemorySize = GetLocalMemorySize(DeviceInfo->Handle); @@ -746,7 +721,12 @@ SanitizerInterceptor::findAllocInfoByAddress(uptr Address) { if (It == m_AllocationMap.begin()) { return std::optional{}; } - return --It; + --It; + auto &AI = It->second; + // Make sure we got the right AllocInfo + assert(Address >= AI->AllocBegin && + Address < AI->AllocBegin + AI->AllocSize); + return It; } LaunchInfo::~LaunchInfo() { diff --git a/source/loader/layers/sanitizer/asan_interceptor.hpp b/source/loader/layers/sanitizer/asan_interceptor.hpp index a691bee7b7..6393f91b02 100644 --- a/source/loader/layers/sanitizer/asan_interceptor.hpp +++ b/source/loader/layers/sanitizer/asan_interceptor.hpp @@ -219,11 +219,6 @@ class SanitizerInterceptor { AllocationMap m_AllocationMap; ur_shared_mutex m_AllocationMapMutex; - // We use "uint64_t" here because EnqueueWriteGlobal will fail when it's "uint32_t" - uint64_t cl_Debug = 0; - uint32_t cl_MaxQuarantineSizeMB = 0; - bool cl_DetectLocals = true; - std::unique_ptr m_Quarantine; }; diff --git a/source/loader/layers/sanitizer/asan_options.hpp b/source/loader/layers/sanitizer/asan_options.hpp new file mode 100644 index 0000000000..89791569d3 --- /dev/null +++ b/source/loader/layers/sanitizer/asan_options.hpp @@ -0,0 +1,71 @@ +/* + * + * Copyright (C) 2024 Intel Corporation + * + * Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM Exceptions. + * See LICENSE.TXT + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + * @file asan_options.hpp + * + */ + +#pragma once + +#include "common/ur_util.hpp" +#include "ur/ur.hpp" + +#include + +namespace ur_sanitizer_layer { + +struct AsanOptions { + public: + AsanOptions(AsanOptions &other) = delete; + void operator=(const AsanOptions &) = delete; + + static AsanOptions &getInstance() { + static AsanOptions instance; + return instance; + } + + // We use "uint64_t" here because EnqueueWriteGlobal will fail when it's "uint32_t" + uint64_t Debug = 0; + uint32_t MaxQuarantineSizeMB = 0; + bool DetectLocals = true; + + private: + AsanOptions() { + auto OptionsEnvMap = getenv_to_map("UR_LAYER_ASAN_OPTIONS"); + if (!OptionsEnvMap.has_value()) { + return; + } + + auto KV = OptionsEnvMap->find("debug"); + if (KV != OptionsEnvMap->end()) { + auto Value = KV->second.front(); + Debug = Value == "1" || Value == "true" ? 1 : 0; + } + + KV = OptionsEnvMap->find("quarantine_size_mb"); + if (KV != OptionsEnvMap->end()) { + auto Value = KV->second.front(); + try { + MaxQuarantineSizeMB = std::stoul(Value); + } catch (...) { + die("[ERROR]: \"quarantine_size_mb\" should be " + "an positive integer"); + } + } + + KV = OptionsEnvMap->find("detect_locals"); + if (KV != OptionsEnvMap->end()) { + auto Value = KV->second.front(); + DetectLocals = Value == "1" || Value == "true" ? true : false; + } + } +}; + +inline AsanOptions &Options() { return AsanOptions::getInstance(); } + +} // namespace ur_sanitizer_layer diff --git a/source/loader/layers/sanitizer/asan_report.cpp b/source/loader/layers/sanitizer/asan_report.cpp index 56cbbb4b21..01509b52ff 100644 --- a/source/loader/layers/sanitizer/asan_report.cpp +++ b/source/loader/layers/sanitizer/asan_report.cpp @@ -11,6 +11,7 @@ */ #include "asan_report.hpp" +#include "asan_options.hpp" #include "asan_allocator.hpp" #include "asan_interceptor.hpp" @@ -131,27 +132,35 @@ void ReportUseAfterFree(const DeviceSanitizerReport &Report, context.logger.always(" #0 {} {}:{}", Func, File, Report.Line); context.logger.always(""); - auto AllocInfoItOp = - context.interceptor->findAllocInfoByAddress(Report.Address); - if (!AllocInfoItOp) { - context.logger.always("Failed to find which chunck {} is allocated", - (void *)Report.Address); - } else { - auto &AllocInfo = (*AllocInfoItOp)->second; - if (AllocInfo->Context != Context) { + if (Options().MaxQuarantineSizeMB > 0) { + auto AllocInfoItOp = + context.interceptor->findAllocInfoByAddress(Report.Address); + + if (!AllocInfoItOp) { context.logger.always("Failed to find which chunck {} is allocated", (void *)Report.Address); + } else { + auto &AllocInfo = (*AllocInfoItOp)->second; + if (AllocInfo->Context != Context) { + context.logger.always( + "Failed to find which chunck {} is allocated", + (void *)Report.Address); + } + assert(AllocInfo->IsReleased); + + context.logger.always( + "{} is located inside of {} region [{}, {})", + (void *)Report.Address, ToString(AllocInfo->Type), + (void *)AllocInfo->UserBegin, (void *)AllocInfo->UserEnd); + context.logger.always("allocated here:"); + AllocInfo->AllocStack.print(); + context.logger.always("released here:"); + AllocInfo->ReleaseStack.print(); } - assert(AllocInfo->IsReleased); - - context.logger.always("{} is located inside of {} region [{}, {})", - (void *)Report.Address, ToString(AllocInfo->Type), - (void *)AllocInfo->UserBegin, - (void *)AllocInfo->UserEnd); - context.logger.always("allocated here:"); - AllocInfo->AllocStack.print(); - context.logger.always("released here:"); - AllocInfo->ReleaseStack.print(); + } else { + context.logger.always( + "Please enable quarantine to get more information like memory " + "chunck's kind and where the chunck was allocated and released."); } exit(1); From 9c877d9a28d7bd63fadbd6e035b57c1ead261d39 Mon Sep 17 00:00:00 2001 From: "Wu, Yingcong" Date: Tue, 21 May 2024 06:20:22 +0200 Subject: [PATCH 2/3] minor fix --- source/loader/layers/sanitizer/asan_interceptor.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/source/loader/layers/sanitizer/asan_interceptor.cpp b/source/loader/layers/sanitizer/asan_interceptor.cpp index 493195c7ff..e055c97ad9 100644 --- a/source/loader/layers/sanitizer/asan_interceptor.cpp +++ b/source/loader/layers/sanitizer/asan_interceptor.cpp @@ -745,10 +745,9 @@ SanitizerInterceptor::findAllocInfoByAddress(uptr Address) { return std::optional{}; } --It; - auto &AI = It->second; // Make sure we got the right AllocInfo - assert(Address >= AI->AllocBegin && - Address < AI->AllocBegin + AI->AllocSize); + assert(Address >= It->second->AllocBegin && + Address < It->second->AllocBegin + It->second->AllocSize); return It; } From 63b96a1b37a45c5e50552b89ffb1c01745ad619e Mon Sep 17 00:00:00 2001 From: "Wu, Yingcong" Date: Mon, 27 May 2024 04:06:17 +0200 Subject: [PATCH 3/3] update impl --- .../layers/sanitizer/asan_interceptor.cpp | 10 ++- .../loader/layers/sanitizer/asan_options.hpp | 78 ++++++++++++++----- 2 files changed, 65 insertions(+), 23 deletions(-) diff --git a/source/loader/layers/sanitizer/asan_interceptor.cpp b/source/loader/layers/sanitizer/asan_interceptor.cpp index e055c97ad9..e9be892638 100644 --- a/source/loader/layers/sanitizer/asan_interceptor.cpp +++ b/source/loader/layers/sanitizer/asan_interceptor.cpp @@ -145,7 +145,7 @@ ur_result_t enqueueMemSetShadow(ur_context_handle_t Context, SanitizerInterceptor::SanitizerInterceptor() { if (Options().MaxQuarantineSizeMB) { m_Quarantine = std::make_unique( - Options().MaxQuarantineSizeMB * 1024 * 1024); + static_cast(Options().MaxQuarantineSizeMB) * 1024 * 1024); } } @@ -646,8 +646,9 @@ ur_result_t SanitizerInterceptor::prepareLaunch( }; // Write debug - EnqueueWriteGlobal(kSPIR_AsanDebug, &(Options().Debug), - sizeof(Options().Debug)); + // We use "uint64_t" here because EnqueueWriteGlobal will fail when it's "uint32_t" + uint64_t Debug = Options().Debug ? 1 : 0; + EnqueueWriteGlobal(kSPIR_AsanDebug, &Debug, sizeof(Debug)); // Write shadow memory offset for global memory EnqueueWriteGlobal(kSPIR_AsanShadowMemoryGlobalStart, @@ -747,7 +748,8 @@ SanitizerInterceptor::findAllocInfoByAddress(uptr Address) { --It; // Make sure we got the right AllocInfo assert(Address >= It->second->AllocBegin && - Address < It->second->AllocBegin + It->second->AllocSize); + Address < It->second->AllocBegin + It->second->AllocSize && + "Wrong AllocInfo for the address"); return It; } diff --git a/source/loader/layers/sanitizer/asan_options.hpp b/source/loader/layers/sanitizer/asan_options.hpp index 7dd3e86858..cbaec0bd59 100644 --- a/source/loader/layers/sanitizer/asan_options.hpp +++ b/source/loader/layers/sanitizer/asan_options.hpp @@ -16,7 +16,9 @@ #include "ur/ur.hpp" #include "ur_sanitizer_layer.hpp" -#include +#include +#include +#include namespace ur_sanitizer_layer { @@ -30,9 +32,7 @@ struct AsanOptions { return instance; } - // We use "uint64_t" here because EnqueueWriteGlobal will fail when it's "uint32_t" - uint64_t Debug = 0; - + bool Debug = false; uint64_t MinRZSize = 16; uint64_t MaxRZSize = 2048; uint32_t MaxQuarantineSizeMB = 0; @@ -45,29 +45,69 @@ struct AsanOptions { return; } - auto KV = OptionsEnvMap->find("debug"); - if (KV != OptionsEnvMap->end()) { - auto Value = KV->second.front(); - Debug = Value == "1" || Value == "true" ? 1 : 0; - } + const char *TrueStrings[] = {"1", "true"}; + const char *FalseStrings[] = {"0", "false"}; + + auto InplaceToLower = [](std::string &S) { + std::transform(S.begin(), S.end(), S.begin(), + [](unsigned char C) { return std::tolower(C); }); + }; + auto IsTrue = [&](const std::string &S) { + return std::any_of(std::begin(TrueStrings), std::end(TrueStrings), + [&](const char *CS) { return S == CS; }); + }; + auto IsFalse = [&](const std::string &S) { + return std::any_of(std::begin(FalseStrings), std::end(FalseStrings), + [&](const char *CS) { return S == CS; }); + }; + + auto SetBoolOption = [&](const std::string &Name, bool &Opt) { + auto KV = OptionsEnvMap->find(Name); + if (KV != OptionsEnvMap->end()) { + auto Value = KV->second.front(); + InplaceToLower(Value); + if (IsTrue(Value)) { + Opt = true; + } else if (IsFalse(Value)) { + Opt = false; + } else { + std::stringstream SS; + SS << "[ERROR]: \"" << Name << "\" is set to \"" + << Value << "\", which is not an valid setting. "; + SS << "Acceptable input are: for enable, use:"; + for (auto &S : TrueStrings) { + SS << " \"" << S << "\""; + } + SS << "; "; + SS << "for disable, use:"; + for (auto &S : FalseStrings) { + SS << " \"" << S << "\""; + } + SS << "."; + die(SS.str().c_str()); + } + } + }; - KV = OptionsEnvMap->find("quarantine_size_mb"); + SetBoolOption("debug", Debug); + SetBoolOption("detect_locals", DetectLocals); + + auto KV = OptionsEnvMap->find("quarantine_size_mb"); if (KV != OptionsEnvMap->end()) { auto Value = KV->second.front(); try { - MaxQuarantineSizeMB = std::stoul(Value); + auto temp_long = std::stoul(Value); + if (temp_long > UINT32_MAX) { + throw std::out_of_range(""); + } + MaxQuarantineSizeMB = temp_long; } catch (...) { die("[ERROR]: \"quarantine_size_mb\" should be " - "an integer"); + "an positive integer that smaller than or equal to " + "4294967295."); } } - KV = OptionsEnvMap->find("detect_locals"); - if (KV != OptionsEnvMap->end()) { - auto Value = KV->second.front(); - DetectLocals = Value == "1" || Value == "true" ? true : false; - } - KV = OptionsEnvMap->find("redzone"); if (KV != OptionsEnvMap->end()) { auto Value = KV->second.front(); @@ -101,6 +141,6 @@ struct AsanOptions { } }; -inline AsanOptions &Options() { return AsanOptions::getInstance(); } +inline const AsanOptions &Options() { return AsanOptions::getInstance(); } } // namespace ur_sanitizer_layer