mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-14 18:03:44 +00:00
8361447: [REDO] Checked version of JNI Release<type>ArrayElements needs to filter out known wrapped arrays
8361754: New test runtime/jni/checked/TestCharArrayReleasing.java can cause disk full errors Reviewed-by: coleenp Backport-of: f67e4354316dcec185eac66adec2395e20b62579
This commit is contained in:
parent
4d5211ccb0
commit
9adc480ec3
@ -25,11 +25,12 @@
|
||||
#include "nmt/memTag.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
|
||||
void* GuardedMemory::wrap_copy(const void* ptr, const size_t len, const void* tag) {
|
||||
void* GuardedMemory::wrap_copy(const void* ptr, const size_t len,
|
||||
const void* tag, const void* tag2) {
|
||||
size_t total_sz = GuardedMemory::get_total_size(len);
|
||||
void* outerp = os::malloc(total_sz, mtInternal);
|
||||
if (outerp != nullptr) {
|
||||
GuardedMemory guarded(outerp, len, tag);
|
||||
GuardedMemory guarded(outerp, len, tag, tag2);
|
||||
void* innerp = guarded.get_user_ptr();
|
||||
if (ptr != nullptr) {
|
||||
memcpy(innerp, ptr, len);
|
||||
@ -58,8 +59,8 @@ void GuardedMemory::print_on(outputStream* st) const {
|
||||
return;
|
||||
}
|
||||
st->print_cr("GuardedMemory(" PTR_FORMAT ") base_addr=" PTR_FORMAT
|
||||
" tag=" PTR_FORMAT " user_size=%zu user_data=" PTR_FORMAT,
|
||||
p2i(this), p2i(_base_addr), p2i(get_tag()), get_user_size(), p2i(get_user_ptr()));
|
||||
" tag=" PTR_FORMAT " tag2=" PTR_FORMAT " user_size=%zu user_data=" PTR_FORMAT,
|
||||
p2i(this), p2i(_base_addr), p2i(get_tag()), p2i(get_tag2()), 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"));
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2025, 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
|
||||
@ -26,6 +26,7 @@
|
||||
#define SHARE_MEMORY_GUARDEDMEMORY_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
/**
|
||||
@ -43,13 +44,14 @@
|
||||
* |base_addr | 0xABABABABABABABAB | Head guard |
|
||||
* |+16 | <size_t:user_size> | User data size |
|
||||
* |+sizeof(uintptr_t) | <tag> | Tag word |
|
||||
* |+sizeof(uintptr_t) | <tag2> | 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
|
||||
* - tag word and tag2 word are general purpose
|
||||
* - user data
|
||||
* -- initially padded with "uninitBlockPad" (0xF1),
|
||||
* -- to "freeBlockPad" (0xBA), when freed
|
||||
@ -111,6 +113,10 @@ protected:
|
||||
}
|
||||
|
||||
bool verify() const {
|
||||
// We may not be able to dereference directly.
|
||||
if (!os::is_readable_range((const void*) _guard, (const void*) (_guard + GUARD_SIZE))) {
|
||||
return false;
|
||||
}
|
||||
u_char* c = (u_char*) _guard;
|
||||
u_char* end = c + GUARD_SIZE;
|
||||
while (c < end) {
|
||||
@ -137,6 +143,7 @@ protected:
|
||||
size_t _user_size;
|
||||
};
|
||||
void* _tag;
|
||||
void* _tag2;
|
||||
public:
|
||||
void set_user_size(const size_t usz) { _user_size = usz; }
|
||||
size_t get_user_size() const { return _user_size; }
|
||||
@ -144,6 +151,8 @@ protected:
|
||||
void set_tag(const void* tag) { _tag = (void*) tag; }
|
||||
void* get_tag() const { return _tag; }
|
||||
|
||||
void set_tag2(const void* tag2) { _tag2 = (void*) tag2; }
|
||||
void* get_tag2() const { return _tag2; }
|
||||
}; // GuardedMemory::GuardHeader
|
||||
|
||||
// Guarded Memory...
|
||||
@ -162,9 +171,11 @@ protected:
|
||||
* @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.
|
||||
* @param tag2 optional second general purpose tag.
|
||||
*/
|
||||
GuardedMemory(void* base_ptr, const size_t user_size, const void* tag = nullptr) {
|
||||
wrap_with_guards(base_ptr, user_size, tag);
|
||||
GuardedMemory(void* base_ptr, const size_t user_size,
|
||||
const void* tag = nullptr, const void* tag2 = nullptr) {
|
||||
wrap_with_guards(base_ptr, user_size, tag, tag2);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -189,16 +200,19 @@ protected:
|
||||
* @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.
|
||||
* @param tag2 optional second 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 = nullptr) {
|
||||
void* wrap_with_guards(void* base_ptr, size_t user_size,
|
||||
const void* tag = nullptr, const void* tag2 = nullptr) {
|
||||
assert(base_ptr != nullptr, "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_tag2(tag2);
|
||||
set_user_bytes(uninitBlockPad);
|
||||
assert(verify_guards(), "Expected valid memory guards");
|
||||
return get_user_ptr();
|
||||
@ -230,6 +244,20 @@ protected:
|
||||
*/
|
||||
void* get_tag() const { return get_head_guard()->get_tag(); }
|
||||
|
||||
/**
|
||||
* Set the second general purpose tag.
|
||||
*
|
||||
* @param tag general purpose tag.
|
||||
*/
|
||||
void set_tag2(const void* tag) { get_head_guard()->set_tag2(tag); }
|
||||
|
||||
/**
|
||||
* Return the second general purpose tag.
|
||||
*
|
||||
* @return the second general purpose tag, defaults to null.
|
||||
*/
|
||||
void* get_tag2() const { return get_head_guard()->get_tag2(); }
|
||||
|
||||
/**
|
||||
* Return the size of the user data.
|
||||
*
|
||||
@ -302,10 +330,12 @@ protected:
|
||||
* @param ptr the memory to be copied
|
||||
* @param len the length of the copy
|
||||
* @param tag optional general purpose tag (see GuardedMemory::get_tag())
|
||||
* @param tag2 optional general purpose tag (see GuardedMemory::get_tag2())
|
||||
*
|
||||
* @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 = nullptr);
|
||||
static void* wrap_copy(const void* p, const size_t len,
|
||||
const void* tag = nullptr, const void* tag2 = nullptr);
|
||||
|
||||
/**
|
||||
* Free wrapped copy.
|
||||
|
||||
@ -350,24 +350,33 @@ check_is_obj_array(JavaThread* thr, jarray jArray) {
|
||||
}
|
||||
}
|
||||
|
||||
// Arbitrary (but well-known) tag for GetStringChars
|
||||
const void* STRING_TAG = (void*)0x47114711;
|
||||
|
||||
// Arbitrary (but well-known) tag for GetStringUTFChars
|
||||
const void* STRING_UTF_TAG = (void*) 0x48124812;
|
||||
|
||||
// Arbitrary (but well-known) tag for GetPrimitiveArrayCritical
|
||||
const void* CRITICAL_TAG = (void*)0x49134913;
|
||||
|
||||
/*
|
||||
* 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* orig_elements, jboolean is_critical = JNI_FALSE) {
|
||||
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);
|
||||
result = GuardedMemory::wrap_copy(orig_elements, len, orig_elements, is_critical ? CRITICAL_TAG : nullptr);
|
||||
)
|
||||
return result;
|
||||
}
|
||||
|
||||
static void* check_wrapped_array(JavaThread* thr, const char* fn_name,
|
||||
void* obj, void* carray, size_t* rsz) {
|
||||
void* obj, void* carray, size_t* rsz, jboolean is_critical) {
|
||||
if (carray == nullptr) {
|
||||
tty->print_cr("%s: elements vector null" PTR_FORMAT, fn_name, p2i(obj));
|
||||
NativeReportJNIFatalError(thr, "Elements vector null");
|
||||
@ -386,6 +395,29 @@ static void* check_wrapped_array(JavaThread* thr, const char* fn_name,
|
||||
DEBUG_ONLY(guarded.print_on(tty);) // This may crash.
|
||||
NativeReportJNIFatalError(thr, err_msg("%s: unrecognized elements", fn_name));
|
||||
}
|
||||
if (orig_result == STRING_TAG || orig_result == STRING_UTF_TAG) {
|
||||
bool was_utf = orig_result == STRING_UTF_TAG;
|
||||
tty->print_cr("%s: called on something allocated by %s",
|
||||
fn_name, was_utf ? "GetStringUTFChars" : "GetStringChars");
|
||||
DEBUG_ONLY(guarded.print_on(tty);) // This may crash.
|
||||
NativeReportJNIFatalError(thr, err_msg("%s called on something allocated by %s",
|
||||
fn_name, was_utf ? "GetStringUTFChars" : "GetStringChars"));
|
||||
}
|
||||
|
||||
if (is_critical && (guarded.get_tag2() != CRITICAL_TAG)) {
|
||||
tty->print_cr("%s: called on something not allocated by GetPrimitiveArrayCritical", fn_name);
|
||||
DEBUG_ONLY(guarded.print_on(tty);) // This may crash.
|
||||
NativeReportJNIFatalError(thr, err_msg("%s called on something not allocated by GetPrimitiveArrayCritical",
|
||||
fn_name));
|
||||
}
|
||||
|
||||
if (!is_critical && (guarded.get_tag2() == CRITICAL_TAG)) {
|
||||
tty->print_cr("%s: called on something allocated by GetPrimitiveArrayCritical", fn_name);
|
||||
DEBUG_ONLY(guarded.print_on(tty);) // This may crash.
|
||||
NativeReportJNIFatalError(thr, err_msg("%s called on something allocated by GetPrimitiveArrayCritical",
|
||||
fn_name));
|
||||
}
|
||||
|
||||
if (rsz != nullptr) {
|
||||
*rsz = guarded.get_user_size();
|
||||
}
|
||||
@ -395,7 +427,7 @@ static void* check_wrapped_array(JavaThread* thr, const char* fn_name,
|
||||
static void* check_wrapped_array_release(JavaThread* thr, const char* fn_name,
|
||||
void* obj, void* carray, jint mode, jboolean is_critical) {
|
||||
size_t sz;
|
||||
void* orig_result = check_wrapped_array(thr, fn_name, obj, carray, &sz);
|
||||
void* orig_result = check_wrapped_array(thr, fn_name, obj, carray, &sz, is_critical);
|
||||
switch (mode) {
|
||||
case 0:
|
||||
memcpy(orig_result, carray, sz);
|
||||
@ -1430,9 +1462,6 @@ JNI_ENTRY_CHECKED(jsize,
|
||||
return result;
|
||||
JNI_END
|
||||
|
||||
// Arbitrary (but well-known) tag
|
||||
const void* STRING_TAG = (void*)0x47114711;
|
||||
|
||||
JNI_ENTRY_CHECKED(const jchar *,
|
||||
checked_jni_GetStringChars(JNIEnv *env,
|
||||
jstring str,
|
||||
@ -1535,9 +1564,6 @@ JNI_ENTRY_CHECKED(jlong,
|
||||
return result;
|
||||
JNI_END
|
||||
|
||||
// Arbitrary (but well-known) tag - different than GetStringChars
|
||||
const void* STRING_UTF_TAG = (void*) 0x48124812;
|
||||
|
||||
JNI_ENTRY_CHECKED(const char *,
|
||||
checked_jni_GetStringUTFChars(JNIEnv *env,
|
||||
jstring str,
|
||||
@ -1859,7 +1885,7 @@ JNI_ENTRY_CHECKED(void *,
|
||||
)
|
||||
void *result = UNCHECKED()->GetPrimitiveArrayCritical(env, array, isCopy);
|
||||
if (result != nullptr) {
|
||||
result = check_jni_wrap_copy_array(thr, array, result);
|
||||
result = check_jni_wrap_copy_array(thr, array, result, JNI_TRUE);
|
||||
}
|
||||
functionExit(thr);
|
||||
return result;
|
||||
|
||||
@ -57,7 +57,7 @@ TEST(GuardedMemory, size) {
|
||||
}
|
||||
|
||||
// Test the basic characteristics
|
||||
TEST(GuardedMemory, basic) {
|
||||
TEST_VM(GuardedMemory, basic) {
|
||||
u_char* basep =
|
||||
(u_char*) os::malloc(GuardedMemory::get_total_size(1), mtInternal);
|
||||
GuardedMemory guarded(basep, 1, GEN_PURPOSE_TAG);
|
||||
@ -78,7 +78,7 @@ TEST(GuardedMemory, basic) {
|
||||
}
|
||||
|
||||
// Test a number of odd sizes
|
||||
TEST(GuardedMemory, odd_sizes) {
|
||||
TEST_VM(GuardedMemory, odd_sizes) {
|
||||
u_char* basep =
|
||||
(u_char*) os::malloc(GuardedMemory::get_total_size(1), mtInternal);
|
||||
GuardedMemory guarded(basep, 1, GEN_PURPOSE_TAG);
|
||||
@ -99,7 +99,7 @@ TEST(GuardedMemory, odd_sizes) {
|
||||
}
|
||||
|
||||
// Test buffer overrun into head...
|
||||
TEST(GuardedMemory, buffer_overrun_head) {
|
||||
TEST_VM(GuardedMemory, buffer_overrun_head) {
|
||||
u_char* basep =
|
||||
(u_char*) os::malloc(GuardedMemory::get_total_size(1), mtInternal);
|
||||
GuardedMemory guarded(basep, 1, GEN_PURPOSE_TAG);
|
||||
@ -111,7 +111,7 @@ TEST(GuardedMemory, buffer_overrun_head) {
|
||||
}
|
||||
|
||||
// Test buffer overrun into tail with a number of odd sizes
|
||||
TEST(GuardedMemory, buffer_overrun_tail) {
|
||||
TEST_VM(GuardedMemory, buffer_overrun_tail) {
|
||||
u_char* basep =
|
||||
(u_char*) os::malloc(GuardedMemory::get_total_size(1), mtInternal);
|
||||
GuardedMemory guarded(basep, 1, GEN_PURPOSE_TAG);
|
||||
@ -128,7 +128,7 @@ TEST(GuardedMemory, buffer_overrun_tail) {
|
||||
}
|
||||
|
||||
// Test wrap_copy/wrap_free
|
||||
TEST(GuardedMemory, wrap) {
|
||||
TEST_VM(GuardedMemory, wrap) {
|
||||
EXPECT_TRUE(GuardedMemory::free_copy(nullptr)) << "Expected free nullptr to be OK";
|
||||
|
||||
const char* str = "Check my bounds out";
|
||||
@ -146,3 +146,10 @@ TEST(GuardedMemory, wrap) {
|
||||
EXPECT_TRUE(GuardedMemory::free_copy(no_data_copy))
|
||||
<< "Expected valid guards even for no data copy";
|
||||
}
|
||||
|
||||
// Test passing back a bogus GuardedMemory region
|
||||
TEST_VM(GuardedMemory, unmapped) {
|
||||
char* unmapped_base = (char*) (GuardedMemoryTest::get_guard_header_size() + 0x1000 + 1); // Avoids assert in constructor
|
||||
GuardedMemory guarded(unmapped_base);
|
||||
EXPECT_FALSE(guarded.verify_guards()) << "Guard was not broken as expected";
|
||||
}
|
||||
|
||||
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 2025, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8357601
|
||||
* @requires vm.flagless
|
||||
* @library /test/lib
|
||||
* @run main/othervm/native TestCharArrayReleasing 0 0
|
||||
* @run main/othervm/native TestCharArrayReleasing 1 0
|
||||
* @run main/othervm/native TestCharArrayReleasing 2 0
|
||||
* @run main/othervm/native TestCharArrayReleasing 3 0
|
||||
* @run main/othervm/native TestCharArrayReleasing 4 0
|
||||
* @run main/othervm/native TestCharArrayReleasing 0 1
|
||||
* @run main/othervm/native TestCharArrayReleasing 1 1
|
||||
* @run main/othervm/native TestCharArrayReleasing 2 1
|
||||
* @run main/othervm/native TestCharArrayReleasing 3 1
|
||||
* @run main/othervm/native TestCharArrayReleasing 4 1
|
||||
* @run main/othervm/native TestCharArrayReleasing 0 2
|
||||
* @run main/othervm/native TestCharArrayReleasing 1 2
|
||||
* @run main/othervm/native TestCharArrayReleasing 2 2
|
||||
* @run main/othervm/native TestCharArrayReleasing 3 2
|
||||
* @run main/othervm/native TestCharArrayReleasing 4 2
|
||||
* @run main/othervm/native TestCharArrayReleasing 0 3
|
||||
* @run main/othervm/native TestCharArrayReleasing 1 3
|
||||
* @run main/othervm/native TestCharArrayReleasing 2 3
|
||||
* @run main/othervm/native TestCharArrayReleasing 3 3
|
||||
* @run main/othervm/native TestCharArrayReleasing 4 3
|
||||
*/
|
||||
|
||||
import jdk.test.lib.Platform;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
|
||||
// Test the behaviour of the JNI "char" releasing functions, under Xcheck:jni,
|
||||
// when they are passed "char" arrays obtained from different sources:
|
||||
// - source_mode indicates which array to use
|
||||
// - 0: use a raw malloc'd array
|
||||
// - 1: use an array from GetCharArrayElements
|
||||
// - 2: use an array from GetStringChars
|
||||
// - 3: use an array from GetStringUTFChars
|
||||
// - 4: use an array from GetPrimitiveArrayCritical
|
||||
// - release_mode indicates which releasing function to use
|
||||
// - 0: ReleaseCharArrayElements
|
||||
// - 1: ReleaseStringChars
|
||||
// - 2: ReleaseStringUTFChars
|
||||
// - 3: ReleasePrimitiveArrayCritical
|
||||
|
||||
public class TestCharArrayReleasing {
|
||||
|
||||
static native void testIt(int srcMode, int releaseMode);
|
||||
|
||||
static class Driver {
|
||||
|
||||
static {
|
||||
System.loadLibrary("CharArrayReleasing");
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
int srcMode = Integer.parseInt(args[0]);
|
||||
int relMode = Integer.parseInt(args[1]);
|
||||
testIt(srcMode, relMode);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
int ABRT = 1;
|
||||
int[][] errorCodes = new int[][] {
|
||||
{ ABRT, 0, ABRT, ABRT, ABRT },
|
||||
{ ABRT, ABRT, 0, ABRT, ABRT },
|
||||
{ ABRT, ABRT, ABRT, 0, ABRT },
|
||||
{ ABRT, ABRT, ABRT, ABRT, 0 },
|
||||
};
|
||||
|
||||
String rcae = "ReleaseCharArrayElements called on something allocated by GetStringChars";
|
||||
String rcaeUTF = "ReleaseCharArrayElements called on something allocated by GetStringUTFChars";
|
||||
String rcaeCrit = "ReleaseCharArrayElements called on something allocated by GetPrimitiveArrayCritical";
|
||||
String rcaeBounds = "ReleaseCharArrayElements: release array failed bounds check";
|
||||
String rsc = "ReleaseStringChars called on something not allocated by GetStringChars";
|
||||
String rscBounds = "ReleaseStringChars: release chars failed bounds check";
|
||||
String rsuc = "ReleaseStringUTFChars called on something not allocated by GetStringUTFChars";
|
||||
String rsucBounds = "ReleaseStringUTFChars: release chars failed bounds check";
|
||||
String rpac = "ReleasePrimitiveArrayCritical called on something not allocated by GetPrimitiveArrayCritical";
|
||||
String rpacBounds = "ReleasePrimitiveArrayCritical: release array failed bounds check";
|
||||
String rpacStr = "ReleasePrimitiveArrayCritical called on something allocated by GetStringChars";
|
||||
String rpacStrUTF = "ReleasePrimitiveArrayCritical called on something allocated by GetStringUTFChars";
|
||||
|
||||
String[][] errorMsgs = new String[][] {
|
||||
{ rcaeBounds, "", rcae, rcaeUTF, rcaeCrit },
|
||||
{ rscBounds, rsc, "", rsc, rsc },
|
||||
{ rsucBounds, rsuc, rsuc, "", rsuc },
|
||||
{ rpacBounds, rpac, rpacStr, rpacStrUTF, "" },
|
||||
};
|
||||
|
||||
int srcMode = Integer.parseInt(args[0]);
|
||||
int relMode = Integer.parseInt(args[1]);
|
||||
|
||||
ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(
|
||||
"-Djava.library.path=" + System.getProperty("test.nativepath"),
|
||||
"--enable-native-access=ALL-UNNAMED",
|
||||
"-XX:-CreateCoredumpOnCrash",
|
||||
"-Xcheck:jni",
|
||||
"TestCharArrayReleasing$Driver",
|
||||
args[0], args[1]);
|
||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||
output.shouldHaveExitValue(errorCodes[relMode][srcMode]);
|
||||
output.shouldContain(errorMsgs[relMode][srcMode]);
|
||||
}
|
||||
}
|
||||
125
test/hotspot/jtreg/runtime/jni/checked/libCharArrayReleasing.c
Normal file
125
test/hotspot/jtreg/runtime/jni/checked/libCharArrayReleasing.c
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (c) 2025, 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
|
||||
// Test the behaviour of the JNI "char" releasing functions, under Xcheck:jni,
|
||||
// when they are passed "char" arrays obtained from different sources:
|
||||
// - source_mode indicates which array to use
|
||||
// - 0: use a raw malloc'd array
|
||||
// - 1: use an array from GetCharArrayElements
|
||||
// - 2: use an array from GetStringChars
|
||||
// - 3: use an array from GetStringUTFChars
|
||||
// - 4: use an array from GetPrimitiveArrayCritical
|
||||
// - release_mode indicates which releasing function to use
|
||||
// - 0: ReleaseCharArrayElements
|
||||
// - 1: ReleaseStringChars
|
||||
// - 2: ReleaseStringUTFChars
|
||||
// - 3: ReleasePrimitiveArrayCritical
|
||||
//
|
||||
|
||||
static char* source[] = {
|
||||
"malloc",
|
||||
"GetCharArrayElements",
|
||||
"GetStringChars",
|
||||
"GetStringUTFChars",
|
||||
"GetPrimitiveArrayCritical"
|
||||
};
|
||||
|
||||
static char* release_func[] = {
|
||||
"ReleaseCharArrayElements",
|
||||
"ReleaseStringChars",
|
||||
"ReleaseStringUTFChars",
|
||||
"ReleasePrimitiveArrayCritical"
|
||||
};
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_TestCharArrayReleasing_testIt(JNIEnv *env, jclass cls, jint source_mode,
|
||||
jint release_mode) {
|
||||
|
||||
// First create some Java objects to be used as the sources for jchar[]
|
||||
// extraction.
|
||||
const int len = 10;
|
||||
jcharArray ca = (*env)->NewCharArray(env, len);
|
||||
jstring str = (*env)->NewStringUTF(env, "A_String");
|
||||
|
||||
jthrowable exc = (*env)->ExceptionOccurred(env);
|
||||
if (exc != NULL) {
|
||||
fprintf(stderr, "ERROR: Unexpected exception during test set up:\n");
|
||||
(*env)->ExceptionDescribe(env);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
fprintf(stdout, "Testing release function %s with array from %s\n",
|
||||
release_func[release_mode], source[source_mode]);
|
||||
fflush(stdout);
|
||||
|
||||
jboolean is_copy = JNI_FALSE;
|
||||
jchar* to_release;
|
||||
switch(source_mode) {
|
||||
case 0: {
|
||||
to_release = malloc(10 * sizeof(jchar));
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
to_release = (*env)->GetCharArrayElements(env, ca, &is_copy);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
to_release = (jchar*) (*env)->GetStringChars(env, str, &is_copy);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
to_release = (jchar*) (*env)->GetStringUTFChars(env, str, &is_copy);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
to_release = (jchar*) (*env)->GetPrimitiveArrayCritical(env, ca, &is_copy);
|
||||
break;
|
||||
}
|
||||
default: fprintf(stderr, "Unexpected source_mode %d\n", source_mode);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
switch (release_mode) {
|
||||
case 0:
|
||||
(*env)->ReleaseCharArrayElements(env, ca, to_release, 0);
|
||||
break;
|
||||
case 1:
|
||||
(*env)->ReleaseStringChars(env, str, to_release);
|
||||
break;
|
||||
case 2:
|
||||
(*env)->ReleaseStringUTFChars(env, str, (const char*)to_release);
|
||||
break;
|
||||
case 3:
|
||||
(*env)->ReleasePrimitiveArrayCritical(env, ca, to_release, 0);
|
||||
break;
|
||||
default: fprintf(stderr, "Unexpected release_mode %d\n", source_mode);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user