mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-15 08:34:30 +02:00
6311046: -Xcheck:jni should support checking of GetPrimitiveArrayCritical
Wrapped memory with standard bounds checking "GuardedMemory". Reviewed-by: zgu, fparain, dcubed
This commit is contained in:
parent
d5b7b9ffe3
commit
6f97a45429
5 changed files with 671 additions and 191 deletions
161
hotspot/src/share/vm/memory/guardedMemory.cpp
Normal file
161
hotspot/src/share/vm/memory/guardedMemory.cpp
Normal file
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
#include "precompiled.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/guardedMemory.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
|
||||
void* GuardedMemory::wrap_copy(const void* ptr, const size_t len, const void* tag) {
|
||||
size_t total_sz = GuardedMemory::get_total_size(len);
|
||||
void* outerp = os::malloc(total_sz, mtInternal);
|
||||
if (outerp != NULL) {
|
||||
GuardedMemory guarded(outerp, len, tag);
|
||||
void* innerp = guarded.get_user_ptr();
|
||||
memcpy(innerp, ptr, len);
|
||||
return innerp;
|
||||
}
|
||||
return NULL; // OOM
|
||||
}
|
||||
|
||||
bool GuardedMemory::free_copy(void* p) {
|
||||
if (p == NULL) {
|
||||
return true;
|
||||
}
|
||||
GuardedMemory guarded((u_char*)p);
|
||||
bool verify_ok = guarded.verify_guards();
|
||||
|
||||
/* always attempt to free, pass problem on to any nested memchecker */
|
||||
os::free(guarded.release_for_freeing());
|
||||
|
||||
return verify_ok;
|
||||
}
|
||||
|
||||
void GuardedMemory::print_on(outputStream* st) const {
|
||||
if (_base_addr == NULL) {
|
||||
st->print_cr("GuardedMemory(" PTR_FORMAT ") not associated to any memory", p2i(this));
|
||||
return;
|
||||
}
|
||||
st->print_cr("GuardedMemory(" PTR_FORMAT ") base_addr=" PTR_FORMAT
|
||||
" tag=" PTR_FORMAT " user_size=" SIZE_FORMAT " user_data=" PTR_FORMAT,
|
||||
p2i(this), p2i(_base_addr), p2i(get_tag()), get_user_size(), p2i(get_user_ptr()));
|
||||
|
||||
Guard* guard = get_head_guard();
|
||||
st->print_cr(" Header guard @" PTR_FORMAT " is %s", p2i(guard), (guard->verify() ? "OK" : "BROKEN"));
|
||||
guard = get_tail_guard();
|
||||
st->print_cr(" Trailer guard @" PTR_FORMAT " is %s", p2i(guard), (guard->verify() ? "OK" : "BROKEN"));
|
||||
|
||||
u_char udata = *get_user_ptr();
|
||||
switch (udata) {
|
||||
case uninitBlockPad:
|
||||
st->print_cr(" User data appears unused");
|
||||
break;
|
||||
case freeBlockPad:
|
||||
st->print_cr(" User data appears to have been freed");
|
||||
break;
|
||||
default:
|
||||
st->print_cr(" User data appears to be in use");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// test code...
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
||||
static void guarded_memory_test_check(void* p, size_t sz, void* tag) {
|
||||
assert(p != NULL, "NULL pointer given to check");
|
||||
u_char* c = (u_char*) p;
|
||||
GuardedMemory guarded(c);
|
||||
assert(guarded.get_tag() == tag, "Tag is not the same as supplied");
|
||||
assert(guarded.get_user_ptr() == c, "User pointer is not the same as supplied");
|
||||
assert(guarded.get_user_size() == sz, "User size is not the same as supplied");
|
||||
assert(guarded.verify_guards(), "Guard broken");
|
||||
}
|
||||
|
||||
void GuardedMemory::test_guarded_memory() {
|
||||
// Test the basic characteristics...
|
||||
size_t total_sz = GuardedMemory::get_total_size(1);
|
||||
assert(total_sz > 1 && total_sz >= (sizeof(GuardHeader) + 1 + sizeof(Guard)), "Unexpected size");
|
||||
u_char* basep = (u_char*) os::malloc(total_sz, mtInternal);
|
||||
|
||||
GuardedMemory guarded(basep, 1, (void*)0xf000f000);
|
||||
|
||||
assert(*basep == badResourceValue, "Expected guard in the form of badResourceValue");
|
||||
u_char* userp = guarded.get_user_ptr();
|
||||
assert(*userp == uninitBlockPad, "Expected uninitialized data in the form of uninitBlockPad");
|
||||
guarded_memory_test_check(userp, 1, (void*)0xf000f000);
|
||||
|
||||
void* freep = guarded.release_for_freeing();
|
||||
assert((u_char*)freep == basep, "Expected the same pointer guard was ");
|
||||
assert(*userp == freeBlockPad, "Expected user data to be free block padded");
|
||||
assert(!guarded.verify_guards(), "Expected failed");
|
||||
os::free(freep);
|
||||
|
||||
// Test a number of odd sizes...
|
||||
size_t sz = 0;
|
||||
do {
|
||||
void* p = os::malloc(GuardedMemory::get_total_size(sz), mtInternal);
|
||||
void* up = guarded.wrap_with_guards(p, sz, (void*)1);
|
||||
memset(up, 0, sz);
|
||||
guarded_memory_test_check(up, sz, (void*)1);
|
||||
os::free(guarded.release_for_freeing());
|
||||
sz = (sz << 4) + 1;
|
||||
} while (sz < (256 * 1024));
|
||||
|
||||
// Test buffer overrun into head...
|
||||
basep = (u_char*) os::malloc(GuardedMemory::get_total_size(1), mtInternal);
|
||||
guarded.wrap_with_guards(basep, 1);
|
||||
*basep = 0;
|
||||
assert(!guarded.verify_guards(), "Expected failure");
|
||||
os::free(basep);
|
||||
|
||||
// Test buffer overrun into tail with a number of odd sizes...
|
||||
sz = 1;
|
||||
do {
|
||||
void* p = os::malloc(GuardedMemory::get_total_size(sz), mtInternal);
|
||||
void* up = guarded.wrap_with_guards(p, sz, (void*)1);
|
||||
memset(up, 0, sz + 1); // Buffer-overwrite (within guard)
|
||||
assert(!guarded.verify_guards(), "Guard was not broken as expected");
|
||||
os::free(guarded.release_for_freeing());
|
||||
sz = (sz << 4) + 1;
|
||||
} while (sz < (256 * 1024));
|
||||
|
||||
// Test wrap_copy/wrap_free...
|
||||
assert(GuardedMemory::free_copy(NULL), "Expected free NULL to be OK");
|
||||
|
||||
const char* str = "Check my bounds out";
|
||||
size_t str_sz = strlen(str) + 1;
|
||||
char* str_copy = (char*) GuardedMemory::wrap_copy(str, str_sz);
|
||||
guarded_memory_test_check(str_copy, str_sz, NULL);
|
||||
assert(strcmp(str, str_copy) == 0, "Not identical copy");
|
||||
assert(GuardedMemory::free_copy(str_copy), "Free copy failed to verify");
|
||||
|
||||
void* no_data = NULL;
|
||||
void* no_data_copy = GuardedMemory::wrap_copy(no_data, 0);
|
||||
assert(GuardedMemory::free_copy(no_data_copy), "Expected valid guards even for no data copy");
|
||||
}
|
||||
|
||||
#endif // !PRODUCT
|
||||
|
326
hotspot/src/share/vm/memory/guardedMemory.hpp
Normal file
326
hotspot/src/share/vm/memory/guardedMemory.hpp
Normal file
|
@ -0,0 +1,326 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_MEMORY_GUARDED_MEMORY_HPP
|
||||
#define SHARE_VM_MEMORY_GUARDED_MEMORY_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
/**
|
||||
* Guarded memory for detecting buffer overrun.
|
||||
*
|
||||
* Allows allocations to be wrapped with padded bytes of a known byte pattern,
|
||||
* that is a "guard". Guard patterns may be verified to detect buffer overruns.
|
||||
*
|
||||
* Primarily used by "debug malloc" and "checked JNI".
|
||||
*
|
||||
* Memory layout:
|
||||
*
|
||||
* |Offset | Content | Description |
|
||||
* |------------------------------------------------------------
|
||||
* |base_addr | 0xABABABABABABABAB | Head guard |
|
||||
* |+16 | <size_t:user_size> | User data size |
|
||||
* |+sizeof(uintptr_t) | <tag> | Tag word |
|
||||
* |+sizeof(void*) | 0xF1 <user_data> ( | User data |
|
||||
* |+user_size | 0xABABABABABABABAB | Tail guard |
|
||||
* -------------------------------------------------------------
|
||||
*
|
||||
* Where:
|
||||
* - guard padding uses "badResourceValue" (0xAB)
|
||||
* - tag word is general purpose
|
||||
* - user data
|
||||
* -- initially padded with "uninitBlockPad" (0xF1),
|
||||
* -- to "freeBlockPad" (0xBA), when freed
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* * Allocations: one may wrap allocations with guard memory:
|
||||
* <code>
|
||||
* Thing* alloc_thing() {
|
||||
* void* mem = user_alloc_fn(GuardedMemory::get_total_size(sizeof(thing)));
|
||||
* GuardedMemory guarded(mem, sizeof(thing));
|
||||
* return (Thing*) guarded.get_user_ptr();
|
||||
* }
|
||||
* </code>
|
||||
* * Verify: memory guards are still in tact
|
||||
* <code>
|
||||
* bool verify_thing(Thing* thing) {
|
||||
* GuardedMemory guarded((void*)thing);
|
||||
* return guarded.verify_guards();
|
||||
* }
|
||||
* </code>
|
||||
* * Free: one may mark bytes as freed (further debugging support)
|
||||
* <code>
|
||||
* void free_thing(Thing* thing) {
|
||||
* GuardedMemory guarded((void*)thing);
|
||||
* assert(guarded.verify_guards(), "Corrupt thing");
|
||||
* user_free_fn(guards.release_for_freeing();
|
||||
* }
|
||||
* </code>
|
||||
*/
|
||||
class GuardedMemory : StackObj { // Wrapper on stack
|
||||
|
||||
// Private inner classes for memory layout...
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Guard class for header and trailer known pattern to test for overwrites.
|
||||
*/
|
||||
class Guard { // Class for raw memory (no vtbl allowed)
|
||||
friend class GuardedMemory;
|
||||
protected:
|
||||
enum {
|
||||
GUARD_SIZE = 16
|
||||
};
|
||||
|
||||
u_char _guard[GUARD_SIZE];
|
||||
|
||||
public:
|
||||
|
||||
void build() {
|
||||
u_char* c = _guard; // Possibly unaligned if tail guard
|
||||
u_char* end = c + GUARD_SIZE;
|
||||
while (c < end) {
|
||||
*c = badResourceValue;
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
bool verify() const {
|
||||
u_char* c = (u_char*) _guard;
|
||||
u_char* end = c + GUARD_SIZE;
|
||||
while (c < end) {
|
||||
if (*c != badResourceValue) {
|
||||
return false;
|
||||
}
|
||||
c++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}; // GuardedMemory::Guard
|
||||
|
||||
/**
|
||||
* Header guard and size
|
||||
*/
|
||||
class GuardHeader : Guard {
|
||||
friend class GuardedMemory;
|
||||
protected:
|
||||
// Take care in modifying fields here, will effect alignment
|
||||
// e.g. x86 ABI 16 byte stack alignment
|
||||
union {
|
||||
uintptr_t __unused_full_word1;
|
||||
size_t _user_size;
|
||||
};
|
||||
void* _tag;
|
||||
public:
|
||||
void set_user_size(const size_t usz) { _user_size = usz; }
|
||||
size_t get_user_size() const { return _user_size; }
|
||||
|
||||
void set_tag(const void* tag) { _tag = (void*) tag; }
|
||||
void* get_tag() const { return _tag; }
|
||||
|
||||
}; // GuardedMemory::GuardHeader
|
||||
|
||||
// Guarded Memory...
|
||||
|
||||
protected:
|
||||
u_char* _base_addr;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Create new guarded memory.
|
||||
*
|
||||
* Wraps, starting at the given "base_ptr" with guards. Use "get_user_ptr()"
|
||||
* to return a pointer suitable for user data.
|
||||
*
|
||||
* @param base_ptr allocation wishing to be wrapped, must be at least "GuardedMemory::get_total_size()" bytes.
|
||||
* @param user_size the size of the user data to be wrapped.
|
||||
* @param tag optional general purpose tag.
|
||||
*/
|
||||
GuardedMemory(void* base_ptr, const size_t user_size, const void* tag = NULL) {
|
||||
wrap_with_guards(base_ptr, user_size, tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap existing guarded memory.
|
||||
*
|
||||
* To use this constructor, one must have created guarded memory with
|
||||
* "GuardedMemory(void*, size_t, void*)" (or indirectly via helper, e.g. "wrap_copy()").
|
||||
*
|
||||
* @param user_p existing wrapped memory.
|
||||
*/
|
||||
GuardedMemory(void* userp) {
|
||||
u_char* user_ptr = (u_char*) userp;
|
||||
assert((uintptr_t)user_ptr > (sizeof(GuardHeader) + 0x1000), "Invalid pointer");
|
||||
_base_addr = (user_ptr - sizeof(GuardHeader));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new guarded memory.
|
||||
*
|
||||
* Wraps, starting at the given "base_ptr" with guards. Allows reuse of stack allocated helper.
|
||||
*
|
||||
* @param base_ptr allocation wishing to be wrapped, must be at least "GuardedMemory::get_total_size()" bytes.
|
||||
* @param user_size the size of the user data to be wrapped.
|
||||
* @param tag optional general purpose tag.
|
||||
*
|
||||
* @return user data pointer (inner pointer to supplied "base_ptr").
|
||||
*/
|
||||
void* wrap_with_guards(void* base_ptr, size_t user_size, const void* tag = NULL) {
|
||||
assert(base_ptr != NULL, "Attempt to wrap NULL with memory guard");
|
||||
_base_addr = (u_char*)base_ptr;
|
||||
get_head_guard()->build();
|
||||
get_head_guard()->set_user_size(user_size);
|
||||
get_tail_guard()->build();
|
||||
set_tag(tag);
|
||||
set_user_bytes(uninitBlockPad);
|
||||
assert(verify_guards(), "Expected valid memory guards");
|
||||
return get_user_ptr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify head and tail guards.
|
||||
*
|
||||
* @return true if guards are intact, false would indicate a buffer overrun.
|
||||
*/
|
||||
bool verify_guards() const {
|
||||
if (_base_addr != NULL) {
|
||||
return (get_head_guard()->verify() && get_tail_guard()->verify());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the general purpose tag.
|
||||
*
|
||||
* @param tag general purpose tag.
|
||||
*/
|
||||
void set_tag(const void* tag) { get_head_guard()->set_tag(tag); }
|
||||
|
||||
/**
|
||||
* Return the general purpose tag.
|
||||
*
|
||||
* @return the general purpose tag, defaults to NULL.
|
||||
*/
|
||||
void* get_tag() const { return get_head_guard()->get_tag(); }
|
||||
|
||||
/**
|
||||
* Return the size of the user data.
|
||||
*
|
||||
* @return the size of the user data.
|
||||
*/
|
||||
size_t get_user_size() const {
|
||||
assert(_base_addr, "Not wrapping any memory");
|
||||
return get_head_guard()->get_user_size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the user data pointer.
|
||||
*
|
||||
* @return the user data pointer.
|
||||
*/
|
||||
u_char* get_user_ptr() const {
|
||||
assert(_base_addr, "Not wrapping any memory");
|
||||
return _base_addr + sizeof(GuardHeader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the wrapped pointer for resource freeing.
|
||||
*
|
||||
* Pads the user data with "freeBlockPad", and dis-associates the helper.
|
||||
*
|
||||
* @return the original base pointer used to wrap the data.
|
||||
*/
|
||||
void* release_for_freeing() {
|
||||
set_user_bytes(freeBlockPad);
|
||||
return release();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dis-associate the help from the original base address.
|
||||
*
|
||||
* @return the original base pointer used to wrap the data.
|
||||
*/
|
||||
void* release() {
|
||||
void* p = (void*) _base_addr;
|
||||
_base_addr = NULL;
|
||||
return p;
|
||||
}
|
||||
|
||||
virtual void print_on(outputStream* st) const;
|
||||
|
||||
protected:
|
||||
GuardHeader* get_head_guard() const { return (GuardHeader*) _base_addr; }
|
||||
Guard* get_tail_guard() const { return (Guard*) (get_user_ptr() + get_user_size()); };
|
||||
void set_user_bytes(u_char ch) {
|
||||
memset(get_user_ptr(), ch, get_user_size());
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Return the total size required for wrapping the given user size.
|
||||
*
|
||||
* @return the total size required for wrapping the given user size.
|
||||
*/
|
||||
static size_t get_total_size(size_t user_size) {
|
||||
size_t total_size = sizeof(GuardHeader) + user_size + sizeof(Guard);
|
||||
assert(total_size > user_size, "Unexpected wrap-around");
|
||||
return total_size;
|
||||
}
|
||||
|
||||
// Helper functions...
|
||||
|
||||
/**
|
||||
* Wrap a copy of size "len" of "ptr".
|
||||
*
|
||||
* @param ptr the memory to be copied
|
||||
* @param len the length of the copy
|
||||
* @param tag optional general purpose tag (see GuardedMemory::get_tag())
|
||||
*
|
||||
* @return guarded wrapped memory pointer to the user area, or NULL if OOM.
|
||||
*/
|
||||
static void* wrap_copy(const void* p, const size_t len, const void* tag = NULL);
|
||||
|
||||
/**
|
||||
* Free wrapped copy.
|
||||
*
|
||||
* Frees memory copied with "wrap_copy()".
|
||||
*
|
||||
* @param p memory returned by "wrap_copy()".
|
||||
*
|
||||
* @return true if guards were verified as intact. false indicates a buffer overrun.
|
||||
*/
|
||||
static bool free_copy(void* p);
|
||||
|
||||
// Testing...
|
||||
#ifndef PRODUCT
|
||||
static void test_guarded_memory(void);
|
||||
#endif
|
||||
}; // GuardedMemory
|
||||
|
||||
#endif // SHARE_VM_MEMORY_GUARDED_MEMORY_HPP
|
|
@ -3858,6 +3858,7 @@ _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_GetDefaultJavaVMInitArgs(void *args_) {
|
|||
#if INCLUDE_ALL_GCS
|
||||
#include "gc_implementation/g1/heapRegionRemSet.hpp"
|
||||
#endif
|
||||
#include "memory/guardedMemory.hpp"
|
||||
#include "utilities/quickSort.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
#if INCLUDE_VM_STRUCTS
|
||||
|
@ -3901,6 +3902,7 @@ void execute_internal_vm_tests() {
|
|||
run_unit_test(arrayOopDesc::test_max_array_length());
|
||||
run_unit_test(CollectedHeap::test_is_in());
|
||||
run_unit_test(QuickSort::test_quick_sort());
|
||||
run_unit_test(GuardedMemory::test_guarded_memory());
|
||||
run_unit_test(AltHashing::test_alt_hash());
|
||||
run_unit_test(test_loggc_filename());
|
||||
run_unit_test(TestNewSize_test());
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "precompiled.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "memory/guardedMemory.hpp"
|
||||
#include "oops/instanceKlass.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "oops/symbol.hpp"
|
||||
|
@ -323,6 +324,74 @@ check_is_obj_array(JavaThread* thr, jarray jArray) {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy and wrap array elements for bounds checking.
|
||||
* Remember the original elements (GuardedMemory::get_tag())
|
||||
*/
|
||||
static void* check_jni_wrap_copy_array(JavaThread* thr, jarray array,
|
||||
void* orig_elements) {
|
||||
void* result;
|
||||
IN_VM(
|
||||
oop a = JNIHandles::resolve_non_null(array);
|
||||
size_t len = arrayOop(a)->length() <<
|
||||
TypeArrayKlass::cast(a->klass())->log2_element_size();
|
||||
result = GuardedMemory::wrap_copy(orig_elements, len, orig_elements);
|
||||
)
|
||||
return result;
|
||||
}
|
||||
|
||||
static void* check_wrapped_array(JavaThread* thr, const char* fn_name,
|
||||
void* obj, void* carray, size_t* rsz) {
|
||||
if (carray == NULL) {
|
||||
tty->print_cr("%s: elements vector NULL" PTR_FORMAT, fn_name, p2i(obj));
|
||||
NativeReportJNIFatalError(thr, "Elements vector NULL");
|
||||
}
|
||||
GuardedMemory guarded(carray);
|
||||
void* orig_result = guarded.get_tag();
|
||||
if (!guarded.verify_guards()) {
|
||||
tty->print_cr("ReleasePrimitiveArrayCritical: release array failed bounds "
|
||||
"check, incorrect pointer returned ? array: " PTR_FORMAT " carray: "
|
||||
PTR_FORMAT, p2i(obj), p2i(carray));
|
||||
guarded.print_on(tty);
|
||||
NativeReportJNIFatalError(thr, "ReleasePrimitiveArrayCritical: "
|
||||
"failed bounds check");
|
||||
}
|
||||
if (orig_result == NULL) {
|
||||
tty->print_cr("ReleasePrimitiveArrayCritical: unrecognized elements. array: "
|
||||
PTR_FORMAT " carray: " PTR_FORMAT, p2i(obj), p2i(carray));
|
||||
guarded.print_on(tty);
|
||||
NativeReportJNIFatalError(thr, "ReleasePrimitiveArrayCritical: "
|
||||
"unrecognized elements");
|
||||
}
|
||||
if (rsz != NULL) {
|
||||
*rsz = guarded.get_user_size();
|
||||
}
|
||||
return orig_result;
|
||||
}
|
||||
|
||||
static void* check_wrapped_array_release(JavaThread* thr, const char* fn_name,
|
||||
void* obj, void* carray, jint mode) {
|
||||
size_t sz;
|
||||
void* orig_result = check_wrapped_array(thr, fn_name, obj, carray, &sz);
|
||||
switch (mode) {
|
||||
case 0:
|
||||
memcpy(orig_result, carray, sz);
|
||||
GuardedMemory::free_copy(carray);
|
||||
break;
|
||||
case JNI_COMMIT:
|
||||
memcpy(orig_result, carray, sz);
|
||||
break;
|
||||
case JNI_ABORT:
|
||||
GuardedMemory::free_copy(carray);
|
||||
break;
|
||||
default:
|
||||
tty->print_cr("%s: Unrecognized mode %i releasing array "
|
||||
PTR_FORMAT " elements " PTR_FORMAT, fn_name, mode, p2i(obj), p2i(carray));
|
||||
NativeReportJNIFatalError(thr, "Unrecognized array release mode");
|
||||
}
|
||||
return orig_result;
|
||||
}
|
||||
|
||||
oop jniCheck::validate_handle(JavaThread* thr, jobject obj) {
|
||||
if (JNIHandles::is_frame_handle(thr, obj) ||
|
||||
JNIHandles::is_local_handle(thr, obj) ||
|
||||
|
@ -1314,7 +1383,7 @@ JNI_ENTRY_CHECKED(jsize,
|
|||
JNI_END
|
||||
|
||||
// Arbitrary (but well-known) tag
|
||||
const jint STRING_TAG = 0x47114711;
|
||||
const void* STRING_TAG = (void*)0x47114711;
|
||||
|
||||
JNI_ENTRY_CHECKED(const jchar *,
|
||||
checked_jni_GetStringChars(JNIEnv *env,
|
||||
|
@ -1324,21 +1393,22 @@ JNI_ENTRY_CHECKED(const jchar *,
|
|||
IN_VM(
|
||||
checkString(thr, str);
|
||||
)
|
||||
jchar* newResult = NULL;
|
||||
jchar* new_result = NULL;
|
||||
const jchar *result = UNCHECKED()->GetStringChars(env,str,isCopy);
|
||||
assert (isCopy == NULL || *isCopy == JNI_TRUE, "GetStringChars didn't return a copy as expected");
|
||||
if (result != NULL) {
|
||||
size_t len = UNCHECKED()->GetStringLength(env,str) + 1; // + 1 for NULL termination
|
||||
jint* tagLocation = (jint*) AllocateHeap(len * sizeof(jchar) + sizeof(jint), mtInternal);
|
||||
*tagLocation = STRING_TAG;
|
||||
newResult = (jchar*) (tagLocation + 1);
|
||||
memcpy(newResult, result, len * sizeof(jchar));
|
||||
len *= sizeof(jchar);
|
||||
new_result = (jchar*) GuardedMemory::wrap_copy(result, len, STRING_TAG);
|
||||
if (new_result == NULL) {
|
||||
vm_exit_out_of_memory(len, OOM_MALLOC_ERROR, "checked_jni_GetStringChars");
|
||||
}
|
||||
// Avoiding call to UNCHECKED()->ReleaseStringChars() since that will fire unexpected dtrace probes
|
||||
// Note that the dtrace arguments for the allocated memory will not match up with this solution.
|
||||
FreeHeap((char*)result);
|
||||
}
|
||||
functionExit(env);
|
||||
return newResult;
|
||||
return new_result;
|
||||
JNI_END
|
||||
|
||||
JNI_ENTRY_CHECKED(void,
|
||||
|
@ -1354,11 +1424,23 @@ JNI_ENTRY_CHECKED(void,
|
|||
UNCHECKED()->ReleaseStringChars(env,str,chars);
|
||||
}
|
||||
else {
|
||||
jint* tagLocation = ((jint*) chars) - 1;
|
||||
if (*tagLocation != STRING_TAG) {
|
||||
NativeReportJNIFatalError(thr, "ReleaseStringChars called on something not allocated by GetStringChars");
|
||||
}
|
||||
UNCHECKED()->ReleaseStringChars(env,str,(const jchar*)tagLocation);
|
||||
GuardedMemory guarded((void*)chars);
|
||||
if (guarded.verify_guards()) {
|
||||
tty->print_cr("ReleaseStringChars: release chars failed bounds check. "
|
||||
"string: " PTR_FORMAT " chars: " PTR_FORMAT, p2i(str), p2i(chars));
|
||||
guarded.print_on(tty);
|
||||
NativeReportJNIFatalError(thr, "ReleaseStringChars: "
|
||||
"release chars failed bounds check.");
|
||||
}
|
||||
if (guarded.get_tag() != STRING_TAG) {
|
||||
tty->print_cr("ReleaseStringChars: called on something not allocated "
|
||||
"by GetStringChars. string: " PTR_FORMAT " chars: " PTR_FORMAT,
|
||||
p2i(str), p2i(chars));
|
||||
NativeReportJNIFatalError(thr, "ReleaseStringChars called on something "
|
||||
"not allocated by GetStringChars");
|
||||
}
|
||||
UNCHECKED()->ReleaseStringChars(env, str,
|
||||
(const jchar*) guarded.release_for_freeing());
|
||||
}
|
||||
functionExit(env);
|
||||
JNI_END
|
||||
|
@ -1385,7 +1467,7 @@ JNI_ENTRY_CHECKED(jsize,
|
|||
JNI_END
|
||||
|
||||
// Arbitrary (but well-known) tag - different than GetStringChars
|
||||
const jint STRING_UTF_TAG = 0x48124812;
|
||||
const void* STRING_UTF_TAG = (void*) 0x48124812;
|
||||
|
||||
JNI_ENTRY_CHECKED(const char *,
|
||||
checked_jni_GetStringUTFChars(JNIEnv *env,
|
||||
|
@ -1395,21 +1477,21 @@ JNI_ENTRY_CHECKED(const char *,
|
|||
IN_VM(
|
||||
checkString(thr, str);
|
||||
)
|
||||
char* newResult = NULL;
|
||||
char* new_result = NULL;
|
||||
const char *result = UNCHECKED()->GetStringUTFChars(env,str,isCopy);
|
||||
assert (isCopy == NULL || *isCopy == JNI_TRUE, "GetStringUTFChars didn't return a copy as expected");
|
||||
if (result != NULL) {
|
||||
size_t len = strlen(result) + 1; // + 1 for NULL termination
|
||||
jint* tagLocation = (jint*) AllocateHeap(len + sizeof(jint), mtInternal);
|
||||
*tagLocation = STRING_UTF_TAG;
|
||||
newResult = (char*) (tagLocation + 1);
|
||||
strcpy(newResult, result);
|
||||
new_result = (char*) GuardedMemory::wrap_copy(result, len, STRING_UTF_TAG);
|
||||
if (new_result == NULL) {
|
||||
vm_exit_out_of_memory(len, OOM_MALLOC_ERROR, "checked_jni_GetStringUTFChars");
|
||||
}
|
||||
// Avoiding call to UNCHECKED()->ReleaseStringUTFChars() since that will fire unexpected dtrace probes
|
||||
// Note that the dtrace arguments for the allocated memory will not match up with this solution.
|
||||
FreeHeap((char*)result, mtInternal);
|
||||
}
|
||||
functionExit(env);
|
||||
return newResult;
|
||||
return new_result;
|
||||
JNI_END
|
||||
|
||||
JNI_ENTRY_CHECKED(void,
|
||||
|
@ -1425,11 +1507,23 @@ JNI_ENTRY_CHECKED(void,
|
|||
UNCHECKED()->ReleaseStringUTFChars(env,str,chars);
|
||||
}
|
||||
else {
|
||||
jint* tagLocation = ((jint*) chars) - 1;
|
||||
if (*tagLocation != STRING_UTF_TAG) {
|
||||
NativeReportJNIFatalError(thr, "ReleaseStringUTFChars called on something not allocated by GetStringUTFChars");
|
||||
}
|
||||
UNCHECKED()->ReleaseStringUTFChars(env,str,(const char*)tagLocation);
|
||||
GuardedMemory guarded((void*)chars);
|
||||
if (guarded.verify_guards()) {
|
||||
tty->print_cr("ReleaseStringUTFChars: release chars failed bounds check. "
|
||||
"string: " PTR_FORMAT " chars: " PTR_FORMAT, p2i(str), p2i(chars));
|
||||
guarded.print_on(tty);
|
||||
NativeReportJNIFatalError(thr, "ReleaseStringUTFChars: "
|
||||
"release chars failed bounds check.");
|
||||
}
|
||||
if (guarded.get_tag() != STRING_UTF_TAG) {
|
||||
tty->print_cr("ReleaseStringUTFChars: called on something not "
|
||||
"allocated by GetStringUTFChars. string: " PTR_FORMAT " chars: "
|
||||
PTR_FORMAT, p2i(str), p2i(chars));
|
||||
NativeReportJNIFatalError(thr, "ReleaseStringUTFChars "
|
||||
"called on something not allocated by GetStringUTFChars");
|
||||
}
|
||||
UNCHECKED()->ReleaseStringUTFChars(env, str,
|
||||
(const char*) guarded.release_for_freeing());
|
||||
}
|
||||
functionExit(env);
|
||||
JNI_END
|
||||
|
@ -1514,6 +1608,9 @@ JNI_ENTRY_CHECKED(ElementType *, \
|
|||
ElementType *result = UNCHECKED()->Get##Result##ArrayElements(env, \
|
||||
array, \
|
||||
isCopy); \
|
||||
if (result != NULL) { \
|
||||
result = (ElementType *) check_jni_wrap_copy_array(thr, array, result); \
|
||||
} \
|
||||
functionExit(env); \
|
||||
return result; \
|
||||
JNI_END
|
||||
|
@ -1538,12 +1635,10 @@ JNI_ENTRY_CHECKED(void, \
|
|||
check_primitive_array_type(thr, array, ElementTag); \
|
||||
ASSERT_OOPS_ALLOWED; \
|
||||
typeArrayOop a = typeArrayOop(JNIHandles::resolve_non_null(array)); \
|
||||
/* cannot check validity of copy, unless every request is logged by
|
||||
* checking code. Implementation of this check is deferred until a
|
||||
* subsequent release.
|
||||
*/ \
|
||||
) \
|
||||
UNCHECKED()->Release##Result##ArrayElements(env,array,elems,mode); \
|
||||
ElementType* orig_result = (ElementType *) check_wrapped_array_release( \
|
||||
thr, "checked_jni_Release"#Result"ArrayElements", array, elems, mode); \
|
||||
UNCHECKED()->Release##Result##ArrayElements(env, array, orig_result, mode); \
|
||||
functionExit(env); \
|
||||
JNI_END
|
||||
|
||||
|
@ -1694,6 +1789,9 @@ JNI_ENTRY_CHECKED(void *,
|
|||
check_is_primitive_array(thr, array);
|
||||
)
|
||||
void *result = UNCHECKED()->GetPrimitiveArrayCritical(env, array, isCopy);
|
||||
if (result != NULL) {
|
||||
result = check_jni_wrap_copy_array(thr, array, result);
|
||||
}
|
||||
functionExit(env);
|
||||
return result;
|
||||
JNI_END
|
||||
|
@ -1707,10 +1805,9 @@ JNI_ENTRY_CHECKED(void,
|
|||
IN_VM(
|
||||
check_is_primitive_array(thr, array);
|
||||
)
|
||||
/* The Hotspot JNI code does not use the parameters, so just check the
|
||||
* array parameter as a minor sanity check
|
||||
*/
|
||||
UNCHECKED()->ReleasePrimitiveArrayCritical(env, array, carray, mode);
|
||||
// Check the element array...
|
||||
void* orig_result = check_wrapped_array_release(thr, "ReleasePrimitiveArrayCritical", array, carray, mode);
|
||||
UNCHECKED()->ReleasePrimitiveArrayCritical(env, array, orig_result, mode);
|
||||
functionExit(env);
|
||||
JNI_END
|
||||
|
||||
|
|
|
@ -32,6 +32,9 @@
|
|||
#include "gc_implementation/shared/vmGCOperations.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#ifdef ASSERT
|
||||
#include "memory/guardedMemory.hpp"
|
||||
#endif
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "prims/jvm.h"
|
||||
#include "prims/jvm_misc.hpp"
|
||||
|
@ -523,121 +526,20 @@ char *os::strdup(const char *str, MEMFLAGS flags) {
|
|||
}
|
||||
|
||||
|
||||
|
||||
#ifdef ASSERT
|
||||
#define space_before (MallocCushion + sizeof(double))
|
||||
#define space_after MallocCushion
|
||||
#define size_addr_from_base(p) (size_t*)(p + space_before - sizeof(size_t))
|
||||
#define size_addr_from_obj(p) ((size_t*)p - 1)
|
||||
// MallocCushion: size of extra cushion allocated around objects with +UseMallocOnly
|
||||
// NB: cannot be debug variable, because these aren't set from the command line until
|
||||
// *after* the first few allocs already happened
|
||||
#define MallocCushion 16
|
||||
#else
|
||||
#define space_before 0
|
||||
#define space_after 0
|
||||
#define size_addr_from_base(p) should not use w/o ASSERT
|
||||
#define size_addr_from_obj(p) should not use w/o ASSERT
|
||||
#define MallocCushion 0
|
||||
#endif
|
||||
#define paranoid 0 /* only set to 1 if you suspect checking code has bug */
|
||||
|
||||
#ifdef ASSERT
|
||||
inline size_t get_size(void* obj) {
|
||||
size_t size = *size_addr_from_obj(obj);
|
||||
if (size < 0) {
|
||||
fatal(err_msg("free: size field of object #" PTR_FORMAT " was overwritten ("
|
||||
SIZE_FORMAT ")", obj, size));
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
u_char* find_cushion_backwards(u_char* start) {
|
||||
u_char* p = start;
|
||||
while (p[ 0] != badResourceValue || p[-1] != badResourceValue ||
|
||||
p[-2] != badResourceValue || p[-3] != badResourceValue) p--;
|
||||
// ok, we have four consecutive marker bytes; find start
|
||||
u_char* q = p - 4;
|
||||
while (*q == badResourceValue) q--;
|
||||
return q + 1;
|
||||
}
|
||||
|
||||
u_char* find_cushion_forwards(u_char* start) {
|
||||
u_char* p = start;
|
||||
while (p[0] != badResourceValue || p[1] != badResourceValue ||
|
||||
p[2] != badResourceValue || p[3] != badResourceValue) p++;
|
||||
// ok, we have four consecutive marker bytes; find end of cushion
|
||||
u_char* q = p + 4;
|
||||
while (*q == badResourceValue) q++;
|
||||
return q - MallocCushion;
|
||||
}
|
||||
|
||||
void print_neighbor_blocks(void* ptr) {
|
||||
// find block allocated before ptr (not entirely crash-proof)
|
||||
if (MallocCushion < 4) {
|
||||
tty->print_cr("### cannot find previous block (MallocCushion < 4)");
|
||||
return;
|
||||
}
|
||||
u_char* start_of_this_block = (u_char*)ptr - space_before;
|
||||
u_char* end_of_prev_block_data = start_of_this_block - space_after -1;
|
||||
// look for cushion in front of prev. block
|
||||
u_char* start_of_prev_block = find_cushion_backwards(end_of_prev_block_data);
|
||||
ptrdiff_t size = *size_addr_from_base(start_of_prev_block);
|
||||
u_char* obj = start_of_prev_block + space_before;
|
||||
if (size <= 0 ) {
|
||||
// start is bad; may have been confused by OS data in between objects
|
||||
// search one more backwards
|
||||
start_of_prev_block = find_cushion_backwards(start_of_prev_block);
|
||||
size = *size_addr_from_base(start_of_prev_block);
|
||||
obj = start_of_prev_block + space_before;
|
||||
}
|
||||
|
||||
if (start_of_prev_block + space_before + size + space_after == start_of_this_block) {
|
||||
tty->print_cr("### previous object: " PTR_FORMAT " (" SSIZE_FORMAT " bytes)", obj, size);
|
||||
} else {
|
||||
tty->print_cr("### previous object (not sure if correct): " PTR_FORMAT " (" SSIZE_FORMAT " bytes)", obj, size);
|
||||
}
|
||||
|
||||
// now find successor block
|
||||
u_char* start_of_next_block = (u_char*)ptr + *size_addr_from_obj(ptr) + space_after;
|
||||
start_of_next_block = find_cushion_forwards(start_of_next_block);
|
||||
u_char* next_obj = start_of_next_block + space_before;
|
||||
ptrdiff_t next_size = *size_addr_from_base(start_of_next_block);
|
||||
if (start_of_next_block[0] == badResourceValue &&
|
||||
start_of_next_block[1] == badResourceValue &&
|
||||
start_of_next_block[2] == badResourceValue &&
|
||||
start_of_next_block[3] == badResourceValue) {
|
||||
tty->print_cr("### next object: " PTR_FORMAT " (" SSIZE_FORMAT " bytes)", next_obj, next_size);
|
||||
} else {
|
||||
tty->print_cr("### next object (not sure if correct): " PTR_FORMAT " (" SSIZE_FORMAT " bytes)", next_obj, next_size);
|
||||
static void verify_memory(void* ptr) {
|
||||
GuardedMemory guarded(ptr);
|
||||
if (!guarded.verify_guards()) {
|
||||
tty->print_cr("## nof_mallocs = " UINT64_FORMAT ", nof_frees = " UINT64_FORMAT, os::num_mallocs, os::num_frees);
|
||||
tty->print_cr("## memory stomp:");
|
||||
guarded.print_on(tty);
|
||||
fatal("memory stomping error");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void report_heap_error(void* memblock, void* bad, const char* where) {
|
||||
tty->print_cr("## nof_mallocs = " UINT64_FORMAT ", nof_frees = " UINT64_FORMAT, os::num_mallocs, os::num_frees);
|
||||
tty->print_cr("## memory stomp: byte at " PTR_FORMAT " %s object " PTR_FORMAT, bad, where, memblock);
|
||||
print_neighbor_blocks(memblock);
|
||||
fatal("memory stomping error");
|
||||
}
|
||||
|
||||
void verify_block(void* memblock) {
|
||||
size_t size = get_size(memblock);
|
||||
if (MallocCushion) {
|
||||
u_char* ptr = (u_char*)memblock - space_before;
|
||||
for (int i = 0; i < MallocCushion; i++) {
|
||||
if (ptr[i] != badResourceValue) {
|
||||
report_heap_error(memblock, ptr+i, "in front of");
|
||||
}
|
||||
}
|
||||
u_char* end = (u_char*)memblock + size + space_after;
|
||||
for (int j = -MallocCushion; j < 0; j++) {
|
||||
if (end[j] != badResourceValue) {
|
||||
report_heap_error(memblock, end+j, "after");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
|
@ -686,16 +588,18 @@ void* os::malloc(size_t size, MEMFLAGS memflags, address caller) {
|
|||
size = 1;
|
||||
}
|
||||
|
||||
const size_t alloc_size = size + space_before + space_after;
|
||||
|
||||
#ifndef ASSERT
|
||||
const size_t alloc_size = size;
|
||||
#else
|
||||
const size_t alloc_size = GuardedMemory::get_total_size(size);
|
||||
if (size > alloc_size) { // Check for rollover.
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
NOT_PRODUCT(if (MallocVerifyInterval > 0) check_heap());
|
||||
|
||||
u_char* ptr;
|
||||
|
||||
if (MallocMaxTestWords > 0) {
|
||||
ptr = testMalloc(alloc_size);
|
||||
} else {
|
||||
|
@ -703,28 +607,26 @@ void* os::malloc(size_t size, MEMFLAGS memflags, address caller) {
|
|||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
if (ptr == NULL) return NULL;
|
||||
if (MallocCushion) {
|
||||
for (u_char* p = ptr; p < ptr + MallocCushion; p++) *p = (u_char)badResourceValue;
|
||||
u_char* end = ptr + space_before + size;
|
||||
for (u_char* pq = ptr+MallocCushion; pq < end; pq++) *pq = (u_char)uninitBlockPad;
|
||||
for (u_char* q = end; q < end + MallocCushion; q++) *q = (u_char)badResourceValue;
|
||||
if (ptr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
// put size just before data
|
||||
*size_addr_from_base(ptr) = size;
|
||||
// Wrap memory with guard
|
||||
GuardedMemory guarded(ptr, size);
|
||||
ptr = guarded.get_user_ptr();
|
||||
#endif
|
||||
u_char* memblock = ptr + space_before;
|
||||
if ((intptr_t)memblock == (intptr_t)MallocCatchPtr) {
|
||||
tty->print_cr("os::malloc caught, " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, memblock);
|
||||
if ((intptr_t)ptr == (intptr_t)MallocCatchPtr) {
|
||||
tty->print_cr("os::malloc caught, " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, ptr);
|
||||
breakpoint();
|
||||
}
|
||||
debug_only(if (paranoid) verify_block(memblock));
|
||||
if (PrintMalloc && tty != NULL) tty->print_cr("os::malloc " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, memblock);
|
||||
debug_only(if (paranoid) verify_memory(ptr));
|
||||
if (PrintMalloc && tty != NULL) {
|
||||
tty->print_cr("os::malloc " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, ptr);
|
||||
}
|
||||
|
||||
// we do not track MallocCushion memory
|
||||
MemTracker::record_malloc((address)memblock, size, memflags, caller == 0 ? CALLER_PC : caller);
|
||||
// we do not track guard memory
|
||||
MemTracker::record_malloc((address)ptr, size, memflags, caller == 0 ? CALLER_PC : caller);
|
||||
|
||||
return memblock;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
|
@ -743,27 +645,32 @@ void* os::realloc(void *memblock, size_t size, MEMFLAGS memflags, address caller
|
|||
return ptr;
|
||||
#else
|
||||
if (memblock == NULL) {
|
||||
return malloc(size, memflags, (caller == 0 ? CALLER_PC : caller));
|
||||
return os::malloc(size, memflags, (caller == 0 ? CALLER_PC : caller));
|
||||
}
|
||||
if ((intptr_t)memblock == (intptr_t)MallocCatchPtr) {
|
||||
tty->print_cr("os::realloc caught " PTR_FORMAT, memblock);
|
||||
breakpoint();
|
||||
}
|
||||
verify_block(memblock);
|
||||
verify_memory(memblock);
|
||||
NOT_PRODUCT(if (MallocVerifyInterval > 0) check_heap());
|
||||
if (size == 0) return NULL;
|
||||
if (size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
// always move the block
|
||||
void* ptr = malloc(size, memflags, caller == 0 ? CALLER_PC : caller);
|
||||
if (PrintMalloc) tty->print_cr("os::remalloc " SIZE_FORMAT " bytes, " PTR_FORMAT " --> " PTR_FORMAT, size, memblock, ptr);
|
||||
void* ptr = os::malloc(size, memflags, caller == 0 ? CALLER_PC : caller);
|
||||
if (PrintMalloc) {
|
||||
tty->print_cr("os::remalloc " SIZE_FORMAT " bytes, " PTR_FORMAT " --> " PTR_FORMAT, size, memblock, ptr);
|
||||
}
|
||||
// Copy to new memory if malloc didn't fail
|
||||
if ( ptr != NULL ) {
|
||||
memcpy(ptr, memblock, MIN2(size, get_size(memblock)));
|
||||
if (paranoid) verify_block(ptr);
|
||||
GuardedMemory guarded(memblock);
|
||||
memcpy(ptr, memblock, MIN2(size, guarded.get_user_size()));
|
||||
if (paranoid) verify_memory(ptr);
|
||||
if ((intptr_t)ptr == (intptr_t)MallocCatchPtr) {
|
||||
tty->print_cr("os::realloc caught, " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, ptr);
|
||||
breakpoint();
|
||||
}
|
||||
free(memblock);
|
||||
os::free(memblock);
|
||||
}
|
||||
return ptr;
|
||||
#endif
|
||||
|
@ -771,6 +678,7 @@ void* os::realloc(void *memblock, size_t size, MEMFLAGS memflags, address caller
|
|||
|
||||
|
||||
void os::free(void *memblock, MEMFLAGS memflags) {
|
||||
address trackp = (address) memblock;
|
||||
NOT_PRODUCT(inc_stat_counter(&num_frees, 1));
|
||||
#ifdef ASSERT
|
||||
if (memblock == NULL) return;
|
||||
|
@ -778,34 +686,20 @@ void os::free(void *memblock, MEMFLAGS memflags) {
|
|||
if (tty != NULL) tty->print_cr("os::free caught " PTR_FORMAT, memblock);
|
||||
breakpoint();
|
||||
}
|
||||
verify_block(memblock);
|
||||
verify_memory(memblock);
|
||||
NOT_PRODUCT(if (MallocVerifyInterval > 0) check_heap());
|
||||
// Added by detlefs.
|
||||
if (MallocCushion) {
|
||||
u_char* ptr = (u_char*)memblock - space_before;
|
||||
for (u_char* p = ptr; p < ptr + MallocCushion; p++) {
|
||||
guarantee(*p == badResourceValue,
|
||||
"Thing freed should be malloc result.");
|
||||
*p = (u_char)freeBlockPad;
|
||||
}
|
||||
size_t size = get_size(memblock);
|
||||
inc_stat_counter(&free_bytes, size);
|
||||
u_char* end = ptr + space_before + size;
|
||||
for (u_char* q = end; q < end + MallocCushion; q++) {
|
||||
guarantee(*q == badResourceValue,
|
||||
"Thing freed should be malloc result.");
|
||||
*q = (u_char)freeBlockPad;
|
||||
}
|
||||
if (PrintMalloc && tty != NULL)
|
||||
|
||||
GuardedMemory guarded(memblock);
|
||||
size_t size = guarded.get_user_size();
|
||||
inc_stat_counter(&free_bytes, size);
|
||||
memblock = guarded.release_for_freeing();
|
||||
if (PrintMalloc && tty != NULL) {
|
||||
fprintf(stderr, "os::free " SIZE_FORMAT " bytes --> " PTR_FORMAT "\n", size, (uintptr_t)memblock);
|
||||
} else if (PrintMalloc && tty != NULL) {
|
||||
// tty->print_cr("os::free %p", memblock);
|
||||
fprintf(stderr, "os::free " PTR_FORMAT "\n", (uintptr_t)memblock);
|
||||
}
|
||||
#endif
|
||||
MemTracker::record_free((address)memblock, memflags);
|
||||
MemTracker::record_free(trackp, memflags);
|
||||
|
||||
::free((char*)memblock - space_before);
|
||||
::free(memblock);
|
||||
}
|
||||
|
||||
void os::init_random(long initval) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue