It is possible to unmap a MappedByteBuffer safely with little effect
on efficiency: my basic idea is to add an indirection which all
callers (even those using derived buffers) have to use to access the
memory, and then removing most uses of this indirection with a little
compiler magic. A few will still remain, but these will be the
minimum required to guarantee security and won't affect the speed of
I have a plan to implement this, but it requires changes to the Java
Memory Model and to the compilers. I didn't get it done in time for
JDK 9 because of being distracted by a ton of other things, but I hope
I'll get it done by JDK 10.
I'm taking this bug; I hope that's OK.
"I have two suggested fixes:
"1. Have an unmap method that throws if a SecurityManager is present.
Non-secure code that owns its own JVM (i.e. nearly all of it) would then be
able to unmap files and delete them on Windows. Sandboxed code would still
suffer, but OK, so be it.
"2. Have an internal subclass or wrapper object around MappedByteBuffer that
is only used when a SecurityManager is present, which does the check
against the volatile field. The JVM should optimise out the virtual method
call or inline the wrapper code, thus ensuring only sandboxed code pays the
There is no unmap() method on mapped byte buffers because there is no known
technique for providing one without running into insurmountable security and
Suppose that a thread operating on behalf of Alice maps a file into memory and
then unmaps it. A second thread operating on behalf of Bob then maps some
other file that the underlying operating system happens to assign to the same
memory address. Now Alice's thread can read, and possibly even modify, the
contents of Bob's file. Oops.
This problem could be avoided by defining a private volatile field in a mapped
buffer to indicate whether or not the mapping is still valid, and having every
access to the buffer's content first check this field and throw an appropriate
exception if the mapping is no longer valid. This solution would significantly
slow down access, however, and fast access is the whole point of supporting
mapped buffers in the first place.
Another potential solution is to implement unmap() by unmapping the buffer's
memory region and then immediately remapping it from /dev/null, setting the
page protections so that any further access to the region would cause a SIGSEGV
(or the equivalent) to be raised and then translated into an appropriate
The remapped region would need to remain valid for as long as the original
buffer object is valid, eventually being released by the cleaner thread. This
solution therefore wouldn't reduce virtual-memory footprint but it would at
least allow the underlying file to be manipulated on those operating systems
(e.g., Windows) that forbid certain file manipulations when valid mappings
To avoid the race condition between the unmap and remap operations we'd need to
globally synchronize all mapping operations within the same VM; this could,
theoretically, limit scalability on some higher-end systems.
The downfall of this second approach is that while we can avoid this race
condition within the VM we can't avoid it everywhere within the VM's process.
Memory-mapped files are pretty widely used these days, by everything from C's
stdio functions (on some systems) to dynamic linkers (on most Unix systems).
If a mapping operation were initiated by one of these subsystems, or by native
application code (perhaps unknowingly, via an intermediate library), at just
the wrong moment, and it happened to overlap our soon-to-be-remapped region,
then the remap operation would fail.
We at Sun have given this problem a lot of thought, both during the original
development of NIO and in the time since. We have yet to come up with a way to
implement an unmap() method that's safe, efficient, and plausibly portable
across operating systems. We've explored several other alternatives aside from
the two described above, but all of them were even more problematic. We'd be
thrilled if someone could come up with a workable solution, so we'll leave this
bug open in the hope that it will attract attention from someone more clever
than we are.
With regard to the "workaround", described in the JDC comments, of (ab)using
reflection in order to invoke a mapped buffer's cleaner object: This is highly
inadvisable, to put it mildly. It is exceedingly dangerous to forcibly unmap a
mapped byte buffer that's visible to Java code. Doing so risks both the
security and stability of the system.
###@###.### 2005-03-23 02:41:14 GMT