Compare commits

...

45 Commits

Author SHA1 Message Date
Erik Gahlin
f4a39323bf 8272588: Enhanced recording parsing
Reviewed-by: mgronlun
2022-02-08 09:26:10 -08:00
Erik Gahlin
eb2f497cf0 8272594: Better record of recordings
Reviewed-by: mgronlun
2022-02-08 09:26:09 -08:00
Ravi Reddy
41fe8d2200 8277672: Better invocation handler handling
Backport-of: 0691804665559f1935b7361d5f1207ac46f823f0
2022-02-08 09:26:09 -08:00
Daniel Fuchs
71640f2870 8278972: Improve URL supports
Backport-of: 94f1fbfd6d23f18ade3cc1b36f6dd368963c9d02
2022-02-08 09:26:08 -08:00
robm
84afe806bd Merge 2022-02-08 09:23:12 -08:00
robm
7796859f04 Merge 2022-02-07 13:54:30 -08:00
Rob McKenna
f1c769462d 8277795: ldap connection timeout not honoured under contention
Backport-of: 3d926dd66e
2022-02-07 20:06:49 +00:00
Sean Coffey
fbc28a7047 8278851: Correct signer logic for jars signed with multiple digestalgs
Backport-of: 61b8944327
2022-02-07 14:37:59 +00:00
Matthias Baesken
1f039b3e1d 8280414: Memory leak in DefaultProxySelector
Backport-of: fe77250fa4
2022-02-03 08:09:07 +00:00
Tobias Hartmann
68a08070ca 8280123: C2: Infinite loop in CMoveINode::Ideal during IGVN
Backport-of: 3f747368b9
2022-02-03 06:24:40 +00:00
Tobias Hartmann
93453364ed 8258814: Compilation logging crashes for thread suspension / debugging tests
Backport-of: 35ee0f38c6
2022-02-03 06:23:43 +00:00
Tobias Hartmann
d21b5e77fa 8279412: [JVMCI] failed speculations list must outlive any nmethod that refers to it
Backport-of: 1ffdc52cf0
2022-02-03 06:22:43 +00:00
Tobias Hartmann
34f2864680 8273139: C2: assert(f <= 1 && f >= 0) failed: Incorrect frequency
Backport-of: 68b40ec286
2022-02-03 06:21:53 +00:00
Tobias Hartmann
313932af0a 8279225: [arm32] C1 longs comparison operation destroys argument registers
Backport-of: 299022dfac
2022-02-03 06:20:49 +00:00
Tobias Hartmann
2b74a8d2a1 8279437: [JVMCI] exception in HotSpotJVMCIRuntime.translate can exit the VM
Backport-of: e14fb4f4aa
2022-02-03 06:19:41 +00:00
Sergey Bylokhov
e32fb7fc20 8280910: Update openjdk project in jcheck to "jdk-updates" for jdk18u
Reviewed-by: erikj
2022-02-02 22:51:10 +00:00
robm
c3653f2400 Merge 2022-02-01 21:12:17 +00:00
robm
355f7fe2c5 Merge 2022-02-01 17:50:08 +00:00
robm
74e1fdbb12 Merge 2022-02-01 15:05:19 +00:00
Erik Gahlin
c305c3e18e 8272261: Improve JFR recording file processing
Reviewed-by: mikael
2022-02-01 14:14:49 +00:00
Ravi Reddy
e161e135c0 8269938: Enhance XML processing passes redux
Reviewed-by: joehw
Backport-of: ff4e11b1a83d6910e39f1d46bea154f0876f39da
2022-02-01 14:14:48 +00:00
Alexander Zuev
f32637c0ba 8272255: Completely handle MIDI files
Backport-of: 6efdd1870e7ddb77a04d8c8183ced385039d0913
2022-02-01 14:14:48 +00:00
Aleksey Shipilev
5b8f9ff39a 8280526: x86_32 Math.sqrt performance regression with -XX:UseSSE={0,1}
Backport-of: a24f44d17d
2022-01-31 18:22:07 +00:00
Aleksey Shipilev
86956ee964 8279445: Update JMH devkit to 1.34
Backport-of: 0f98efbf2f
2022-01-31 18:20:59 +00:00
Alexey Ivanov
cd5a9a9522 8278472: Invalid value set to CANDIDATEFORM structure
Backport-of: 2426d58e59
2022-01-28 18:19:17 +00:00
Dmitry Markov
bb5bc6a87e 8274751: Drag And Drop hangs on Windows
Backport-of: 7a0a6c95a5
2022-01-28 10:23:13 +00:00
Harold Seigel
76a2b3bfaf 8267341: macos attempt_reserve_memory_at(arg1, arg2, true) failure
Backport-of: d1efb0cc56
2022-01-27 18:18:37 +00:00
pavel_kharskii
a9622b1c93 8280785: change milestone to fcs for releases: jdk-11.0.15, jdk-17.0.3, jdk-18.0.1
Reviewed-by: robm, coffeys
2022-01-27 17:09:58 +00:00
robm
fcd258a07f Merge 2022-01-25 20:36:21 +00:00
Jayathirth D V
8b416ea00c 8278805: Enhance BMP image loading
Reviewed-by: azvegint
Backport-of: 6319119be51e595be82f253b9f5e9495e72d4ad9
2022-01-25 20:14:00 +00:00
Weijun Wang
56b0dfffb7 8278449: Improve keychain support
Backport-of: 2376bb88eff3ae6922c4cae276e1d703a520853d
2022-01-25 20:13:55 +00:00
Anthony Scarpino
715b432ae5 8275151: Improved Object Identification
Backport-of: 4cffe1cc913f895f54281de8e91ca39f4bde4b5f
2022-01-25 20:13:50 +00:00
robm
be731606e2 Merge 2022-01-25 09:06:17 +00:00
Erik Joelsson
338d3d2d8a 8279223: Define version in .jcheck/conf
Reviewed-by: kcr, iris
2022-01-14 21:23:57 +00:00
Valerie Peng
29ce3ae34b 8277227: Better identification of OIDs
Reviewed-by: coffeys
Backport-of: 3ac5f0175356fad40b59f879322fa7d89dfbcaab
2022-01-11 21:36:03 +00:00
Weijun Wang
bab7d80317 8274221: More definite BER encodings
Backport-of: ee39b0fc22a55a051b8a4d5754c34105fe4b734e
2022-01-11 20:34:46 +00:00
robm
d0e26d3e7c Merge 2022-01-11 14:37:37 +00:00
robm
f357fdefad Merge 2022-01-11 13:35:05 +00:00
Weijun Wang
6caa851218 8277233: Improve ECDSA signature support
Backport-of: 34714d63f1be267c2bc2ae7a55f936deab8ea6d2
2022-01-10 21:08:58 +00:00
robm
cbcb39119d Merge 2022-01-10 17:23:39 +00:00
Harold Seigel
a2d1450011 8278384: Bytecodes::result_type() for arraylength returns T_VOID instead of T_INT
Backport-of: 769f14db84
2022-01-10 13:30:53 +00:00
robm
b260c5c939 Merge 2022-01-10 12:47:06 +00:00
robm
419f9ccd83 Merge 2022-01-10 10:23:45 +00:00
Tobias Hartmann
d2ee0647a5 8278798: Improve supported intrinsic
Reviewed-by: chagedorn
Backport-of: 7ed3d37203da74f3f2cc92d06250f74aa5ceccd1
2022-01-07 13:48:08 +00:00
Pavel Kharskii
6d45bba88a 8278869: Bump version numbers for OPENJDK 18.0.1
Reviewed-by: coffeys
2021-12-23 21:12:29 +00:00
75 changed files with 2411 additions and 777 deletions

View File

@@ -1,6 +1,7 @@
[general]
project=jdk
project=jdk-updates
jbs=JDK
version=18.0.1
[checks]
error=author,committer,reviewers,merge,issues,executable,symlink,message,hg-tag,whitespace,problemlists

View File

@@ -28,15 +28,15 @@
DEFAULT_VERSION_FEATURE=18
DEFAULT_VERSION_INTERIM=0
DEFAULT_VERSION_UPDATE=0
DEFAULT_VERSION_UPDATE=1
DEFAULT_VERSION_PATCH=0
DEFAULT_VERSION_EXTRA1=0
DEFAULT_VERSION_EXTRA2=0
DEFAULT_VERSION_EXTRA3=0
DEFAULT_VERSION_DATE=2022-03-22
DEFAULT_VERSION_DATE=2022-04-19
DEFAULT_VERSION_CLASSFILE_MAJOR=62 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`"
DEFAULT_VERSION_CLASSFILE_MINOR=0
DEFAULT_VERSION_DOCS_API_SINCE=11
DEFAULT_ACCEPTABLE_BOOT_VERSIONS="17 18"
DEFAULT_JDK_SOURCE_TARGET_VERSION=18
DEFAULT_PROMOTED_VERSION_PRE=ea
DEFAULT_PROMOTED_VERSION_PRE=

View File

@@ -26,7 +26,7 @@
# Create a bundle in the build directory, containing what's needed to
# build and run JMH microbenchmarks from the OpenJDK build.
JMH_VERSION=1.33
JMH_VERSION=1.34
COMMONS_MATH3_VERSION=3.2
JOPT_SIMPLE_VERSION=4.6

View File

@@ -1820,8 +1820,8 @@ void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2,
__ teq(xhi, yhi);
__ teq(xlo, ylo, eq);
} else {
__ subs(xlo, xlo, ylo);
__ sbcs(xhi, xhi, yhi);
__ subs(Rtemp, xlo, ylo);
__ sbcs(Rtemp, xhi, yhi);
}
} else {
ShouldNotReachHere();

View File

@@ -1607,9 +1607,14 @@ const bool Matcher::match_rule_supported(int opcode) {
}
break;
case Op_SqrtD:
#ifdef _LP64
if (UseSSE < 2) {
return false;
}
#else
// x86_32.ad has a special match rule for SqrtD.
// Together with common x86 rules, this handles all UseSSE cases.
#endif
break;
}
return true; // Match rules are supported by default.

View File

@@ -1970,6 +1970,8 @@ void CompileBroker::compiler_thread_loop() {
method->clear_queued_for_compilation();
task->set_failure_reason("compilation is disabled");
}
} else {
task->set_failure_reason("breakpoints are present");
}
if (UseDynamicNumberOfCompilerThreads) {

View File

@@ -1029,7 +1029,6 @@ int ExceptionMessageBuilder::do_instruction(int bci) {
break;
case Bytecodes::_arraylength:
// The return type of arraylength is wrong in the bytecodes table (T_VOID).
stack->pop(1);
stack->push(bci, T_INT);
break;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2021, 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
@@ -471,7 +471,7 @@ void Bytecodes::initialize() {
def(_new , "new" , "bkk" , NULL , T_OBJECT , 1, true );
def(_newarray , "newarray" , "bc" , NULL , T_OBJECT , 0, true );
def(_anewarray , "anewarray" , "bkk" , NULL , T_OBJECT , 0, true );
def(_arraylength , "arraylength" , "b" , NULL , T_VOID , 0, true );
def(_arraylength , "arraylength" , "b" , NULL , T_INT , 0, true );
def(_athrow , "athrow" , "b" , NULL , T_VOID , -1, true );
def(_checkcast , "checkcast" , "bkk" , NULL , T_OBJECT , 0, true );
def(_instanceof , "instanceof" , "bkk" , NULL , T_INT , 0, true );

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2022, 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
@@ -2376,7 +2376,7 @@ C2V_VMENTRY_PREFIX(void, detachCurrentThread, (JNIEnv* env, jobject c2vm))
}
C2V_END
C2V_VMENTRY_0(jlong, translate, (JNIEnv* env, jobject, jobject obj_handle))
C2V_VMENTRY_0(jlong, translate, (JNIEnv* env, jobject, jobject obj_handle, jboolean callPostTranslation))
requireJVMCINativeLibrary(JVMCI_CHECK_0);
if (obj_handle == NULL) {
return 0L;
@@ -2427,7 +2427,9 @@ C2V_VMENTRY_0(jlong, translate, (JNIEnv* env, jobject, jobject obj_handle))
const char* cstring = name_string.is_null() ? NULL : thisEnv->as_utf8_string(name_string);
// Create a new HotSpotNmethod instance in the peer runtime
result = peerEnv->new_HotSpotNmethod(mh, cstring, isDefault, compileIdSnapshot, JVMCI_CHECK_0);
if (nm == NULL) {
if (result.is_null()) {
// exception occurred (e.g. OOME) creating a new HotSpotNmethod
} else if (nm == NULL) {
// nmethod must have been unloaded
} else {
// Link the new HotSpotNmethod to the nmethod
@@ -2450,6 +2452,13 @@ C2V_VMENTRY_0(jlong, translate, (JNIEnv* env, jobject, jobject obj_handle))
JVMCI_THROW_MSG_0(IllegalArgumentException,
err_msg("Cannot translate object of type: %s", thisEnv->klass_name(obj)));
}
if (callPostTranslation) {
peerEnv->call_HotSpotJVMCIRuntime_postTranslation(result, JVMCI_CHECK_0);
}
// Propagate any exception that occurred while creating the translated object
if (peerEnv->transfer_pending_exception(thread, thisEnv)) {
return 0L;
}
return (jlong) peerEnv->make_global(result).as_jobject();
}
@@ -2790,7 +2799,7 @@ JNINativeMethod CompilerToVM::methods[] = {
{CC "getCurrentJavaThread", CC "()J", FN_PTR(getCurrentJavaThread)},
{CC "attachCurrentThread", CC "([BZ)Z", FN_PTR(attachCurrentThread)},
{CC "detachCurrentThread", CC "()V", FN_PTR(detachCurrentThread)},
{CC "translate", CC "(" OBJECT ")J", FN_PTR(translate)},
{CC "translate", CC "(" OBJECT "Z)J", FN_PTR(translate)},
{CC "unhand", CC "(J)" OBJECT, FN_PTR(unhand)},
{CC "updateHotSpotNmethod", CC "(" HS_NMETHOD ")V", FN_PTR(updateHotSpotNmethod)},
{CC "getCode", CC "(" HS_INSTALLED_CODE ")[B", FN_PTR(getCode)},

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2022, 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
@@ -278,35 +278,141 @@ void JVMCIEnv::describe_pending_exception(bool clear) {
}
}
void JVMCIEnv::translate_hotspot_exception_to_jni_exception(JavaThread* THREAD, const Handle& throwable) {
assert(!is_hotspot(), "must_be");
// Resolve HotSpotJVMCIRuntime class explicitly as HotSpotJVMCI::compute_offsets
// may not have been called.
Klass* runtimeKlass = SystemDictionary::resolve_or_fail(vmSymbols::jdk_vm_ci_hotspot_HotSpotJVMCIRuntime(), true, CHECK);
JavaCallArguments jargs;
jargs.push_oop(throwable);
JavaValue result(T_OBJECT);
JavaCalls::call_static(&result,
runtimeKlass,
vmSymbols::encodeThrowable_name(),
vmSymbols::encodeThrowable_signature(), &jargs, THREAD);
if (HAS_PENDING_EXCEPTION) {
JVMCIRuntime::fatal_exception(this, "HotSpotJVMCIRuntime.encodeThrowable should not throw an exception");
// Shared code for translating an exception from HotSpot to libjvmci or vice versa.
class ExceptionTranslation: public StackObj {
protected:
JVMCIEnv* _from_env; // Source of translation. Can be nullptr.
JVMCIEnv* _to_env; // Destination of translation. Never nullptr.
ExceptionTranslation(JVMCIEnv* from_env, JVMCIEnv* to_env) : _from_env(from_env), _to_env(to_env) {}
// Encodes the exception in `_from_env` into `buffer`.
// Where N is the number of bytes needed for the encoding, returns N if N <= `buffer_size`
// and the encoding was written to `buffer` otherwise returns -N.
virtual int encode(JavaThread* THREAD, Klass* runtimeKlass, jlong buffer, int buffer_size) = 0;
// Decodes the exception in `buffer` in `_to_env` and throws it.
virtual void decode(JavaThread* THREAD, Klass* runtimeKlass, jlong buffer) = 0;
public:
void doit(JavaThread* THREAD) {
// Resolve HotSpotJVMCIRuntime class explicitly as HotSpotJVMCI::compute_offsets
// may not have been called.
Klass* runtimeKlass = SystemDictionary::resolve_or_fail(vmSymbols::jdk_vm_ci_hotspot_HotSpotJVMCIRuntime(), true, CHECK);
int buffer_size = 2048;
while (true) {
ResourceMark rm;
jlong buffer = (jlong) NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, jbyte, buffer_size);
int res = encode(THREAD, runtimeKlass, buffer, buffer_size);
if ((_from_env != nullptr && _from_env->has_pending_exception()) || HAS_PENDING_EXCEPTION) {
JVMCIRuntime::fatal_exception(_from_env, "HotSpotJVMCIRuntime.encodeThrowable should not throw an exception");
}
if (res < 0) {
int required_buffer_size = -res;
if (required_buffer_size > buffer_size) {
buffer_size = required_buffer_size;
}
} else {
decode(THREAD, runtimeKlass, buffer);
if (!_to_env->has_pending_exception()) {
JVMCIRuntime::fatal_exception(_to_env, "HotSpotJVMCIRuntime.decodeAndThrowThrowable should throw an exception");
}
return;
}
}
}
};
// Translates an exception on the HotSpot heap to an exception on the shared library heap.
class HotSpotToSharedLibraryExceptionTranslation : public ExceptionTranslation {
private:
const Handle& _throwable;
int encode(JavaThread* THREAD, Klass* runtimeKlass, jlong buffer, int buffer_size) {
JavaCallArguments jargs;
jargs.push_oop(_throwable);
jargs.push_long(buffer);
jargs.push_int(buffer_size);
JavaValue result(T_INT);
JavaCalls::call_static(&result,
runtimeKlass,
vmSymbols::encodeThrowable_name(),
vmSymbols::encodeThrowable_signature(), &jargs, THREAD);
return result.get_jint();
}
oop encoded_throwable_string = result.get_oop();
void decode(JavaThread* THREAD, Klass* runtimeKlass, jlong buffer) {
JNIAccessMark jni(_to_env, THREAD);
jni()->CallStaticVoidMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(),
JNIJVMCI::HotSpotJVMCIRuntime::decodeAndThrowThrowable_method(),
buffer);
}
public:
HotSpotToSharedLibraryExceptionTranslation(JVMCIEnv* hotspot_env, JVMCIEnv* jni_env, const Handle& throwable) :
ExceptionTranslation(hotspot_env, jni_env), _throwable(throwable) {}
};
ResourceMark rm;
const char* encoded_throwable_chars = java_lang_String::as_utf8_string(encoded_throwable_string);
// Translates an exception on the shared library heap to an exception on the HotSpot heap.
class SharedLibraryToHotSpotExceptionTranslation : public ExceptionTranslation {
private:
jthrowable _throwable;
JNIAccessMark jni(this, THREAD);
jobject jni_encoded_throwable_string = jni()->NewStringUTF(encoded_throwable_chars);
jthrowable jni_throwable = (jthrowable) jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(),
JNIJVMCI::HotSpotJVMCIRuntime::decodeThrowable_method(),
jni_encoded_throwable_string);
jni()->Throw(jni_throwable);
int encode(JavaThread* THREAD, Klass* runtimeKlass, jlong buffer, int buffer_size) {
JNIAccessMark jni(_from_env, THREAD);
return jni()->CallStaticIntMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(),
JNIJVMCI::HotSpotJVMCIRuntime::encodeThrowable_method(),
_throwable, buffer, buffer_size);
}
void decode(JavaThread* THREAD, Klass* runtimeKlass, jlong buffer) {
JavaCallArguments jargs;
jargs.push_long(buffer);
JavaValue result(T_VOID);
JavaCalls::call_static(&result,
runtimeKlass,
vmSymbols::decodeAndThrowThrowable_name(),
vmSymbols::long_void_signature(), &jargs, THREAD);
}
public:
SharedLibraryToHotSpotExceptionTranslation(JVMCIEnv* hotspot_env, JVMCIEnv* jni_env, jthrowable throwable) :
ExceptionTranslation(jni_env, hotspot_env), _throwable(throwable) {}
};
void JVMCIEnv::translate_to_jni_exception(JavaThread* THREAD, const Handle& throwable, JVMCIEnv* hotspot_env, JVMCIEnv* jni_env) {
HotSpotToSharedLibraryExceptionTranslation(hotspot_env, jni_env, throwable).doit(THREAD);
}
void JVMCIEnv::translate_from_jni_exception(JavaThread* THREAD, jthrowable throwable, JVMCIEnv* hotspot_env, JVMCIEnv* jni_env) {
SharedLibraryToHotSpotExceptionTranslation(hotspot_env, jni_env, throwable).doit(THREAD);
}
jboolean JVMCIEnv::transfer_pending_exception(JavaThread* THREAD, JVMCIEnv* peer_env) {
if (is_hotspot()) {
if (HAS_PENDING_EXCEPTION) {
Handle throwable = Handle(THREAD, PENDING_EXCEPTION);
CLEAR_PENDING_EXCEPTION;
translate_to_jni_exception(THREAD, throwable, this, peer_env);
return true;
}
} else {
jthrowable ex = nullptr;
{
JNIAccessMark jni(this, THREAD);
ex = jni()->ExceptionOccurred();
if (ex != nullptr) {
jni()->ExceptionClear();
}
}
if (ex != nullptr) {
translate_from_jni_exception(THREAD, ex, peer_env, this);
return true;
}
}
return false;
}
JVMCIEnv::~JVMCIEnv() {
if (_throw_to_caller) {
if (is_hotspot()) {
@@ -318,7 +424,7 @@ JVMCIEnv::~JVMCIEnv() {
if (HAS_PENDING_EXCEPTION) {
Handle throwable = Handle(THREAD, PENDING_EXCEPTION);
CLEAR_PENDING_EXCEPTION;
translate_hotspot_exception_to_jni_exception(THREAD, throwable);
translate_to_jni_exception(THREAD, throwable, nullptr, this);
}
}
}
@@ -801,6 +907,23 @@ JVMCIObject JVMCIEnv::call_HotSpotJVMCIRuntime_callToString(JVMCIObject object,
}
}
void JVMCIEnv::call_HotSpotJVMCIRuntime_postTranslation(JVMCIObject object, JVMCIEnv* JVMCIENV) {
JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current()); // For exception macros.
if (is_hotspot()) {
JavaCallArguments jargs;
jargs.push_oop(Handle(THREAD, HotSpotJVMCI::resolve(object)));
JavaValue result(T_VOID);
JavaCalls::call_static(&result,
HotSpotJVMCI::HotSpotJVMCIRuntime::klass(),
vmSymbols::postTranslation_name(),
vmSymbols::object_void_signature(), &jargs, CHECK);
} else {
JNIAccessMark jni(this, THREAD);
jni()->CallStaticVoidMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(),
JNIJVMCI::HotSpotJVMCIRuntime::postTranslation_method(),
object.as_jobject());
}
}
JVMCIObject JVMCIEnv::call_JavaConstant_forPrimitive(JVMCIObject kind, jlong value, JVMCI_TRAPS) {
JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current()); // For exception macros.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2022, 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
@@ -171,11 +171,15 @@ class JVMCIEnv : public ResourceObj {
const char* _file; // The file and ...
int _line; // ... line where this JNIEnv was created
// Translates an exception on the HotSpot heap to an exception on
// the shared library heap. The translation includes the stack and
// causes of `throwable`. The translated exception is pending in the
// shared library thread upon returning.
void translate_hotspot_exception_to_jni_exception(JavaThread* THREAD, const Handle& throwable);
// Translates an exception on the HotSpot heap (i.e., hotspot_env) to an exception on
// the shared library heap (i.e., jni_env). The translation includes the stack and cause(s) of `throwable`.
// The translated exception is pending in jni_env upon returning.
static void translate_to_jni_exception(JavaThread* THREAD, const Handle& throwable, JVMCIEnv* hotspot_env, JVMCIEnv* jni_env);
// Translates an exception on the shared library heap (i.e., jni_env) to an exception on
// the HotSpot heap (i.e., hotspot_env). The translation includes the stack and cause(s) of `throwable`.
// The translated exception is pending in hotspot_env upon returning.
static void translate_from_jni_exception(JavaThread* THREAD, jthrowable throwable, JVMCIEnv* hotspot_env, JVMCIEnv* jni_env);
public:
// Opens a JVMCIEnv scope for a Java to VM call (e.g., via CompilerToVM).
@@ -225,6 +229,11 @@ public:
jboolean has_pending_exception();
void clear_pending_exception();
// If this env has a pending exception, it is translated to be a pending
// exception in `peer_env` and is cleared from this env. Returns true
// if a pending exception was transferred, false otherwise.
jboolean transfer_pending_exception(JavaThread* THREAD, JVMCIEnv* peer_env);
// Prints an exception and stack trace of a pending exception.
void describe_pending_exception(bool clear);
@@ -311,6 +320,8 @@ public:
jboolean call_HotSpotJVMCIRuntime_isGCSupported(JVMCIObject runtime, jint gcIdentifier);
void call_HotSpotJVMCIRuntime_postTranslation(JVMCIObject object, JVMCI_TRAPS);
BasicType kindToBasicType(JVMCIObject kind, JVMCI_TRAPS);
#define DO_THROW(name) \

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2022, 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

View File

@@ -349,13 +349,14 @@
objectarray_field(HotSpotJVMCIRuntime, excludeFromJVMCICompilation, "[Ljava/lang/Module;") \
jvmci_method(CallNonvirtualObjectMethod, GetMethodID, call_special, JVMCIObject, HotSpotJVMCIRuntime, compileMethod, compileMethod_signature, (JVMCIObject runtime, JVMCIObject method, int entry_bci, jlong env, int id)) \
jvmci_method(CallNonvirtualObjectMethod, GetMethodID, call_special, JVMCIObject, HotSpotJVMCIRuntime, isGCSupported, int_bool_signature, (JVMCIObject runtime, int gcIdentifier)) \
jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, HotSpotJVMCIRuntime, encodeThrowable, encodeThrowable_signature, (JVMCIObject throwable)) \
jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, HotSpotJVMCIRuntime, decodeThrowable, decodeThrowable_signature, (JVMCIObject encodedThrowable)) \
jvmci_method(CallStaticBooleanMethod, GetStaticMethodID, call_static, bool, HotSpotJVMCIRuntime, encodeThrowable, encodeThrowable_signature, (JVMCIObject throwable, jlong buffer, int buffer_size)) \
jvmci_method(CallStaticVoidMethod, GetStaticMethodID, call_static, void, HotSpotJVMCIRuntime, decodeAndThrowThrowable, long_void_signature, (jlong buffer)) \
jvmci_method(CallNonvirtualVoidMethod, GetMethodID, call_special, void, HotSpotJVMCIRuntime, bootstrapFinished, void_method_signature, (JVMCIObject runtime, JVMCI_TRAPS)) \
jvmci_method(CallNonvirtualVoidMethod, GetMethodID, call_special, void, HotSpotJVMCIRuntime, shutdown, void_method_signature, (JVMCIObject runtime)) \
jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, HotSpotJVMCIRuntime, runtime, runtime_signature, (JVMCI_TRAPS)) \
jvmci_method(CallObjectMethod, GetMethodID, call_virtual, JVMCIObject, HotSpotJVMCIRuntime, getCompiler, getCompiler_signature, (JVMCIObject runtime, JVMCI_TRAPS)) \
jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, HotSpotJVMCIRuntime, callToString, callToString_signature, (JVMCIObject object, JVMCI_TRAPS)) \
jvmci_method(CallStaticVoidMethod, GetStaticMethodID, call_static, void, HotSpotJVMCIRuntime, postTranslation, object_void_signature, (JVMCIObject object, JVMCI_TRAPS)) \
end_class \
start_class(JVMCIError, jdk_vm_ci_common_JVMCIError) \
jvmci_constructor(JVMCIError, "(Ljava/lang/String;)V") \

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2022, 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
@@ -105,9 +105,8 @@
template(compileMethod_signature, "(Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethod;IJI)Ljdk/vm/ci/hotspot/HotSpotCompilationRequestResult;") \
template(isGCSupported_name, "isGCSupported") \
template(encodeThrowable_name, "encodeThrowable") \
template(encodeThrowable_signature, "(Ljava/lang/Throwable;)Ljava/lang/String;") \
template(decodeThrowable_name, "decodeThrowable") \
template(decodeThrowable_signature, "(Ljava/lang/String;)Ljava/lang/Throwable;") \
template(encodeThrowable_signature, "(Ljava/lang/Throwable;JI)I") \
template(decodeAndThrowThrowable_name, "decodeAndThrowThrowable") \
template(fromMetaspace_name, "fromMetaspace") \
template(method_fromMetaspace_signature, "(J)Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethod;") \
template(constantPool_fromMetaspace_signature, "(J)Ljdk/vm/ci/hotspot/HotSpotConstantPool;") \
@@ -123,6 +122,7 @@
template(getCompiler_signature, "()Ljdk/vm/ci/runtime/JVMCICompiler;") \
template(callToString_name, "callToString") \
template(callToString_signature, "(Ljava/lang/Object;)Ljava/lang/String;") \
template(postTranslation_name, "postTranslation") \
template(getName_name, "getName") \
template(bootstrapFinished_name, "bootstrapFinished") \
template(forPrimitive_name, "forPrimitive") \

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2022, 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
@@ -1580,7 +1580,7 @@ bool LibraryCallKit::inline_string_char_access(bool is_store) {
if (is_store) {
access_store_at(value, adr, TypeAryPtr::BYTES, ch, TypeInt::CHAR, T_CHAR, IN_HEAP | MO_UNORDERED | C2_MISMATCHED);
} else {
ch = access_load_at(value, adr, TypeAryPtr::BYTES, TypeInt::CHAR, T_CHAR, IN_HEAP | MO_UNORDERED | C2_MISMATCHED | C2_CONTROL_DEPENDENT_LOAD);
ch = access_load_at(value, adr, TypeAryPtr::BYTES, TypeInt::CHAR, T_CHAR, IN_HEAP | MO_UNORDERED | C2_MISMATCHED | C2_CONTROL_DEPENDENT_LOAD | C2_UNKNOWN_CONTROL_LOAD);
set_result(ch);
}
return true;

View File

@@ -1024,13 +1024,15 @@ private:
GrowableArray<float> _freqs; // cache frequencies
PhaseIdealLoop* _phase;
void set_rounding(int mode) {
// fesetround is broken on windows
NOT_WINDOWS(fesetround(mode);)
}
void check_frequency(float f) {
NOT_WINDOWS(assert(f <= 1 && f >= 0, "Incorrect frequency");)
float check_and_truncate_frequency(float f) {
assert(f >= 0, "Incorrect frequency");
// We do not perform an exact (f <= 1) check
// this would be error prone with rounding of floats.
// Performing a check like (f <= 1+eps) would be of benefit,
// however, it is not evident how to determine such an eps,
// given that an arbitrary number of add/mul operations
// are performed on these frequencies.
return (f > 1) ? 1 : f;
}
public:
@@ -1040,7 +1042,6 @@ public:
float to(Node* n) {
// post order walk on the CFG graph from n to _dom
set_rounding(FE_TOWARDZERO); // make sure rounding doesn't push frequency above 1
IdealLoopTree* loop = _phase->get_loop(_dom);
Node* c = n;
for (;;) {
@@ -1067,14 +1068,12 @@ public:
inner_head = inner_loop->_head->as_Loop();
inner_head->verify_strip_mined(1);
}
set_rounding(FE_UPWARD); // make sure rounding doesn't push frequency above 1
float loop_exit_cnt = 0.0f;
for (uint i = 0; i < inner_loop->_body.size(); i++) {
Node *n = inner_loop->_body[i];
float c = inner_loop->compute_profile_trip_cnt_helper(n);
loop_exit_cnt += c;
}
set_rounding(FE_TOWARDZERO);
float cnt = -1;
if (n->in(0)->is_If()) {
IfNode* iff = n->in(0)->as_If();
@@ -1094,9 +1093,9 @@ public:
cnt = p * jmp->_fcnt;
}
float this_exit_f = cnt > 0 ? cnt / loop_exit_cnt : 0;
check_frequency(this_exit_f);
this_exit_f = check_and_truncate_frequency(this_exit_f);
f = f * this_exit_f;
check_frequency(f);
f = check_and_truncate_frequency(f);
} else {
float p = -1;
if (n->in(0)->is_If()) {
@@ -1109,7 +1108,7 @@ public:
p = n->in(0)->as_Jump()->_probs[n->as_JumpProj()->_con];
}
f = f * p;
check_frequency(f);
f = check_and_truncate_frequency(f);
}
_freqs.at_put_grow(n->_idx, (float)f, -1);
_stack.pop();
@@ -1117,7 +1116,7 @@ public:
float prev_f = _freqs_stack.pop();
float new_f = f;
f = new_f + prev_f;
check_frequency(f);
f = check_and_truncate_frequency(f);
uint i = _stack.index();
if (i < n->req()) {
c = n->in(i);
@@ -1130,9 +1129,7 @@ public:
}
}
if (_stack.size() == 0) {
set_rounding(FE_TONEAREST);
check_frequency(f);
return f;
return check_and_truncate_frequency(f);
}
} else if (c->is_Loop()) {
ShouldNotReachHere();

View File

@@ -75,21 +75,25 @@
// Return a node which is more "ideal" than the current node.
// Move constants to the right.
Node *CMoveNode::Ideal(PhaseGVN *phase, bool can_reshape) {
if( in(0) && remove_dead_region(phase, can_reshape) ) return this;
if (in(0) != NULL && remove_dead_region(phase, can_reshape)) {
return this;
}
// Don't bother trying to transform a dead node
if( in(0) && in(0)->is_top() ) return NULL;
if (in(0) != NULL && in(0)->is_top()) {
return NULL;
}
assert(in(Condition) != this &&
in(IfFalse) != this &&
in(IfTrue) != this, "dead loop in CMoveNode::Ideal" );
if( phase->type(in(Condition)) == Type::TOP )
return NULL; // return NULL when Condition is dead
if( in(IfFalse)->is_Con() && !in(IfTrue)->is_Con() ) {
if( in(Condition)->is_Bool() ) {
BoolNode* b = in(Condition)->as_Bool();
BoolNode* b2 = b->negate(phase);
return make(in(Control), phase->transform(b2), in(IfTrue), in(IfFalse), _type);
}
in(IfFalse) != this &&
in(IfTrue) != this, "dead loop in CMoveNode::Ideal");
if (phase->type(in(Condition)) == Type::TOP ||
phase->type(in(IfFalse)) == Type::TOP ||
phase->type(in(IfTrue)) == Type::TOP) {
return NULL;
}
// Canonicalize the node by moving constants to the right input.
if (in(Condition)->is_Bool() && phase->type(in(IfFalse))->singleton() && !phase->type(in(IfTrue))->singleton()) {
BoolNode* b = in(Condition)->as_Bool()->negate(phase);
return make(in(Control), phase->transform(b), in(IfTrue), in(IfFalse), _type);
}
return NULL;
}
@@ -191,14 +195,10 @@ Node *CMoveINode::Ideal(PhaseGVN *phase, bool can_reshape) {
// If zero is on the left (false-case, no-move-case) it must mean another
// constant is on the right (otherwise the shared CMove::Ideal code would
// have moved the constant to the right). This situation is bad for Intel
// and a don't-care for Sparc. It's bad for Intel because the zero has to
// be manifested in a register with a XOR which kills flags, which are live
// on input to the CMoveI, leading to a situation which causes excessive
// spilling on Intel. For Sparc, if the zero in on the left the Sparc will
// zero a register via G0 and conditionally-move the other constant. If the
// zero is on the right, the Sparc will load the first constant with a
// 13-bit set-lo and conditionally move G0. See bug 4677505.
// have moved the constant to the right). This situation is bad for x86 because
// the zero has to be manifested in a register with a XOR which kills flags,
// which are live on input to the CMoveI, leading to a situation which causes
// excessive spilling. See bug 4677505.
if( phase->type(in(IfFalse)) == TypeInt::ZERO && !(phase->type(in(IfTrue)) == TypeInt::ZERO) ) {
if( in(Condition)->is_Bool() ) {
BoolNode* b = in(Condition)->as_Bool();

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2022, 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
@@ -68,6 +68,25 @@ public final class KeychainStore extends KeyStoreSpi {
Certificate cert;
long certRef; // SecCertificateRef for this key
// Each KeyStore.TrustedCertificateEntry have 2 attributes:
// 1. "trustSettings" -> trustSettings.toString()
// 2. "2.16.840.1.113894.746875.1.1" -> trustedKeyUsageValue
// The 1st one is mainly for debugging use. The 2nd one is similar
// to the attribute with the same key in a PKCS12KeyStore.
// The SecTrustSettingsCopyTrustSettings() output for this certificate
// inside the KeyChain in its original array of CFDictionaryRef objects
// structure with values dumped as strings. For each trust, an extra
// entry "SecPolicyOid" is added whose value is the OID for this trust.
// The extra entries are used to construct trustedKeyUsageValue.
List<Map<String, String>> trustSettings;
// One or more OIDs defined in http://oidref.com/1.2.840.113635.100.1.
// It can also be "2.5.29.37.0" for a self-signed certificate with
// an empty trust settings. This value is never empty. When there are
// multiple OID values, it takes the form of "[1.1.1, 1.1.2]".
String trustedKeyUsageValue;
};
/**
@@ -300,6 +319,35 @@ public final class KeychainStore extends KeyStoreSpi {
}
}
private record LocalAttr(String name, String value)
implements KeyStore.Entry.Attribute {
@Override
public String getName() {
return name;
}
@Override
public String getValue() {
return value;
}
}
@Override
public KeyStore.Entry engineGetEntry(String alias, KeyStore.ProtectionParameter protParam)
throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableEntryException {
if (engineIsCertificateEntry(alias)) {
Object entry = entries.get(alias.toLowerCase());
if (entry instanceof TrustedCertEntry tEntry) {
return new KeyStore.TrustedCertificateEntry(
tEntry.cert, Set.of(
new LocalAttr(KnownOIDs.ORACLE_TrustedKeyUsage.value(), tEntry.trustedKeyUsageValue),
new LocalAttr("trustSettings", tEntry.trustSettings.toString())));
}
}
return super.engineGetEntry(alias, protParam);
}
/**
* Returns the creation date of the entry identified by the given alias.
*
@@ -453,55 +501,12 @@ public final class KeychainStore extends KeyStoreSpi {
}
/**
* Assigns the given certificate to the given alias.
*
* <p>If the given alias already exists in this keystore and identifies a
* <i>trusted certificate entry</i>, the certificate associated with it is
* overridden by the given certificate.
*
* @param alias the alias name
* @param cert the certificate
*
* @exception KeyStoreException if the given alias already exists and does
* not identify a <i>trusted certificate entry</i>, or this operation
* fails for some other reason.
* Adding trusted certificate entry is not supported.
*/
public void engineSetCertificateEntry(String alias, Certificate cert)
throws KeyStoreException
{
permissionCheck();
synchronized(entries) {
Object entry = entries.get(alias.toLowerCase());
if ((entry != null) && (entry instanceof KeyEntry)) {
throw new KeyStoreException
("Cannot overwrite key entry with certificate");
}
// This will be slow, but necessary. Enumerate the values and then see if the cert matches the one in the trusted cert entry.
// Security framework doesn't support the same certificate twice in a keychain.
Collection<Object> allValues = entries.values();
for (Object value : allValues) {
if (value instanceof TrustedCertEntry) {
TrustedCertEntry tce = (TrustedCertEntry)value;
if (tce.cert.equals(cert)) {
throw new KeyStoreException("Keychain does not support mulitple copies of same certificate.");
}
}
}
TrustedCertEntry trustedCertEntry = new TrustedCertEntry();
trustedCertEntry.cert = cert;
trustedCertEntry.date = new Date();
String lowerAlias = alias.toLowerCase();
if (entries.get(lowerAlias) != null) {
deletedEntries.put(lowerAlias, entries.get(lowerAlias));
}
entries.put(lowerAlias, trustedCertEntry);
addedEntries.put(lowerAlias, trustedCertEntry);
}
throws KeyStoreException {
throw new KeyStoreException("Cannot set trusted certificate entry." +
" Use the macOS \"security add-trusted-cert\" command instead.");
}
/**
@@ -680,10 +685,7 @@ public final class KeychainStore extends KeyStoreSpi {
String alias = e.nextElement();
Object entry = addedEntries.get(alias);
if (entry instanceof TrustedCertEntry) {
TrustedCertEntry tce = (TrustedCertEntry)entry;
Certificate certElem;
certElem = tce.cert;
tce.certRef = addCertificateToKeychain(alias, certElem);
// Cannot set trusted certificate entry
} else {
KeyEntry keyEntry = (KeyEntry)entry;
@@ -778,9 +780,28 @@ public final class KeychainStore extends KeyStoreSpi {
private native void _scanKeychain();
/**
* Callback method from _scanKeychain. If a trusted certificate is found, this method will be called.
* Callback method from _scanKeychain. If a trusted certificate is found,
* this method will be called.
*
* inputTrust is a list of strings in groups. Each group contains key/value
* pairs for one trust setting and ends with a null. Thus the size of the
* whole list is (2 * s_1 + 1) + (2 * s_2 + 1) + ... + (2 * s_n + 1),
* where s_i is the size of mapping for the i'th trust setting,
* and n is the number of trust settings. Ex:
*
* key1 for trust1
* value1 for trust1
* ..
* null (end of trust1)
* key1 for trust2
* value1 for trust2
* ...
* null (end of trust2)
* ...
* null (end if trust_n)
*/
private void createTrustedCertEntry(String alias, long keychainItemRef, long creationDate, byte[] derStream) {
private void createTrustedCertEntry(String alias, List<String> inputTrust,
long keychainItemRef, long creationDate, byte[] derStream) {
TrustedCertEntry tce = new TrustedCertEntry();
try {
@@ -791,6 +812,69 @@ public final class KeychainStore extends KeyStoreSpi {
tce.cert = cert;
tce.certRef = keychainItemRef;
tce.trustSettings = new ArrayList<>();
Map<String,String> tmpMap = new LinkedHashMap<>();
for (int i = 0; i < inputTrust.size(); i++) {
if (inputTrust.get(i) == null) {
tce.trustSettings.add(tmpMap);
if (i < inputTrust.size() - 1) {
// Prepare an empty map for the next trust setting.
// Do not just clear(), must be a new object.
// Only create if not at end of list.
tmpMap = new LinkedHashMap<>();
}
} else {
tmpMap.put(inputTrust.get(i), inputTrust.get(i+1));
i++;
}
}
boolean isSelfSigned;
try {
cert.verify(cert.getPublicKey());
isSelfSigned = true;
} catch (Exception e) {
isSelfSigned = false;
}
if (tce.trustSettings.isEmpty()) {
if (isSelfSigned) {
// If a self-signed certificate has an empty trust settings,
// trust it for all purposes
tce.trustedKeyUsageValue = KnownOIDs.anyExtendedKeyUsage.value();
} else {
// Otherwise, return immediately. The certificate is not
// added into entries.
return;
}
} else {
List<String> values = new ArrayList<>();
for (var oneTrust : tce.trustSettings) {
var result = oneTrust.get("kSecTrustSettingsResult");
// https://developer.apple.com/documentation/security/sectrustsettingsresult?language=objc
// 1 = kSecTrustSettingsResultTrustRoot, 2 = kSecTrustSettingsResultTrustAsRoot
// If missing, a default value of kSecTrustSettingsResultTrustRoot is assumed
// for self-signed certificates (see doc for SecTrustSettingsCopyTrustSettings).
// Note that the same SecPolicyOid can appear in multiple trust settings
// for different kSecTrustSettingsAllowedError and/or kSecTrustSettingsPolicyString.
if ((result == null && isSelfSigned)
|| "1".equals(result) || "2".equals(result)) {
// When no kSecTrustSettingsPolicy, it means everything
String oid = oneTrust.getOrDefault("SecPolicyOid",
KnownOIDs.anyExtendedKeyUsage.value());
if (!values.contains(oid)) {
values.add(oid);
}
}
}
if (values.isEmpty()) {
return;
}
if (values.size() == 1) {
tce.trustedKeyUsageValue = values.get(0);
} else {
tce.trustedKeyUsageValue = values.toString();
}
}
// Make a creation date.
if (creationDate != 0)
tce.date = new Date(creationDate);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2022, 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
@@ -368,6 +368,14 @@ errOut:
}
}
#define ADD(list, str) { \
jobject localeObj = (*env)->NewStringUTF(env, [str UTF8String]); \
(*env)->CallBooleanMethod(env, list, jm_listAdd, localeObj); \
(*env)->DeleteLocalRef(env, localeObj); \
}
#define ADDNULL(list) (*env)->CallBooleanMethod(env, list, jm_listAdd, NULL)
static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore)
{
// Search the user keychain list for all X509 certificates.
@@ -379,8 +387,15 @@ static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore)
jclass jc_KeychainStore = (*env)->FindClass(env, "apple/security/KeychainStore");
CHECK_NULL(jc_KeychainStore);
jmethodID jm_createTrustedCertEntry = (*env)->GetMethodID(
env, jc_KeychainStore, "createTrustedCertEntry", "(Ljava/lang/String;JJ[B)V");
env, jc_KeychainStore, "createTrustedCertEntry", "(Ljava/lang/String;Ljava/util/List;JJ[B)V");
CHECK_NULL(jm_createTrustedCertEntry);
jclass jc_arrayListClass = (*env)->FindClass(env, "java/util/ArrayList");
CHECK_NULL(jc_arrayListClass);
jmethodID jm_arrayListCons = (*env)->GetMethodID(env, jc_arrayListClass, "<init>", "()V");
CHECK_NULL(jm_arrayListCons);
jmethodID jm_listAdd = (*env)->GetMethodID(env, jc_arrayListClass, "add", "(Ljava/lang/Object;)Z");
CHECK_NULL(jm_listAdd);
do {
searchResult = SecKeychainSearchCopyNext(keychainItemSearch, &theItem);
@@ -401,12 +416,50 @@ static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore)
goto errOut;
}
// Only add certificates with trusted settings
CFArrayRef trustSettings;
if (SecTrustSettingsCopyTrustSettings(certRef, kSecTrustSettingsDomainUser, &trustSettings)
== errSecItemNotFound) {
continue;
}
// See KeychainStore::createTrustedCertEntry for content of inputTrust
jobject inputTrust = (*env)->NewObject(env, jc_arrayListClass, jm_arrayListCons);
CHECK_NULL(inputTrust);
// Dump everything inside trustSettings into inputTrust
CFIndex count = CFArrayGetCount(trustSettings);
for (int i = 0; i < count; i++) {
CFDictionaryRef oneTrust = (CFDictionaryRef) CFArrayGetValueAtIndex(trustSettings, i);
CFIndex size = CFDictionaryGetCount(oneTrust);
const void * keys [size];
const void * values [size];
CFDictionaryGetKeysAndValues(oneTrust, keys, values);
for (int j = 0; j < size; j++) {
NSString* s = [NSString stringWithFormat:@"%@", keys[j]];
ADD(inputTrust, s);
s = [NSString stringWithFormat:@"%@", values[j]];
ADD(inputTrust, s);
}
SecPolicyRef certPolicy;
certPolicy = (SecPolicyRef)CFDictionaryGetValue(oneTrust, kSecTrustSettingsPolicy);
if (certPolicy != NULL) {
CFDictionaryRef policyDict = SecPolicyCopyProperties(certPolicy);
ADD(inputTrust, @"SecPolicyOid");
NSString* s = [NSString stringWithFormat:@"%@", CFDictionaryGetValue(policyDict, @"SecPolicyOid")];
ADD(inputTrust, s);
CFRelease(policyDict);
}
ADDNULL(inputTrust);
}
CFRelease(trustSettings);
// Find the creation date.
jlong creationDate = getModDateFromItem(env, theItem);
// Call back to the Java object to create Java objects corresponding to this security object.
jlong nativeRef = ptr_to_jlong(certRef);
(*env)->CallVoidMethod(env, keyStore, jm_createTrustedCertEntry, alias, nativeRef, creationDate, certData);
(*env)->CallVoidMethod(env, keyStore, jm_createTrustedCertEntry, alias, inputTrust, nativeRef, creationDate, certData);
JNU_CHECK_EXCEPTION(env);
}
} while (searchResult == noErr);
@@ -522,8 +575,8 @@ NSString* JavaStringToNSString(JNIEnv *env, jstring jstr) {
/*
* Class: apple_security_KeychainStore
* Method: _addItemToKeychain
* Signature: (Ljava/lang/String;[B)I
*/
* Signature: (Ljava/lang/String;Z[B[C)J
*/
JNIEXPORT jlong JNICALL Java_apple_security_KeychainStore__1addItemToKeychain
(JNIEnv *env, jobject this, jstring alias, jboolean isCertificate, jbyteArray rawDataObj, jcharArray passwordObj)
{

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2022, 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
@@ -96,6 +96,10 @@ class JarVerifier {
/** collect -DIGEST-MANIFEST values for deny list */
private List<Object> manifestDigests;
/* A cache mapping code signers to the algorithms used to digest jar
entries, and whether or not the algorithms are permitted. */
private Map<CodeSigner[], Map<String, Boolean>> signersToAlgs;
public JarVerifier(String name, byte[] rawBytes) {
manifestName = name;
manifestRawBytes = rawBytes;
@@ -105,6 +109,7 @@ class JarVerifier {
pendingBlocks = new ArrayList<>();
baos = new ByteArrayOutputStream();
manifestDigests = new ArrayList<>();
signersToAlgs = new HashMap<>();
}
/**
@@ -244,7 +249,8 @@ class JarVerifier {
if (!parsingBlockOrSF) {
JarEntry je = mev.getEntry();
if ((je != null) && (je.signers == null)) {
je.signers = mev.verify(verifiedSigners, sigFileSigners);
je.signers = mev.verify(verifiedSigners, sigFileSigners,
signersToAlgs);
je.certs = mapSignersToCertArray(je.signers);
}
} else {

View File

@@ -658,8 +658,8 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable {
if (!(memberType.isInstance(value) ||
value instanceof ExceptionProxy)) {
value = new AnnotationTypeMismatchExceptionProxy(
value.getClass() + "[" + value + "]").setMember(
annotationType.members().get(name));
objectToString(value))
.setMember(annotationType.members().get(name));
}
}
mv.put(name, value);
@@ -669,6 +669,15 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable {
UnsafeAccessor.setMemberValues(this, mv);
}
/*
* Create a textual representation of the argument without calling
* any overridable methods of the argument.
*/
private static String objectToString(Object value) {
return value.getClass().getName() + "@" +
Integer.toHexString(System.identityHashCode(value));
}
private static class UnsafeAccessor {
private static final jdk.internal.misc.Unsafe unsafe
= jdk.internal.misc.Unsafe.getUnsafe();

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2021, 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
@@ -362,7 +362,8 @@ abstract class DSA extends SignatureSpi {
s = new BigInteger(1, s.toByteArray());
}
if ((r.compareTo(presetQ) == -1) && (s.compareTo(presetQ) == -1)) {
if ((r.compareTo(presetQ) == -1) && (s.compareTo(presetQ) == -1)
&& r.signum() > 0 && s.signum() > 0) {
BigInteger w = generateW(presetP, presetQ, presetG, s);
BigInteger v = generateV(presetY, presetP, presetQ, presetG, w, r);
return v.equals(r);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2022, 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
@@ -2209,6 +2209,9 @@ public final class Main {
out.println(mf);
dumpCert(cert, out);
} else if (debug) {
for (var attr : keyStore.getEntry(alias, null).getAttributes()) {
System.out.println("Attribute " + attr.getName() + ": " + attr.getValue());
}
out.println(cert.toString());
} else {
out.println("trustedCertEntry, ");

View File

@@ -144,15 +144,14 @@ class DerIndefLenConverter {
* then skip the tag and its 1 byte length of zero.
*/
private void writeTag() {
if (dataPos == dataSize) {
return;
}
assert dataPos + 1 < dataSize;
if (isEOC(data, dataPos)) {
dataPos += 2; // skip tag and length
writeTag();
} else {
newData[newDataPos++] = data[dataPos++];
while (dataPos < dataSize) {
assert dataPos + 1 < dataSize;
if (isEOC(data, dataPos)) {
dataPos += 2; // skip tag and length
} else {
newData[newDataPos++] = data[dataPos++];
break;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2022, 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
@@ -192,7 +192,8 @@ public class ManifestEntryVerifier {
*
*/
public CodeSigner[] verify(Hashtable<String, CodeSigner[]> verifiedSigners,
Hashtable<String, CodeSigner[]> sigFileSigners)
Hashtable<String, CodeSigner[]> sigFileSigners,
Map<CodeSigner[], Map<String, Boolean>> signersToAlgs)
throws JarException
{
if (skip) {
@@ -207,38 +208,60 @@ public class ManifestEntryVerifier {
return signers;
}
JarConstraintsParameters params =
getParams(verifiedSigners, sigFileSigners);
CodeSigner[] entrySigners = sigFileSigners.get(name);
Map<String, Boolean> algsPermittedStatus =
algsPermittedStatusForSigners(signersToAlgs, entrySigners);
// Flag that indicates if only disabled algorithms are used and jar
// entry should be treated as unsigned.
boolean disabledAlgs = true;
JarConstraintsParameters params = null;
for (int i=0; i < digests.size(); i++) {
MessageDigest digest = digests.get(i);
if (params != null) {
try {
params.setExtendedExceptionMsg(JarFile.MANIFEST_NAME,
name + " entry");
DisabledAlgorithmConstraints.jarConstraints()
.permits(digest.getAlgorithm(), params, false);
} catch (GeneralSecurityException e) {
if (debug != null) {
debug.println("Digest algorithm is restricted: " + e);
String digestAlg = digest.getAlgorithm();
// Check if this algorithm is permitted, skip if false.
if (algsPermittedStatus != null) {
Boolean permitted = algsPermittedStatus.get(digestAlg);
if (permitted == null) {
if (params == null) {
params = new JarConstraintsParameters(entrySigners);
}
return null;
if (!checkConstraints(digestAlg, params)) {
algsPermittedStatus.put(digestAlg, Boolean.FALSE);
continue;
} else {
algsPermittedStatus.put(digestAlg, Boolean.TRUE);
}
} else if (!permitted) {
continue;
}
}
// A non-disabled algorithm was used.
disabledAlgs = false;
byte [] manHash = manifestHashes.get(i);
byte [] theHash = digest.digest();
if (debug != null) {
debug.println("Manifest Entry: " +
name + " digest=" + digest.getAlgorithm());
name + " digest=" + digestAlg);
debug.println(" manifest " + HexFormat.of().formatHex(manHash));
debug.println(" computed " + HexFormat.of().formatHex(theHash));
debug.println();
}
if (!MessageDigest.isEqual(theHash, manHash))
throw new SecurityException(digest.getAlgorithm()+
if (!MessageDigest.isEqual(theHash, manHash)) {
throw new SecurityException(digestAlg +
" digest error for "+name);
}
}
// If there were only disabled algorithms used, return null and jar
// entry will be treated as unsigned.
if (disabledAlgs) {
return null;
}
// take it out of sigFileSigners and put it in verifiedSigners...
@@ -249,40 +272,36 @@ public class ManifestEntryVerifier {
return signers;
}
/**
* Get constraints parameters for JAR. The constraints should be
* checked against all code signers. Returns the parameters,
* or null if the signers for this entry have already been checked
* or there are no signers for this entry.
*/
private JarConstraintsParameters getParams(
Map<String, CodeSigner[]> verifiedSigners,
Map<String, CodeSigner[]> sigFileSigners) {
// Gets the algorithms permitted status for the signers of this entry.
private static Map<String, Boolean> algsPermittedStatusForSigners(
Map<CodeSigner[], Map<String, Boolean>> signersToAlgs,
CodeSigner[] signers) {
if (signers != null) {
Map<String, Boolean> algs = signersToAlgs.get(signers);
// create new HashMap if absent
if (algs == null) {
algs = new HashMap<>();
signersToAlgs.put(signers, algs);
}
return algs;
}
return null;
}
// verifiedSigners is usually preloaded with the Manifest's signers.
// If verifiedSigners contains the Manifest, then it will have all of
// the signers of the JAR. But if it doesn't then we need to fallback
// and check verifiedSigners to see if the signers of this entry have
// been checked already.
if (verifiedSigners.containsKey(manifestFileName)) {
if (verifiedSigners.size() > 1) {
// this means we already checked it previously
return null;
} else {
return new JarConstraintsParameters(
verifiedSigners.get(manifestFileName));
}
} else {
// Checks the algorithm constraints against the signers of this entry.
private boolean checkConstraints(String algorithm,
JarConstraintsParameters params) {
try {
params.setExtendedExceptionMsg(JarFile.MANIFEST_NAME,
name + " entry");
DisabledAlgorithmConstraints.jarConstraints()
.permits(algorithm, params, false);
return true;
} catch (GeneralSecurityException e) {
if (debug != null) {
debug.println(manifestFileName + " not present in verifiedSigners");
}
CodeSigner[] signers = sigFileSigners.get(name);
if (signers == null || verifiedSigners.containsValue(signers)) {
return null;
} else {
return new JarConstraintsParameters(signers);
debug.println("Digest algorithm is restricted: " + e);
}
return false;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2021, 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
@@ -365,7 +365,7 @@ public final class ObjectIdentifier implements Serializable {
if ((encoding[i] & 0x80) == 0) {
// one section [fromPos..i]
if (i - fromPos + 1 > 4) {
BigInteger big = new BigInteger(pack(encoding,
BigInteger big = new BigInteger(1, pack(encoding,
fromPos, i-fromPos+1, 7, 8));
if (fromPos == 0) {
result[which++] = 2;
@@ -434,7 +434,7 @@ public final class ObjectIdentifier implements Serializable {
sb.append('.');
}
if (i - fromPos + 1 > 4) { // maybe big integer
BigInteger big = new BigInteger(
BigInteger big = new BigInteger(1,
pack(encoding, fromPos, i-fromPos+1, 7, 8));
if (fromPos == 0) {
// first section encoded with more than 4 bytes,
@@ -684,6 +684,10 @@ public final class ObjectIdentifier implements Serializable {
}
private static void checkOidSize(int oidLength) throws IOException {
if (oidLength < 0) {
throw new IOException("ObjectIdentifier encoded length was " +
"negative: " + oidLength);
}
if (oidLength > MAXIMUM_OID_SIZE) {
throw new IOException(
"ObjectIdentifier encoded length exceeds " +

View File

@@ -104,7 +104,6 @@ static int createProxyList(LPWSTR win_proxy, const WCHAR *pproto, list_item **he
int nr_elems = 0;
wchar_t *context = NULL;
wchar_t *current_proxy = NULL;
BOOL error = FALSE;
/*
* The proxy server list contains one or more of the following strings
@@ -116,7 +115,6 @@ static int createProxyList(LPWSTR win_proxy, const WCHAR *pproto, list_item **he
LPWSTR pport;
LPWSTR phost;
int portVal = 0;
wchar_t *next_proxy = NULL;
list_item *proxy = NULL;
wchar_t* pos = NULL;
@@ -290,7 +288,6 @@ Java_sun_net_spi_DefaultProxySelector_getSystemProxies(JNIEnv *env,
}
if (win_proxy != NULL) {
wchar_t *context = NULL;
int defport = 0;
int nr_elems = 0;
@@ -313,27 +310,28 @@ Java_sun_net_spi_DefaultProxySelector_getSystemProxies(JNIEnv *env,
nr_elems = createProxyList(win_proxy, lpProto, &head);
if (nr_elems != 0 && head != NULL) {
int index = 0;
list_item *current = head;
proxy_array = (*env)->NewObjectArray(env, nr_elems, proxy_class, NULL);
if (proxy_array == NULL || (*env)->ExceptionCheck(env)) {
goto noproxy;
}
while (head != NULL && index < nr_elems) {
while (current != NULL && index < nr_elems) {
jstring jhost;
jobject isa;
jobject proxy;
if (head->host != NULL && proxy_array != NULL) {
if (current->host != NULL && proxy_array != NULL) {
/* Let's create the appropriate Proxy object then. */
if (head->port == 0) {
head->port = defport;
if (current->port == 0) {
current->port = defport;
}
jhost = (*env)->NewString(env, head->host, (jsize)wcslen(head->host));
jhost = (*env)->NewString(env, current->host, (jsize)wcslen(current->host));
if (jhost == NULL || (*env)->ExceptionCheck(env)) {
proxy_array = NULL;
}
isa = (*env)->CallStaticObjectMethod(env, isaddr_class,
isaddr_createUnresolvedID, jhost,
head->port);
current->port);
if (isa == NULL || (*env)->ExceptionCheck(env)) {
proxy_array = NULL;
}
@@ -347,7 +345,7 @@ Java_sun_net_spi_DefaultProxySelector_getSystemProxies(JNIEnv *env,
}
index++;
}
head = head->next;
current = current->next;
}
}
}

View File

@@ -67,6 +67,7 @@ import javax.imageio.stream.ImageInputStream;
import com.sun.imageio.plugins.common.I18N;
import com.sun.imageio.plugins.common.ImageUtil;
import com.sun.imageio.plugins.common.ReaderUtil;
/** This class is the Java Image IO plugin reader for BMP images.
* It may subsample the image, clip the image, select sub-bands,
@@ -1542,9 +1543,8 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
}
// Read till we have the whole image
byte[] values = new byte[imSize];
int bytesRead = 0;
iis.readFully(values, 0, imSize);
byte[] values = ReaderUtil.
staggeredReadByteStream(iis, imSize);
// Since data is compressed, decompress it
decodeRLE8(imSize, padding, values, bdata);
@@ -1726,8 +1726,8 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
}
// Read till we have the whole image
byte[] values = new byte[imSize];
iis.readFully(values, 0, imSize);
byte[] values = ReaderUtil.
staggeredReadByteStream(iis, imSize);
// Decompress the RLE4 compressed data.
decodeRLE4(imSize, padding, values, bdata);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2022, 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

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2021, 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
@@ -78,12 +78,26 @@ public final class AudioFileSoundbankReader extends SoundbankReader {
public Soundbank getSoundbank(AudioInputStream ais)
throws InvalidMidiDataException, IOException {
int MEGABYTE = 1048576;
int DEFAULT_BUFFER_SIZE = 65536;
int MAX_FRAME_SIZE = 1024;
try {
byte[] buffer;
if (ais.getFrameLength() == -1) {
int frameSize = ais.getFormat().getFrameSize();
if (frameSize <= 0 || frameSize > MAX_FRAME_SIZE) {
throw new InvalidMidiDataException("Formats with frame size "
+ frameSize + " are not supported");
}
long totalSize = ais.getFrameLength() * frameSize;
if (totalSize >= Integer.MAX_VALUE - 2) {
throw new InvalidMidiDataException(
"Can not allocate enough memory to read audio data.");
}
if (ais.getFrameLength() == -1 || totalSize > MEGABYTE) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buff = new byte[1024
- (1024 % ais.getFormat().getFrameSize())];
byte[] buff = new byte[DEFAULT_BUFFER_SIZE - (DEFAULT_BUFFER_SIZE % frameSize)];
int ret;
while ((ret = ais.read(buff)) != -1) {
baos.write(buff, 0, ret);
@@ -91,8 +105,7 @@ public final class AudioFileSoundbankReader extends SoundbankReader {
ais.close();
buffer = baos.toByteArray();
} else {
buffer = new byte[(int) (ais.getFrameLength()
* ais.getFormat().getFrameSize())];
buffer = new byte[(int) totalSize];
new DataInputStream(ais).readFully(buffer);
}
ModelByteBufferWavetable osc = new ModelByteBufferWavetable(

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2022, 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
@@ -3917,11 +3917,11 @@ void AwtComponent::SetCandidateWindow(int iCandType, int x, int y)
HIMC hIMC = ImmGetContext(hwnd);
if (hIMC) {
CANDIDATEFORM cf;
cf.dwStyle = CFS_POINT;
cf.dwStyle = CFS_CANDIDATEPOS;
ImmGetCandidateWindow(hIMC, 0, &cf);
if (x != cf.ptCurrentPos.x || y != cf.ptCurrentPos.y) {
cf.dwIndex = iCandType;
cf.dwStyle = CFS_POINT;
cf.dwStyle = CFS_CANDIDATEPOS;
cf.ptCurrentPos = {x, y};
cf.rcArea = {0, 0, 0, 0};
ImmSetCandidateWindow(hIMC, &cf);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2022, 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
@@ -267,13 +267,13 @@ void AwtDragSource::_DoDragDrop(void* param) {
dragSource->Signal();
AwtToolkit &toolkit = AwtToolkit::GetInstance();
toolkit.isInDoDragDropLoop = TRUE;
toolkit.isDnDSourceActive = TRUE;
res = ::DoDragDrop(dragSource,
dragSource,
convertActionsToDROPEFFECT(dragSource->m_actions),
&effects
);
toolkit.isInDoDragDropLoop = FALSE;
toolkit.isDnDSourceActive = FALSE;
if (effects == DROPEFFECT_NONE && dragSource->m_dwPerformedDropEffect != DROPEFFECT_NONE) {
effects = dragSource->m_dwPerformedDropEffect;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2022, 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
@@ -141,7 +141,7 @@ static void ScaleDown(POINT &cp, HWND m_window) {
HRESULT __stdcall AwtDropTarget::DragEnter(IDataObject __RPC_FAR *pDataObj, DWORD grfKeyState, POINTL pt, DWORD __RPC_FAR *pdwEffect) {
TRY;
AwtToolkit::GetInstance().isInDoDragDropLoop = TRUE;
AwtToolkit::GetInstance().isDnDTargetActive = TRUE;
if (NULL != m_pIDropTargetHelper) {
m_pIDropTargetHelper->DragEnter(
m_window,
@@ -161,7 +161,7 @@ HRESULT __stdcall AwtDropTarget::DragEnter(IDataObject __RPC_FAR *pDataObj, DWOR
(IsLocalDnD() && !IsLocalDataObject(pDataObj)))
{
*pdwEffect = retEffect;
AwtToolkit::GetInstance().isInDoDragDropLoop = FALSE;
AwtToolkit::GetInstance().isDnDTargetActive = FALSE;
return ret;
}
@@ -173,7 +173,7 @@ HRESULT __stdcall AwtDropTarget::DragEnter(IDataObject __RPC_FAR *pDataObj, DWOR
}
if (JNU_IsNull(env, m_dtcp) || !JNU_IsNull(env, safe_ExceptionOccurred(env))) {
AwtToolkit::GetInstance().isInDoDragDropLoop = FALSE;
AwtToolkit::GetInstance().isDnDTargetActive = FALSE;
return ret;
}
@@ -200,12 +200,12 @@ HRESULT __stdcall AwtDropTarget::DragEnter(IDataObject __RPC_FAR *pDataObj, DWOR
env->ExceptionDescribe();
env->ExceptionClear();
actions = java_awt_dnd_DnDConstants_ACTION_NONE;
AwtToolkit::GetInstance().isInDoDragDropLoop = FALSE;
AwtToolkit::GetInstance().isDnDTargetActive = FALSE;
}
} catch (std::bad_alloc&) {
retEffect = ::convertActionsToDROPEFFECT(actions);
*pdwEffect = retEffect;
AwtToolkit::GetInstance().isInDoDragDropLoop = FALSE;
AwtToolkit::GetInstance().isDnDTargetActive = FALSE;
throw;
}
@@ -421,7 +421,7 @@ void AwtDropTarget::DropDone(jboolean success, jint action) {
m_dropSuccess = success;
m_dropActions = action;
AwtToolkit::GetInstance().QuitMessageLoop(AwtToolkit::EXIT_ENCLOSING_LOOP);
AwtToolkit::GetInstance().isInDoDragDropLoop = FALSE;
AwtToolkit::GetInstance().isDnDTargetActive = FALSE;
}
/**
@@ -1136,7 +1136,7 @@ void AwtDropTarget::UnloadCache() {
void AwtDropTarget::DragCleanup(void) {
UnloadCache();
AwtToolkit::GetInstance().isInDoDragDropLoop = FALSE;
AwtToolkit::GetInstance().isDnDTargetActive = FALSE;
}
BOOL AwtDropTarget::IsLocalDataObject(IDataObject __RPC_FAR *pDataObject) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2022, 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
@@ -344,7 +344,8 @@ AwtToolkit::AwtToolkit() {
m_waitEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
m_inputMethodWaitEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
isInDoDragDropLoop = FALSE;
isDnDSourceActive = FALSE;
isDnDTargetActive = FALSE;
eventNumber = 0;
}
@@ -3012,7 +3013,7 @@ Java_sun_awt_windows_WToolkit_syncNativeQueue(JNIEnv *env, jobject self, jlong t
tk.PostMessage(WM_SYNC_WAIT, 0, 0);
for(long t = 2; t < timeout &&
WAIT_TIMEOUT == ::WaitForSingleObject(tk.m_waitEvent, 2); t+=2) {
if (tk.isInDoDragDropLoop) {
if (tk.isDnDSourceActive || tk.isDnDTargetActive) {
break;
}
}
@@ -3216,7 +3217,7 @@ LRESULT AwtToolkit::InvokeInputMethodFunction(UINT msg, WPARAM wParam, LPARAM lP
* the IME completion.
*/
CriticalSection::Lock lock(m_inputMethodLock);
if (isInDoDragDropLoop) {
if (isDnDSourceActive || isDnDTargetActive) {
SendMessage(msg, wParam, lParam);
::ResetEvent(m_inputMethodWaitEvent);
return m_inputMethodData;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2022, 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
@@ -441,7 +441,8 @@ public:
HANDLE m_waitEvent;
volatile DWORD eventNumber;
volatile BOOL isInDoDragDropLoop;
volatile BOOL isDnDSourceActive;
volatile BOOL isDnDTargetActive;
private:
HWND CreateToolkitWnd(LPCTSTR name);

View File

@@ -65,7 +65,23 @@ final class LdapClientFactory implements PooledConnectionFactory {
connTimeout, readTimeout, trace, pcb);
}
public PooledConnection createPooledConnection(PoolCallback pcb, long timeout)
throws NamingException {
return new LdapClient(host, port, socketFactory,
guardedIntegerCast(timeout),
readTimeout, trace, pcb);
}
public String toString() {
return host + ":" + port;
}
private int guardedIntegerCast(long timeout) {
if (timeout < Integer.MIN_VALUE) {
return Integer.MIN_VALUE;
} else if (timeout > Integer.MAX_VALUE) {
return Integer.MAX_VALUE;
}
return (int) timeout;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2002, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2022, 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
@@ -28,6 +28,10 @@ package com.sun.jndi.ldap;
import javax.naming.*;
import java.net.MalformedURLException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Locale;
import java.util.StringTokenizer;
import com.sun.jndi.toolkit.url.Uri;
import com.sun.jndi.toolkit.url.UrlUtil;
@@ -64,6 +68,25 @@ import com.sun.jndi.toolkit.url.UrlUtil;
public final class LdapURL extends Uri {
private static final String PARSE_MODE_PROP = "com.sun.jndi.ldapURLParsing";
private static final ParseMode DEFAULT_PARSE_MODE = ParseMode.COMPAT;
public static final ParseMode PARSE_MODE;
static {
PrivilegedAction<String> action = () ->
System.getProperty(PARSE_MODE_PROP, DEFAULT_PARSE_MODE.toString());
ParseMode parseMode = DEFAULT_PARSE_MODE;
try {
@SuppressWarnings("removal")
String mode = AccessController.doPrivileged(action);
parseMode = ParseMode.valueOf(mode.toUpperCase(Locale.ROOT));
} catch (Throwable t) {
parseMode = DEFAULT_PARSE_MODE;
} finally {
PARSE_MODE = parseMode;
}
}
private boolean useSsl = false;
private String DN = null;
private String attributes = null;
@@ -83,7 +106,7 @@ public final class LdapURL extends Uri {
useSsl = scheme.equalsIgnoreCase("ldaps");
if (! (scheme.equalsIgnoreCase("ldap") || useSsl)) {
throw new MalformedURLException("Not an LDAP URL: " + url);
throw newInvalidURISchemeException(url);
}
parsePathAndQuery(); // DN, attributes, scope, filter, extensions
@@ -99,6 +122,21 @@ public final class LdapURL extends Uri {
}
}
@Override
protected MalformedURLException newInvalidURISchemeException(String uri) {
return new MalformedURLException("Not an LDAP URL: " + uri);
}
@Override
protected boolean isSchemeOnly(String uri) {
return isLdapSchemeOnly(uri);
}
@Override
protected ParseMode parseMode() {
return PARSE_MODE;
}
/**
* Returns true if the URL is an LDAPS URL.
*/
@@ -151,13 +189,33 @@ public final class LdapURL extends Uri {
StringTokenizer st = new StringTokenizer(urlList, " ");
while (st.hasMoreTokens()) {
urls[i++] = st.nextToken();
// we don't accept scheme-only URLs here
urls[i++] = validateURI(st.nextToken());
}
String[] trimmed = new String[i];
System.arraycopy(urls, 0, trimmed, 0, i);
return trimmed;
}
public static boolean isLdapSchemeOnly(String uri) {
return "ldap:".equals(uri) || "ldaps:".equals(uri);
}
public static String validateURI(String uri) {
// no validation in legacy mode parsing
if (PARSE_MODE == ParseMode.LEGACY) {
return uri;
}
// special case of scheme-only URIs
if (isLdapSchemeOnly(uri)) {
return uri;
}
// use java.net.URI to validate the uri syntax
return URI.create(uri).toString();
}
/**
* Determines whether an LDAP URL has query components.
*/
@@ -181,7 +239,8 @@ public final class LdapURL extends Uri {
String p = (port != -1) ? (":" + port) : "";
String d = (dn != null) ? ("/" + UrlUtil.encode(dn, "UTF8")) : "";
return useSsl ? "ldaps://" + h + p + d : "ldap://" + h + p + d;
String uri = useSsl ? "ldaps://" + h + p + d : "ldap://" + h + p + d;
return validateURI(uri);
} catch (UnsupportedEncodingException e) {
// UTF8 should always be supported
throw new IllegalStateException("UTF-8 encoding unavailable");

View File

@@ -27,6 +27,9 @@ package com.sun.jndi.ldap.pool;
import java.util.ArrayList; // JDK 1.2
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
@@ -68,13 +71,19 @@ final class Connections implements PoolCallback {
com.sun.jndi.ldap.LdapPoolManager.trace;
private static final int DEFAULT_SIZE = 10;
final private int initSize;
private final int maxSize;
private final int prefSize;
private final List<ConnectionDesc> conns;
final private PooledConnectionFactory factory;
private boolean closed = false; // Closed for business
private Reference<Object> ref; // maintains reference to id to prevent premature GC
private boolean initialized = false;
private final ReentrantLock lock;
private final Condition connectionsAvailable;
/**
* @param id the identity (connection request) of the connections in the list
* @param initSize the number of connections to create initially
@@ -87,105 +96,73 @@ final class Connections implements PoolCallback {
* when one is removed.
* @param factory The factory responsible for creating a connection
*/
Connections(Object id, int initSize, int prefSize, int maxSize,
PooledConnectionFactory factory) throws NamingException {
Connections(Object id, int initSize, int prefSize, int maxSize, PooledConnectionFactory factory,
ReentrantLock lock) throws NamingException {
this.maxSize = maxSize;
this.lock = lock;
this.connectionsAvailable = lock.newCondition();
this.factory = factory;
if (maxSize > 0) {
// prefSize and initSize cannot exceed specified maxSize
this.prefSize = Math.min(prefSize, maxSize);
initSize = Math.min(initSize, maxSize);
this.initSize = Math.min(initSize, maxSize);
} else {
this.prefSize = prefSize;
this.initSize = initSize;
}
conns = new ArrayList<>(maxSize > 0 ? maxSize : DEFAULT_SIZE);
this.conns = new ArrayList<>(maxSize > 0 ? maxSize : DEFAULT_SIZE);
this.initialized = initSize <= 0;
// Maintain soft ref to id so that this Connections' entry in
// Pool doesn't get GC'ed prematurely
ref = new SoftReference<>(id);
this.ref = new SoftReference<>(id);
d("init size=", initSize);
d("max size=", maxSize);
d("preferred size=", prefSize);
}
// Create initial connections
PooledConnection conn;
for (int i = 0; i < initSize; i++) {
conn = factory.createPooledConnection(this);
td("Create ", conn ,factory);
conns.add(new ConnectionDesc(conn)); // Add new idle conn to pool
void waitForAvailableConnection() throws InterruptedNamingException {
try {
d("get(): waiting");
connectionsAvailable.await();
} catch (InterruptedException e) {
throw new InterruptedNamingException(
"Interrupted while waiting for a connection");
}
}
/**
* Retrieves a PooledConnection from this list of connections.
* Use an existing one if one is idle, or create one if the list's
* max size hasn't been reached. If max size has been reached, wait
* for a PooledConnection to be returned, or one to be removed (thus
* not reaching the max size any longer).
*
* @param timeout if > 0, msec to wait until connection is available
* @param factory creates the PooledConnection if one needs to be created
*
* @return A non-null PooledConnection
* @throws NamingException PooledConnection cannot be created, because this
* thread was interrupted while it waited for an available connection,
* or if it timed out while waiting, or the creation of a connection
* resulted in an error.
*/
synchronized PooledConnection get(long timeout,
PooledConnectionFactory factory) throws NamingException {
PooledConnection conn;
long start = (timeout > 0 ? System.currentTimeMillis() : 0);
long waittime = timeout;
d("get(): before");
while ((conn = getOrCreateConnection(factory)) == null) {
if (timeout > 0 && waittime <= 0) {
throw new CommunicationException(
"Timeout exceeded while waiting for a connection: " +
timeout + "ms");
}
try {
d("get(): waiting");
if (waittime > 0) {
wait(waittime); // Wait until one is released or removed
} else {
wait();
}
} catch (InterruptedException e) {
throw new InterruptedNamingException(
void waitForAvailableConnection(long waitTime) throws InterruptedNamingException {
try {
d("get(): waiting");
connectionsAvailable.await(waitTime, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
throw new InterruptedNamingException(
"Interrupted while waiting for a connection");
}
// Check whether we timed out
if (timeout > 0) {
long now = System.currentTimeMillis();
waittime = timeout - (now - start);
}
}
d("get(): after");
return conn;
}
/**
* Retrieves an idle connection from this list if one is available.
* If none is available, create a new one if maxSize hasn't been reached.
* If maxSize has been reached, return null.
* Always called from a synchronized method.
*/
private PooledConnection getOrCreateConnection(
PooledConnectionFactory factory) throws NamingException {
PooledConnection getAvailableConnection(long timeout) throws NamingException {
if (!initialized) {
PooledConnection conn = createConnection(factory, timeout);
if (conns.size() >= initSize) {
this.initialized = true;
}
return conn;
}
int size = conns.size(); // Current number of idle/nonidle conns
PooledConnection conn = null;
if (prefSize <= 0 || size >= prefSize) {
// If no prefSize specified, or list size already meets or
// exceeds prefSize, then first look for an idle connection
ConnectionDesc entry;
for (int i = 0; i < size; i++) {
entry = conns.get(i);
for (ConnectionDesc connectionDesc : conns) {
PooledConnection conn;
entry = connectionDesc;
if ((conn = entry.tryUse()) != null) {
d("get(): use ", conn);
td("Use ", conn);
@@ -193,17 +170,25 @@ final class Connections implements PoolCallback {
}
}
}
return null;
}
// Check if list size already at maxSize specified
if (maxSize > 0 && size >= maxSize) {
return null; // List size is at limit; cannot create any more
/*
* Creates a new Connection if maxSize hasn't been reached.
* If maxSize has been reached, return null.
* Caller must hold the ReentrantLock.
*/
PooledConnection createConnection(PooledConnectionFactory factory, long timeout)
throws NamingException {
int size = conns.size(); // Current number of idle/non-idle connections
if (maxSize == 0 || size < maxSize) {
PooledConnection conn = factory.createPooledConnection(this, timeout);
td("Create and use ", conn, factory);
conns.add(new ConnectionDesc(conn, true)); // Add new conn to pool
return conn;
}
conn = factory.createPooledConnection(this);
td("Create and use ", conn, factory);
conns.add(new ConnectionDesc(conn, true)); // Add new conn to pool
return conn;
return null;
}
/**
@@ -211,43 +196,45 @@ final class Connections implements PoolCallback {
* If the list size is below prefSize, the connection may be reused.
* If the list size exceeds prefSize, then the connection is closed
* and removed from the list.
*
* <p>
* public because implemented as part of PoolCallback.
*/
public synchronized boolean releasePooledConnection(PooledConnection conn) {
ConnectionDesc entry;
int loc = conns.indexOf(entry=new ConnectionDesc(conn));
public boolean releasePooledConnection(PooledConnection conn) {
lock.lock();
try {
ConnectionDesc entry;
int loc = conns.indexOf(entry = new ConnectionDesc(conn));
d("release(): ", conn);
d("release(): ", conn);
if (loc >= 0) {
// Found entry
if (loc >= 0) {
// Found entry
if (closed || (prefSize > 0 && conns.size() > prefSize)) {
// If list size exceeds prefSize, close connection
if (closed || (prefSize > 0 && conns.size() > prefSize)) {
// If list size exceeds prefSize, close connection
d("release(): closing ", conn);
td("Close ", conn);
d("release(): closing ", conn);
td("Close ", conn);
// size must be >= 2 so don't worry about empty list
conns.remove(entry);
conn.closeConnection();
} else {
d("release(): release ", conn);
td("Release ", conn);
// Get ConnectionDesc from list to get correct state info
entry = conns.get(loc);
// Return connection to list, ready for reuse
entry.release();
// size must be >= 2 so don't worry about empty list
conns.remove(entry);
conn.closeConnection();
} else {
d("release(): release ", conn);
td("Release ", conn);
// Get ConnectionDesc from list to get correct state info
entry = conns.get(loc);
// Return connection to list, ready for reuse
entry.release();
}
connectionsAvailable.signalAll();
d("release(): notify");
return true;
}
notifyAll();
d("release(): notify");
return true;
} else {
return false;
} finally {
lock.unlock();
}
return false;
}
/**
@@ -257,29 +244,34 @@ final class Connections implements PoolCallback {
* when using the connection and wants it removed from the pool.
*
* @return true if conn removed; false if it was not in pool
*
* <p>
* public because implemented as part of PoolCallback.
*/
public synchronized boolean removePooledConnection(PooledConnection conn) {
if (conns.remove(new ConnectionDesc(conn))) {
d("remove(): ", conn);
public boolean removePooledConnection(PooledConnection conn) {
lock.lock();
try {
if (conns.remove(new ConnectionDesc(conn))) {
d("remove(): ", conn);
notifyAll();
connectionsAvailable.signalAll();
d("remove(): notify");
td("Remove ", conn);
d("remove(): notify");
td("Remove ", conn);
if (conns.isEmpty()) {
// Remove softref to make pool entry eligible for GC.
// Once ref has been removed, it cannot be reinstated.
ref = null;
if (conns.isEmpty()) {
// Remove softref to make pool entry eligible for GC.
// Once ref has been removed, it cannot be reinstated.
ref = null;
}
return true;
} else {
d("remove(): not found ", conn);
}
return true;
} else {
d("remove(): not found ", conn);
return false;
} finally {
lock.unlock();
}
return false;
}
/**
@@ -291,8 +283,11 @@ final class Connections implements PoolCallback {
*/
boolean expire(long threshold) {
List<ConnectionDesc> clonedConns;
synchronized(this) {
lock.lock();
try {
clonedConns = new ArrayList<>(conns);
} finally {
lock.unlock();
}
List<ConnectionDesc> expired = new ArrayList<>();
@@ -304,12 +299,15 @@ final class Connections implements PoolCallback {
}
}
synchronized (this) {
lock.lock();
try {
conns.removeAll(expired);
// Don't need to call notify() because we're
// removing only idle connections. If there were
// idle connections, then there should be no waiters.
return conns.isEmpty(); // whether whole list has 'expired'
} finally {
lock.unlock();
}
}
@@ -355,6 +353,29 @@ final class Connections implements PoolCallback {
+ "; idle=" + idle + "; expired=" + expired;
}
boolean grabLock(long timeout) throws InterruptedNamingException {
final long start = System.nanoTime();
long current = start;
long remaining = timeout;
boolean locked = false;
while (!locked && remaining > 0) {
try {
locked = lock.tryLock(remaining, TimeUnit.MILLISECONDS);
remaining -= TimeUnit.NANOSECONDS.toMillis(current - start);
} catch (InterruptedException ignore) {
throw new InterruptedNamingException(
"Interrupted while waiting for the connection pool lock");
}
current = System.nanoTime();
remaining -= TimeUnit.NANOSECONDS.toMillis(current - start);
}
return locked;
}
void unlock() {
lock.unlock();
}
private void d(String msg, Object o1) {
if (debug) {
d(msg + o1);

View File

@@ -31,10 +31,13 @@ import java.util.WeakHashMap;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.io.PrintStream;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import javax.naming.CommunicationException;
import javax.naming.NamingException;
/**
@@ -117,45 +120,109 @@ public final class Pool {
public PooledConnection getPooledConnection(Object id, long timeout,
PooledConnectionFactory factory) throws NamingException {
final long start = System.nanoTime();
long remaining = timeout;
d("get(): ", id);
if (debug) {
synchronized (map) {
d("size: ", map.size());
}
remaining = checkRemaining(start, remaining);
}
expungeStaleConnections();
Connections conns;
synchronized (map) {
conns = getConnections(id);
if (conns == null) {
d("get(): creating new connections list for ", id);
Connections conns = getOrCreateConnections(factory, id);
d("get(): size after: ", map.size());
remaining = checkRemaining(start, remaining);
// No connections for this id so create a new list
conns = new Connections(id, initSize, prefSize, maxSize,
factory);
ConnectionsRef connsRef = new ConnectionsRef(conns);
map.put(id, connsRef);
// Create a weak reference to ConnectionsRef
Reference<ConnectionsRef> weakRef =
new ConnectionsWeakRef(connsRef, queue);
// Keep the weak reference through the element of a linked list
weakRefs.add(weakRef);
}
d("get(): size after: ", map.size());
if (!conns.grabLock(remaining)) {
throw new CommunicationException("Timed out waiting for lock");
}
return conns.get(timeout, factory); // get one connection from list
try {
remaining = checkRemaining(start, remaining);
PooledConnection conn = null;
while (remaining > 0 && conn == null) {
conn = getOrCreatePooledConnection(factory, conns, start, remaining);
// don't loop if the timeout has expired
remaining = checkRemaining(start, timeout);
}
return conn;
} finally {
conns.unlock();
}
}
private Connections getConnections(Object id) {
ConnectionsRef ref = map.get(id);
return (ref != null) ? ref.getConnections() : null;
private Connections getOrCreateConnections(PooledConnectionFactory factory, Object id)
throws NamingException {
Connections conns;
synchronized (map) {
ConnectionsRef ref = map.get(id);
if (ref != null) {
return ref.getConnections();
}
d("get(): creating new connections list for ", id);
// No connections for this id so create a new list
conns = new Connections(id, initSize, prefSize, maxSize,
factory, new ReentrantLock());
ConnectionsRef connsRef = new ConnectionsRef(conns);
map.put(id, connsRef);
// Create a weak reference to ConnectionsRef
Reference<ConnectionsRef> weakRef = new ConnectionsWeakRef(connsRef, queue);
// Keep the weak reference through the element of a linked list
weakRefs.add(weakRef);
}
return conns;
}
private PooledConnection getOrCreatePooledConnection(
PooledConnectionFactory factory, Connections conns, long start, long timeout)
throws NamingException {
PooledConnection conn = conns.getAvailableConnection(timeout);
if (conn != null) {
return conn;
}
// no available cached connection
// check if list size already at maxSize before creating a new one
conn = conns.createConnection(factory, timeout);
if (conn != null) {
return conn;
}
// max number of connections already created,
// try waiting around for one to become available
if (timeout <= 0) {
conns.waitForAvailableConnection();
} else {
long remaining = checkRemaining(start, timeout);
conns.waitForAvailableConnection(remaining);
}
return null;
}
// Check whether we timed out
private long checkRemaining(long start, long timeout) throws CommunicationException {
if (timeout > 0) {
long current = System.nanoTime();
long remaining = timeout - TimeUnit.NANOSECONDS.toMillis(current - start);
if (remaining <= 0) {
throw new CommunicationException(
"Timeout exceeded while waiting for a connection: " +
timeout + "ms");
}
return remaining;
}
return Long.MAX_VALUE;
}
/**
* Goes through the connections in this Pool and expires ones that
* have been idle before 'threshold'. An expired connection is closed

View File

@@ -44,4 +44,13 @@ public interface PooledConnectionFactory {
*/
public abstract PooledConnection createPooledConnection(PoolCallback pcb)
throws NamingException;
/**
* Creates a pooled connection.
* @param pcb callback responsible for removing and releasing the pooled
* connection from the pool.
* @param timeout the connection timeout
*/
public abstract PooledConnection createPooledConnection(PoolCallback pcb, long timeout)
throws NamingException;
};

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2022, 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
@@ -32,6 +32,8 @@ import javax.naming.spi.NamingManager;
import java.util.Hashtable;
import java.net.MalformedURLException;
import com.sun.jndi.toolkit.url.Uri.ParseMode;
/**
* This abstract class is a generic URL context that accepts as the
* name argument either a string URL or a Name whose first component
@@ -48,6 +50,7 @@ import java.net.MalformedURLException;
* @author Rosanna Lee
*/
public abstract class GenericURLContext implements Context {
protected Hashtable<String, Object> myEnv = null;
@SuppressWarnings("unchecked") // Expect Hashtable<String, Object>
@@ -161,8 +164,18 @@ public abstract class GenericURLContext implements Context {
if (url.startsWith("//", start)) {
start += 2; // skip double slash
// find last slash
int posn = url.indexOf('/', start);
// find where the authority component ends
// and the rest of the URL starts
int slash = url.indexOf('/', start);
int qmark = url.indexOf('?', start);
int fmark = url.indexOf('#', start);
if (fmark > -1 && qmark > fmark) qmark = -1;
if (fmark > -1 && slash > fmark) slash = -1;
if (qmark > -1 && slash > qmark) slash = -1;
int posn = slash > -1 ? slash
: (qmark > -1 ? qmark
: (fmark > -1 ? fmark
: url.length()));
if (posn >= 0) {
start = posn;
} else {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2022, 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
@@ -27,6 +27,8 @@ package com.sun.jndi.toolkit.url;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
/**
@@ -36,15 +38,17 @@ import java.net.MalformedURLException;
*
* <p> The java.net.URL class cannot be used to parse URIs since it
* requires the installation of URL stream handlers that may not be
* available. The hack of getting around this by temporarily
* replacing the scheme part of a URI is not appropriate here: JNDI
* service providers must work on older Java platforms, and we want
* new features and bug fixes that are not available in old versions
* of the URL class.
* available.
*
* <p> It may be appropriate to drop this code in favor of the
* java.net.URI class. The changes would need to be written so as to
* still run on pre-1.4 platforms not containing that class.
* <p> The {@linkplain ParseMode#STRICT strict} parsing mode uses
* the java.net.URI class to syntactically validate URI strings.
* The {@linkplain ParseMode#COMPAT compat} mode validate the
* URI authority and rejects URI fragments, but doesn't perform any
* additional validation on path and query, other than that
* which may be implemented in the concrete the Uri subclasses.
* The {@linkplain ParseMode#LEGACY legacy} mode should not be
* used unless the application is capable of validating all URI
* strings before any constructors of this class is invoked.
*
* <p> The format of an absolute URI (see the RFCs mentioned above) is:
* <blockquote><pre>{@code
@@ -105,6 +109,28 @@ import java.net.MalformedURLException;
public class Uri {
// three parsing modes
public enum ParseMode {
/**
* Strict validation mode.
* Validate the URI syntactically using {@link java.net.URI}.
* Rejects URI fragments unless explicitly supported by the
* subclass.
*/
STRICT,
/**
* Compatibility mode. The URI authority is syntactically validated.
* Rejects URI fragments unless explicitly supported by the
* subclass.
* This is the default.
*/
COMPAT,
/**
* Legacy mode. In this mode, no validation is performed.
*/
LEGACY
}
protected String uri;
protected String scheme;
protected String host = null;
@@ -112,6 +138,7 @@ public class Uri {
protected boolean hasAuthority;
protected String path;
protected String query = null;
protected String fragment;
/**
@@ -128,6 +155,15 @@ public class Uri {
protected Uri() {
}
/**
* The parse mode for parsing this URI.
* The default is {@link ParseMode#COMPAT}.
* @return the parse mode for parsing this URI.
*/
protected ParseMode parseMode() {
return ParseMode.COMPAT;
}
/**
* Initializes a Uri object given a URI string.
* This method must be called exactly once, and before any other Uri
@@ -135,7 +171,7 @@ public class Uri {
*/
protected void init(String uri) throws MalformedURLException {
this.uri = uri;
parse(uri);
parse(uri, parseMode());
}
/**
@@ -188,10 +224,229 @@ public class Uri {
return uri;
}
private void parse(String uri, ParseMode mode) throws MalformedURLException {
switch (mode) {
case STRICT -> parseStrict(uri);
case COMPAT -> parseCompat(uri);
case LEGACY -> parseLegacy(uri);
}
}
/*
* Parses a URI string and sets this object's fields accordingly.
* Use java.net.URI to validate the uri string syntax
*/
private void parse(String uri) throws MalformedURLException {
private void parseStrict(String uri) throws MalformedURLException {
try {
if (!isSchemeOnly(uri)) {
URI u = new URI(uri);
scheme = u.getScheme();
if (scheme == null) throw new MalformedURLException("Invalid URI: " + uri);
var auth = u.getRawAuthority();
hasAuthority = auth != null;
if (hasAuthority) {
var host = u.getHost();
var port = u.getPort();
if (host != null) this.host = host;
if (port != -1) this.port = port;
String hostport = (host == null ? "" : host)
+ (port == -1 ? "" : (":" + port));
if (!hostport.equals(auth)) {
// throw if we have user info or regname
throw new MalformedURLException("unsupported authority: " + auth);
}
}
path = u.getRawPath();
if (u.getRawQuery() != null) {
query = "?" + u.getRawQuery();
}
if (u.getRawFragment() != null) {
if (!acceptsFragment()) {
throw new MalformedURLException("URI fragments not supported: " + uri);
}
fragment = "#" + u.getRawFragment();
}
} else {
// scheme-only URIs are not supported by java.net.URI
// validate the URI by appending "/" to the uri string.
var s = uri.substring(0, uri.indexOf(':'));
URI u = new URI(uri + "/");
if (!s.equals(u.getScheme())
|| !checkSchemeOnly(uri, u.getScheme())) {
throw newInvalidURISchemeException(uri);
}
scheme = s;
path = "";
}
} catch (URISyntaxException e) {
var mue = new MalformedURLException(e.getMessage());
mue.initCause(e);
throw mue;
}
}
/*
* Parses a URI string and sets this object's fields accordingly.
* Compatibility mode. Use java.net.URI to validate the syntax of
* the uri string authority.
*/
private void parseCompat(String uri) throws MalformedURLException {
int i; // index into URI
i = uri.indexOf(':'); // parse scheme
int slash = uri.indexOf('/');
int qmark = uri.indexOf('?');
int fmark = uri.indexOf('#');
if (i < 0 || slash > 0 && i > slash || qmark > 0 && i > qmark || fmark > 0 && i > fmark) {
throw new MalformedURLException("Invalid URI: " + uri);
}
if (fmark > -1) {
if (!acceptsFragment()) {
throw new MalformedURLException("URI fragments not supported: " + uri);
}
}
if (i == uri.length() - 1) {
if (!isSchemeOnly(uri)) {
throw newInvalidURISchemeException(uri);
}
}
scheme = uri.substring(0, i);
i++; // skip past ":"
hasAuthority = uri.startsWith("//", i);
if (fmark > -1 && qmark > fmark) qmark = -1;
int endp = qmark > -1 ? qmark : fmark > -1 ? fmark : uri.length();
if (hasAuthority) { // parse "//host:port"
i += 2; // skip past "//"
int starta = i;
// authority ends at the first appearance of /, ?, or #
int enda = uri.indexOf('/', i);
if (enda == -1 || qmark > -1 && qmark < enda) enda = qmark;
if (enda == -1 || fmark > -1 && fmark < enda) enda = fmark;
if (enda < 0) {
enda = uri.length();
}
if (uri.startsWith(":", i)) {
// LdapURL supports empty host.
i++;
host = "";
if (enda > i) {
port = Integer.parseInt(uri.substring(i, enda));
}
} else {
// Use URI to parse authority
try {
// URI requires at least one char after authority:
// we use "/" and expect that the resulting URI path
// will be exactly "/".
URI u = new URI(uri.substring(0, enda) + "/");
String auth = uri.substring(starta, enda);
host = u.getHost();
port = u.getPort();
String p = u.getRawPath();
String q = u.getRawQuery();
String f = u.getRawFragment();
String ui = u.getRawUserInfo();
if (ui != null) {
throw new MalformedURLException("user info not supported in authority: " + ui);
}
if (!"/".equals(p)) {
throw new MalformedURLException("invalid authority: " + auth);
}
if (q != null) {
throw new MalformedURLException("invalid trailing characters in authority: ?" + q);
}
if (f != null) {
throw new MalformedURLException("invalid trailing characters in authority: #" + f);
}
String hostport = (host == null ? "" : host)
+ (port == -1?"":(":" + port));
if (!auth.equals(hostport)) {
// throw if we have user info or regname
throw new MalformedURLException("unsupported authority: " + auth);
}
} catch (URISyntaxException e) {
var mue = new MalformedURLException(e.getMessage());
mue.initCause(e);
throw mue;
}
}
i = enda;
}
path = uri.substring(i, endp);
// look for query
if (qmark > -1) {
if (fmark > -1) {
query = uri.substring(qmark, fmark);
} else {
query = uri.substring(qmark);
}
}
if (fmark > -1) {
fragment = uri.substring(fmark);
}
}
/**
* A subclass of {@code Uri} that supports scheme only
* URIs can override this method and return true in the
* case where the URI string is a scheme-only URI that
* the subclass supports.
* @implSpec
* The default implementation of this method returns false,
* always.
* @param uri An URI string
* @return if this is a scheme-only URI supported by the subclass
*/
protected boolean isSchemeOnly(String uri) {
return false;
}
/**
* Checks whether the given uri string should be considered
* as a scheme-only URI. For some protocols - e.g. DNS, we
* might accept "dns://" as a valid URL denoting default DNS.
* For others - we might only accept "scheme:".
* @implSpec
* The default implementation of this method returns true if
* the URI is of the form {@code "<scheme>:"} with nothing
* after the scheme delimiter.
* @param uri the URI
* @param scheme the scheme
* @return true if the URI should be considered as a scheme-only
* URI supported by this URI scheme.
*/
protected boolean checkSchemeOnly(String uri, String scheme) {
return uri.equals(scheme + ":");
}
/**
* Creates a {@code MalformedURLException} to be thrown when the
* URI scheme is not supported.
*
* @param uri the URI string
* @return a {@link MalformedURLException}
*/
protected MalformedURLException newInvalidURISchemeException(String uri) {
return new MalformedURLException("Invalid URI scheme: " + uri);
}
/**
* Whether fragments are supported.
* @implSpec
* The default implementation of this method retturns false, always.
* @return true if fragments are supported.
*/
protected boolean acceptsFragment() {
return parseMode() == ParseMode.LEGACY;
}
/*
* Parses a URI string and sets this object's fields accordingly.
* Legacy parsing mode.
*/
private void parseLegacy(String uri) throws MalformedURLException {
int i; // index into URI
i = uri.indexOf(':'); // parse scheme

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -56,6 +56,7 @@ import com.sun.org.apache.xerces.internal.xs.ElementPSVI;
import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
import java.util.Locale;
import java.util.Stack;
import jdk.xml.internal.JdkXmlUtils;
import org.w3c.dom.Attr;
import org.w3c.dom.CDATASection;
import org.w3c.dom.Comment;
@@ -84,7 +85,7 @@ import org.xml.sax.SAXException;
* @author Andy Clark, IBM
* @author Elena Litani, IBM
*
* @LastModified: Jan 2019
* @LastModified: July 2021
*/
public class AbstractDOMParser extends AbstractXMLDocumentParser {
@@ -2041,17 +2042,8 @@ public class AbstractDOMParser extends AbstractXMLDocumentParser {
else {
fInternalSubset.append (name);
}
fInternalSubset.append (' ');
if (publicId != null) {
fInternalSubset.append ("PUBLIC '");
fInternalSubset.append (publicId);
fInternalSubset.append ("' '");
}
else {
fInternalSubset.append ("SYSTEM '");
}
fInternalSubset.append (literalSystemId);
fInternalSubset.append ("'>\n");
fInternalSubset.append (JdkXmlUtils.getDTDExternalDecl(publicId, literalSystemId));
fInternalSubset.append (">\n");
}
// NOTE: We only know how to create these nodes for the Xerces
@@ -2181,20 +2173,8 @@ public class AbstractDOMParser extends AbstractXMLDocumentParser {
if (fInternalSubset != null && !fInDTDExternalSubset) {
fInternalSubset.append ("<!ENTITY ");
fInternalSubset.append (name);
fInternalSubset.append (' ');
if (publicId != null) {
fInternalSubset.append ("PUBLIC '");
fInternalSubset.append (publicId);
if (literalSystemId != null) {
fInternalSubset.append ("' '");
fInternalSubset.append (literalSystemId);
}
}
else {
fInternalSubset.append ("SYSTEM '");
fInternalSubset.append (literalSystemId);
}
fInternalSubset.append ("' NDATA ");
fInternalSubset.append (JdkXmlUtils.getDTDExternalDecl(publicId, literalSystemId));
fInternalSubset.append (" NDATA ");
fInternalSubset.append (notation);
fInternalSubset.append (">\n");
}
@@ -2261,19 +2241,8 @@ public class AbstractDOMParser extends AbstractXMLDocumentParser {
if (fInternalSubset != null && !fInDTDExternalSubset) {
fInternalSubset.append ("<!NOTATION ");
fInternalSubset.append (name);
if (publicId != null) {
fInternalSubset.append (" PUBLIC '");
fInternalSubset.append (publicId);
if (literalSystemId != null) {
fInternalSubset.append ("' '");
fInternalSubset.append (literalSystemId);
}
}
else {
fInternalSubset.append (" SYSTEM '");
fInternalSubset.append (literalSystemId);
}
fInternalSubset.append ("'>\n");
fInternalSubset.append (JdkXmlUtils.getDTDExternalDecl(publicId, literalSystemId));
fInternalSubset.append (">\n");
}
// NOTE: We only know how to create these nodes for the Xerces

View File

@@ -31,6 +31,7 @@ import org.xml.sax.SAXException;
import com.sun.org.apache.xml.internal.serializer.utils.MsgKey;
import com.sun.org.apache.xml.internal.serializer.utils.Utils;
import javax.xml.transform.ErrorListener;
import jdk.xml.internal.JdkXmlUtils;
/**
* This serializer takes a series of SAX or
@@ -41,7 +42,7 @@ import javax.xml.transform.ErrorListener;
* because it is used from another package.
*
* @xsl.usage internal
* @LastModified: June 2021
* @LastModified: July 2021
*/
public final class ToHTMLStream extends ToStream
{
@@ -679,28 +680,10 @@ public final class ToHTMLStream extends ToStream
final java.io.Writer writer = m_writer;
try
{
writer.write("<!DOCTYPE html");
if (null != doctypePublic)
{
writer.write(" PUBLIC \"");
writer.write(doctypePublic);
writer.write('"');
}
if (null != doctypeSystem)
{
if (null == doctypePublic)
writer.write(" SYSTEM \"");
else
writer.write(" \"");
writer.write(doctypeSystem);
writer.write('"');
}
writer.write('>');
outputLineSep();
writer.write("<!DOCTYPE html");
writer.write(JdkXmlUtils.getDTDExternalDecl(doctypePublic, doctypeSystem));
writer.write('>');
outputLineSep();
}
catch(IOException e)
{

View File

@@ -54,7 +54,7 @@ import org.xml.sax.SAXException;
* serializers (xml, html, text ...) that write output to a stream.
*
* @xsl.usage internal
* @LastModified: June 2021
* @LastModified: July 2021
*/
abstract public class ToStream extends SerializerBase {
@@ -895,16 +895,8 @@ abstract public class ToStream extends SerializerBase {
m_writer.write("<!ENTITY ");
m_writer.write(name);
if (publicId != null) {
m_writer.write(" PUBLIC \"");
m_writer.write(publicId);
}
else {
m_writer.write(" SYSTEM \"");
m_writer.write(systemId);
}
m_writer.write("\" >");
m_writer.write(JdkXmlUtils.getDTDExternalDecl(publicId, systemId));
m_writer.write(">");
m_writer.write(m_lineSep, 0, m_lineSepLen);
} catch (IOException e) {
// TODO Auto-generated catch block
@@ -1967,27 +1959,11 @@ abstract public class ToStream extends SerializerBase {
final Writer writer = m_writer;
writer.write("<!DOCTYPE ");
writer.write(name);
String systemId = getDoctypeSystem();
writer.write(JdkXmlUtils.getDTDExternalDecl(getDoctypePublic(), systemId));
String doctypePublic = getDoctypePublic();
if (null != doctypePublic)
if (null != systemId)
{
writer.write(" PUBLIC \"");
writer.write(doctypePublic);
writer.write('\"');
}
String doctypeSystem = getDoctypeSystem();
if (null != doctypeSystem)
{
char quote = JdkXmlUtils.getQuoteChar(doctypeSystem);
if (null == doctypePublic) {
writer.write(" SYSTEM");
}
writer.write(" ");
writer.write(quote);
writer.write(doctypeSystem);
writer.write(quote);
if (closeDecl)
{
writer.write(">");
@@ -1995,17 +1971,6 @@ abstract public class ToStream extends SerializerBase {
closeDecl = false; // done closing
}
}
boolean dothis = false;
if (dothis)
{
// at one point this code seemed right,
// but not anymore - Brian M.
if (closeDecl)
{
writer.write('>');
writer.write(m_lineSep, 0, m_lineSepLen);
}
}
}
catch (IOException e)
{
@@ -3570,16 +3535,8 @@ abstract public class ToStream extends SerializerBase {
m_writer.write("<!NOTATION ");
m_writer.write(name);
if (pubID != null) {
m_writer.write(" PUBLIC \"");
m_writer.write(pubID);
}
else {
m_writer.write(" SYSTEM \"");
m_writer.write(sysID);
}
m_writer.write("\" >");
m_writer.write(JdkXmlUtils.getDTDExternalDecl(pubID, sysID));
m_writer.write(">");
m_writer.write(m_lineSep, 0, m_lineSepLen);
} catch (IOException e) {
// TODO Auto-generated catch block
@@ -3600,16 +3557,8 @@ abstract public class ToStream extends SerializerBase {
m_writer.write("<!ENTITY ");
m_writer.write(name);
if (pubID != null) {
m_writer.write(" PUBLIC \"");
m_writer.write(pubID);
}
else {
m_writer.write(" SYSTEM \"");
m_writer.write(sysID);
}
m_writer.write("\" NDATA ");
m_writer.write(JdkXmlUtils.getDTDExternalDecl(pubID, sysID));
m_writer.write(" NDATA ");
m_writer.write(notationName);
m_writer.write(" >");
m_writer.write(m_lineSep, 0, m_lineSepLen);

View File

@@ -63,7 +63,7 @@ import org.xml.sax.helpers.LocatorImpl;
* parameters and filters if any during serialization.
*
* @xsl.usage internal
* @LastModified: Apr 2021
* @LastModified: July 2021
*/
final class DOM3TreeWalker {
@@ -506,23 +506,7 @@ final class DOM3TreeWalker {
dtd.append("<!DOCTYPE ");
dtd.append(docTypeName);
if (null != publicId) {
dtd.append(" PUBLIC \"");
dtd.append(publicId);
dtd.append('\"');
}
if (null != systemId) {
char quote = JdkXmlUtils.getQuoteChar(systemId);
if (null == publicId) {
dtd.append(" SYSTEM ").append(quote);
} else {
dtd.append(" ").append(quote);
}
dtd.append(systemId);
dtd.append(quote);
}
dtd.append(JdkXmlUtils.getDTDExternalDecl(publicId, systemId));
dtd.append(" [ ");
dtd.append(fNewLine);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2021, 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
@@ -28,6 +28,7 @@ package com.sun.xml.internal.stream.events;
import javax.xml.stream.events.EntityDeclaration;
import javax.xml.stream.events.XMLEvent;
import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
import jdk.xml.internal.JdkXmlUtils;
/**
*
@@ -129,18 +130,12 @@ public class EntityDeclarationImpl extends DummyEvent implements EntityDeclarati
//escape quotes, lt and amps
writer.write(" \"");
charEncode(writer, fReplacementText);
writer.write("\"");
} else {
//external entity
String pubId = getPublicId();
if (pubId != null) {
writer.write(" PUBLIC \"");
writer.write(pubId);
} else {
writer.write(" SYSTEM \"");
writer.write(getSystemId());
}
writer.write(JdkXmlUtils.getDTDExternalDecl(getPublicId(), getSystemId()));
}
writer.write("\"");
if (fNotationName != null) {
writer.write(" NDATA ");
writer.write(fNotationName);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2021, 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
@@ -28,6 +28,7 @@ package com.sun.xml.internal.stream.events;
import javax.xml.stream.events.NotationDeclaration;
import javax.xml.stream.events.XMLEvent;
import com.sun.xml.internal.stream.dtd.nonvalidating.XMLNotationDecl;
import jdk.xml.internal.JdkXmlUtils;
/**
* Implementation of NotationDeclaration event.
@@ -88,16 +89,7 @@ public class NotationDeclarationImpl extends DummyEvent implements NotationDecla
{
writer.write("<!NOTATION ");
writer.write(getName());
if (fPublicId != null) {
writer.write(" PUBLIC \"");
writer.write(fPublicId);
writer.write("\"");
} else if (fSystemId != null) {
writer.write(" SYSTEM");
writer.write(" \"");
writer.write(fSystemId);
writer.write("\"");
}
writer.write(JdkXmlUtils.getDTDExternalDecl(fPublicId, fSystemId));
writer.write('>');
}
}

View File

@@ -367,19 +367,40 @@ public class JdkXmlUtils {
}
/**
* Returns the character to be used to quote the input content. Between
* single and double quotes, this method returns the one that is not found
* in the input. Returns double quote by default.
* Returns the external declaration for a DTD construct.
*
* @param s the input string
* @return returns the quote not found in the input
* @param publicId the public identifier
* @param systemId the system identifier
* @return a DTD external declaration
*/
public static char getQuoteChar(String s) {
if (s != null && s.indexOf('"') > -1) {
return '\'';
} else {
return '"';
public static String getDTDExternalDecl(String publicId, String systemId) {
StringBuilder sb = new StringBuilder();
if (null != publicId) {
sb.append(" PUBLIC ");
sb.append(quoteString(publicId));
}
if (null != systemId) {
if (null == publicId) {
sb.append(" SYSTEM ");
} else {
sb.append(" ");
}
sb.append(quoteString(systemId));
}
return sb.toString();
}
/**
* Returns the input string quoted with double quotes or single ones if
* there is a double quote in the string.
* @param s the input string, can not be null
* @return the quoted string
*/
private static String quoteString(String s) {
char c = (s.indexOf('"') > -1) ? '\'' : '"';
return c + s + c;
}
private static XMLReader getXMLReaderWSAXFactory(boolean overrideDefaultParser) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, 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
@@ -30,6 +30,7 @@ import sun.security.util.ArrayUtil;
import sun.security.util.math.*;
import static sun.security.ec.ECOperations.IntermediateValueException;
import java.math.BigInteger;
import java.security.ProviderException;
import java.security.spec.*;
import java.util.Arrays;
@@ -200,7 +201,8 @@ public class ECDSAOperations {
IntegerFieldModuloP field = ecOps.getField();
IntegerFieldModuloP orderField = ecOps.getOrderField();
int length = (orderField.getSize().bitLength() + 7) / 8;
BigInteger mod = orderField.getSize();
int length = (mod.bitLength() + 7) / 8;
byte[] r;
byte[] s;
@@ -218,6 +220,13 @@ public class ECDSAOperations {
System.arraycopy(sig, encodeLength, s, length - encodeLength, encodeLength);
}
BigInteger rb = new BigInteger(1, r);
BigInteger sb = new BigInteger(1, s);
if (rb.signum() == 0 || sb.signum() == 0
|| rb.compareTo(mod) >= 0 || sb.compareTo(mod) >= 0) {
return false;
}
ArrayUtil.reverse(r);
ArrayUtil.reverse(s);
IntegerModuloP ri = orderField.getElement(r);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2022, 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
@@ -849,7 +849,7 @@ final class CompilerToVM {
/**
* @see HotSpotJVMCIRuntime#translate(Object)
*/
native long translate(Object obj);
native long translate(Object obj, boolean callPostTranslation);
/**
* @see HotSpotJVMCIRuntime#unhand(Class, long)

View File

@@ -109,22 +109,12 @@ public class HotSpotCodeCacheProvider implements CodeCacheProvider {
HotSpotCompiledCode hsCompiledCode = (HotSpotCompiledCode) compiledCode;
String name = hsCompiledCode.getName();
HotSpotCompiledNmethod hsCompiledNmethod = null;
if (method == null) {
// Must be a stub
resultInstalledCode = new HotSpotRuntimeStub(name);
} else {
hsCompiledNmethod = (HotSpotCompiledNmethod) hsCompiledCode;
HotSpotResolvedJavaMethodImpl hsMethod = (HotSpotResolvedJavaMethodImpl) method;
resultInstalledCode = new HotSpotNmethod(hsMethod, name, isDefault, hsCompiledNmethod.id);
}
HotSpotSpeculationLog speculationLog = null;
if (log != null) {
if (log.hasSpeculations()) {
speculationLog = (HotSpotSpeculationLog) log;
}
}
byte[] speculations;
long failedSpeculationsAddress;
if (speculationLog != null) {
@@ -134,6 +124,18 @@ public class HotSpotCodeCacheProvider implements CodeCacheProvider {
speculations = new byte[0];
failedSpeculationsAddress = 0L;
}
if (method == null) {
// Must be a stub
resultInstalledCode = new HotSpotRuntimeStub(name);
} else {
hsCompiledNmethod = (HotSpotCompiledNmethod) hsCompiledCode;
HotSpotResolvedJavaMethodImpl hsMethod = (HotSpotResolvedJavaMethodImpl) method;
HotSpotNmethod nmethod = new HotSpotNmethod(hsMethod, name, isDefault, hsCompiledNmethod.id);
nmethod.setSpeculationLog(speculationLog);
resultInstalledCode = nmethod;
}
int result = runtime.getCompilerToVM().installCode(target, (HotSpotCompiledCode) compiledCode, resultInstalledCode, failedSpeculationsAddress, speculations);
if (result != config.codeInstallResultOk) {
String resultDesc = config.getCodeInstallResultDescription(result);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2022, 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
@@ -46,6 +46,8 @@ import java.util.Map;
import java.util.Objects;
import java.util.ServiceLoader;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import jdk.internal.misc.Unsafe;
import jdk.vm.ci.code.Architecture;
@@ -66,6 +68,7 @@ import jdk.vm.ci.runtime.JVMCICompiler;
import jdk.vm.ci.runtime.JVMCICompilerFactory;
import jdk.vm.ci.runtime.JVMCIRuntime;
import jdk.vm.ci.services.JVMCIServiceLocator;
import jdk.vm.ci.services.Services;
/**
* HotSpot implementation of a JVMCI runtime.
@@ -199,14 +202,44 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
return result;
}
/**
* Decodes the exception encoded in {@code buffer} and throws it.
*
* @param buffer a native byte buffer containing an exception encoded by
* {@link #encodeThrowable}
*/
@VMEntryPoint
static Throwable decodeThrowable(String encodedThrowable) throws Throwable {
return TranslatedException.decodeThrowable(encodedThrowable);
static void decodeAndThrowThrowable(long buffer) throws Throwable {
Unsafe unsafe = UnsafeAccess.UNSAFE;
int encodingLength = unsafe.getInt(buffer);
byte[] encoding = new byte[encodingLength];
unsafe.copyMemory(null, buffer + 4, encoding, Unsafe.ARRAY_BYTE_BASE_OFFSET, encodingLength);
throw TranslatedException.decodeThrowable(encoding);
}
/**
* If {@code bufferSize} is large enough, encodes {@code throwable} into a byte array and writes
* it to {@code buffer}. The encoding in {@code buffer} can be decoded by
* {@link #decodeAndThrowThrowable}.
*
* @param throwable the exception to encode
* @param buffer a native byte buffer
* @param bufferSize the size of {@code buffer} in bytes
* @return the number of bytes written into {@code buffer} if {@code bufferSize} is large
* enough, otherwise {@code -N} where {@code N} is the value {@code bufferSize} needs to
* be to fit the encoding
*/
@VMEntryPoint
static String encodeThrowable(Throwable throwable) throws Throwable {
return TranslatedException.encodeThrowable(throwable);
static int encodeThrowable(Throwable throwable, long buffer, int bufferSize) throws Throwable {
byte[] encoding = TranslatedException.encodeThrowable(throwable);
int requiredSize = 4 + encoding.length;
if (bufferSize < requiredSize) {
return -requiredSize;
}
Unsafe unsafe = UnsafeAccess.UNSAFE;
unsafe.putInt(buffer, encoding.length);
unsafe.copyMemory(encoding, Unsafe.ARRAY_BYTE_BASE_OFFSET, null, buffer + 4, encoding.length);
return requiredSize;
}
@VMEntryPoint
@@ -235,6 +268,10 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
// Note: The following one is not used (see InitTimer.ENABLED). It is added here
// so that -XX:+JVMCIPrintProperties shows the option.
InitTimer(Boolean.class, false, "Specifies if initialization timing is enabled."),
ForceTranslateFailure(String.class, null, "Forces HotSpotJVMCIRuntime.translate to throw an exception in the context " +
"of the peer runtime. The value is a filter that can restrict the forced failure to matching translated " +
"objects. See HotSpotJVMCIRuntime.postTranslation for more details. This option exists soley to test " +
"correct handling of translation failure."),
PrintConfig(Boolean.class, false, "Prints VM configuration available via JVMCI."),
AuditHandles(Boolean.class, false, "Record stack trace along with scoped foreign object reference wrappers " +
"to debug issue with a wrapper being used after its scope has closed."),
@@ -1180,7 +1217,88 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
* @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references"
*/
public long translate(Object obj) {
return compilerToVm.translate(obj);
return compilerToVm.translate(obj, Option.ForceTranslateFailure.getString() != null);
}
private static final Pattern FORCE_TRANSLATE_FAILURE_FILTER_RE = Pattern.compile("(?:(method|type|nmethod)/)?([^:]+)(?::(hotspot|native))?");
/**
* Forces translation failure based on {@code translatedObject} and the value of
* {@link Option#ForceTranslateFailure}. The value is zero or more filters separated by a comma.
* The syntax for a filter is:
*
* <pre>
* Filter = [ TypeSelector "/" ] Substring [ ":" JVMCIEnvSelector ] .
* TypeSelector = "type" | "method" | "nmethod"
* JVMCIEnvSelector = "native" | "hotspot"
* </pre>
*
* For example:
*
* <pre>
* -Djvmci.ForceTranslateFailure=nmethod/StackOverflowError:native,method/computeHash,execute
* </pre>
*
* will cause failure of:
* <ul>
* <li>translating a {@link HotSpotNmethod} to the libjvmci heap whose fully qualified name
* contains "StackOverflowError"</li>
* <li>translating a {@link HotSpotResolvedJavaMethodImpl} to the libjvmci or HotSpot heap whose
* fully qualified name contains "computeHash"</li>
* <li>translating a {@link HotSpotNmethod}, {@link HotSpotResolvedJavaMethodImpl} or
* {@link HotSpotResolvedObjectTypeImpl} to the libjvmci or HotSpot heap whose fully qualified
* name contains "execute"</li>
* </ul>
*/
@VMEntryPoint
static void postTranslation(Object translatedObject) {
String value = Option.ForceTranslateFailure.getString();
String toMatch;
String type;
if (translatedObject instanceof HotSpotResolvedJavaMethodImpl) {
toMatch = ((HotSpotResolvedJavaMethodImpl) translatedObject).format("%H.%n");
type = "method";
} else if (translatedObject instanceof HotSpotResolvedObjectTypeImpl) {
toMatch = ((HotSpotResolvedObjectTypeImpl) translatedObject).toJavaName();
type = "type";
} else if (translatedObject instanceof HotSpotNmethod) {
HotSpotNmethod nmethod = (HotSpotNmethod) translatedObject;
if (nmethod.getMethod() != null) {
toMatch = nmethod.getMethod().format("%H.%n");
} else {
toMatch = String.valueOf(nmethod.getName());
}
type = "nmethod";
} else {
return;
}
String[] filters = value.split(",");
for (String filter : filters) {
Matcher m = FORCE_TRANSLATE_FAILURE_FILTER_RE.matcher(filter);
if (!m.matches()) {
throw new JVMCIError(Option.ForceTranslateFailure + " filter does not match " + FORCE_TRANSLATE_FAILURE_FILTER_RE + ": " + filter);
}
String typeSelector = m.group(1);
String substring = m.group(2);
String jvmciEnvSelector = m.group(3);
if (jvmciEnvSelector != null) {
if (jvmciEnvSelector.equals("native")) {
if (!Services.IS_IN_NATIVE_IMAGE) {
continue;
}
} else {
if (Services.IS_IN_NATIVE_IMAGE) {
continue;
}
}
}
if (typeSelector != null && !typeSelector.equals(type)) {
continue;
}
if (toMatch.contains(substring)) {
throw new JVMCIError("translation of " + translatedObject + " failed due to matching " + Option.ForceTranslateFailure + " filter \"" + filter + "\"");
}
}
}
/**

View File

@@ -68,8 +68,8 @@ public class HotSpotNmethod extends HotSpotInstalledCode {
/**
* If this field is 0, this object is in the oops table of the nmethod. Otherwise, the value of
* the field records the nmethod's compile identifier. This value is used to confirm an entry in
* the code cache retrieved by {@link #address} is indeed the nmethod represented by this
* the field records the nmethod's compile identifier. This value is used to confirm if an entry
* in the code cache retrieved by {@link #address} is indeed the nmethod represented by this
* object.
*
* @see #inOopsTable
@@ -85,6 +85,23 @@ public class HotSpotNmethod extends HotSpotInstalledCode {
assert inOopsTable || compileId != 0L : this;
}
/**
* Attaches {@code log} to this object. If {@code log.managesFailedSpeculations() == true}, this
* ensures the failed speculation list lives at least as long as this object.
*/
public void setSpeculationLog(HotSpotSpeculationLog log) {
this.speculationLog = log;
}
/**
* The speculation log containing speculations embedded in the nmethod.
*
* If {@code speculationLog.managesFailedSpeculations() == true}, this field ensures the failed
* speculation list lives at least as long as this object. This prevents deoptimization from
* appending to an already freed list.
*/
@SuppressWarnings("unused") private HotSpotSpeculationLog speculationLog;
/**
* Determines if the nmethod associated with this object is the compiled entry point for
* {@link #getMethod()}.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2022, 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
@@ -22,13 +22,20 @@
*/
package jdk.vm.ci.hotspot;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Formatter;
import java.util.List;
import java.util.Objects;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import jdk.vm.ci.common.JVMCIError;
/**
* Support for translating exceptions between different runtime heaps.
@@ -36,6 +43,26 @@ import java.util.Objects;
@SuppressWarnings("serial")
final class TranslatedException extends Exception {
/**
* The value returned by {@link #encodeThrowable(Throwable)} when encoding fails due to an
* {@link OutOfMemoryError}.
*/
private static final byte[] FALLBACK_ENCODED_OUTOFMEMORYERROR_BYTES;
/**
* The value returned by {@link #encodeThrowable(Throwable)} when encoding fails for any reason
* other than {@link OutOfMemoryError}.
*/
private static final byte[] FALLBACK_ENCODED_THROWABLE_BYTES;
static {
try {
FALLBACK_ENCODED_THROWABLE_BYTES = encodeThrowable(new TranslatedException("error during encoding", "<unknown>"), false);
FALLBACK_ENCODED_OUTOFMEMORYERROR_BYTES = encodeThrowable(new OutOfMemoryError(), false);
} catch (IOException e) {
throw new JVMCIError(e);
}
}
/**
* Class name of exception that could not be instantiated.
*/
@@ -110,83 +137,74 @@ final class TranslatedException extends Exception {
}
}
/**
* Encodes an exception message to distinguish a null message from an empty message.
*
* @return {@code value} with a space prepended iff {@code value != null}
*/
private static String encodeMessage(String value) {
return value != null ? ' ' + value : value;
private static String emptyIfNull(String value) {
return value == null ? "" : value;
}
private static String decodeMessage(String value) {
if (value.length() == 0) {
return null;
}
return value.substring(1);
}
private static String encodedString(String value) {
return Objects.toString(value, "").replace('|', '_');
private static String emptyAsNull(String value) {
return value.isEmpty() ? null : value;
}
/**
* Encodes {@code throwable} including its stack and causes as a string. The encoding format of
* a single exception is:
*
* <pre>
* <exception class name> '|' <exception message> '|' <stack size> '|' [ <classLoader> '|' <module> '|' <moduleVersion> '|' <class> '|' <method> '|' <file> '|' <line> '|' ]*
* </pre>
*
* Each exception is encoded before the exception it causes.
* Encodes {@code throwable} including its stack and causes as a {@linkplain GZIPOutputStream
* compressed} byte array that can be decoded by {@link #decodeThrowable}.
*/
@VMEntryPoint
static String encodeThrowable(Throwable throwable) throws Throwable {
static byte[] encodeThrowable(Throwable throwable) throws Throwable {
try {
Formatter enc = new Formatter();
return encodeThrowable(throwable, true);
} catch (OutOfMemoryError e) {
return FALLBACK_ENCODED_OUTOFMEMORYERROR_BYTES;
} catch (Throwable e) {
return FALLBACK_ENCODED_THROWABLE_BYTES;
}
}
private static byte[] encodeThrowable(Throwable throwable, boolean withCauseAndStack) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (DataOutputStream dos = new DataOutputStream(new GZIPOutputStream(baos))) {
List<Throwable> throwables = new ArrayList<>();
for (Throwable current = throwable; current != null; current = current.getCause()) {
throwables.add(current);
if (!withCauseAndStack) {
break;
}
}
// Encode from inner most cause outwards
Collections.reverse(throwables);
for (Throwable current : throwables) {
enc.format("%s|%s|", current.getClass().getName(), encodedString(encodeMessage(current.getMessage())));
StackTraceElement[] stackTrace = current.getStackTrace();
dos.writeUTF(current.getClass().getName());
dos.writeUTF(emptyIfNull(current.getMessage()));
StackTraceElement[] stackTrace = withCauseAndStack ? current.getStackTrace() : null;
if (stackTrace == null) {
stackTrace = new StackTraceElement[0];
}
enc.format("%d|", stackTrace.length);
dos.writeInt(stackTrace.length);
for (int i = 0; i < stackTrace.length; i++) {
StackTraceElement frame = stackTrace[i];
if (frame != null) {
enc.format("%s|%s|%s|%s|%s|%s|%d|", encodedString(frame.getClassLoaderName()),
encodedString(frame.getModuleName()), encodedString(frame.getModuleVersion()),
frame.getClassName(), frame.getMethodName(),
encodedString(frame.getFileName()), frame.getLineNumber());
dos.writeUTF(emptyIfNull(frame.getClassLoaderName()));
dos.writeUTF(emptyIfNull(frame.getModuleName()));
dos.writeUTF(emptyIfNull(frame.getModuleVersion()));
dos.writeUTF(emptyIfNull(frame.getClassName()));
dos.writeUTF(emptyIfNull(frame.getMethodName()));
dos.writeUTF(emptyIfNull(frame.getFileName()));
dos.writeInt(frame.getLineNumber());
}
}
}
return enc.toString();
} catch (Throwable e) {
assert printStackTrace(e);
try {
return e.getClass().getName() + "|" + encodedString(e.getMessage()) + "|0|";
} catch (Throwable e2) {
assert printStackTrace(e2);
return "java.lang.Throwable|too many errors during encoding|0|";
}
}
return baos.toByteArray();
}
/**
* Gets the stack of the current thread without the frames between this call and the one just
* below the frame of the first method in {@link CompilerToVM}. The chopped frames are specific
* to the implementation of {@link HotSpotJVMCIRuntime#decodeThrowable(String)}.
* below the frame of the first method in {@link CompilerToVM}. The chopped frames are for the
* VM call to {@link HotSpotJVMCIRuntime#decodeAndThrowThrowable}.
*/
private static StackTraceElement[] getStackTraceSuffix() {
private static StackTraceElement[] getMyStackTrace() {
StackTraceElement[] stack = new Exception().getStackTrace();
for (int i = 0; i < stack.length; i++) {
StackTraceElement e = stack[i];
@@ -206,43 +224,47 @@ final class TranslatedException extends Exception {
* {@link #encodeThrowable}
*/
@VMEntryPoint
static Throwable decodeThrowable(String encodedThrowable) {
try {
int i = 0;
String[] parts = encodedThrowable.split("\\|");
static Throwable decodeThrowable(byte[] encodedThrowable) {
try (DataInputStream dis = new DataInputStream(new GZIPInputStream(new ByteArrayInputStream(encodedThrowable)))) {
Throwable cause = null;
Throwable throwable = null;
while (i != parts.length) {
String exceptionClassName = parts[i++];
String exceptionMessage = decodeMessage(parts[i++]);
StackTraceElement[] myStack = getMyStackTrace();
while (dis.available() != 0) {
String exceptionClassName = dis.readUTF();
String exceptionMessage = emptyAsNull(dis.readUTF());
throwable = create(exceptionClassName, exceptionMessage, cause);
int stackTraceDepth = Integer.parseInt(parts[i++]);
StackTraceElement[] suffix = getStackTraceSuffix();
StackTraceElement[] stackTrace = new StackTraceElement[stackTraceDepth + suffix.length];
int stackTraceDepth = dis.readInt();
StackTraceElement[] stackTrace = new StackTraceElement[stackTraceDepth + myStack.length];
int stackTraceIndex = 0;
int myStackIndex = 0;
for (int j = 0; j < stackTraceDepth; j++) {
String classLoaderName = parts[i++];
String moduleName = parts[i++];
String moduleVersion = parts[i++];
String className = parts[i++];
String methodName = parts[i++];
String fileName = parts[i++];
int lineNumber = Integer.parseInt(parts[i++]);
if (classLoaderName.isEmpty()) {
classLoaderName = null;
String classLoaderName = emptyAsNull(dis.readUTF());
String moduleName = emptyAsNull(dis.readUTF());
String moduleVersion = emptyAsNull(dis.readUTF());
String className = emptyAsNull(dis.readUTF());
String methodName = emptyAsNull(dis.readUTF());
String fileName = emptyAsNull(dis.readUTF());
int lineNumber = dis.readInt();
StackTraceElement ste = new StackTraceElement(classLoaderName, moduleName, moduleVersion, className, methodName, fileName, lineNumber);
if (ste.isNativeMethod()) {
// Best effort attempt to weave stack traces from two heaps into
// a single stack trace using native method frames as stitching points.
// This is not 100% reliable as there's no guarantee that native method
// frames only exist for calls between HotSpot and libjvmci.
while (myStackIndex < myStack.length) {
StackTraceElement suffixSTE = myStack[myStackIndex++];
if (suffixSTE.isNativeMethod()) {
break;
}
stackTrace[stackTraceIndex++] = suffixSTE;
}
}
if (moduleName.isEmpty()) {
moduleName = null;
}
if (moduleVersion.isEmpty()) {
moduleVersion = null;
}
if (fileName.isEmpty()) {
fileName = null;
}
stackTrace[j] = new StackTraceElement(classLoaderName, moduleName, moduleVersion, className, methodName, fileName, lineNumber);
stackTrace[stackTraceIndex++] = ste;
}
while (myStackIndex < myStack.length) {
stackTrace[stackTraceIndex++] = myStack[myStackIndex++];
}
System.arraycopy(suffix, 0, stackTrace, stackTraceDepth, suffix.length);
throwable.setStackTrace(stackTrace);
cause = throwable;
}

View File

@@ -154,6 +154,8 @@ public interface EventStream extends AutoCloseable {
* <p>
* By default, the stream starts with the next event flushed by Flight
* Recorder.
* <p>
* Only trusted disk repositories should be opened.
*
* @param directory location of the disk repository, not {@code null}
*
@@ -184,6 +186,8 @@ public interface EventStream extends AutoCloseable {
* Creates an event stream from a file.
* <p>
* By default, the stream starts with the first event in the file.
* <p>
* Only recording files from trusted sources should be opened.
*
* @param file location of the file, not {@code null}
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2021, 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
@@ -72,6 +72,8 @@ public final class RecordingFile implements Closeable {
/**
* Creates a recording file.
* <p>
* Only recording files from trusted sources should be used.
*
* @param file the path of the file to open, not {@code null}
* @throws IOException if it's not a valid recording file, or an I/O error
@@ -211,6 +213,8 @@ public final class RecordingFile implements Closeable {
* <p>
* This method is intended for simple cases where it's convenient to read all
* events in a single operation. It isn't intended for reading large files.
* <p>
* Only recording files from trusted sources should be used.
*
* @param path the path to the file, not {@code null}
*

View File

@@ -66,6 +66,7 @@ final class MetadataReader {
public MetadataReader(RecordingInput input) throws IOException {
this.input = input;
int size = input.readInt();
input.require(size, "Metadata string pool size %d exceeds available data" );
this.pool = new ArrayList<>(size);
StringParser p = new StringParser(null, false);
for (int i = 0; i < size; i++) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2021, 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
@@ -114,7 +114,7 @@ public final class ChunkHeader {
byte fileState1;
input.positionPhysical(absoluteChunkStart + FILE_STATE_POSITION);
while ((fileState1 = input.readPhysicalByte()) == UPDATING_CHUNK_HEADER) {
Utils.takeNap(1);
input.pollWait();
input.positionPhysical(absoluteChunkStart + FILE_STATE_POSITION);
}
input.positionPhysical(absoluteChunkStart + CHUNK_SIZE_POSITION);
@@ -184,7 +184,7 @@ public final class ChunkHeader {
finished = true;
return;
}
Utils.takeNap(1);
input.pollWait();
}
} finally {
input.position(pos);

View File

@@ -148,6 +148,7 @@ public class EventDirectoryStream extends AbstractEventStream {
}
currentChunkStartNanos = repositoryFiles.getTimestamp(path);
try (RecordingInput input = new RecordingInput(path.toFile(), fileAccess)) {
input.setStreamed();
currentParser = new ChunkParser(input, disp.parserConfiguration, parserState);
long segmentStart = currentParser.getStartNanos() + currentParser.getChunkDuration();
long filterStart = validStartTime ? disp.startNanos : segmentStart;

View File

@@ -50,6 +50,7 @@ public final class EventFileStream extends AbstractEventStream {
super(acc, null, Collections.emptyList());
Objects.requireNonNull(path);
this.input = new RecordingInput(path.toFile(), FileAccess.UNPRIVILEGED);
this.input.setStreamed();
}
@Override

View File

@@ -214,6 +214,7 @@ public final class OngoingStream extends EventByteStream {
return false;
}
input = new RecordingInput(path.toFile(), SecuritySupport.PRIVILEGED);
input.setStreamed();
header = new ChunkHeader(input);
}
return true;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2021, 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
@@ -296,6 +296,7 @@ final class ParserFactory {
@Override
public Object parse(RecordingInput input) throws IOException {
final int size = input.readInt();
input.require(size, "Array size %d exceeds available data" );
final Object[] array = new Object[size];
for (int i = 0; i < size; i++) {
array[i] = elementParser.parse(input);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2021, 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
@@ -31,6 +31,7 @@ import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.file.Path;
import jdk.jfr.internal.Utils;
public final class RecordingInput implements DataInput, AutoCloseable {
@@ -66,6 +67,7 @@ public final class RecordingInput implements DataInput, AutoCloseable {
}
private final int blockSize;
private final FileAccess fileAccess;
private long pollCount = 1000;
private RandomAccessFile file;
private String filename;
private Block currentBlock = new Block();
@@ -418,6 +420,15 @@ public final class RecordingInput implements DataInput, AutoCloseable {
return filename;
}
// Purpose of this method is to prevent OOM by sanity check
// the minimum required number of bytes against what is available in
// segment/chunk/file
public void require(int minimumBytes, String errorMessage) throws IOException {
if (position + minimumBytes > size) {
throw new IOException(String.format(errorMessage, minimumBytes));
}
}
// Purpose of this method is to reuse block cache from a
// previous RecordingInput
public void setFile(Path path) throws IOException {
@@ -430,4 +441,18 @@ public final class RecordingInput implements DataInput, AutoCloseable {
initialize(path.toFile());
}
// Marks that it is OK to poll indefinitely for file update
// By default, only 1000 polls are allowed
public void setStreamed() {
this.pollCount = Long.MAX_VALUE;
}
// Wait for file to be updated
public void pollWait() throws IOException {
pollCount--;
if (pollCount < 0) {
throw new IOException("Recording file is stuck in locked stream state.");
}
Utils.takeNap(1);
}
}

View File

@@ -70,6 +70,7 @@ public final class StringParser extends Parser {
@Override
public Object parse(RecordingInput input) throws IOException {
int size = input.readInt();
input.require(size, "String size %d exceeds available data");
ensureSize(size);
if (lastSize == size) {
boolean equalsLastString = true;
@@ -115,6 +116,7 @@ public final class StringParser extends Parser {
@Override
public Object parse(RecordingInput input) throws IOException {
int size = input.readInt();
input.require(size, "String size %d exceeds available data");
ensureSize(size);
if (lastSize == size) {
boolean equalsLastString = true;

View File

@@ -185,7 +185,7 @@ final class JSONWriter extends EventPrintWriter {
private void printDataStructureName(String text) {
printIndent();
print("\"");
print(text);
printEscaped(text);
print("\": ");
}

View File

@@ -83,7 +83,11 @@ final class XMLWriter extends EventPrintWriter {
}
private void printAttribute(String name, String value) {
print(" ", name, "=\"", value, "\"");
print(" ");
print(name); // Only known strings
print("=\"");
printEscaped(value);
print("\"");
}
public void printObject(RecordedObject struct) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2002, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2022, 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
@@ -27,7 +27,11 @@ package com.sun.jndi.dns;
import java.net.MalformedURLException;
import java.util.Hashtable;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Locale;
import java.util.StringTokenizer;
import com.sun.jndi.toolkit.url.Uri;
@@ -56,6 +60,24 @@ import com.sun.jndi.toolkit.url.UrlUtil;
public class DnsUrl extends Uri {
private static final String PARSE_MODE_PROP = "com.sun.jndi.dnsURLParsing";
private static final ParseMode DEFAULT_PARSE_MODE = ParseMode.COMPAT;
public static final ParseMode PARSE_MODE;
static {
PrivilegedAction<String> action = () ->
System.getProperty(PARSE_MODE_PROP, DEFAULT_PARSE_MODE.toString());
ParseMode parseMode = DEFAULT_PARSE_MODE;
try {
@SuppressWarnings("removal")
String mode = AccessController.doPrivileged(action);
parseMode = ParseMode.valueOf(mode.toUpperCase(Locale.ROOT));
} catch (Throwable t) {
parseMode = DEFAULT_PARSE_MODE;
} finally {
PARSE_MODE = parseMode;
}
}
private String domain; // domain name of the context
@@ -71,19 +93,58 @@ public class DnsUrl extends Uri {
StringTokenizer st = new StringTokenizer(urlList, " ");
while (st.hasMoreTokens()) {
urls[i++] = new DnsUrl(st.nextToken());
try {
urls[i++] = new DnsUrl(validateURI(st.nextToken()));
} catch (URISyntaxException e) {
MalformedURLException mue = new MalformedURLException(e.getMessage());
mue.initCause(e);
throw mue;
}
}
DnsUrl[] trimmed = new DnsUrl[i];
System.arraycopy(urls, 0, trimmed, 0, i);
return trimmed;
}
@Override
protected ParseMode parseMode() {
return PARSE_MODE;
}
@Override
protected final boolean isSchemeOnly(String uri) {
return isDnsSchemeOnly(uri);
}
@Override
protected boolean checkSchemeOnly(String uri, String scheme) {
return uri.equals(scheme + ":") || uri.equals(scheme + "://");
}
@Override
protected final MalformedURLException newInvalidURISchemeException(String uri) {
return new MalformedURLException(
uri + " is not a valid DNS pseudo-URL");
}
private static boolean isDnsSchemeOnly(String uri) {
return "dns:".equals(uri) || "dns://".equals(uri);
}
private static String validateURI(String uri) throws URISyntaxException {
// no validation in legacy parsing mode
if (PARSE_MODE == ParseMode.LEGACY) return uri;
// special case of scheme-only URIs
if (isDnsSchemeOnly(uri)) return uri;
// use java.net.URI to validate the uri syntax
return new URI(uri).toString();
}
public DnsUrl(String url) throws MalformedURLException {
super(url);
if (!scheme.equals("dns")) {
throw new MalformedURLException(
url + " is not a valid DNS pseudo-URL");
throw newInvalidURISchemeException(url);
}
domain = path.startsWith("/")

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2022, 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
@@ -25,12 +25,17 @@
package com.sun.jndi.url.rmi;
import java.net.URI;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Hashtable;
import java.util.Locale;
import javax.naming.*;
import javax.naming.spi.ResolveResult;
import com.sun.jndi.toolkit.url.GenericURLContext;
import com.sun.jndi.rmi.registry.RegistryContext;
import com.sun.jndi.toolkit.url.Uri.ParseMode;
/**
@@ -47,10 +52,244 @@ import com.sun.jndi.rmi.registry.RegistryContext;
*/
public class rmiURLContext extends GenericURLContext {
private static final String PARSE_MODE_PROP = "com.sun.jndi.rmiURLParsing";
private static final ParseMode DEFAULT_PARSE_MODE = ParseMode.COMPAT;
public static final ParseMode PARSE_MODE;
static {
PrivilegedAction<String> action = () ->
System.getProperty(PARSE_MODE_PROP, DEFAULT_PARSE_MODE.toString());
ParseMode parseMode = DEFAULT_PARSE_MODE;
try {
@SuppressWarnings("removal")
String mode = AccessController.doPrivileged(action);
parseMode = ParseMode.valueOf(mode.toUpperCase(Locale.ROOT));
} catch (Throwable t) {
parseMode = DEFAULT_PARSE_MODE;
} finally {
PARSE_MODE = parseMode;
}
}
public rmiURLContext(Hashtable<?,?> env) {
super(env);
}
public static class Parser {
final String url;
final ParseMode mode;
String host = null;
int port = -1;
String objName = null;
public Parser(String url) {
this(url, PARSE_MODE);
}
public Parser(String url, ParseMode mode) {
this.url = url;
this.mode = mode;
}
public String url() {return url;}
public String host() {return host;}
public int port() {return port;}
public String objName() {return objName;}
public ParseMode mode() {return mode;}
public void parse() throws NamingException {
if (!url.startsWith("rmi:")) {
throw (new IllegalArgumentException(
"rmiURLContext: name is not an RMI URL: " + url));
}
switch (mode) {
case STRICT -> parseStrict();
case COMPAT -> parseCompat();
case LEGACY -> parseLegacy();
}
}
private void parseStrict() throws NamingException {
assert url.startsWith("rmi:");
if (url.equals("rmi:") || url.equals("rmi://")) return;
// index into url, following the "rmi:"
int i = 4;
if (url.startsWith("//", i)) {
i += 2;
try {
URI uri = URI.create(url);
host = uri.getHost();
port = uri.getPort();
String auth = uri.getRawAuthority();
String hostport = (host == null ? "" : host)
+ (port == -1 ? "" : ":" + port);
if (!hostport.equals(auth)) {
boolean failed = true;
if (hostport.equals("") && auth.startsWith(":")) {
// supports missing host
try {
port = Integer.parseInt(auth.substring(1));
failed = false;
} catch (NumberFormatException x) {
failed = true;
}
}
if (failed) {
throw newNamingException(new IllegalArgumentException("invalid authority: "
+ auth));
}
}
i += auth.length();
} catch (IllegalArgumentException iae) {
throw newNamingException(iae);
}
}
if ("".equals(host)) {
host = null;
}
if (url.startsWith("/", i)) { // skip "/" before object name
i++;
}
if (i < url.length()) {
objName = url.substring(i);
}
}
private void parseCompat() throws NamingException {
assert url.startsWith("rmi:");
int i = 4; // index into url, following the "rmi:"
boolean hasAuthority = url.startsWith("//", i);
if (hasAuthority) i += 2; // skip past "//"
int slash = url.indexOf('/', i);
int qmark = url.indexOf('?', i);
int fmark = url.indexOf('#', i);
if (fmark > -1 && qmark > fmark) qmark = -1;
if (fmark > -1 && slash > fmark) slash = -1;
if (qmark > -1 && slash > qmark) slash = -1;
// The end of the authority component is either the
// slash (slash will be -1 if it doesn't come before
// query or fragment), or the question mark (qmark will
// be -1 if it doesn't come before the fragment), or
// the fragment separator, or the end of the URI
// string if there is no path, no query, and no fragment.
int enda = slash > -1 ? slash
: (qmark > -1 ? qmark
: (fmark > -1 ? fmark
: url.length()));
if (fmark > -1) {
if (!acceptsFragment()) {
throw newNamingException(new IllegalArgumentException("URI fragments not supported: " + url));
}
}
if (hasAuthority && enda > i) { // parse "//host:port"
if (url.startsWith(":", i)) {
// LdapURL supports empty host.
i++;
host = "";
if (enda > i) {
port = Integer.parseInt(url.substring(i, enda));
}
} else {
try {
URI uri = URI.create(url.substring(0, enda));
host = uri.getHost();
port = uri.getPort();
String hostport = (host == null ? "" : host)
+ (port == -1 ? "" : ":" + port);
if (!hostport.equals(uri.getRawAuthority())) {
throw newNamingException(new IllegalArgumentException("invalid authority: "
+ uri.getRawAuthority()));
}
} catch (IllegalArgumentException iae) {
throw newNamingException(iae);
}
}
i = enda;
}
if ("".equals(host)) {
host = null;
}
if (url.startsWith("/", i)) { // skip "/" before object name
i++;
}
if (i < url.length()) {
objName = url.substring(i);
}
}
// The legacy parsing used to only throw IllegalArgumentException
// and continues to do so
private void parseLegacy() {
assert url.startsWith("rmi:");
// Parse the URL.
int i = 4; // index into url, following the "rmi:"
if (url.startsWith("//", i)) { // parse "//host:port"
i += 2; // skip past "//"
int slash = url.indexOf('/', i);
if (slash < 0) {
slash = url.length();
}
if (url.startsWith("[", i)) { // at IPv6 literal
int brac = url.indexOf(']', i + 1);
if (brac < 0 || brac > slash) {
throw new IllegalArgumentException(
"rmiURLContext: name is an Invalid URL: " + url);
}
host = url.substring(i, brac + 1); // include brackets
i = brac + 1; // skip past "[...]"
} else { // at host name or IPv4
int colon = url.indexOf(':', i);
int hostEnd = (colon < 0 || colon > slash)
? slash
: colon;
if (i < hostEnd) {
host = url.substring(i, hostEnd);
}
i = hostEnd; // skip past host
}
if ((i + 1 < slash)) {
if ( url.startsWith(":", i)) { // parse port
i++; // skip past ":"
port = Integer.parseInt(url.substring(i, slash));
} else {
throw new IllegalArgumentException(
"rmiURLContext: name is an Invalid URL: " + url);
}
}
i = slash;
}
if ("".equals(host)) {
host = null;
}
if (url.startsWith("/", i)) { // skip "/" before object name
i++;
}
if (i < url.length()) {
objName = url.substring(i);
}
}
NamingException newNamingException(Throwable cause) {
NamingException ne = new NamingException(cause.getMessage());
ne.initCause(cause);
return ne;
}
boolean acceptsFragment() {
return true;
}
}
/**
* Resolves the registry portion of "url" to the corresponding
* RMI registry, and returns the atomic object name as the
@@ -59,63 +298,11 @@ public class rmiURLContext extends GenericURLContext {
protected ResolveResult getRootURLContext(String url, Hashtable<?,?> env)
throws NamingException
{
if (!url.startsWith("rmi:")) {
throw (new IllegalArgumentException(
"rmiURLContext: name is not an RMI URL: " + url));
}
// Parse the URL.
String host = null;
int port = -1;
String objName = null;
int i = 4; // index into url, following the "rmi:"
if (url.startsWith("//", i)) { // parse "//host:port"
i += 2; // skip past "//"
int slash = url.indexOf('/', i);
if (slash < 0) {
slash = url.length();
}
if (url.startsWith("[", i)) { // at IPv6 literal
int brac = url.indexOf(']', i + 1);
if (brac < 0 || brac > slash) {
throw new IllegalArgumentException(
"rmiURLContext: name is an Invalid URL: " + url);
}
host = url.substring(i, brac + 1); // include brackets
i = brac + 1; // skip past "[...]"
} else { // at host name or IPv4
int colon = url.indexOf(':', i);
int hostEnd = (colon < 0 || colon > slash)
? slash
: colon;
if (i < hostEnd) {
host = url.substring(i, hostEnd);
}
i = hostEnd; // skip past host
}
if ((i + 1 < slash)) {
if ( url.startsWith(":", i)) { // parse port
i++; // skip past ":"
port = Integer.parseInt(url.substring(i, slash));
} else {
throw new IllegalArgumentException(
"rmiURLContext: name is an Invalid URL: " + url);
}
}
i = slash;
}
if ("".equals(host)) {
host = null;
}
if (url.startsWith("/", i)) { // skip "/" before object name
i++;
}
if (i < url.length()) {
objName = url.substring(i);
}
Parser parser = new Parser(url);
parser.parse();
String host = parser.host;
int port = parser.port;
String objName = parser.objName;
// Represent object name as empty or single-component composite name.
CompositeName remaining = new CompositeName();

View File

@@ -351,6 +351,23 @@ TEST_VM(os, jio_snprintf) {
test_snprintf(jio_snprintf, false);
}
#ifdef __APPLE__
// Not all macOS versions can use os::reserve_memory (i.e. anon_mmap) API
// to reserve executable memory, so before attempting to use it,
// we need to verify that we can do so by asking for a tiny executable
// memory chunk.
static inline bool can_reserve_executable_memory(void) {
bool executable = true;
size_t len = 128;
char* p = os::reserve_memory(len, executable);
bool exec_supported = (p != NULL);
if (exec_supported) {
os::release_memory(p, len);
}
return exec_supported;
}
#endif
// Test that os::release_memory() can deal with areas containing multiple mappings.
#define PRINT_MAPPINGS(s) { tty->print_cr("%s", s); os::print_memory_mappings((char*)p, total_range_len, tty); }
//#define PRINT_MAPPINGS
@@ -360,6 +377,13 @@ TEST_VM(os, jio_snprintf) {
// (from multiple calls to os::reserve_memory)
static address reserve_multiple(int num_stripes, size_t stripe_len) {
assert(is_aligned(stripe_len, os::vm_allocation_granularity()), "Sanity");
#ifdef __APPLE__
// Workaround: try reserving executable memory to figure out
// if such operation is supported on this macOS version
const bool exec_supported = can_reserve_executable_memory();
#endif
size_t total_range_len = num_stripes * stripe_len;
// Reserve a large contiguous area to get the address space...
address p = (address)os::reserve_memory(total_range_len);
@@ -371,7 +395,11 @@ static address reserve_multiple(int num_stripes, size_t stripe_len) {
address q = p + (stripe * stripe_len);
// Commit, alternatingly with or without exec permission,
// to prevent kernel from folding these mappings.
#ifdef __APPLE__
const bool executable = exec_supported ? (stripe % 2 == 0) : false;
#else
const bool executable = stripe % 2 == 0;
#endif
q = (address)os::attempt_reserve_memory_at((char*)q, stripe_len, executable);
EXPECT_NE(q, (address)NULL);
EXPECT_TRUE(os::commit_memory((char*)q, stripe_len, executable));
@@ -413,11 +441,7 @@ struct NUMASwitcher {
#endif
#ifndef _AIX // JDK-8257041
#if defined(__APPLE__) && !defined(AARCH64) // See JDK-8267341.
TEST_VM(os, DISABLED_release_multi_mappings) {
#else
TEST_VM(os, release_multi_mappings) {
#endif
// With NMT enabled, this will trigger JDK-8263464. For now disable the test if NMT=on.
if (MemTracker::tracking_level() > NMT_off) {

View File

@@ -0,0 +1,68 @@
/*
* Copyright (c) 2022, 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
* @key stress randomness
* @bug 8280123
* @run main/othervm -Xcomp -XX:-TieredCompilation
* -XX:CompileCommand=compileonly,compiler.c2.TestCMoveInfiniteGVN::test
* -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN -XX:StressSeed=43739875
* compiler.c2.TestCMoveInfiniteGVN
* @run main/othervm -Xcomp -XX:-TieredCompilation
* -XX:CompileCommand=compileonly,compiler.c2.TestCMoveInfiniteGVN::test
* -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN
* compiler.c2.TestCMoveInfiniteGVN
*/
package compiler.c2;
public class TestCMoveInfiniteGVN {
static int test(boolean b, int i) {
int iArr[] = new int[2];
double d = Math.max(i, i);
for (int i1 = 1; i1 < 2; i1++) {
if (i1 != 0) {
return (b ? 1 : 0); // CMoveI
}
for (int i2 = 1; i2 < 2; i2++) {
switch (i2) {
case 1: d -= Math.max(i1, i2); break;
}
d -= iArr[i1 - 1];
}
}
return 0;
}
static void test() {
test(true, 234);
}
public static void main(String[] strArr) {
test(); // compilation, then nmethod invalidation during execution
test(); // trigger crashing recompilation
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -24,7 +24,8 @@
/*
* @test
* @requires vm.jvmci
* @modules jdk.internal.vm.ci/jdk.vm.ci.hotspot:open
* @modules jdk.internal.vm.ci/jdk.vm.ci.hotspot:+open
* java.base/jdk.internal.misc
* @library /compiler/jvmci/jdk.vm.ci.hotspot.test/src
* @run testng/othervm
* -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler
@@ -41,6 +42,9 @@ import java.lang.reflect.Method;
import org.testng.Assert;
import org.testng.annotations.Test;
import jdk.internal.misc.Unsafe;
import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
public class TestTranslatedException {
@SuppressWarnings("serial")
public static class Untranslatable extends RuntimeException {
@@ -56,7 +60,7 @@ public class TestTranslatedException {
Class<?> translatedExceptionClass = Class.forName("jdk.vm.ci.hotspot.TranslatedException");
Method encode = translatedExceptionClass.getDeclaredMethod("encodeThrowable", Throwable.class);
Method decode = translatedExceptionClass.getDeclaredMethod("decodeThrowable", String.class);
Method decode = translatedExceptionClass.getDeclaredMethod("decodeThrowable", byte[].class);
encode.setAccessible(true);
decode.setAccessible(true);
@@ -64,11 +68,50 @@ public class TestTranslatedException {
for (int i = 0; i < 10; i++) {
throwable = new ExceptionInInitializerError(new InvocationTargetException(new RuntimeException(String.valueOf(i), throwable), "invoke"));
}
String encoding = (String) encode.invoke(null, throwable);
byte[] encoding = (byte[]) encode.invoke(null, throwable);
Throwable decoded = (Throwable) decode.invoke(null, encoding);
assertThrowableEquals(throwable, decoded);
}
@SuppressWarnings("unchecked")
@Test
public void encodeDecodeTest2() throws Exception {
Unsafe unsafe = Unsafe.getUnsafe();
int bufferSize = 512;
long buffer = 0L;
while (true) {
buffer = unsafe.allocateMemory(bufferSize);
try {
Throwable throwable = new ExceptionInInitializerError(new InvocationTargetException(new Untranslatable("test exception", new NullPointerException()), "invoke"));
for (int i = 0; i < 10; i++) {
throwable = new ExceptionInInitializerError(new InvocationTargetException(new RuntimeException(String.valueOf(i), throwable), "invoke"));
}
Method encode = HotSpotJVMCIRuntime.class.getDeclaredMethod("encodeThrowable", Throwable.class, long.class, int.class);
Method decode = HotSpotJVMCIRuntime.class.getDeclaredMethod("decodeAndThrowThrowable", long.class);
encode.setAccessible(true);
decode.setAccessible(true);
int res = (Integer) encode.invoke(null, throwable, buffer, bufferSize);
if (res < 0) {
bufferSize = -res;
} else {
try {
decode.invoke(null, buffer);
throw new AssertionError("expected decodeAndThrowThrowable to throw an exception");
} catch (InvocationTargetException e) {
Throwable decoded = e.getCause();
assertThrowableEquals(throwable, decoded);
}
return;
}
} finally {
unsafe.freeMemory(buffer);
}
}
}
private static void assertThrowableEquals(Throwable original, Throwable decoded) {
try {
Assert.assertEquals(original == null, decoded == null);

View File

@@ -0,0 +1,139 @@
/*
* Copyright (c) 2021, 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 8277795
* @summary Multi-threaded client timeout tests for ldap pool
* @library /test/lib
* lib/
* @run testng/othervm LdapPoolTimeoutTest
*/
import org.testng.Assert;
import org.testng.annotations.Test;
import java.io.IOException;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.InitialDirContext;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.TimeUnit;
import static jdk.test.lib.Utils.adjustTimeout;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.expectThrows;
public class LdapPoolTimeoutTest {
/*
* Practical representation of an infinite timeout.
*/
private static final long INFINITY_MILLIS = adjustTimeout(20_000);
/*
* The acceptable variation in timeout measurements.
*/
private static final long TOLERANCE = adjustTimeout( 3_500);
private static final long CONNECT_MILLIS = adjustTimeout( 3_000);
private static final long READ_MILLIS = adjustTimeout(10_000);
static {
// a series of checks to make sure this timeouts configuration is
// consistent and the timeouts do not overlap
assert (TOLERANCE >= 0);
// context creation
assert (2 * CONNECT_MILLIS + TOLERANCE < READ_MILLIS);
// context creation immediately followed by search
assert (2 * CONNECT_MILLIS + READ_MILLIS + TOLERANCE < INFINITY_MILLIS);
}
@Test
public void test() throws Exception {
List<Future<?>> futures = new ArrayList<>();
ExecutorService executorService = Executors.newCachedThreadPool();
Hashtable<Object, Object> env = new Hashtable<>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put("com.sun.jndi.ldap.read.timeout", String.valueOf(READ_MILLIS));
env.put("com.sun.jndi.ldap.connect.timeout", String.valueOf(CONNECT_MILLIS));
env.put("com.sun.jndi.ldap.connect.pool", "true");
env.put(Context.PROVIDER_URL, "ldap://example.com:1234");
try {
futures.add(executorService.submit(() -> { attemptConnect(env); return null; }));
futures.add(executorService.submit(() -> { attemptConnect(env); return null; }));
futures.add(executorService.submit(() -> { attemptConnect(env); return null; }));
futures.add(executorService.submit(() -> { attemptConnect(env); return null; }));
futures.add(executorService.submit(() -> { attemptConnect(env); return null; }));
futures.add(executorService.submit(() -> { attemptConnect(env); return null; }));
futures.add(executorService.submit(() -> { attemptConnect(env); return null; }));
futures.add(executorService.submit(() -> { attemptConnect(env); return null; }));
} finally {
executorService.shutdown();
}
int failedCount = 0;
for (var f : futures) {
try {
f.get();
} catch (ExecutionException e) {
failedCount++;
e.getCause().printStackTrace(System.out);
}
}
if (failedCount > 0)
throw new RuntimeException(failedCount + " (sub)tests failed");
}
private static void attemptConnect(Hashtable<Object, Object> env) throws Exception {
try {
LdapTimeoutTest.assertCompletion(CONNECT_MILLIS - 1000,
2 * CONNECT_MILLIS + TOLERANCE,
() -> new InitialDirContext(env));
} catch (RuntimeException e) {
String msg = e.getCause() == null ? e.getMessage() : e.getCause().getMessage();
System.err.println("MSG RTE: " + msg);
// assertCompletion may wrap a CommunicationException in an RTE
assertTrue(msg != null && msg.contains("Network is unreachable"));
} catch (NamingException ex) {
String msg = ex.getCause() == null ? ex.getMessage() : ex.getCause().getMessage();
System.err.println("MSG: " + msg);
assertTrue(msg != null &&
(msg.contains("Network is unreachable")
|| msg.contains("Timed out waiting for lock")
|| msg.contains("Connect timed out")
|| msg.contains("Timeout exceeded while waiting for a connection")));
} catch (Throwable t) {
throw new RuntimeException(t);
}
}
}

View File

@@ -0,0 +1,169 @@
/*
* Copyright (c) 2022, 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 8278851
* @summary Check that jar entry with at least one non-disabled digest
* algorithm in manifest is treated as signed
* @modules java.base/sun.security.tools.keytool
* @library /test/lib
* @build jdk.test.lib.util.JarUtils
* jdk.test.lib.security.SecurityUtils
* @run main/othervm JarWithOneNonDisabledDigestAlg
*/
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.CodeSigner;
import java.security.KeyStore;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.ZipFile;
import jdk.security.jarsigner.JarSigner;
import jdk.test.lib.util.JarUtils;
import jdk.test.lib.security.SecurityUtils;
public class JarWithOneNonDisabledDigestAlg {
private static final String PASS = "changeit";
private static final String TESTFILE1 = "testfile1";
private static final String TESTFILE2 = "testfile2";
public static void main(String[] args) throws Exception {
SecurityUtils.removeFromDisabledAlgs("jdk.jar.disabledAlgorithms",
List.of("SHA1"));
Files.write(Path.of(TESTFILE1), TESTFILE1.getBytes());
JarUtils.createJarFile(Path.of("unsigned.jar"), Path.of("."),
Path.of(TESTFILE1));
genkeypair("-alias SHA1 -sigalg SHA1withRSA");
genkeypair("-alias SHA256 -sigalg SHA256withRSA");
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
try (FileInputStream fis = new FileInputStream("keystore")) {
ks.load(fis, PASS.toCharArray());
}
// Sign JAR twice with same signer but different digest algorithms
// so that each entry in manifest file contains two digest values.
signJarFile(ks, "SHA1", "MD5", "unsigned.jar", "signed.jar");
signJarFile(ks, "SHA1", "SHA1", "signed.jar", "signed2.jar");
checkThatJarIsSigned("signed2.jar", false);
// add another file to the JAR
Files.write(Path.of(TESTFILE2), "testFile2".getBytes());
JarUtils.updateJarFile(Path.of("signed2.jar"), Path.of("."),
Path.of(TESTFILE2));
// Sign again with different signer (SHA256) and SHA-1 digestalg.
// TESTFILE1 should have two signers and TESTFILE2 should have one
// signer.
signJarFile(ks, "SHA256", "SHA1", "signed2.jar", "multi-signed.jar");
checkThatJarIsSigned("multi-signed.jar", true);
}
private static KeyStore.PrivateKeyEntry getEntry(KeyStore ks, String alias)
throws Exception {
return (KeyStore.PrivateKeyEntry)
ks.getEntry(alias,
new KeyStore.PasswordProtection(PASS.toCharArray()));
}
private static void genkeypair(String cmd) throws Exception {
cmd = "-genkeypair -keystore keystore -storepass " + PASS +
" -keypass " + PASS + " -keyalg rsa -dname CN=Duke " + cmd;
sun.security.tools.keytool.Main.main(cmd.split(" "));
}
private static void signJarFile(KeyStore ks, String alias,
String digestAlg, String inputFile, String outputFile)
throws Exception {
JarSigner signer = new JarSigner.Builder(getEntry(ks, alias))
.digestAlgorithm(digestAlg)
.signerName(alias)
.build();
try (ZipFile in = new ZipFile(inputFile);
FileOutputStream out = new FileOutputStream(outputFile)) {
signer.sign(in, out);
}
}
private static void checkThatJarIsSigned(String jarFile, boolean multi)
throws Exception {
try (JarFile jf = new JarFile(jarFile, true)) {
Enumeration<JarEntry> entries = jf.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (entry.isDirectory() || isSigningRelated(entry.getName())) {
continue;
}
InputStream is = jf.getInputStream(entry);
while (is.read() != -1);
CodeSigner[] signers = entry.getCodeSigners();
if (signers == null) {
throw new Exception("JarEntry " + entry.getName() +
" is not signed");
} else if (multi) {
if (entry.getName().equals(TESTFILE1) &&
signers.length != 2) {
throw new Exception("Unexpected number of signers " +
"for " + entry.getName() + ": " + signers.length);
} else if (entry.getName().equals(TESTFILE2) &&
signers.length != 1) {
throw new Exception("Unexpected number of signers " +
"for " + entry.getName() + ": " + signers.length);
}
}
}
}
}
private static boolean isSigningRelated(String name) {
name = name.toUpperCase(Locale.ENGLISH);
if (!name.startsWith("META-INF/")) {
return false;
}
name = name.substring(9);
if (name.indexOf('/') != -1) {
return false;
}
return name.endsWith(".SF")
|| name.endsWith(".DSA")
|| name.endsWith(".RSA")
|| name.endsWith(".EC")
|| name.equals("MANIFEST.MF");
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2022, 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
@@ -23,6 +23,7 @@
package jdk.test.lib;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
@@ -275,5 +276,63 @@ public class SecurityTools {
}
return result;
}
// Create a temporary keychain in macOS and use it. The original
// keychains will be restored when the object is closed.
public static class TemporaryKeychain implements Closeable {
// name of new keychain
private final String newChain;
// names of the original keychains
private final List<String> oldChains;
public TemporaryKeychain(String name) {
Path p = Path.of(name + ".keychain-db");
newChain = p.toAbsolutePath().toString();
try {
oldChains = ProcessTools.executeProcess("security", "list-keychains")
.shouldHaveExitValue(0)
.getStdout()
.lines()
.map(String::trim)
.map(x -> x.startsWith("\"") ? x.substring(1, x.length() - 1) : x)
.collect(Collectors.toList());
if (!Files.exists(p)) {
ProcessTools.executeProcess("security", "create-keychain", "-p", "changeit", newChain)
.shouldHaveExitValue(0);
}
ProcessTools.executeProcess("security", "unlock-keychain", "-p", "changeit", newChain)
.shouldHaveExitValue(0);
ProcessTools.executeProcess("security", "list-keychains", "-s", newChain)
.shouldHaveExitValue(0);
} catch (Throwable t) {
if (t instanceof RuntimeException re) {
throw re;
} else {
throw new RuntimeException(t);
}
}
}
public String chain() {
return newChain;
}
@Override
public void close() throws IOException {
List<String> cmds = new ArrayList<>();
cmds.addAll(List.of("security", "list-keychains", "-s"));
cmds.addAll(oldChains);
try {
ProcessTools.executeProcess(cmds.toArray(new String[0]))
.shouldHaveExitValue(0);
} catch (Throwable t) {
if (t instanceof RuntimeException re) {
throw re;
} else {
throw new RuntimeException(t);
}
}
}
}
}