8316337: (bf) Concurrency issue in DirectByteBuffer.Deallocator

Reviewed-by: alanb, liach
This commit is contained in:
Per Minborg 2023-09-19 13:10:51 +00:00
parent 4461eeb31d
commit cf74b8c2a3
3 changed files with 31 additions and 45 deletions

View file

@ -75,31 +75,15 @@ class Direct$Type$Buffer$RW$$BO$
#if[byte] #if[byte]
private static class Deallocator private record Deallocator(long address, long size, int capacity) implements Runnable {
implements Runnable private Deallocator {
{ assert address != 0;
private long address;
private long size;
private int capacity;
private Deallocator(long address, long size, int capacity) {
assert (address != 0);
this.address = address;
this.size = size;
this.capacity = capacity;
} }
public void run() { public void run() {
if (address == 0) {
// Paranoia
return;
}
UNSAFE.freeMemory(address); UNSAFE.freeMemory(address);
address = 0;
Bits.unreserveMemory(size, capacity); Bits.unreserveMemory(size, capacity);
} }
} }
private final Cleaner cleaner; private final Cleaner cleaner;

View file

@ -116,28 +116,33 @@ public abstract sealed class MappedByteBuffer
} }
UnmapperProxy unmapper() { UnmapperProxy unmapper() {
return fd != null ? return fd == null
new UnmapperProxy() { ? null
@Override : new UnmapperProxy() {
public long address() {
return address;
}
@Override // Ensure safe publication as MappedByteBuffer.this.address is not final
public FileDescriptor fileDescriptor() { private final long addr = address;
return fd;
}
@Override @Override
public boolean isSync() { public long address() {
return isSync; return addr;
} }
@Override @Override
public void unmap() { public FileDescriptor fileDescriptor() {
Unsafe.getUnsafe().invokeCleaner(MappedByteBuffer.this); return fd;
} }
} : null;
@Override
public boolean isSync() {
return isSync;
}
@Override
public void unmap() {
Unsafe.getUnsafe().invokeCleaner(MappedByteBuffer.this);
}
};
} }
/** /**

View file

@ -1154,10 +1154,10 @@ public class FileChannelImpl
// -- Memory-mapped buffers -- // -- Memory-mapped buffers --
private abstract static class Unmapper private sealed abstract static class Unmapper
implements Runnable, UnmapperProxy implements Runnable, UnmapperProxy
{ {
private volatile long address; private final long address;
protected final long size; protected final long size;
protected final long cap; protected final long cap;
private final FileDescriptor fd; private final FileDescriptor fd;
@ -1194,10 +1194,7 @@ public class FileChannelImpl
} }
public void unmap() { public void unmap() {
if (address == 0)
return;
nd.unmap(address, size); nd.unmap(address, size);
address = 0;
// if this mapping has a valid file descriptor then we close it // if this mapping has a valid file descriptor then we close it
if (fd.valid()) { if (fd.valid()) {
@ -1214,7 +1211,7 @@ public class FileChannelImpl
protected abstract void decrementStats(); protected abstract void decrementStats();
} }
private static class DefaultUnmapper extends Unmapper { private static final class DefaultUnmapper extends Unmapper {
// keep track of non-sync mapped buffer usage // keep track of non-sync mapped buffer usage
static volatile int count; static volatile int count;
@ -1247,7 +1244,7 @@ public class FileChannelImpl
} }
} }
private static class SyncUnmapper extends Unmapper { private static final class SyncUnmapper extends Unmapper {
// keep track of mapped buffer usage // keep track of mapped buffer usage
static volatile int count; static volatile int count;