================ @@ -0,0 +1,330 @@ +//===----------------------------------------------------------------------===// +// +// 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 +/// Watchpoint-based host data race detector inspired by KCSAN. The host and GPU +/// runtimes share a configurable packed-watchpoint implementation. +/// +//===----------------------------------------------------------------------===// + +#include "csan.h" +#include "csan_watch.h" + +#include "sanitizer_common/sanitizer_atomic.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_flag_parser.h" +#include "sanitizer_common/sanitizer_flags.h" +#include "sanitizer_common/sanitizer_internal_defs.h" +#include "sanitizer_common/sanitizer_libc.h" +#include "sanitizer_common/sanitizer_mutex.h" +#include "sanitizer_common/sanitizer_stacktrace.h" +#include "sanitizer_common/sanitizer_symbolizer.h" + +using namespace __sanitizer; + +#define INTERFACE extern "C" SANITIZER_INTERFACE_ATTRIBUTE + +static constexpr u32 kHostWatchpointEntries = 64; +static constexpr u32 kHostCheckAdjacent = 1; +static constexpr uptr kHostSlotRange = 4096; +static constexpr uptr kHostMaxAccessSize = + kHostSlotRange * (1 + kHostCheckAdjacent); +static_assert(__atomic_always_lock_free(sizeof(u64), nullptr), + "host watchpoints must be lock-free"); + +using HostWatchpointTable = + __csan::WatchpointTable<kHostMaxAccessSize, kHostCheckAdjacent>; +static u64 HostWatchpoints[kHostWatchpointEntries + + HostWatchpointTable::OverflowEntries]; +static_assert(HostWatchpointTable::AddressBits == 48, + "host watchpoints require 48-bit pointers"); + +static HostWatchpointTable GetHostWatchpoints() { + return HostWatchpointTable(HostWatchpoints); +} + +static u32 HostWatchpointSlot(uptr Address) { + return Address / kHostSlotRange % kHostWatchpointEntries; +} + +namespace __csan { + +Flags flags_data; + +static void Initialize(); + +static atomic_uint64_t NumDataRaces; +static THREADLOCAL u32 DisableCount; +static THREADLOCAL s32 Skip; +static THREADLOCAL u32 RandState; + +namespace { +struct ScopedDisable { + ScopedDisable() { ++DisableCount; } + ~ScopedDisable() { --DisableCount; } +}; +} // namespace + +void RecordDataRace() { + atomic_fetch_add(&NumDataRaces, 1, memory_order_relaxed); +} + +void Flags::SetDefaults() { +#define CSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; +#include "csan_flags.inc" +#undef CSAN_FLAG +} + +static void RegisterCsanFlags(FlagParser *Parser, Flags *F) { +#define CSAN_FLAG(Type, Name, DefaultValue, Description) \ + RegisterFlag(Parser, #Name, Description, &F->Name); +#include "csan_flags.inc" +#undef CSAN_FLAG +} + +void InitializeFlags() { + SetCommonFlagsDefaults(); + { + CommonFlags CF; + CF.CopyFrom(*common_flags()); + CF.external_symbolizer_path = GetEnv("CSAN_SYMBOLIZER_PATH"); + OverrideCommonFlags(CF); + } + + flags()->SetDefaults(); + + FlagParser Parser; + RegisterCommonFlags(&Parser); + RegisterCsanFlags(&Parser, flags()); + Parser.ParseString(__csan_default_options()); + Parser.ParseStringFromEnv("CSAN_OPTIONS"); + InitializeCommonFlags(); + if (Verbosity()) + ReportUnrecognizedFlags(); + if (common_flags()->help) + Parser.PrintFlagDescriptions(); +} + +static u32 Random(u32 EpRo) { + if (EpRo <= 1) + return 0; + u32 State = RandState; + if (!State) + State = (u32)__builtin_readcyclecounter() | 1u; + State = 1664525u * State + 1013904223u; + RandState = State; + return State % EpRo; +} + +static void ResetSkip() { + s32 Count = flags()->skip_watch; + if (Count < 0) + Count = 0; + if (Count) + Count -= (s32)Random((u32)Count); + Skip = Count; +} + +static bool ShouldWatch(int Type) { + if (Type & CSAN_ACCESS_ATOMIC) + return false; + if (--Skip >= 0) + return false; + return true; +} + +static void DelayAccess(int Type) { + s32 Delay = flags()->udelay; + if (Delay < 0) + Delay = 0; + if (Delay) { + u32 Skew = (Type & CSAN_ACCESS_COMPOUND) ? 1u : 0u; + u32 Span = (u32)Delay >> Skew; + if (!Span) + Span = (u32)Delay; + Delay -= (s32)Random(Span); + } + if (Delay) + internal_usleep((u64)Delay); +} + +static u64 ReadRange(const volatile u8 *Bytes, uptr Size) { + u64 Sum = 0xcbf29ce484222325ull; + uptr I = 0; + for (; I < Size && ((uptr)(Bytes + I) & 7u); ++I) + Sum = (Sum ^ Bytes[I]) * 0x100000001b3ull; + for (; I + 8 <= Size; I += 8) + Sum = (Sum ^ *(const volatile u64 *)(Bytes + I)) * 0x100000001b3ull; + for (; I < Size; ++I) + Sum = (Sum ^ Bytes[I]) * 0x100000001b3ull; + return Sum; +} + +static u64 ReadInstrumented(const volatile void *Ptr, uptr Size) { + switch (Size) { + case 1: + return *(const volatile u8 *)Ptr; ---------------- vitalybuka wrote:
it looks like it used for __csan_unaligned_read* which make here unaligned load https://github.com/llvm/llvm-project/pull/225782 _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
