You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/** Free the native memory and set peer to zero */
public void close() {
peer = 0;
cleanable.clean();
}
However, cleanable is of type CleanerRef which extends PhantomReference and thus calling it in code does not imply reachability. When the Cleaner does its work, the reference is removed from the queue and the instance variable becomes null.
Executing close() in this situation can result in an NPE.
Steps to reproduce
I updated my project to use try-with-resources blocks on all of my Memory allocations, and added AutoCloseable wrapper classes for (nearly all of) my uses of classes which extend ByReference and Structure. One such example:
class CloseableLUID extends LUID implements AutoCloseable {
@Override
public void close() {
Util.freeMemory(getPointer());
}
}
and the Util class:
public static void freeMemory(Pointer p) {
if (p instanceof Memory) {
((Memory) p).close();
}
}
Then, in a method:
try (CloseableLUID luid = new CloseableLUID()) {
// ...
} // exception occurs here when try-with-resources calls close()
Hundreds of similar implementations like this worked well, but this one fails.
Possibly/probably related, it's in an initializer of one of the first classes to be instantiated, and may very well have been the very first reference in the cleaner queue, giving it a significant advantage in a race condition.
Version of JNA and related jars
5.12.0
Version and vendor of the java virtual machine
OpenJDK 64-Bit Server VM Homebrew (build 18.0.1.1+0, mixed mode, sharing)
Operating system
macOS 12.4 (Monterey)
System architecture (CPU type, bitness of the JVM)
64-bit Intel Core i9
Complete description of the problem
In Remove use of finalizers in JNA and improve concurrency for
Memory,CallbackReferenceandNativeLibrary#1402, aclose()method was added toMemory, which also implementedCloseable(which extendsAutoCloseableon newer JDKs). The implementation assumes the private instance variablecleanablestill exists:jna/src/com/sun/jna/Memory.java
Lines 182 to 186 in 1eec7dd
However,
cleanableis of typeCleanerRefwhich extendsPhantomReferenceand thus calling it in code does not imply reachability. When theCleanerdoes its work, the reference is removed from the queue and the instance variable becomesnull.Executing
close()in this situation can result in an NPE.I updated my project to use try-with-resources blocks on all of my
Memoryallocations, and addedAutoCloseablewrapper classes for (nearly all of) my uses of classes which extendByReferenceandStructure. One such example:and the Util class:
Then, in a method:
Hundreds of similar implementations like this worked well, but this one fails.
Possibly/probably related, it's in an initializer of one of the first classes to be instantiated, and may very well have been the very first reference in the cleaner queue, giving it a significant advantage in a race condition.
My tests seem to be running fine by removing this one mapping, so this is likely an exceedingly rare race condition.