/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/oop.inline.hpp"
#include "oops/symbol.hpp"
#include "prims/jniCheck.hpp"
#include "prims/jvm_misc.hpp"
#include "runtime/fieldDescriptor.hpp"
#include "runtime/handles.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/jfieldIDWorkaround.hpp"
#include "runtime/thread.hpp"
#ifdef TARGET_ARCH_x86
# include "jniTypes_x86.hpp"
#endif
#ifdef TARGET_ARCH_sparc
# include "jniTypes_sparc.hpp"
#endif
#ifdef TARGET_ARCH_zero
# include "jniTypes_zero.hpp"
#endif
#ifdef TARGET_ARCH_arm
# include "jniTypes_arm.hpp"
#endif
#ifdef TARGET_ARCH_ppc
# include "jniTypes_ppc.hpp"
#endif
// Heap objects are allowed to be directly referenced only in VM code,
// not in native code.
#define ASSERT_OOPS_ALLOWED \
"jniCheck examining oops in bad state.")
// Execute the given block of source code with the thread in VM state.
// To do this, transition from the NATIVE state to the VM state, execute
// the code, and transtition back. The ThreadInVMfromNative constructor
// performs the transition to VM state, its destructor restores the
// NATIVE state.
{ \
} \
}
/*
* DECLARATIONS
*/
/*
* MACRO DEFINITIONS
*/
// All JNI checked functions here use JNI_ENTRY_CHECKED() instead of the
// QUICK_ENTRY or LEAF variants found in jni.cpp. This allows handles
// to be created if a fatal error should occur.
// Check for thread not attached to VM; need to catch this before
// assertions in the wrapper routines might fire
// Check for env being the one value appropriate for this thread.
extern "C" { \
} \
} \
static const char * warn_bad_class_descriptor = "JNI FindClass received a bad class descriptor \"%s\". A correct class descriptor " \
"has no leading \"L\" or trailing \";\". Incorrect descriptors will not be accepted in future releases.";
static const char * fatal_using_jnienv_in_nonjava = "FATAL ERROR in native method: Using JNIEnv in non-Java thread";
static const char * warn_other_function_in_critical = "Warning: Calling other JNI functions in the scope of " \
static const char * fatal_class_not_a_throwable_class = "JNI Throw or ThrowNew received a class argument that is not a Throwable or Throwable subclass";
static const char * fatal_wrong_class_or_method = "Wrong object class or methodID passed to JNI call";
static const char * fatal_unknown_array_object = "Unknown array object passed to JNI array operations";
static const char * fatal_object_array_expected = "Object array expected but not received for JNI array operation";
static const char * fatal_static_field_not_found = "Static field not found in JNI get/set field operations";
static const char * fatal_static_field_mismatch = "Field type (static) mismatch in JNI get/set field operations";
static const char * fatal_instance_field_not_found = "Instance field not found in JNI get/set field operations";
static const char * fatal_instance_field_mismatch = "Field type (instance) mismatch in JNI get/set field operations";
// When in VM state:
thr->print_stack();
}
// When in NATIVE state:
)
}
)
}
/*
* SUPPORT FUNCTIONS
*/
static inline void
{
if (thr->has_pending_exception()) {
}
}
static inline void
{
}
static inline void
{
if (thr->in_critical()) {
}
if (thr->has_pending_exception()) {
}
}
static inline void
{
if (thr->in_critical()) {
}
}
static inline void
{
/* nothing to do at this time */
}
static inline void
{
/* make sure it is a static field */
/* validate the class being passed */
/* check for proper subclass hierarchy */
/* check for proper field type */
}
}
static inline void
{
/* make sure it is an instance field */
/* validate the object being passed and then get its class */
if (!oopObj) {
}
}
/* make sure the field exists */
/* check for proper field type */
false, &fd))
}
}
static inline void
{
if (!s || !java_lang_String::is_instance(s))
}
static inline void
{
if (elementType != -1) {
if (aOop->is_typeArray()) {
if (array_type != elementType)
} else if (aOop->is_objArray()) {
if ( T_OBJECT != elementType)
} else {
}
}
}
}
return NULL;
}
// do the fast jmethodID check first
}
// jmethodIDs are supposed to be weak global handles, but that
// can be expensive so check it last
}
return moop;
}
if (!obj)
return NULL;
if (!oopObj) {
}
return oopObj;
}
// Warn if a class descriptor is in decorated form; class descriptors
// passed to JNI findClass should not be decorated unless they are
// array descriptors.
if (len >= 2 &&
}
}
if (!mirror) {
}
}
// Make allowances for primitive classes ...
}
return k;
}
}
}
/* validate the object being passed */
}
/* validate the class being passed */
}
/*
* IMPLEMENTATION OF FUNCTIONS IN CHECKED TABLE
*/
const char *name,
)
return result;
const char *name))
)
return result;
)
return result;
)
return result;
)
isStatic);
return result;
)
return result;
)
return result;
)
isStatic);
return result;
// Unchecked Throw tolerates a NULL obj, so just warn
} else {
}
)
return result;
const char *msg))
)
return result;
return result;
JNI_ENTRY_CHECKED(void,
JNI_ENTRY_CHECKED(void,
JNI_ENTRY_CHECKED(void,
const char *msg))
if (capacity < 0)
return result;
return res;
}
)
return result;
JNI_ENTRY_CHECKED(void,
"Invalid global JNI handle passed to DeleteGlobalRef");
}
)
JNI_ENTRY_CHECKED(void,
"Invalid local JNI handle passed to DeleteLocalRef");
)
/* This JNI function can be used to compare weak global references
* to NULL objects. If the handles are valid, but contain NULL,
* then don't attempt to validate the object.
*/
}
}
)
return result;
}
)
return result;
if (capacity < 0) {
}
return result;
)
return result;
...))
)
return result;
)
return result;
)
return result;
)
return result;
)
return result;
const char *name,
const char *sig))
)
return result;
...)) \
functionEnter(thr); \
IN_VM( \
) \
args); \
functionExit(env); \
return result; \
JNI_END \
\
functionEnter(thr); \
IN_VM(\
) \
args); \
functionExit(env); \
return result; \
JNI_END \
\
functionEnter(thr); \
IN_VM( \
) \
args); \
functionExit(env); \
return result; \
JNI_ENTRY_CHECKED(void,
...))
)
JNI_ENTRY_CHECKED(void,
)
JNI_ENTRY_CHECKED(void,
)
...)) \
functionEnter(thr); \
IN_VM( \
) \
obj, \
clazz, \
methodID,\
args); \
functionExit(env); \
return result; \
JNI_END \
\
functionEnter(thr); \
IN_VM( \
) \
obj, \
clazz, \
methodID,\
args); \
functionExit(env); \
return result; \
JNI_END \
\
functionEnter(thr); \
IN_VM( \
) \
obj, \
clazz, \
methodID,\
args); \
functionExit(env); \
return result; \
JNI_ENTRY_CHECKED(void,
...))
)
JNI_ENTRY_CHECKED(void,
)
JNI_ENTRY_CHECKED(void,
)
const char *name,
const char *sig))
)
return result;
functionEnter(thr); \
IN_VM( \
) \
functionExit(env); \
return result; \
JNI_ENTRY_CHECKED(void, \
functionEnter(thr); \
IN_VM( \
) \
functionExit(env); \
const char *name,
const char *sig))
)
return result;
...)) \
functionEnter(thr); \
IN_VM( \
) \
clazz, \
methodID, \
args); \
functionExit(env); \
return result; \
JNI_END \
\
functionEnter(thr); \
IN_VM( \
) \
clazz, \
methodID, \
args); \
functionExit(env); \
return result; \
JNI_END \
\
functionEnter(thr); \
IN_VM( \
) \
clazz, \
methodID, \
args); \
functionExit(env); \
return result; \
JNI_ENTRY_CHECKED(void,
...))
)
JNI_ENTRY_CHECKED(void,
)
JNI_ENTRY_CHECKED(void,
)
const char *name,
const char *sig))
)
return result;
functionEnter(thr); \
IN_VM( \
) \
clazz, \
fieldID); \
functionExit(env); \
return result; \
JNI_ENTRY_CHECKED(void, \
functionEnter(thr); \
IN_VM( \
) \
functionExit(env); \
return result;
)
return result;
// Arbitrary (but well-known) tag
JNI_ENTRY_CHECKED(const jchar *,
)
// Avoiding call to UNCHECKED()->ReleaseStringChars() since that will fire unexpected dtrace probes
// Note that the dtrace arguments for the allocated memory will not match up with this solution.
return newResult;
JNI_ENTRY_CHECKED(void,
)
// still do the unchecked call to allow dtrace probes
}
else {
if (*tagLocation != STRING_TAG) {
NativeReportJNIFatalError(thr, "ReleaseStringChars called on something not allocated by GetStringChars");
}
}
const char *utf))
return result;
)
return result;
// Arbitrary (but well-known) tag - different than GetStringChars
JNI_ENTRY_CHECKED(const char *,
)
assert (isCopy == NULL || *isCopy == JNI_TRUE, "GetStringUTFChars didn't return a copy as expected");
// Avoiding call to UNCHECKED()->ReleaseStringUTFChars() since that will fire unexpected dtrace probes
// Note that the dtrace arguments for the allocated memory will not match up with this solution.
return newResult;
JNI_ENTRY_CHECKED(void,
const char* chars))
)
// still do the unchecked call to allow dtrace probes
}
else {
if (*tagLocation != STRING_UTF_TAG) {
NativeReportJNIFatalError(thr, "ReleaseStringUTFChars called on something not allocated by GetStringUTFChars");
}
}
)
return result;
return result;
)
return result;
JNI_ENTRY_CHECKED(void,
)
functionEnter(thr); \
functionExit(env); \
functionEnter(thr); \
IN_VM( \
) \
array, \
isCopy); \
functionExit(env); \
return result; \
JNI_ENTRY_CHECKED(void, \
ElementType *elems, \
IN_VM( \
/* cannot check validity of copy, unless every request is logged by
* checking code. Implementation of this check is deferred until a
* subsequent release.
*/ \
) \
functionExit(env); \
JNI_ENTRY_CHECKED(void, \
ElementType *buf)) \
functionEnter(thr); \
IN_VM( \
) \
functionExit(env); \
JNI_ENTRY_CHECKED(void, \
const ElementType *buf)) \
functionEnter(thr); \
IN_VM( \
) \
functionExit(env); \
const JNINativeMethod *methods,
return result;
return result;
)
return result;
)
return result;
return result;
JNI_ENTRY_CHECKED(void,
)
JNI_ENTRY_CHECKED(void,
char *buf))
)
JNI_ENTRY_CHECKED(void *,
)
return result;
JNI_ENTRY_CHECKED(void,
void *carray,
)
/* The Hotspot JNI code does not use the parameters, so just check the
* array parameter as a minor sanity check
*/
JNI_ENTRY_CHECKED(const jchar*,
)
return result;
JNI_ENTRY_CHECKED(void,
)
/* The Hotspot JNI code does not use the parameters, so just check the
* string parameter as a minor sanity check
*/
}
)
return result;
JNI_ENTRY_CHECKED(void,
return result;
void *address,
return result;
JNI_ENTRY_CHECKED(void *,
return result;
return result;
/* validate the object being passed */
)
return result;
return result;
/*
* Structure containing all checked jni functions
*/
NULL,
NULL,
NULL,
NULL,
// New 1.6 Features
};
// Returns the function structure
// make sure the last pointer in the checked table is not null, indicating
// an addition to the JNINativeInterface_ structure without initializing
// it in the checked table.
sizeof(*unchecked_jni_NativeInterface) - sizeof(char *));)
"Mismatched JNINativeInterface tables, check for new entries");
// with -verbose:jni this message will print
if (PrintJNIResolving) {
"validate JNI usage");
}
return &checked_jni_NativeInterface;
}