Skip to content

Commit 594264d

Browse files
committed
Ensure ChunkCacheEntry doesn't get used after it has been released
1 parent f192ba5 commit 594264d

File tree

1 file changed

+14
-4
lines changed

1 file changed

+14
-4
lines changed

common/src/main/java/dev/booky/betterview/common/ChunkCacheEntry.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public final class ChunkCacheEntry {
2020
private final McChunkPos pos;
2121

2222
private volatile @Nullable CompletableFuture<@Nullable ByteBuf> future;
23+
private volatile boolean released = false;
2324

2425
public ChunkCacheEntry(LevelHook level, McChunkPos pos) {
2526
this.level = level;
@@ -56,19 +57,25 @@ public ChunkCacheEntry(LevelHook level, McChunkPos pos) {
5657
}
5758

5859
public CompletableFuture<@Nullable ByteBuf> get() {
59-
// all of this code runs synchronized on this cache entry to
60+
// all of this code runs synchronized on this cache entry
6061
synchronized (this) {
62+
if (this.released) {
63+
throw new IllegalStateException("Can't get buffer for " + this.pos + " in "
64+
+ this.level.getName() + ", cache entry has already been released");
65+
}
6166
{
6267
CompletableFuture<@Nullable ByteBuf> future = this.future;
6368
if (future != null) {
64-
// future is valid, return immediately
69+
// future is already set, return
6570
return future;
6671
}
6772
}
6873
CompletableFuture<@Nullable ByteBuf> future = CompletableFuture.completedFuture(null)
6974
// launch chunk handling asynchronously to minimize lock time
7075
.thenComposeAsync(__ -> this.tryGet())
7176
.thenApply(buf -> {
77+
// if the bytebuf is null, clear the future; this makes it
78+
// possible to retry getting this chunk on the next attempt
7279
if (buf == null) {
7380
// can't cause deadlock as this is run asynchronously
7481
synchronized (this) {
@@ -77,8 +84,8 @@ public ChunkCacheEntry(LevelHook level, McChunkPos pos) {
7784
}
7885
return buf;
7986
});
80-
// mark the running future as valid; if chunk generation fails,
81-
// it will be automatically marked as invalid after it's done
87+
// save the future to return for later calls; this future will
88+
// be cleared if getting the chunk fails (see above)
8289
this.future = future;
8390
return future;
8491
}
@@ -90,6 +97,9 @@ public void release() {
9097
if (future != null) {
9198
future.thenAccept(ReferenceCountUtil::release);
9299
}
100+
// clear saved future and mark chunk as released
101+
this.future = null;
102+
this.released = true;
93103
}
94104
}
95105
}

0 commit comments

Comments
 (0)