aboutsummaryrefslogtreecommitdiff
path: root/compiler-rt
diff options
context:
space:
mode:
Diffstat (limited to 'compiler-rt')
-rw-r--r--compiler-rt/include/profile/MemProfData.inc40
-rw-r--r--compiler-rt/lib/memprof/memprof_interface_internal.h10
-rw-r--r--compiler-rt/lib/memprof/memprof_rawprofile.cpp32
-rw-r--r--compiler-rt/lib/memprof/tests/CMakeLists.txt1
-rw-r--r--compiler-rt/lib/memprof/tests/histogram_encoding.cpp35
-rw-r--r--compiler-rt/lib/scudo/standalone/allocator_config.def3
-rw-r--r--compiler-rt/lib/scudo/standalone/allocator_config_wrapper.h12
-rw-r--r--compiler-rt/lib/scudo/standalone/combined.h34
-rw-r--r--compiler-rt/lib/scudo/standalone/secondary.h21
-rw-r--r--compiler-rt/lib/scudo/standalone/tests/combined_test.cpp103
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_report.h13
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_rtl.h3
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cpp6
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp77
-rw-r--r--compiler-rt/test/asan/TestCases/Linux/long-object-path.cpp6
-rw-r--r--compiler-rt/test/fuzzer/afl-driver-stderr.test3
-rw-r--r--compiler-rt/test/memprof/TestCases/memprof_histogram_uint8.cpp38
-rw-r--r--compiler-rt/test/sanitizer_common/TestCases/suffix-log-path_test.c9
-rw-r--r--compiler-rt/test/xray/TestCases/Posix/fdr-mode-inmemory.cpp8
-rw-r--r--compiler-rt/test/xray/TestCases/Posix/fdr-mode-multiple.cpp8
20 files changed, 384 insertions, 78 deletions
diff --git a/compiler-rt/include/profile/MemProfData.inc b/compiler-rt/include/profile/MemProfData.inc
index 3f785bd..26baddd 100644
--- a/compiler-rt/include/profile/MemProfData.inc
+++ b/compiler-rt/include/profile/MemProfData.inc
@@ -33,11 +33,10 @@
(uint64_t)'o' << 24 | (uint64_t)'f' << 16 | (uint64_t)'r' << 8 | (uint64_t)129)
// The version number of the raw binary format.
-#define MEMPROF_RAW_VERSION 4ULL
+#define MEMPROF_RAW_VERSION 5ULL
// Currently supported versions.
-#define MEMPROF_RAW_SUPPORTED_VERSIONS \
- { 3ULL, 4ULL }
+#define MEMPROF_RAW_SUPPORTED_VERSIONS {3ULL, 4ULL, 5ULL}
#define MEMPROF_V3_MIB_SIZE 132ULL;
@@ -229,6 +228,41 @@ void Merge(const MemInfoBlock &newMIB) {
} __attribute__((__packed__));
#endif
+constexpr int MantissaBits = 12;
+constexpr int ExponentBits = 4;
+constexpr uint16_t MaxMantissa = (1U << MantissaBits) - 1;
+constexpr uint16_t MaxExponent = (1U << ExponentBits) - 1;
+constexpr uint64_t MaxRepresentableValue = static_cast<uint64_t>(MaxMantissa)
+ << MaxExponent;
+
+// Encodes a 64-bit unsigned integer into a 16-bit scaled integer format.
+inline uint16_t encodeHistogramCount(uint64_t Count) {
+ if (Count == 0)
+ return 0;
+
+ if (Count > MaxRepresentableValue)
+ Count = MaxRepresentableValue;
+
+ if (Count <= MaxMantissa)
+ return Count;
+
+ uint64_t M = Count;
+ uint16_t E = 0;
+ while (M > MaxMantissa) {
+ M = (M + 1) >> 1;
+ E++;
+ }
+ return (E << MantissaBits) | static_cast<uint16_t>(M);
+}
+
+// Decodes a 16-bit scaled integer and returns the
+// decoded 64-bit unsigned integer.
+inline uint64_t decodeHistogramCount(uint16_t EncodedValue) {
+ const uint16_t E = EncodedValue >> MantissaBits;
+ const uint16_t M = EncodedValue & MaxMantissa;
+ return static_cast<uint64_t>(M) << E;
+}
+
} // namespace memprof
} // namespace llvm
diff --git a/compiler-rt/lib/memprof/memprof_interface_internal.h b/compiler-rt/lib/memprof/memprof_interface_internal.h
index 7d3a937..1fd0748 100644
--- a/compiler-rt/lib/memprof/memprof_interface_internal.h
+++ b/compiler-rt/lib/memprof/memprof_interface_internal.h
@@ -36,8 +36,14 @@ SANITIZER_INTERFACE_ATTRIBUTE
void __memprof_record_access(void const volatile *addr);
SANITIZER_INTERFACE_ATTRIBUTE
+void __memprof_record_access_hist(void const volatile *addr);
+
+SANITIZER_INTERFACE_ATTRIBUTE
void __memprof_record_access_range(void const volatile *addr, uptr size);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __memprof_record_access_range_hist(void const volatile *addr, uptr size);
+
SANITIZER_INTERFACE_ATTRIBUTE void __memprof_print_accumulated_stats();
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE extern char
@@ -51,6 +57,10 @@ extern uptr __memprof_shadow_memory_dynamic_address;
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE extern char
__memprof_profile_filename[1];
+
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE extern bool
+ __memprof_histogram;
+
SANITIZER_INTERFACE_ATTRIBUTE int __memprof_profile_dump();
SANITIZER_INTERFACE_ATTRIBUTE void __memprof_profile_reset();
diff --git a/compiler-rt/lib/memprof/memprof_rawprofile.cpp b/compiler-rt/lib/memprof/memprof_rawprofile.cpp
index a897648..f579e12 100644
--- a/compiler-rt/lib/memprof/memprof_rawprofile.cpp
+++ b/compiler-rt/lib/memprof/memprof_rawprofile.cpp
@@ -7,10 +7,7 @@
#include "sanitizer_common/sanitizer_allocator_internal.h"
#include "sanitizer_common/sanitizer_array_ref.h"
#include "sanitizer_common/sanitizer_common.h"
-#include "sanitizer_common/sanitizer_linux.h"
-#include "sanitizer_common/sanitizer_procmaps.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
-#include "sanitizer_common/sanitizer_stackdepotbase.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
#include "sanitizer_common/sanitizer_vector.h"
@@ -19,10 +16,20 @@ using ::__sanitizer::Vector;
using ::llvm::memprof::MemInfoBlock;
using SegmentEntry = ::llvm::memprof::SegmentEntry;
using Header = ::llvm::memprof::Header;
+using ::llvm::memprof::encodeHistogramCount;
namespace {
template <class T> char *WriteBytes(const T &Pod, char *Buffer) {
- *(T *)Buffer = Pod;
+ static_assert(is_trivially_copyable<T>::value, "T must be POD");
+ const uint8_t *Src = reinterpret_cast<const uint8_t *>(&Pod);
+
+ for (size_t I = 0; I < sizeof(T); ++I)
+#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ // Reverse byte order since reader is little-endian.
+ Buffer[I] = Src[sizeof(T) - 1 - I];
+#else
+ Buffer[I] = Src[I];
+#endif
return Buffer + sizeof(T);
}
@@ -32,7 +39,6 @@ void RecordStackId(const uptr Key, UNUSED LockedMemInfoBlock *const &MIB,
auto *StackIds = reinterpret_cast<Vector<u64> *>(Arg);
StackIds->PushBack(Key);
}
-} // namespace
u64 SegmentSizeBytes(ArrayRef<LoadedModule> Modules) {
u64 NumSegmentsToRecord = 0;
@@ -169,18 +175,21 @@ void SerializeMIBInfoToBuffer(MIBMapTy &MIBMap, const Vector<u64> &StackIds,
// FIXME: We unnecessarily serialize the AccessHistogram pointer. Adding a
// serialization schema will fix this issue. See also FIXME in
// deserialization.
- Ptr = WriteBytes((*h)->mib, Ptr);
- for (u64 j = 0; j < (*h)->mib.AccessHistogramSize; ++j) {
- u64 HistogramEntry = ((u64 *)((*h)->mib.AccessHistogram))[j];
+ auto &MIB = (*h)->mib;
+ Ptr = WriteBytes(MIB, Ptr);
+ for (u64 j = 0; j < MIB.AccessHistogramSize; ++j) {
+ u16 HistogramEntry =
+ encodeHistogramCount(((u64 *)(MIB.AccessHistogram))[j]);
Ptr = WriteBytes(HistogramEntry, Ptr);
}
- if ((*h)->mib.AccessHistogramSize > 0) {
- InternalFree((void *)((*h)->mib.AccessHistogram));
+ if (MIB.AccessHistogramSize > 0) {
+ InternalFree((void *)MIB.AccessHistogram);
}
}
CHECK(ExpectedNumBytes >= static_cast<u64>(Ptr - Buffer) &&
"Expected num bytes != actual bytes written");
}
+} // namespace
// Format
// ---------- Header
@@ -249,7 +258,7 @@ u64 SerializeToRawProfile(MIBMapTy &MIBMap, ArrayRef<LoadedModule> Modules,
},
reinterpret_cast<void *>(&TotalAccessHistogramEntries));
const u64 NumHistogramBytes =
- RoundUpTo(TotalAccessHistogramEntries * sizeof(uint64_t), 8);
+ RoundUpTo(TotalAccessHistogramEntries * sizeof(uint16_t), 8);
const u64 NumStackBytes = RoundUpTo(StackSizeBytes(StackIds), 8);
@@ -285,5 +294,4 @@ u64 SerializeToRawProfile(MIBMapTy &MIBMap, ArrayRef<LoadedModule> Modules,
return TotalSizeBytes;
}
-
} // namespace __memprof
diff --git a/compiler-rt/lib/memprof/tests/CMakeLists.txt b/compiler-rt/lib/memprof/tests/CMakeLists.txt
index 0b5c302..1603d47 100644
--- a/compiler-rt/lib/memprof/tests/CMakeLists.txt
+++ b/compiler-rt/lib/memprof/tests/CMakeLists.txt
@@ -26,6 +26,7 @@ set(MEMPROF_SOURCES
../memprof_rawprofile.cpp)
set(MEMPROF_UNITTESTS
+ histogram_encoding.cpp
rawprofile.cpp
driver.cpp)
diff --git a/compiler-rt/lib/memprof/tests/histogram_encoding.cpp b/compiler-rt/lib/memprof/tests/histogram_encoding.cpp
new file mode 100644
index 0000000..be20595
--- /dev/null
+++ b/compiler-rt/lib/memprof/tests/histogram_encoding.cpp
@@ -0,0 +1,35 @@
+#include <cstdint>
+#include <vector>
+
+#include "profile/MemProfData.inc"
+#include "gtest/gtest.h"
+
+namespace llvm {
+namespace memprof {
+namespace {
+TEST(MemProf, F16EncodeDecode) {
+ const std::vector<uint64_t> TestCases = {
+ 0, 100, 4095, 4096, 5000, 8191, 65535, 1000000, 134213640, 200000000,
+ };
+
+ for (const uint64_t TestCase : TestCases) {
+ const uint16_t Encoded = encodeHistogramCount(TestCase);
+ const uint64_t Decoded = decodeHistogramCount(Encoded);
+
+ const uint64_t MaxRepresentable = static_cast<uint64_t>(MaxMantissa)
+ << MaxExponent;
+
+ if (TestCase >= MaxRepresentable) {
+ EXPECT_EQ(Decoded, MaxRepresentable);
+ } else if (TestCase <= MaxMantissa) {
+ EXPECT_EQ(Decoded, TestCase);
+ } else {
+ // The decoded value should be close to the original value.
+ // The error should be less than 1/1024 for larger numbers.
+ EXPECT_NEAR(Decoded, TestCase, static_cast<double>(TestCase) / 1024.0);
+ }
+ }
+}
+} // namespace
+} // namespace memprof
+} // namespace llvm
diff --git a/compiler-rt/lib/scudo/standalone/allocator_config.def b/compiler-rt/lib/scudo/standalone/allocator_config.def
index 84fcec0..7485308 100644
--- a/compiler-rt/lib/scudo/standalone/allocator_config.def
+++ b/compiler-rt/lib/scudo/standalone/allocator_config.def
@@ -54,6 +54,9 @@ BASE_REQUIRED_TEMPLATE_TYPE(SecondaryT)
// Indicates possible support for Memory Tagging.
BASE_OPTIONAL(const bool, MaySupportMemoryTagging, false)
+// Disable the quarantine code.
+BASE_OPTIONAL(const bool, QuarantineDisabled, false)
+
// PRIMARY_REQUIRED_TYPE(NAME)
//
// SizeClassMap to use with the Primary.
diff --git a/compiler-rt/lib/scudo/standalone/allocator_config_wrapper.h b/compiler-rt/lib/scudo/standalone/allocator_config_wrapper.h
index ac639ee..5bfa700 100644
--- a/compiler-rt/lib/scudo/standalone/allocator_config_wrapper.h
+++ b/compiler-rt/lib/scudo/standalone/allocator_config_wrapper.h
@@ -60,6 +60,10 @@ template <typename AllocatorConfig> struct PrimaryConfig {
return BaseConfig<AllocatorConfig>::getMaySupportMemoryTagging();
}
+ static constexpr bool getQuarantineDisabled() {
+ return BaseConfig<AllocatorConfig>::getQuarantineDisabled();
+ }
+
#define PRIMARY_REQUIRED_TYPE(NAME) \
using NAME = typename AllocatorConfig::Primary::NAME;
@@ -92,6 +96,10 @@ template <typename AllocatorConfig> struct SecondaryConfig {
return BaseConfig<AllocatorConfig>::getMaySupportMemoryTagging();
}
+ static constexpr bool getQuarantineDisabled() {
+ return BaseConfig<AllocatorConfig>::getQuarantineDisabled();
+ }
+
#define SECONDARY_REQUIRED_TEMPLATE_TYPE(NAME) \
template <typename T> \
using NAME = typename AllocatorConfig::Secondary::template NAME<T>;
@@ -111,6 +119,10 @@ template <typename AllocatorConfig> struct SecondaryConfig {
return BaseConfig<AllocatorConfig>::getMaySupportMemoryTagging();
}
+ static constexpr bool getQuarantineDisabled() {
+ return BaseConfig<AllocatorConfig>::getQuarantineDisabled();
+ }
+
#define SECONDARY_CACHE_OPTIONAL(TYPE, NAME, DEFAULT) \
OPTIONAL_TEMPLATE(TYPE, NAME, DEFAULT, Cache::NAME) \
static constexpr removeConst<TYPE>::type get##NAME() { \
diff --git a/compiler-rt/lib/scudo/standalone/combined.h b/compiler-rt/lib/scudo/standalone/combined.h
index 87acdec..985bfb4 100644
--- a/compiler-rt/lib/scudo/standalone/combined.h
+++ b/compiler-rt/lib/scudo/standalone/combined.h
@@ -184,9 +184,11 @@ public:
const s32 ReleaseToOsIntervalMs = getFlags()->release_to_os_interval_ms;
Primary.init(ReleaseToOsIntervalMs);
Secondary.init(&Stats, ReleaseToOsIntervalMs);
- Quarantine.init(
- static_cast<uptr>(getFlags()->quarantine_size_kb << 10),
- static_cast<uptr>(getFlags()->thread_local_quarantine_size_kb << 10));
+ if (!AllocatorConfig::getQuarantineDisabled()) {
+ Quarantine.init(
+ static_cast<uptr>(getFlags()->quarantine_size_kb << 10),
+ static_cast<uptr>(getFlags()->thread_local_quarantine_size_kb << 10));
+ }
}
void enableRingBuffer() NO_THREAD_SAFETY_ANALYSIS {
@@ -276,16 +278,20 @@ public:
// the last two items).
void commitBack(TSD<ThisT> *TSD) {
TSD->assertLocked(/*BypassCheck=*/true);
- Quarantine.drain(&TSD->getQuarantineCache(),
- QuarantineCallback(*this, TSD->getSizeClassAllocator()));
+ if (!AllocatorConfig::getQuarantineDisabled()) {
+ Quarantine.drain(&TSD->getQuarantineCache(),
+ QuarantineCallback(*this, TSD->getSizeClassAllocator()));
+ }
TSD->getSizeClassAllocator().destroy(&Stats);
}
void drainCache(TSD<ThisT> *TSD) {
TSD->assertLocked(/*BypassCheck=*/true);
- Quarantine.drainAndRecycle(
- &TSD->getQuarantineCache(),
- QuarantineCallback(*this, TSD->getSizeClassAllocator()));
+ if (!AllocatorConfig::getQuarantineDisabled()) {
+ Quarantine.drainAndRecycle(
+ &TSD->getQuarantineCache(),
+ QuarantineCallback(*this, TSD->getSizeClassAllocator()));
+ }
TSD->getSizeClassAllocator().drain();
}
void drainCaches() { TSDRegistry.drainCaches(this); }
@@ -612,7 +618,8 @@ public:
#endif
TSDRegistry.disable();
Stats.disable();
- Quarantine.disable();
+ if (!AllocatorConfig::getQuarantineDisabled())
+ Quarantine.disable();
Primary.disable();
Secondary.disable();
disableRingBuffer();
@@ -623,7 +630,8 @@ public:
enableRingBuffer();
Secondary.enable();
Primary.enable();
- Quarantine.enable();
+ if (!AllocatorConfig::getQuarantineDisabled())
+ Quarantine.enable();
Stats.enable();
TSDRegistry.enable();
#ifdef GWP_ASAN_HOOKS
@@ -1252,7 +1260,8 @@ private:
// If the quarantine is disabled, the actual size of a chunk is 0 or larger
// than the maximum allowed, we return a chunk directly to the backend.
// This purposefully underflows for Size == 0.
- const bool BypassQuarantine = !Quarantine.getCacheSize() ||
+ const bool BypassQuarantine = AllocatorConfig::getQuarantineDisabled() ||
+ !Quarantine.getCacheSize() ||
((Size - 1) >= QuarantineMaxChunkSize) ||
!Header->ClassId;
if (BypassQuarantine)
@@ -1642,7 +1651,8 @@ private:
uptr getStats(ScopedString *Str) {
Primary.getStats(Str);
Secondary.getStats(Str);
- Quarantine.getStats(Str);
+ if (!AllocatorConfig::getQuarantineDisabled())
+ Quarantine.getStats(Str);
TSDRegistry.getStats(Str);
return Str->length();
}
diff --git a/compiler-rt/lib/scudo/standalone/secondary.h b/compiler-rt/lib/scudo/standalone/secondary.h
index f04c5b7..38c9a9e 100644
--- a/compiler-rt/lib/scudo/standalone/secondary.h
+++ b/compiler-rt/lib/scudo/standalone/secondary.h
@@ -312,7 +312,7 @@ public:
break;
}
- if (Config::getQuarantineSize()) {
+ if (!Config::getQuarantineDisabled() && Config::getQuarantineSize()) {
QuarantinePos =
(QuarantinePos + 1) % Max(Config::getQuarantineSize(), 1u);
if (!Quarantine[QuarantinePos].isValid()) {
@@ -508,14 +508,16 @@ public:
void disableMemoryTagging() EXCLUDES(Mutex) {
ScopedLock L(Mutex);
- for (u32 I = 0; I != Config::getQuarantineSize(); ++I) {
- if (Quarantine[I].isValid()) {
- MemMapT &MemMap = Quarantine[I].MemMap;
- unmapCallBack(MemMap);
- Quarantine[I].invalidate();
+ if (!Config::getQuarantineDisabled()) {
+ for (u32 I = 0; I != Config::getQuarantineSize(); ++I) {
+ if (Quarantine[I].isValid()) {
+ MemMapT &MemMap = Quarantine[I].MemMap;
+ unmapCallBack(MemMap);
+ Quarantine[I].invalidate();
+ }
}
+ QuarantinePos = -1U;
}
- QuarantinePos = -1U;
for (CachedBlock &Entry : LRUEntries)
Entry.MemMap.setMemoryPermission(Entry.CommitBase, Entry.CommitSize, 0);
@@ -575,8 +577,9 @@ private:
if (!LRUEntries.size() || OldestTime == 0 || OldestTime > Time)
return;
OldestTime = 0;
- for (uptr I = 0; I < Config::getQuarantineSize(); I++)
- releaseIfOlderThan(Quarantine[I], Time);
+ if (!Config::getQuarantineDisabled())
+ for (uptr I = 0; I < Config::getQuarantineSize(); I++)
+ releaseIfOlderThan(Quarantine[I], Time);
for (uptr I = 0; I < Config::getEntriesArraySize(); I++)
releaseIfOlderThan(Entries[I], Time);
}
diff --git a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
index 7e8d5b4..1eff9eb 100644
--- a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
+++ b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
@@ -623,20 +623,20 @@ SCUDO_TYPED_TEST(ScudoCombinedDeathTest, DisableMemoryTagging) {
SCUDO_TYPED_TEST(ScudoCombinedTest, Stats) {
auto *Allocator = this->Allocator.get();
- scudo::uptr BufferSize = 8192;
- std::vector<char> Buffer(BufferSize);
- scudo::uptr ActualSize = Allocator->getStats(Buffer.data(), BufferSize);
- while (ActualSize > BufferSize) {
- BufferSize = ActualSize + 1024;
- Buffer.resize(BufferSize);
- ActualSize = Allocator->getStats(Buffer.data(), BufferSize);
+ std::string Stats(10000, '\0');
+ scudo::uptr ActualSize = Allocator->getStats(Stats.data(), Stats.size());
+ if (ActualSize > Stats.size()) {
+ Stats.resize(ActualSize);
+ ActualSize = Allocator->getStats(Stats.data(), Stats.size());
}
- std::string Stats(Buffer.begin(), Buffer.end());
+ EXPECT_GE(Stats.size(), ActualSize);
+
// Basic checks on the contents of the statistics output, which also allows us
// to verify that we got it all.
EXPECT_NE(Stats.find("Stats: SizeClassAllocator"), std::string::npos);
EXPECT_NE(Stats.find("Stats: MapAllocator"), std::string::npos);
- EXPECT_NE(Stats.find("Stats: Quarantine"), std::string::npos);
+ // Do not explicitly check for quarantine stats since a config can disable
+ // them. Other tests verify this (QuarantineEnabled/QuarantineDisabled).
}
SCUDO_TYPED_TEST_SKIP_THREAD_SAFETY(ScudoCombinedTest, Drain) {
@@ -1076,3 +1076,88 @@ TEST(ScudoCombinedTest, BasicTrustyConfig) {
#endif
#endif
+
+struct TestQuarantineSizeClassConfig {
+ static const scudo::uptr NumBits = 1;
+ static const scudo::uptr MinSizeLog = 10;
+ static const scudo::uptr MidSizeLog = 10;
+ static const scudo::uptr MaxSizeLog = 13;
+ static const scudo::u16 MaxNumCachedHint = 8;
+ static const scudo::uptr MaxBytesCachedLog = 12;
+ static const scudo::uptr SizeDelta = 0;
+};
+
+struct TestQuarantineConfig {
+ static const bool MaySupportMemoryTagging = false;
+
+ template <class A> using TSDRegistryT = scudo::TSDRegistrySharedT<A, 1U, 1U>;
+
+ struct Primary {
+ // Tiny allocator, its Primary only serves chunks of four sizes.
+ using SizeClassMap = scudo::FixedSizeClassMap<DeathSizeClassConfig>;
+ static const scudo::uptr RegionSizeLog = DeathRegionSizeLog;
+ static const scudo::s32 MinReleaseToOsIntervalMs = INT32_MIN;
+ static const scudo::s32 MaxReleaseToOsIntervalMs = INT32_MAX;
+ typedef scudo::uptr CompactPtrT;
+ static const scudo::uptr CompactPtrScale = 0;
+ static const bool EnableRandomOffset = true;
+ static const scudo::uptr MapSizeIncrement = 1UL << 18;
+ static const scudo::uptr GroupSizeLog = 18;
+ };
+ template <typename Config>
+ using PrimaryT = scudo::SizeClassAllocator64<Config>;
+
+ struct Secondary {
+ template <typename Config>
+ using CacheT = scudo::MapAllocatorNoCache<Config>;
+ };
+
+ template <typename Config> using SecondaryT = scudo::MapAllocator<Config>;
+};
+
+// Verify that the quarantine exists by default.
+TEST(ScudoCombinedTest, QuarantineEnabled) {
+ using AllocatorT = scudo::Allocator<TestQuarantineConfig>;
+ auto Allocator = std::unique_ptr<AllocatorT>(new AllocatorT());
+
+ const scudo::uptr Size = 1000U;
+ void *P = Allocator->allocate(Size, Origin);
+ EXPECT_NE(P, nullptr);
+ Allocator->deallocate(P, Origin);
+
+ std::string Stats(10000, '\0');
+ scudo::uptr ActualSize = Allocator->getStats(Stats.data(), Stats.size());
+ if (ActualSize > Stats.size()) {
+ Stats.resize(ActualSize);
+ ActualSize = Allocator->getStats(Stats.data(), Stats.size());
+ }
+ EXPECT_GE(Stats.size(), ActualSize);
+
+ // Quarantine stats should be present.
+ EXPECT_NE(Stats.find("Stats: Quarantine"), std::string::npos);
+}
+
+struct TestQuarantineDisabledConfig : TestQuarantineConfig {
+ static const bool QuarantineDisabled = true;
+};
+
+TEST(ScudoCombinedTest, QuarantineDisabled) {
+ using AllocatorT = scudo::Allocator<TestQuarantineDisabledConfig>;
+ auto Allocator = std::unique_ptr<AllocatorT>(new AllocatorT());
+
+ const scudo::uptr Size = 1000U;
+ void *P = Allocator->allocate(Size, Origin);
+ EXPECT_NE(P, nullptr);
+ Allocator->deallocate(P, Origin);
+
+ std::string Stats(10000, '\0');
+ scudo::uptr ActualSize = Allocator->getStats(Stats.data(), Stats.size());
+ if (ActualSize > Stats.size()) {
+ Stats.resize(ActualSize);
+ ActualSize = Allocator->getStats(Stats.data(), Stats.size());
+ }
+ EXPECT_GE(Stats.size(), ActualSize);
+
+ // No quarantine stats should not be present.
+ EXPECT_EQ(Stats.find("Stats: Quarantine"), std::string::npos);
+}
diff --git a/compiler-rt/lib/tsan/rtl/tsan_report.h b/compiler-rt/lib/tsan/rtl/tsan_report.h
index 8975540..53bb219 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_report.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_report.h
@@ -12,6 +12,8 @@
#ifndef TSAN_REPORT_H
#define TSAN_REPORT_H
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
#include "sanitizer_common/sanitizer_symbolizer.h"
#include "sanitizer_common/sanitizer_thread_registry.h"
#include "sanitizer_common/sanitizer_vector.h"
@@ -56,6 +58,7 @@ struct ReportMop {
bool atomic;
uptr external_tag;
Vector<ReportMopMutex> mset;
+ StackTrace stack_trace;
ReportStack *stack;
ReportMop();
@@ -79,6 +82,7 @@ struct ReportLocation {
int fd = 0;
bool fd_closed = false;
bool suppressable = false;
+ StackID stack_id = 0;
ReportStack *stack = nullptr;
};
@@ -89,15 +93,23 @@ struct ReportThread {
ThreadType thread_type;
char *name;
Tid parent_tid;
+ StackID stack_id;
ReportStack *stack;
+ bool suppressable;
};
struct ReportMutex {
int id;
uptr addr;
+ StackID stack_id;
ReportStack *stack;
};
+struct AddedLocationAddr {
+ uptr addr;
+ usize locs_idx;
+};
+
class ReportDesc {
public:
ReportType typ;
@@ -105,6 +117,7 @@ class ReportDesc {
Vector<ReportStack*> stacks;
Vector<ReportMop*> mops;
Vector<ReportLocation*> locs;
+ Vector<AddedLocationAddr> added_location_addrs;
Vector<ReportMutex*> mutexes;
Vector<ReportThread*> threads;
Vector<Tid> unique_tids;
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.h b/compiler-rt/lib/tsan/rtl/tsan_rtl.h
index 46276f2..0b6d5f0 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.h
@@ -420,6 +420,7 @@ class ScopedReportBase {
void AddSleep(StackID stack_id);
void SetCount(int count);
void SetSigNum(int sig);
+ void SymbolizeStackElems(void);
const ReportDesc *GetReport() const;
@@ -498,7 +499,7 @@ void ForkChildAfter(ThreadState *thr, uptr pc, bool start_thread);
void ReportRace(ThreadState *thr, RawShadow *shadow_mem, Shadow cur, Shadow old,
AccessType typ);
-bool OutputReport(ThreadState *thr, const ScopedReport &srep);
+bool OutputReport(ThreadState *thr, ScopedReport &srep);
bool IsFiredSuppression(Context *ctx, ReportType type, StackTrace trace);
bool IsExpectedReport(uptr addr, uptr size);
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cpp
index 2a8aa19..2a2bf42 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cpp
@@ -539,13 +539,15 @@ void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) {
for (int i = 0; i < r->n; i++) {
for (int j = 0; j < (flags()->second_deadlock_stack ? 2 : 1); j++) {
u32 stk = r->loop[i].stk[j];
+ StackTrace stack;
if (stk && stk != kInvalidStackID) {
- rep.AddStack(StackDepotGet(stk), true);
+ stack = StackDepotGet(stk);
} else {
// Sometimes we fail to extract the stack trace (FIXME: investigate),
// but we should still produce some stack trace in the report.
- rep.AddStack(StackTrace(&dummy_pc, 1), true);
+ stack = StackTrace(&dummy_pc, 1);
}
+ rep.AddStack(stack, true);
}
}
OutputReport(thr, rep);
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp
index 0820bf1..e6f0fda 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_placement_new.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
@@ -187,10 +188,8 @@ void ScopedReportBase::AddMemoryAccess(uptr addr, uptr external_tag, Shadow s,
mop->size = size;
mop->write = !(typ & kAccessRead);
mop->atomic = typ & kAccessAtomic;
- mop->stack = SymbolizeStack(stack);
mop->external_tag = external_tag;
- if (mop->stack)
- mop->stack->suppressable = true;
+ mop->stack_trace = stack;
for (uptr i = 0; i < mset->Size(); i++) {
MutexSet::Desc d = mset->Get(i);
int id = this->AddMutex(d.addr, d.stack_id);
@@ -199,6 +198,56 @@ void ScopedReportBase::AddMemoryAccess(uptr addr, uptr external_tag, Shadow s,
}
}
+void ScopedReportBase::SymbolizeStackElems() {
+ // symbolize memory ops
+ for (usize i = 0, size = rep_->mops.Size(); i < size; i++) {
+ ReportMop *mop = rep_->mops[i];
+ mop->stack = SymbolizeStack(mop->stack_trace);
+ if (mop->stack)
+ mop->stack->suppressable = true;
+ }
+
+ // symbolize locations
+ for (usize i = 0, size = rep_->locs.Size(); i < size; i++) {
+ // added locations have a NULL placeholder - don't dereference them
+ if (ReportLocation *loc = rep_->locs[i])
+ loc->stack = SymbolizeStackId(loc->stack_id);
+ }
+
+ // symbolize any added locations
+ for (usize i = 0, size = rep_->added_location_addrs.Size(); i < size; i++) {
+ AddedLocationAddr *added_loc = &rep_->added_location_addrs[i];
+ if (ReportLocation *loc = SymbolizeData(added_loc->addr)) {
+ loc->suppressable = true;
+ rep_->locs[added_loc->locs_idx] = loc;
+ }
+ }
+
+ // Filter out any added location placeholders that could not be symbolized
+ usize j = 0;
+ for (usize i = 0, size = rep_->locs.Size(); i < size; i++) {
+ if (rep_->locs[i] != nullptr) {
+ rep_->locs[j] = rep_->locs[i];
+ j++;
+ }
+ }
+ rep_->locs.Resize(j);
+
+ // symbolize threads
+ for (usize i = 0, size = rep_->threads.Size(); i < size; i++) {
+ ReportThread *rt = rep_->threads[i];
+ rt->stack = SymbolizeStackId(rt->stack_id);
+ if (rt->stack)
+ rt->stack->suppressable = rt->suppressable;
+ }
+
+ // symbolize mutexes
+ for (usize i = 0, size = rep_->mutexes.Size(); i < size; i++) {
+ ReportMutex *rm = rep_->mutexes[i];
+ rm->stack = SymbolizeStackId(rm->stack_id);
+ }
+}
+
void ScopedReportBase::AddUniqueTid(Tid unique_tid) {
rep_->unique_tids.PushBack(unique_tid);
}
@@ -216,10 +265,8 @@ void ScopedReportBase::AddThread(const ThreadContext *tctx, bool suppressable) {
rt->name = internal_strdup(tctx->name);
rt->parent_tid = tctx->parent_tid;
rt->thread_type = tctx->thread_type;
- rt->stack = 0;
- rt->stack = SymbolizeStackId(tctx->creation_stack_id);
- if (rt->stack)
- rt->stack->suppressable = suppressable;
+ rt->stack_id = tctx->creation_stack_id;
+ rt->suppressable = suppressable;
}
#if !SANITIZER_GO
@@ -270,7 +317,7 @@ int ScopedReportBase::AddMutex(uptr addr, StackID creation_stack_id) {
rep_->mutexes.PushBack(rm);
rm->id = rep_->mutexes.Size() - 1;
rm->addr = addr;
- rm->stack = SymbolizeStackId(creation_stack_id);
+ rm->stack_id = creation_stack_id;
return rm->id;
}
@@ -288,7 +335,7 @@ void ScopedReportBase::AddLocation(uptr addr, uptr size) {
loc->fd_closed = closed;
loc->fd = fd;
loc->tid = creat_tid;
- loc->stack = SymbolizeStackId(creat_stack);
+ loc->stack_id = creat_stack;
rep_->locs.PushBack(loc);
AddThread(creat_tid);
return;
@@ -310,7 +357,7 @@ void ScopedReportBase::AddLocation(uptr addr, uptr size) {
loc->heap_chunk_size = b->siz;
loc->external_tag = b->tag;
loc->tid = b->tid;
- loc->stack = SymbolizeStackId(b->stk);
+ loc->stack_id = b->stk;
rep_->locs.PushBack(loc);
AddThread(b->tid);
return;
@@ -324,11 +371,8 @@ void ScopedReportBase::AddLocation(uptr addr, uptr size) {
AddThread(tctx);
}
#endif
- if (ReportLocation *loc = SymbolizeData(addr)) {
- loc->suppressable = true;
- rep_->locs.PushBack(loc);
- return;
- }
+ rep_->added_location_addrs.PushBack({addr, rep_->locs.Size()});
+ rep_->locs.PushBack(nullptr);
}
#if !SANITIZER_GO
@@ -628,11 +672,12 @@ static bool HandleRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2]) {
return false;
}
-bool OutputReport(ThreadState *thr, const ScopedReport &srep) {
+bool OutputReport(ThreadState *thr, ScopedReport &srep) {
// These should have been checked in ShouldReport.
// It's too late to check them here, we have already taken locks.
CHECK(flags()->report_bugs);
CHECK(!thr->suppress_reports);
+ srep.SymbolizeStackElems();
atomic_store_relaxed(&ctx->last_symbolize_time_ns, NanoTime());
const ReportDesc *rep = srep.GetReport();
CHECK_EQ(thr->current_report, nullptr);
diff --git a/compiler-rt/test/asan/TestCases/Linux/long-object-path.cpp b/compiler-rt/test/asan/TestCases/Linux/long-object-path.cpp
index 592b0ab..ffc2fbf 100644
--- a/compiler-rt/test/asan/TestCases/Linux/long-object-path.cpp
+++ b/compiler-rt/test/asan/TestCases/Linux/long-object-path.cpp
@@ -1,6 +1,6 @@
-// RUN: mkdir -p %T/a-long-directory-name-to-test-allocations-for-exceptions-in-_dl_lookup_symbol_x-since-glibc-2.27
-// RUN: %clangxx_asan -g %s -o %T/long-object-path
-// RUN: %run %T/a-*/../a-*/../a-*/../a-*/../a-*/../a-*/../a-*/../a-*/../long-object-path
+// RUN: mkdir -p %t.dir/a-long-directory-name-to-test-allocations-for-exceptions-in-_dl_lookup_symbol_x-since-glibc-2.27
+// RUN: %clangxx_asan -g %s -o %t.dir/long-object-path
+// RUN: %run %t.dir/a-*/../a-*/../a-*/../a-*/../a-*/../a-*/../a-*/../a-*/../long-object-path
int main(void) {
return 0;
diff --git a/compiler-rt/test/fuzzer/afl-driver-stderr.test b/compiler-rt/test/fuzzer/afl-driver-stderr.test
index 4b0c3b4..1ee0960 100644
--- a/compiler-rt/test/fuzzer/afl-driver-stderr.test
+++ b/compiler-rt/test/fuzzer/afl-driver-stderr.test
@@ -7,7 +7,8 @@ RUN: %no_fuzzer_cpp_compiler %S/AFLDriverTest.cpp %libfuzzer_src/afl/afl_driver.
RUN: env -u AFL_DRIVER_STDERR_DUPLICATE_FILENAME %run %t-AFLDriverTest
; Test that specifying an invalid file causes a crash.
-RUN: env ASAN_OPTIONS= AFL_DRIVER_STDERR_DUPLICATE_FILENAME="%T" not --crash %run %t-AFLDriverTest
+RUN: mkdir -p %t.dir
+RUN: env ASAN_OPTIONS= AFL_DRIVER_STDERR_DUPLICATE_FILENAME="%t.dir" not --crash %run %t-AFLDriverTest
; Test that a file is created when specified as the duplicate stderr.
RUN: env AFL_DRIVER_STDERR_DUPLICATE_FILENAME=%t %run %t-AFLDriverTest
diff --git a/compiler-rt/test/memprof/TestCases/memprof_histogram_uint8.cpp b/compiler-rt/test/memprof/TestCases/memprof_histogram_uint8.cpp
new file mode 100644
index 0000000..ef6fb33
--- /dev/null
+++ b/compiler-rt/test/memprof/TestCases/memprof_histogram_uint8.cpp
@@ -0,0 +1,38 @@
+// Test the histogram support in memprof using the text format output.
+// Shadow memory counters per object are limited to 8b. In memory counters
+// aggregating counts across multiple objects are 64b.
+
+// RUN: %clangxx_memprof -O0 -mllvm -memprof-histogram -mllvm -memprof-use-callbacks=true %s -o %t
+// RUN: %env_memprof_opts=print_text=1:histogram=1:log_path=stdout %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+ // Allocate memory that will create a histogram
+ char *buffer = (char *)malloc(1024);
+ if (!buffer)
+ return 1;
+
+ for (int i = 0; i < 10; ++i) {
+ // Access every 8th byte (since shadow granularity is 8b.
+ buffer[i * 8] = 'A';
+ }
+
+ for (int j = 0; j < 200; ++j) {
+ buffer[8] = 'B'; // Count = previous count + 200
+ }
+
+ for (int j = 0; j < 400; ++j) {
+ buffer[16] = 'B'; // Count is saturated at 255
+ }
+
+ // Free the memory to trigger MIB creation with histogram
+ free(buffer);
+
+ printf("Test completed successfully\n");
+ return 0;
+}
+
+// CHECK: AccessCountHistogram[128]: 1 201 255 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+// CHECK: Test completed successfully
diff --git a/compiler-rt/test/sanitizer_common/TestCases/suffix-log-path_test.c b/compiler-rt/test/sanitizer_common/TestCases/suffix-log-path_test.c
index 8e13105..bf0e4e1 100644
--- a/compiler-rt/test/sanitizer_common/TestCases/suffix-log-path_test.c
+++ b/compiler-rt/test/sanitizer_common/TestCases/suffix-log-path_test.c
@@ -1,12 +1,13 @@
-// RUN: %clang %s -o %T/suffix-log-path_test-binary
+// RUN: rm -rf %t.dir
+// RUN: mkdir -p %t.dir
+// RUN: %clang %s -o %t.dir/suffix-log-path_test-binary
// The glob below requires bash.
// REQUIRES: shell
// Good log_path with suffix.
-// RUN: rm -f %T/sanitizer.log.*.txt
-// RUN: %env_tool_opts=log_path=%T/sanitizer.log:log_exe_name=1:log_suffix=.txt %run %T/suffix-log-path_test-binary 2> %t.out
-// RUN: FileCheck %s < %T/sanitizer.log.suffix-log-path_test-binary.*.txt
+// RUN: %env_tool_opts=log_path=%t.dir/sanitizer.log:log_exe_name=1:log_suffix=.txt %run %t.dir/suffix-log-path_test-binary 2> %t.out
+// RUN: FileCheck %s < %t.dir/sanitizer.log.suffix-log-path_test-binary.*.txt
// UNSUPPORTED: ios, android
diff --git a/compiler-rt/test/xray/TestCases/Posix/fdr-mode-inmemory.cpp b/compiler-rt/test/xray/TestCases/Posix/fdr-mode-inmemory.cpp
index 4a866e2..6c94dbd 100644
--- a/compiler-rt/test/xray/TestCases/Posix/fdr-mode-inmemory.cpp
+++ b/compiler-rt/test/xray/TestCases/Posix/fdr-mode-inmemory.cpp
@@ -1,12 +1,14 @@
// RUN: %clangxx_xray -g -std=c++11 %s -o %t -fxray-modes=xray-fdr
-// RUN: rm -f fdr-inmemory-test-*
+// RUN: rm -rf %t.dir
+// RUN: mkdir -p %t.dir
+// RUN: cd %t.dir
// RUN: XRAY_OPTIONS="patch_premain=false xray_logfile_base=fdr-inmemory-test- \
// RUN: verbosity=1" \
// RUN: XRAY_FDR_OPTIONS="no_file_flush=true func_duration_threshold_us=0" \
// RUN: %run %t 2>&1 | FileCheck %s
-// RUN: FILES=`find %T -name 'fdr-inmemory-test-*' | wc -l`
+// RUN: FILES=`find %t.dir -name 'fdr-inmemory-test-*' | wc -l`
// RUN: [ $FILES -eq 0 ]
-// RUN: rm -f fdr-inmemory-test-*
+// RUN: rm -rf %t.dir
//
// REQUIRES: built-in-llvm-tree
diff --git a/compiler-rt/test/xray/TestCases/Posix/fdr-mode-multiple.cpp b/compiler-rt/test/xray/TestCases/Posix/fdr-mode-multiple.cpp
index b0411a2..f9288d9 100644
--- a/compiler-rt/test/xray/TestCases/Posix/fdr-mode-multiple.cpp
+++ b/compiler-rt/test/xray/TestCases/Posix/fdr-mode-multiple.cpp
@@ -1,12 +1,14 @@
// RUN: %clangxx_xray -g -std=c++11 %s -o %t -fxray-modes=xray-fdr
-// RUN: rm -f fdr-inmemory-test-*
+// RUN: rm -rf %t.dir
+// RUN: mkdir -p %t.dir
+// RUN: cd %t.dir
// RUN: XRAY_OPTIONS="patch_premain=false xray_logfile_base=fdr-inmemory-test- \
// RUN: verbosity=1" \
// RUN: XRAY_FDR_OPTIONS="no_file_flush=true func_duration_threshold_us=0" \
// RUN: %run %t 2>&1 | FileCheck %s
-// RUN: FILES=`find %T -name 'fdr-inmemory-test-*' | wc -l`
+// RUN: FILES=`find %t.dir -name 'fdr-inmemory-test-*' | wc -l`
// RUN: [ $FILES -eq 0 ]
-// RUN: rm -f fdr-inmemory-test-*
+// RUN: rm -rf %t.dir
//
// REQUIRES: built-in-llvm-tree