Merge pull request #4880 from David-cmrg/fix/libc-mspace-realloc-usable
fix(libc): keep a moved mspace block's usable bytes in realloc
This commit is contained in:
commit
495bf91a04
|
|
@ -22,7 +22,6 @@ constexpr std::uintptr_t ArenaHeaderBytes = 64;
|
|||
struct Chunk {
|
||||
std::uintptr_t end;
|
||||
bool used;
|
||||
std::size_t requested;
|
||||
};
|
||||
|
||||
struct Arena {
|
||||
|
|
@ -51,7 +50,7 @@ Arena* Find(void* handle) {
|
|||
}
|
||||
|
||||
void AddFree(Arena& arena, std::uintptr_t start, std::uintptr_t end) {
|
||||
arena.chunks[start] = {end, false, 0};
|
||||
arena.chunks[start] = {end, false};
|
||||
arena.free.emplace(end - start, start);
|
||||
}
|
||||
|
||||
|
|
@ -78,7 +77,7 @@ void* Allocate(Arena* arena, std::size_t size, std::size_t alignment) {
|
|||
if (aligned > start) AddFree(*arena, start, aligned);
|
||||
const auto finish = aligned + needed;
|
||||
if (finish < end) AddFree(*arena, finish, end);
|
||||
arena->chunks[aligned] = {finish, true, size};
|
||||
arena->chunks[aligned] = {finish, true};
|
||||
arena->inUse += needed;
|
||||
arena->peakInUse = std::max(arena->peakInUse, arena->inUse);
|
||||
return reinterpret_cast<void*>(aligned);
|
||||
|
|
@ -220,10 +219,7 @@ void* APS5_VABI sceLibcMspaceRealloc_nid_postfix(void* handle, void* pointer, st
|
|||
if (needed < size) { Error(12); return nullptr; }
|
||||
const auto start = chunk->first;
|
||||
const auto capacity = chunk->second.end - start;
|
||||
if (needed <= capacity) {
|
||||
chunk->second.requested = size;
|
||||
return pointer;
|
||||
}
|
||||
if (needed <= capacity) return pointer;
|
||||
const auto next = std::next(chunk);
|
||||
if (next != arena->chunks.end() && !next->second.used && next->first == chunk->second.end && next->second.end - start >= needed) {
|
||||
const auto nextEnd = next->second.end;
|
||||
|
|
@ -233,13 +229,12 @@ void* APS5_VABI sceLibcMspaceRealloc_nid_postfix(void* handle, void* pointer, st
|
|||
if (finish < nextEnd) AddFree(*arena, finish, nextEnd);
|
||||
arena->inUse += needed - capacity;
|
||||
arena->peakInUse = std::max(arena->peakInUse, arena->inUse);
|
||||
arena->chunks[start] = {finish, true, size};
|
||||
arena->chunks[start] = {finish, true};
|
||||
return pointer;
|
||||
}
|
||||
const auto previousSize = chunk->second.requested;
|
||||
void* result = Allocate(arena, size, Granule);
|
||||
if (result) {
|
||||
std::memcpy(result, pointer, previousSize);
|
||||
std::memcpy(result, pointer, std::min<std::size_t>(capacity, size));
|
||||
Release(*arena, arena->chunks.find(start));
|
||||
}
|
||||
return result;
|
||||
|
|
@ -281,14 +276,11 @@ void* APS5_VABI sceLibcMspaceReallocalign_nid_postfix(void* handle, void* pointe
|
|||
const auto needed = AlignUp(size, Granule);
|
||||
if (needed < size) { Error(12); return nullptr; }
|
||||
const auto start = chunk->first;
|
||||
if (needed <= chunk->second.end - start && (start & (effective - 1)) == 0) {
|
||||
chunk->second.requested = size;
|
||||
return pointer;
|
||||
}
|
||||
const auto previousSize = chunk->second.requested;
|
||||
const auto capacity = chunk->second.end - start;
|
||||
if (needed <= capacity && (start & (effective - 1)) == 0) return pointer;
|
||||
void* result = Allocate(arena, size, effective);
|
||||
if (result) {
|
||||
std::memcpy(result, pointer, std::min(previousSize, size));
|
||||
std::memcpy(result, pointer, std::min<std::size_t>(capacity, size));
|
||||
Release(*arena, arena->chunks.find(start));
|
||||
}
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -79,9 +79,36 @@ static void CheckAdjacentBlocks() {
|
|||
Require(stats.currentInuseSize == static_cast<std::size_t>(end(after) - static_cast<unsigned char*>(blocks[0])));
|
||||
Require(sceLibcMspaceDestroy_nid_postfix(arena) == 0);
|
||||
}
|
||||
static void CheckMovedBlockKeepsUsableBytes() {
|
||||
alignas(32) static std::array<unsigned char, 65536> storage{};
|
||||
void* arena = sceLibcMspaceCreate_nid_postfix("moved", storage.data(), storage.size(), 0);
|
||||
Require(arena != nullptr);
|
||||
const auto fill = [](void* block) {
|
||||
const auto usable = sceLibcMspaceMallocUsableSize_nid_postfix(block);
|
||||
Require(usable > 1);
|
||||
for (std::size_t index = 0; index < usable; ++index) static_cast<unsigned char*>(block)[index] = static_cast<unsigned char>(index + 1);
|
||||
return usable;
|
||||
};
|
||||
const auto kept = [](const void* block, std::size_t usable) {
|
||||
for (std::size_t index = 0; index < usable; ++index) if (static_cast<const unsigned char*>(block)[index] != static_cast<unsigned char>(index + 1)) return false;
|
||||
return true;
|
||||
};
|
||||
void* block = sceLibcMspaceMalloc_nid_postfix(arena, 1);
|
||||
const auto usable = fill(block);
|
||||
Require(sceLibcMspaceMalloc_nid_postfix(arena, 1) != nullptr);
|
||||
void* moved = sceLibcMspaceRealloc_nid_postfix(arena, block, 4096);
|
||||
Require(moved != nullptr && moved != block && kept(moved, usable));
|
||||
void* other = sceLibcMspaceMalloc_nid_postfix(arena, 1);
|
||||
const auto otherUsable = fill(other);
|
||||
Require(sceLibcMspaceMalloc_nid_postfix(arena, 1) != nullptr);
|
||||
void* realigned = sceLibcMspaceReallocalign_nid_postfix(arena, other, 4096, 256);
|
||||
Require(realigned != nullptr && realigned != other && kept(realigned, otherUsable));
|
||||
Require(sceLibcMspaceDestroy_nid_postfix(arena) == 0);
|
||||
}
|
||||
int main() {
|
||||
CheckAlignment();
|
||||
CheckAdjacentBlocks();
|
||||
CheckMovedBlockKeepsUsableBytes();
|
||||
alignas(16) std::array<unsigned char, 65536> storage{};
|
||||
void* arena = sceLibcMspaceCreate_nid_postfix("test", storage.data(), storage.size(), 0);
|
||||
Require(arena != nullptr);
|
||||
|
|
|
|||
Loading…
Reference in New Issue