8297718: Make NMT free:ing protocol more granular

Reviewed-by: stuefe, gziemski
This commit is contained in:
Johan Sjölen 2022-12-08 12:32:59 +00:00
parent fbe7b00738
commit 165dcdd27d
7 changed files with 72 additions and 25 deletions

View file

@ -62,6 +62,7 @@
#include "runtime/vm_version.hpp"
#include "services/attachListener.hpp"
#include "services/mallocTracker.hpp"
#include "services/mallocHeader.inline.hpp"
#include "services/memTracker.hpp"
#include "services/nmtPreInit.hpp"
#include "services/nmtCommon.hpp"
@ -714,30 +715,31 @@ void* os::realloc(void *memblock, size_t size, MEMFLAGS memflags, const NativeCa
return NULL;
}
const size_t old_size = MallocTracker::malloc_header(memblock)->size();
// De-account the old block from NMT *before* calling the real realloc(3) since it
// may invalidate old block including its header. This will also perform integrity checks
// on the old block (e.g. overwriters) and mark the old header as dead.
void* const old_outer_ptr = MemTracker::record_free(memblock);
// Perform integrity checks on and mark the old block as dead *before* calling the real realloc(3) since it
// may invalidate the old block, including its header.
MallocHeader* header = MallocTracker::malloc_header(memblock);
header->assert_block_integrity(); // Assert block hasn't been tampered with.
const MallocHeader::FreeInfo free_info = header->free_info();
header->mark_block_as_dead();
// the real realloc
ALLOW_C_FUNCTION(::realloc, void* const new_outer_ptr = ::realloc(old_outer_ptr, new_outer_size);)
ALLOW_C_FUNCTION(::realloc, void* const new_outer_ptr = ::realloc(header, new_outer_size);)
if (new_outer_ptr == NULL) {
// If realloc(3) failed, the old block still exists. We must re-instantiate the old
// NMT header then, since we marked it dead already. Otherwise subsequent os::realloc()
// or os::free() calls would trigger block integrity asserts.
void* p = MemTracker::record_malloc(old_outer_ptr, old_size, memflags, stack);
assert(p == memblock, "sanity");
return NULL;
// realloc(3) failed and the block still exists.
// We have however marked it as dead, revert this change.
header->revive();
return nullptr;
}
// realloc(3) succeeded, variable header now points to invalid memory and we need to deaccount the old block.
MemTracker::deaccount(free_info);
// After a successful realloc(3), we re-account the resized block with its new size
// to NMT. This re-instantiates the NMT header.
// After a successful realloc(3), we account the resized block with its new size
// to NMT.
void* const new_inner_ptr = MemTracker::record_malloc(new_outer_ptr, size, memflags, stack);
#ifdef ASSERT
size_t old_size = free_info.size;
if (old_size < size) {
// We also zap the newly extended region.
::memset((char*)new_inner_ptr + old_size, uninitBlockPad, size - old_size);
@ -774,7 +776,7 @@ void os::free(void *memblock) {
DEBUG_ONLY(break_if_ptr_caught(memblock);)
// If NMT is enabled, this checks for heap overwrites, then de-accounts the old block.
// When NMT is enabled this checks for heap overwrites, then deaccounts the old block.
void* const old_outer_ptr = MemTracker::record_free(memblock);
ALLOW_C_FUNCTION(::free, ::free(old_outer_ptr);)