c1281e6b45
Reviewed-by: kbarrett, dholmes, jwaters
148 lines
5.8 KiB
C++
148 lines
5.8 KiB
C++
/*
|
|
* Copyright (c) 2021, 2022 SAP SE. All rights reserved.
|
|
* Copyright (c) 2021, 2024, 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 "nmt/memTracker.hpp"
|
|
#include "nmt/nmtPreInit.hpp"
|
|
#include "runtime/os.hpp"
|
|
#include "utilities/debug.hpp"
|
|
#include "utilities/ostream.hpp"
|
|
#include "unittest.hpp"
|
|
|
|
// convenience log. switch on if debugging tests. Don't use tty, plain stdio only.
|
|
//#define LOG(...) { printf(__VA_ARGS__); printf("\n"); fflush(stdout); }
|
|
#define LOG(...)
|
|
|
|
|
|
// This tests the ability of the NMT pre-init system to deal with various combinations
|
|
// of pre- and post-init-allocations.
|
|
|
|
// The tests consist of two phases:
|
|
// 1) before NMT initialization (pre-NMT-init) we allocate and reallocate a bunch of
|
|
// blocks via os::malloc() and os::realloc(), and free some of them via os::free()
|
|
// 2) after NMT initialization, we reallocate some more, then free all of them.
|
|
//
|
|
// The intent is to check that blocks allocated in pre-init phase and potentially realloced
|
|
// in pre-init phase are handled correctly if further realloc'ed or free'd post-init.
|
|
|
|
// We manage to run tests in different phases with this technique:
|
|
// - for the pre-init phase, we start the tests in the constructor of a global object; that constructor will
|
|
// run as part of the dyn. C++ initialization of the gtestlauncher binary. Since the gtestlauncher links
|
|
// *statically* against the libjvm, gtestlauncher and libjvm initialization fold into one and are the same.
|
|
// - for the post-init phase, we just start it inside a TEST_VM scope, which needs to create the VM for
|
|
// us. So inside that scope VM initialization ran and with it the NMT initialization.
|
|
// To be sure, we assert those assumptions.
|
|
|
|
// Some shorts to save writing out the flags every time
|
|
static void* os_malloc(size_t s) { return os::malloc(s, mtTest); }
|
|
static void* os_realloc(void* old, size_t s) { return os::realloc(old, s, mtTest); }
|
|
|
|
static void log_state() {
|
|
// Don't use tty! the only safe thing to use at all times is stringStream.
|
|
char tmp[256];
|
|
stringStream ss(tmp, sizeof(tmp));
|
|
NMTPreInit::print_state(&ss);
|
|
LOG("%s", tmp);
|
|
}
|
|
|
|
class TestAllocations {
|
|
void* p1, *p2, *p3, *p4;
|
|
public:
|
|
TestAllocations() {
|
|
test_pre();
|
|
}
|
|
void test_pre() {
|
|
// Note that this part will run every time a gtestlauncher execs (so, for every TEST_OTHER_VM).
|
|
assert(!MemTracker::is_initialized(),
|
|
"This should be run in pre-init phase (as part of C++ dyn. initialization)");
|
|
LOG("corner cases, pre-init (%d)", os::current_process_id());
|
|
log_state();
|
|
|
|
p1 = os_malloc(100); // normal allocation
|
|
os::free(os_malloc(0)); // 0-sized allocation, should be free-able
|
|
p2 = os_realloc(os_malloc(10), 20); // realloc, growing
|
|
p3 = os_realloc(os_malloc(20), 10); // realloc, shrinking
|
|
p4 = os_realloc(nullptr, 10); // realloc with null pointer
|
|
os_realloc(os_realloc(os_malloc(20), 0), 30); // realloc to size 0 and back up again
|
|
os::free(os_malloc(20)); // malloc, free
|
|
os::free(os_realloc(os_malloc(20), 30)); // malloc, realloc, free
|
|
os::free(nullptr); // free(null)
|
|
DEBUG_ONLY(NMTPreInit::verify();)
|
|
|
|
// This should result in a fatal native oom error from NMT preinit with a clear error message.
|
|
// It should not result in a SEGV or anything similar. Unfortunately difficult to test
|
|
// automatically.
|
|
// Uncomment to test manually.
|
|
|
|
// case 1: overflow
|
|
// os_malloc(SIZE_MAX);
|
|
|
|
// case 2: failing malloc
|
|
// os_malloc(SIZE_MAX - M);
|
|
|
|
// case 3: overflow in realloc
|
|
// void* p = os_malloc(10);
|
|
// p = os_realloc(p, SIZE_MAX);
|
|
|
|
// case 4: failing realloc
|
|
// void* p = os_malloc(10);
|
|
// p = os_realloc(p, SIZE_MAX - M);
|
|
|
|
log_state();
|
|
}
|
|
void test_post() {
|
|
assert(MemTracker::is_initialized(),
|
|
"This should be run in post-init phase (from inside a TEST_VM test)");
|
|
LOG("corner cases, post-init (%d)", os::current_process_id());
|
|
log_state();
|
|
|
|
p1 = os_realloc(p1, 140); // realloc from pre-init-phase, growing
|
|
p2 = os_realloc(p2, 150); // realloc from pre-init-phase, growing
|
|
p3 = os_realloc(p3, 50); // realloc from pre-init-phase, growing
|
|
p4 = os_realloc(p4, 8); // realloc from pre-init-phase, shrinking
|
|
DEBUG_ONLY(NMTPreInit::verify();)
|
|
|
|
log_state();
|
|
}
|
|
void free_all() {
|
|
assert(MemTracker::is_initialized(),
|
|
"This should be run in post-init phase (from inside a TEST_VM test)");
|
|
LOG("corner cases, free-all (%d)", os::current_process_id());
|
|
log_state();
|
|
|
|
os::free(p1); os::free(p2); os::free(p3); os::free(p4);
|
|
DEBUG_ONLY(NMTPreInit::verify();)
|
|
|
|
log_state();
|
|
}
|
|
};
|
|
|
|
static TestAllocations g_test_allocations;
|
|
|
|
TEST_VM(NMTPreInit, pre_to_post_allocs) {
|
|
g_test_allocations.test_post();
|
|
g_test_allocations.free_all();
|
|
}
|