[scudo] Create a non-static getErrorInfo function.#199770
Open
cferris1000 wants to merge 1 commit into
Open
Conversation
Create a getErrorInfo function that operates on the Allocator and doesn't require passing in all of the extra information. Add interface function __scudo_get_fault_error_info that calls this new function. Add all needed functions to support the new getErrorInfo. This is being added to replace the static version from Android that required linking in a copy of libscudo to use. This new version will be used directly from libc.
|
@llvm/pr-subscribers-compiler-rt-sanitizer Author: Christopher Ferris (cferris1000) ChangesCreate a getErrorInfo function that operates on the Allocator and doesn't require passing in all of the extra information. Add interface function __scudo_get_fault_error_info that calls this new function. Add all needed functions to support the new getErrorInfo. This is being added to replace the static version from Android that required linking in a copy of libscudo to use. This new version will be used directly from libc. Patch is 21.21 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/199770.diff 9 Files Affected:
diff --git a/compiler-rt/lib/scudo/standalone/combined.h b/compiler-rt/lib/scudo/standalone/combined.h
index 72b4b361475b2..b37ff23343946 100644
--- a/compiler-rt/lib/scudo/standalone/combined.h
+++ b/compiler-rt/lib/scudo/standalone/combined.h
@@ -988,6 +988,186 @@ class Allocator {
: 0;
}
+ void getErrorInfo(uptr FaultAddr, size_t MinDistance, size_t MaxDistance,
+ scudo_error_report *Reports, size_t &ReportIndex) {
+ auto *RingBuffer = getRingBuffer();
+ if (RingBuffer == nullptr)
+ return;
+
+ // No more room for any more error reports.
+ if (ReportIndex == NumErrorReports)
+ return;
+
+ uptr UntaggedFaultAddr = untagPointer(FaultAddr);
+ BlockInfo Info = Primary.findNearestBlock(UntaggedFaultAddr);
+
+ auto GetBlockInfo = [&](uptr Addr, Chunk::UnpackedHeader *Header,
+ uptr &ChunkAddr) {
+ uptr ChunkOffset = getChunkOffsetFromBlock(
+ reinterpret_cast<const char *>(loadTagUnaligned(Addr)));
+ ChunkAddr = loadTagUnaligned(Addr + ChunkOffset);
+ uptr HeaderAddr = loadTag(Addr + ChunkOffset - Chunk::getHeaderSize());
+ *Header = *reinterpret_cast<const Chunk::UnpackedHeader *>(HeaderAddr);
+ };
+
+ auto CheckOOB = [&](uptr BlockAddr) {
+ if (BlockAddr < Info.RegionBegin || BlockAddr >= Info.RegionEnd)
+ return false;
+
+ uptr ChunkAddr;
+ Chunk::UnpackedHeader Header;
+ GetBlockInfo(BlockAddr, &Header, ChunkAddr);
+ if (Header.State != Chunk::State::Allocated)
+ return false;
+ const u8 ChunkTag = extractTag(ChunkAddr);
+ if (extractTag(FaultAddr) != ChunkTag) {
+ // If the allocated size is zero, then there isn't a tag on this
+ // pointer, so allow a tag mismatch.
+ if (ChunkTag != 0 || Header.SizeOrUnusedBytes != 0)
+ return false;
+ }
+ auto *Report = &Reports[ReportIndex++];
+ uptr UntaggedChunkAddr = untagPointer(ChunkAddr);
+ const u32 *ChunkData = reinterpret_cast<const u32 *>(UntaggedChunkAddr);
+ Report->error_type = UntaggedFaultAddr < UntaggedChunkAddr
+ ? BUFFER_UNDERFLOW
+ : BUFFER_OVERFLOW;
+ Report->allocation_address = UntaggedChunkAddr;
+ Report->allocation_size = Header.SizeOrUnusedBytes;
+ if (RingBuffer->Depot) {
+ const u32 *TracePtr = reinterpret_cast<const u32 *>(loadTagUnaligned(
+ reinterpret_cast<uptr>(&ChunkData[MemTagAllocationTraceIndex])));
+ collectTraceMaybe(RingBuffer->Depot, Report->allocation_trace,
+ *TracePtr);
+ }
+ const u32 *TidPtr = reinterpret_cast<const u32 *>(loadTagUnaligned(
+ reinterpret_cast<uptr>(&ChunkData[MemTagAllocationTidIndex])));
+ Report->allocation_tid = *TidPtr;
+ return ReportIndex == NumErrorReports;
+ };
+
+ if (MinDistance == 0 && CheckOOB(Info.BlockBegin))
+ return;
+
+ for (size_t I = Max<size_t>(MinDistance, 1); I != MaxDistance; ++I)
+ if (CheckOOB(Info.BlockBegin + I * Info.BlockSize) ||
+ CheckOOB(Info.BlockBegin - I * Info.BlockSize))
+ return;
+ }
+
+ void getRingBufferErrorInfo(uintptr_t FaultAddr, scudo_error_report *Reports,
+ size_t &ReportIndex) {
+ auto *RingBuffer = getRingBuffer();
+ if (RingBuffer == nullptr)
+ return;
+
+ // No more room for any more error reports.
+ if (ReportIndex == NumErrorReports)
+ return;
+
+ uptr Pos = atomic_load_relaxed(&RingBuffer->Pos);
+ if (Pos == 0)
+ return;
+
+ const uptr RingBufferElements = RingBuffer->RingBufferElements;
+
+ // Pos is a value that is always increasing.
+ uptr LastPos;
+ if (Pos < RingBufferElements) {
+ LastPos = 0;
+ } else {
+ LastPos = Pos - RingBufferElements;
+ }
+ for (uptr I = Pos; I > LastPos; --I) {
+ auto *Entry =
+ getRingBufferEntry(RingBuffer, (I - 1) % RingBufferElements);
+ uptr EntryPtr = atomic_load_relaxed(&Entry->Ptr);
+ if (!EntryPtr)
+ continue;
+
+ uptr UntaggedEntryPtr = untagPointer(EntryPtr);
+ uptr EntrySize = atomic_load_relaxed(&Entry->AllocationSize);
+ u32 AllocationTrace = atomic_load_relaxed(&Entry->AllocationTrace);
+ u32 AllocationTid = atomic_load_relaxed(&Entry->AllocationTid);
+ u32 DeallocationTrace = atomic_load_relaxed(&Entry->DeallocationTrace);
+ u32 DeallocationTid = atomic_load_relaxed(&Entry->DeallocationTid);
+ if (DeallocationTid) {
+ // For UAF we only consider in-bounds fault addresses because
+ // out-of-bounds UAF is rare and attempting to detect it is very likely
+ // to result in false positives.
+ if (FaultAddr < EntryPtr || FaultAddr >= EntryPtr + EntrySize)
+ continue;
+ } else {
+ // Ring buffer OOB is only possible with secondary allocations. In this
+ // case we are guaranteed a guard region of at least a page on either
+ // side of the allocation (guard page on the right, guard page + tagged
+ // region on the left), so ignore any faults outside of that range.
+ if (FaultAddr < EntryPtr - getPageSizeCached() ||
+ FaultAddr >= EntryPtr + EntrySize + getPageSizeCached())
+ continue;
+
+ // For UAF the ring buffer will contain two entries, one for the
+ // allocation and another for the deallocation. Don't report buffer
+ // overflow/underflow using the allocation entry if we have already
+ // collected a report from the deallocation entry.
+ bool Found = false;
+ for (uptr J = 0; J != ReportIndex; ++J) {
+ if (Reports[J].allocation_address == UntaggedEntryPtr) {
+ Found = true;
+ break;
+ }
+ }
+ if (Found)
+ continue;
+ }
+
+ auto *Report = &Reports[ReportIndex++];
+ if (DeallocationTid)
+ Report->error_type = USE_AFTER_FREE;
+ else if (FaultAddr < EntryPtr)
+ Report->error_type = BUFFER_UNDERFLOW;
+ else
+ Report->error_type = BUFFER_OVERFLOW;
+
+ Report->allocation_address = UntaggedEntryPtr;
+ Report->allocation_size = EntrySize;
+ collectTraceMaybe(RingBuffer->Depot, Report->allocation_trace,
+ AllocationTrace);
+ Report->allocation_tid = AllocationTid;
+ collectTraceMaybe(RingBuffer->Depot, Report->deallocation_trace,
+ DeallocationTrace);
+ Report->deallocation_tid = DeallocationTid;
+ if (ReportIndex == NumErrorReports) {
+ // No more report entries.
+ return;
+ }
+ }
+ }
+
+ void getErrorInfo(uintptr_t FaultAddr, struct scudo_error_info *ErrorInfo) {
+ const Options Options = Primary.Options.load();
+ if (!useMemoryTagging<AllocatorConfig>(Options))
+ return;
+
+ bool TagExists = extractTag(FaultAddr) != 0;
+ size_t ReportIndex = 0;
+ if (TagExists) {
+ // Check for OOB in the current block and the two surrounding blocks.
+ // Beyond that, UAF is more likely.
+ getErrorInfo(FaultAddr, 0, 2, &ErrorInfo->reports[0], ReportIndex);
+ }
+
+ // Check the ring buffer. For primary allocations this will only find UAF;
+ // for secondary allocations we can find either UAF or OOB.
+ getRingBufferErrorInfo(FaultAddr, &ErrorInfo->reports[0], ReportIndex);
+
+ if (TagExists) {
+ // Check for OOB in the 28 blocks surrounding the 3 we checked earlier.
+ // Beyond that we are likely to hit false positives.
+ getErrorInfo(FaultAddr, 2, 16, &ErrorInfo->reports[0], ReportIndex);
+ }
+ }
+
static const uptr MaxTraceSize = 64;
static void collectTraceMaybe(const StackDepot *Depot,
diff --git a/compiler-rt/lib/scudo/standalone/include/scudo/interface.h b/compiler-rt/lib/scudo/standalone/include/scudo/interface.h
index 9f2b93891999d..cf804594c677f 100644
--- a/compiler-rt/lib/scudo/standalone/include/scudo/interface.h
+++ b/compiler-rt/lib/scudo/standalone/include/scudo/interface.h
@@ -123,6 +123,9 @@ size_t __scudo_get_region_info_size(void);
const char *__scudo_get_ring_buffer_addr(void);
size_t __scudo_get_ring_buffer_size(void);
+void __scudo_get_fault_error_info(uintptr_t fault_addr,
+ struct scudo_error_info *error_info);
+
#ifndef M_DECAY_TIME
#define M_DECAY_TIME -100
#endif
diff --git a/compiler-rt/lib/scudo/standalone/memtag.h b/compiler-rt/lib/scudo/standalone/memtag.h
index 073e72c46f68a..653745f3d6147 100644
--- a/compiler-rt/lib/scudo/standalone/memtag.h
+++ b/compiler-rt/lib/scudo/standalone/memtag.h
@@ -259,6 +259,11 @@ inline uptr loadTag(uptr Ptr) {
return TaggedPtr;
}
+inline uptr loadTagUnaligned(uptr Ptr) {
+ uptr AlignedPtr = Ptr & ~static_cast<uptr>(0xF);
+ return loadTag(AlignedPtr) | (Ptr & 0xF);
+}
+
#else
inline constexpr bool systemSupportsMemoryTagging() { return false; }
@@ -303,6 +308,11 @@ inline NORETURN uptr loadTag(uptr Ptr) {
UNREACHABLE("memory tagging not supported");
}
+inline uptr loadTagUnaligned(uptr Ptr) {
+ (void)Ptr;
+ UNREACHABLE("memory tagging not supported");
+}
+
#endif
#pragma GCC diagnostic push
diff --git a/compiler-rt/lib/scudo/standalone/primary32.h b/compiler-rt/lib/scudo/standalone/primary32.h
index 5720c9f308dac..c3705a2b474eb 100644
--- a/compiler-rt/lib/scudo/standalone/primary32.h
+++ b/compiler-rt/lib/scudo/standalone/primary32.h
@@ -134,6 +134,9 @@ template <typename Config> class SizeClassAllocator32 {
const char *getRegionInfoArrayAddress() const { return nullptr; }
static uptr getRegionInfoArraySize() { return 0; }
+ // Not supported in SizeClassAllocator32.
+ BlockInfo findNearestBlock(UNUSED uptr Ptr) { return {}; }
+
// Not supported in SizeClassAllocator32.
static BlockInfo findNearestBlock(UNUSED const char *RegionInfoData,
UNUSED uptr Ptr) {
diff --git a/compiler-rt/lib/scudo/standalone/primary64.h b/compiler-rt/lib/scudo/standalone/primary64.h
index 6ee56d6c99291..2c3ccdf028530 100644
--- a/compiler-rt/lib/scudo/standalone/primary64.h
+++ b/compiler-rt/lib/scudo/standalone/primary64.h
@@ -93,6 +93,8 @@ template <typename Config> class SizeClassAllocator64 {
static BlockInfo findNearestBlock(const char *RegionInfoData,
uptr Ptr) NO_THREAD_SAFETY_ANALYSIS;
+ BlockInfo findNearestBlock(uptr Ptr);
+
void init(s32 ReleaseToOsInterval) NO_THREAD_SAFETY_ANALYSIS;
void unmapTestOnly();
@@ -1350,6 +1352,57 @@ uptr SizeClassAllocator64<Config>::releaseToOS(ReleaseToOS ReleaseType) {
return TotalReleasedBytes;
}
+template <typename Config>
+BlockInfo SizeClassAllocator64<Config>::findNearestBlock(uptr Ptr)
+ NO_THREAD_SAFETY_ANALYSIS {
+ uptr ClassId;
+ uptr MinDistance = -1UL;
+ for (uptr I = 0; I != NumClasses; ++I) {
+ if (I == SizeClassMap::BatchClassId)
+ continue;
+
+ ScopedLock ML(RegionInfoArray[I].MMLock);
+ uptr Begin = RegionInfoArray[I].RegionBeg;
+ uptr End = Begin + RegionInfoArray[I].MemMapInfo.AllocatedUser;
+ if (Begin > End || End - Begin < SizeClassMap::getSizeByClassId(I))
+ continue;
+ uptr RegionDistance;
+ if (Begin <= Ptr) {
+ if (Ptr < End)
+ RegionDistance = 0;
+ else
+ RegionDistance = Ptr - End;
+ } else {
+ RegionDistance = Begin - Ptr;
+ }
+
+ if (RegionDistance < MinDistance) {
+ MinDistance = RegionDistance;
+ ClassId = I;
+ if (RegionDistance == 0)
+ break;
+ }
+ }
+
+ if (MinDistance > 8192) {
+ return {};
+ }
+
+ ScopedLock ML(RegionInfoArray[ClassId].MMLock);
+ BlockInfo B = {};
+ B.RegionBegin = RegionInfoArray[ClassId].RegionBeg;
+ B.RegionEnd =
+ B.RegionBegin + RegionInfoArray[ClassId].MemMapInfo.AllocatedUser;
+ B.BlockSize = SizeClassMap::getSizeByClassId(ClassId);
+ B.BlockBegin = B.RegionBegin + uptr(sptr(Ptr - B.RegionBegin) /
+ sptr(B.BlockSize) * sptr(B.BlockSize));
+ while (B.BlockBegin < B.RegionBegin)
+ B.BlockBegin += B.BlockSize;
+ while (B.RegionEnd < B.BlockBegin + B.BlockSize)
+ B.BlockBegin -= B.BlockSize;
+ return B;
+}
+
template <typename Config>
/* static */ BlockInfo SizeClassAllocator64<Config>::findNearestBlock(
const char *RegionInfoData, uptr Ptr) NO_THREAD_SAFETY_ANALYSIS {
diff --git a/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt b/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt
index a85eb737dba0a..68ffc16bce780 100644
--- a/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt
+++ b/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt
@@ -93,6 +93,7 @@ set(SCUDO_UNIT_TEST_SOURCES
combined_test.cpp
common_test.cpp
condition_variable_test.cpp
+ error_info_test.cpp
flags_test.cpp
list_test.cpp
map_test.cpp
diff --git a/compiler-rt/lib/scudo/standalone/tests/error_info_test.cpp b/compiler-rt/lib/scudo/standalone/tests/error_info_test.cpp
new file mode 100644
index 0000000000000..d8d4dc4c027bc
--- /dev/null
+++ b/compiler-rt/lib/scudo/standalone/tests/error_info_test.cpp
@@ -0,0 +1,160 @@
+//===-- error_info_test.cpp -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "allocator_config.h"
+#include "combined.h"
+#include "memtag.h"
+#include "tests/scudo_unit_test.h"
+#include <stdlib.h>
+
+namespace scudo {
+
+template <typename Config> struct TestAllocator : Allocator<Config> {
+ TestAllocator() { this->initThreadMaybe(); }
+ ~TestAllocator() { this->unmapTestOnly(); }
+};
+
+template <class TypeParam> struct ScudoErrorInfoTest : public Test {
+ ScudoErrorInfoTest() {
+ setenv("SCUDO_OPTIONS", "allocation_ring_buffer_size=32768", 1);
+ Allocator = std::make_unique<AllocatorT>();
+ Allocator->setTrackAllocationStacks(true);
+ }
+
+ ~ScudoErrorInfoTest() {
+ Allocator->releaseToOS(scudo::ReleaseToOS::Force);
+ unsetenv("SCUDO_OPTIONS");
+ }
+
+ using AllocatorT = TestAllocator<TypeParam>;
+ std::unique_ptr<AllocatorT> Allocator;
+};
+
+struct TestConfig : public scudo::DefaultConfig {
+ static const bool MaySupportMemoryTagging = true;
+};
+
+using ScudoErrorInfoTestTypes = ::testing::Types<TestConfig>;
+TYPED_TEST_SUITE(ScudoErrorInfoTest, ScudoErrorInfoTestTypes);
+
+TYPED_TEST(ScudoErrorInfoTest, RingBufferErrorInfo) {
+ auto *Allocator = this->Allocator.get();
+ if (!scudo::archSupportsMemoryTagging() ||
+ !Allocator->useMemoryTaggingTestOnly()) {
+ GTEST_SKIP() << "MTE not supported or enabled";
+ }
+
+ EXPECT_GT(Allocator->getRingBufferSize(), 0u);
+ EXPECT_NE(nullptr, Allocator->getRingBufferAddress());
+
+ const scudo::uptr Size = 64U;
+ void *P = nullptr;
+ P = Allocator->allocate(Size, Chunk::Origin::Malloc);
+ ASSERT_NE(P, nullptr);
+ Allocator->deallocate(P, Chunk::Origin::Malloc);
+
+ scudo::uptr Ptr = reinterpret_cast<scudo::uptr>(P);
+
+ scudo_error_info ErrorInfo = {};
+ size_t ReportIndex = 0;
+ Allocator->getRingBufferErrorInfo(Ptr, &ErrorInfo.reports[0], ReportIndex);
+
+ EXPECT_EQ(ReportIndex, 1U);
+ EXPECT_EQ(ErrorInfo.reports[0].error_type, USE_AFTER_FREE);
+ EXPECT_EQ(ErrorInfo.reports[0].allocation_address, scudo::untagPointer(Ptr));
+ EXPECT_EQ(ErrorInfo.reports[0].allocation_size, Size);
+
+ // Now verify the ReportIndex is followed.
+ memset(&ErrorInfo, 0, sizeof(ErrorInfo));
+ Allocator->getRingBufferErrorInfo(Ptr, &ErrorInfo.reports[0], ReportIndex);
+ EXPECT_EQ(ReportIndex, 2U);
+ EXPECT_EQ(ErrorInfo.reports[0].error_type, UNKNOWN);
+ EXPECT_EQ(ErrorInfo.reports[1].error_type, USE_AFTER_FREE);
+ EXPECT_EQ(ErrorInfo.reports[1].allocation_address, scudo::untagPointer(Ptr));
+ EXPECT_EQ(ErrorInfo.reports[1].allocation_size, Size);
+
+ // Verify if at max, nothing happens.
+ ReportIndex = 3;
+ memset(&ErrorInfo, 0, sizeof(ErrorInfo));
+ Allocator->getRingBufferErrorInfo(Ptr, &ErrorInfo.reports[0], ReportIndex);
+ EXPECT_EQ(ReportIndex, 3U);
+ EXPECT_EQ(ErrorInfo.reports[0].error_type, UNKNOWN);
+ EXPECT_EQ(ErrorInfo.reports[1].error_type, UNKNOWN);
+ EXPECT_EQ(ErrorInfo.reports[2].error_type, UNKNOWN);
+}
+
+TYPED_TEST(ScudoErrorInfoTest, GetErrorInfoUAF) {
+ auto *Allocator = this->Allocator.get();
+ if (!scudo::archSupportsMemoryTagging() ||
+ !Allocator->useMemoryTaggingTestOnly()) {
+ GTEST_SKIP() << "MTE not supported or enabled";
+ }
+
+ const scudo::uptr Size = 64U;
+ void *P = Allocator->allocate(Size, Chunk::Origin::Malloc);
+ ASSERT_NE(P, nullptr);
+ Allocator->deallocate(P, Chunk::Origin::Malloc);
+
+ scudo::uptr Ptr = reinterpret_cast<scudo::uptr>(P);
+ scudo_error_info ErrorInfo = {};
+ Allocator->getErrorInfo(Ptr, &ErrorInfo);
+
+ EXPECT_EQ(ErrorInfo.reports[0].error_type, USE_AFTER_FREE);
+ EXPECT_EQ(ErrorInfo.reports[0].allocation_address, scudo::untagPointer(Ptr));
+ EXPECT_EQ(ErrorInfo.reports[0].allocation_size, Size);
+}
+
+TYPED_TEST(ScudoErrorInfoTest, GetErrorInfoOverflow) {
+ auto *Allocator = this->Allocator.get();
+ if (!scudo::archSupportsMemoryTagging() ||
+ !Allocator->useMemoryTaggingTestOnly()) {
+ GTEST_SKIP() << "MTE not supported or enabled";
+ }
+
+ const scudo::uptr Size = 64U;
+ void *P = Allocator->allocate(Size, Chunk::Origin::Malloc);
+ ASSERT_NE(P, nullptr);
+
+ scudo::uptr PtrAddr = reinterpret_cast<scudo::uptr>(P);
+ scudo::uptr FaultAddr = PtrAddr + Size;
+ scudo_error_info ErrorInfo = {};
+ Allocator->getErrorInfo(FaultAddr, &ErrorInfo);
+
+ EXPECT_EQ(ErrorInfo.reports[0].error_type, BUFFER_OVERFLOW);
+ EXPECT_EQ(ErrorInfo.reports[0].allocation_address,
+ scudo::untagPointer(PtrAddr));
+ EXPECT_EQ(ErrorInfo.reports[0].allocation_size, Size);
+
+ Allocator->deallocate(P, Chunk::Origin::Malloc);
+}
+
+TYPED_TEST(ScudoErrorInfoTest, GetErrorInfoUnderflow) {
+ auto *Allocator = this->Allocator.get();
+ if (!scudo::archSupportsMemoryTagging() ||
+ !Allocator->useMemoryTaggingTestOnly()) {
+ GTEST_SKIP() << "MTE not supported or enabled";
+ }
+
+ const scudo::uptr Size = 64U;
+ void *P = Allocator->allocate(Size, Chunk::Origin::Malloc);
+ ASSERT_NE(P, nullptr);
+
+ scudo::uptr PtrAddr = reinterpret_cast<scudo::uptr>(P);
+ scudo::uptr FaultAddr = PtrAddr - 1;
+ scudo_error_info ErrorInfo = {};
+ Allocator->getErrorInfo(FaultAddr, &ErrorInfo);
+
+ EXPECT_EQ(ErrorInfo.reports[0].error_type, BUFFER_UNDERFLOW);
+ EXPECT_EQ(ErrorInfo.reports[0].allocation_address,
+ scudo::untagPointer(PtrAddr));
+ EXPECT_EQ(ErrorInfo.reports[0].allocation_size, Size);
+
+ Allocator->deallocate(P, Chunk::Origin::Malloc);
+}
+
+} // namespace scudo
diff --git a/compiler-rt/lib/scudo/standalone/tests/primary_test.cpp b/compiler-rt/lib/scudo/standalone/tests/primary_test.cpp
index 3a087c497b1a9..2fbfadfbf6240 100644
--- a/compiler-rt/lib/scudo/standalone/tests/primary_test.cpp
+++ b/compiler-rt/lib/scudo/standalone/tests/primary_test.cpp
@@ -237,6 +237,37 @@ SCUDO_TYPED_TEST(ScudoPrimaryTest, BasicPrimary) {
}
}
+SCUDO_TYPED_TEST(ScudoPrimaryTest, FindNearestBlock) {
+ using Primary = TestAllocator<TypeParam, scudo::DefaultSizeClassMap>;
+ std::unique_ptr<Primary> Allocator(new Primary);
+ Allocator->init(/*ReleaseToOsInterval=*/-1);
+ typename Primary::SizeClassAllocatorT SizeClassAllocator;
+ SizeClassAllocator.init(nullptr, Allocator.get());
+
+ const scudo::uptr Size = 64U;
+ if (Primary::canAllocate(Size)) {
+ const scudo::uptr ClassId = Primary::SizeClassMap::getClassIdBySize(Size);
+ void *P = SizeClassAllocator.allocate(ClassId);
+ ASSERT_NE(P, nullptr);
+
+ scudo::uptr Ptr = reinterpret_cast<scudo::uptr>(P);
+ scudo::BlockInfo Info = Allocator->findNearestBlock(Ptr);
+
+ if (Info.BlockSize != 0) {
+ EXPECT_EQ(Info.BlockBegin, Ptr);
+ EXPECT_EQ(Info.BlockSize,
+ Primary::SizeClassMap::getSizeByClassId(ClassId));
+
+ scudo::BlockInfo Info2 = Allocator->findNearestBlock(Ptr + 10);
+ EXPECT_EQ(Info2.BlockBegin, Ptr);
+ }
+
+ SizeClassAllocator.deallocate(ClassId, P);
+ }
+
+ SizeClassAllocator.destroy(nullptr);
+}
+
struct SmallRegionsConfig {
...
[truncated]
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Create a getErrorInfo function that operates on the Allocator and doesn't require passing in all of the extra information.
Add interface function __scudo_get_fault_error_info that calls this new function.
Add all needed functions to support the new getErrorInfo.
This is being added to replace the static version from Android that required linking in a copy of libscudo to use. This new version will be used directly from libc.