[scudo] Ensure that reallocate copies everything
getUsableSize returns the actual capacity of the underlying block, which may be larger than the size originally requested by the user. If the user writes data into this extra space accessible via getUsableSize and subsequently calls reallocate, the existing implementation only copies the original requested number of bytes. This resulted in data loss for any information stored beyond the requested size but within the usable bounds.
This commit is contained in:
parent
33ca7a4667
commit
7c4b6dee74
@ -614,16 +614,13 @@ public:
|
||||
|
||||
void *BlockBegin = getBlockBegin(OldTaggedPtr, &Header);
|
||||
uptr BlockEnd;
|
||||
uptr OldSize;
|
||||
uptr OldSize = getUsableSize(OldTaggedPtr, &Header);
|
||||
const uptr ClassId = Header.ClassId;
|
||||
if (LIKELY(ClassId)) {
|
||||
BlockEnd = reinterpret_cast<uptr>(BlockBegin) +
|
||||
SizeClassMap::getSizeByClassId(ClassId);
|
||||
OldSize = Header.SizeOrUnusedBytes;
|
||||
} else {
|
||||
BlockEnd = SecondaryT::getBlockEnd(BlockBegin);
|
||||
OldSize = BlockEnd - (reinterpret_cast<uptr>(OldTaggedPtr) +
|
||||
Header.SizeOrUnusedBytes);
|
||||
}
|
||||
// If the new chunk still fits in the previously allocated block (with a
|
||||
// reasonable delta), we just keep the old block, and update the chunk
|
||||
|
||||
@ -1471,6 +1471,30 @@ TEST(ScudoCombinedTest, FullUsableSize) {
|
||||
VerifyIterateOverUsableSize<AllocatorT>(*Allocator);
|
||||
}
|
||||
|
||||
TEST(ScudoCombinedTest, ReallocUsableSize) {
|
||||
using AllocatorT = TestAllocator<TestFullUsableSizeConfig>;
|
||||
auto Allocator = std::unique_ptr<AllocatorT>(new AllocatorT());
|
||||
|
||||
scudo::uptr Size = 1000;
|
||||
void *P = Allocator->allocate(Size, Origin);
|
||||
scudo::uptr UsableSize = Allocator->getUsableSize(P);
|
||||
std::vector<unsigned char> Buffer(UsableSize);
|
||||
for (size_t I = 0; I < UsableSize; I++) {
|
||||
Buffer[I] = I & 0xff;
|
||||
}
|
||||
memcpy(P, Buffer.data(), UsableSize);
|
||||
EXPECT_LE(Size, UsableSize);
|
||||
|
||||
scudo::uptr NewSize = 2 * UsableSize;
|
||||
void *NewP = Allocator->reallocate(P, NewSize);
|
||||
EXPECT_NE(NewP, P);
|
||||
for (size_t I = 0; I < UsableSize; I++) {
|
||||
EXPECT_EQ((reinterpret_cast<unsigned char *>(NewP))[I], I & 0xff)
|
||||
<< "Failed at index " << I;
|
||||
}
|
||||
Allocator->deallocate(NewP, Origin);
|
||||
}
|
||||
|
||||
struct TestFullUsableSizeMTEConfig : TestFullUsableSizeConfig {
|
||||
static const bool MaySupportMemoryTagging = true;
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user