141 lines
5.5 KiB
Text
141 lines
5.5 KiB
Text
|
|
:experimental:
|
|
|
|
[[sect-Defensive_Coding-Java-LowLevel]]
|
|
== Low-level Features of the Virtual Machine
|
|
|
|
[[sect-Defensive_Coding-Java-Reflection]]
|
|
=== Reflection and Private Parts
|
|
|
|
The `setAccessible(boolean)` method of the
|
|
`java.lang.reflect.AccessibleObject` class
|
|
allows a program to disable language-defined access rules for
|
|
specific constructors, methods, or fields. Once the access
|
|
checks are disabled, any code can use the
|
|
`java.lang.reflect.Constructor`,
|
|
`java.lang.reflect.Method`, or
|
|
`java.lang.reflect.Field` object to access the
|
|
underlying Java entity, without further permission checks. This
|
|
breaks encapsulation and can undermine the stability of the
|
|
virtual machine. (In contrast, without using the
|
|
`setAccessible(boolean)` method, this should
|
|
not happen because all the language-defined checks still apply.)
|
|
|
|
This feature should be avoided if possible.
|
|
|
|
[[sect-Defensive_Coding-Java-JNI]]
|
|
=== Java Native Interface (JNI)
|
|
|
|
The Java Native Interface allows calling from Java code
|
|
functions specifically written for this purpose, usually in C or
|
|
C++.
|
|
|
|
The transition between the Java world and the C world is not
|
|
fully type-checked, and the C code can easily break the Java
|
|
virtual machine semantics. Therefore, extra care is needed when
|
|
using this functionality.
|
|
|
|
To provide a moderate amount of type safety, it is recommended
|
|
to recreate the class-specific header file using
|
|
[application]*javah* during the build process,
|
|
include it in the implementation, and use the
|
|
[option]`-Wmissing-declarations` option.
|
|
|
|
Ideally, the required data is directly passed to static JNI
|
|
methods and returned from them, and the code and the C side does
|
|
not have to deal with accessing Java fields (or even methods).
|
|
|
|
When using `GetPrimitiveArrayCritical` or
|
|
`GetStringCritical`, make sure that you only
|
|
perform very little processing between the get and release
|
|
operations. Do not access the file system or the network, and
|
|
not perform locking, because that might introduce blocking.
|
|
When processing large strings or arrays, consider splitting the
|
|
computation into multiple sub-chunks, so that you do not prevent
|
|
the JVM from reaching a safepoint for extended periods of time.
|
|
|
|
If necessary, you can use the Java `long` type
|
|
to store a C pointer in a field of a Java class. On the C side,
|
|
when casting between the `jlong` value and the
|
|
pointer on the C side,
|
|
|
|
You should not try to perform pointer arithmetic on the Java
|
|
side (that is, you should treat pointer-carrying
|
|
`long` values as opaque). When passing a slice
|
|
of an array to the native code, follow the Java convention and
|
|
pass it as the base array, the integer offset of the start of
|
|
the slice, and the integer length of the slice. On the native
|
|
side, check the offset/length combination against the actual
|
|
array length, and use the offset to compute the pointer to the
|
|
beginning of the array.
|
|
|
|
[[ex-Defensive_Coding-Java-JNI-Pointers]]
|
|
.Array length checking in JNI code
|
|
====
|
|
|
|
[source,java]
|
|
----
|
|
include::example$Java-JNI-Pointers.adoc[]
|
|
|
|
----
|
|
|
|
====
|
|
|
|
In any case, classes referring to native resources must be
|
|
declared `final`, and must not be serializeable
|
|
or clonable. Initialization and mutation of the state used by
|
|
the native side must be controlled carefully. Otherwise, it
|
|
might be possible to create an object with inconsistent native
|
|
state which results in a crash (or worse) when used (or perhaps
|
|
only finalized) later. If you need both Java inheritance and
|
|
native resources, you should consider moving the native state to
|
|
a separate class, and only keep a reference to objects of that
|
|
class. This way, cloning and serialization issues can be
|
|
avoided in most cases.
|
|
|
|
If there are native resources associated with an object, the
|
|
class should have an explicit resource deallocation method
|
|
(<<sect-Defensive_Coding-Java-Language-Resources>>) and a
|
|
finalizer (<<sect-Defensive_Coding-Java-Language-Finalizers>>) as a
|
|
last resort. The need for finalization means that a minimum
|
|
amount of synchronization is needed. Code on the native side
|
|
should check that the object is not in a closed/freed state.
|
|
|
|
Many JNI functions create local references. By default, these
|
|
persist until the JNI-implemented method returns. If you create
|
|
many such references (e.g., in a loop), you may have to free
|
|
them using `DeleteLocalRef`, or start using
|
|
`PushLocalFrame` and
|
|
`PopLocalFrame`. Global references must be
|
|
deallocated with `DeleteGlobalRef`, otherwise
|
|
there will be a memory leak, just as with
|
|
`malloc` and `free`.
|
|
|
|
When throwing exceptions using `Throw` or
|
|
`ThrowNew`, be aware that these functions
|
|
return regularly. You have to return control manually to the
|
|
JVM.
|
|
|
|
Technically, the `JNIEnv` pointer is not
|
|
necessarily constant during the lifetime of your JNI module.
|
|
Storing it in a global variable is therefore incorrect.
|
|
Particularly if you are dealing with callbacks, you may have to
|
|
store the pointer in a thread-local variable (defined with
|
|
`__thread`). It is, however, best to avoid the
|
|
complexity of calling back into Java code.
|
|
|
|
Keep in mind that C/C++ and Java are different languages,
|
|
despite very similar syntax for expressions. The Java memory
|
|
model is much more strict than the C or C++ memory models, and
|
|
native code needs more synchronization, usually using JVM
|
|
facilities or POSIX threads mutexes. Integer overflow in Java
|
|
is defined, but in C/C++ it is not (for the
|
|
`jint` and `jlong` types).
|
|
|
|
[[sect-Defensive_Coding-Java-MiscUnsafe]]
|
|
=== `sun.misc.Unsafe`
|
|
|
|
The `sun.misc.Unsafe` class is unportable and
|
|
contains many functions explicitly designed to break Java memory
|
|
safety (for performance and debugging). If possible, avoid
|
|
using this class.
|