mirror of https://github.com/apache/lucene.git
Improve handling of NullPointerException in MMapDirectory's IndexInputs (check the "closed" condition) (#12705)
This commit is contained in:
parent
ad06ee57b8
commit
9729123369
|
@ -183,6 +183,9 @@ Improvements
|
|||
|
||||
* GITHUB#12586: Remove over-counting of deleted terms. (Guo Feng)
|
||||
|
||||
* GITHUB#12705: Improve handling of NullPointerException in MMapDirectory's IndexInputs.
|
||||
(Uwe Schindler, Michael Sokolov)
|
||||
|
||||
Optimizations
|
||||
---------------------
|
||||
* GITHUB#12183: Make TermStates#build concurrent. (Shubham Chaudhary)
|
||||
|
|
|
@ -78,6 +78,10 @@ final class ByteBufferGuard {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean isInvalidated() {
|
||||
return invalidated;
|
||||
}
|
||||
|
||||
private void ensureValid() {
|
||||
if (invalidated) {
|
||||
// this triggers an AlreadyClosedException in ByteBufferIndexInput:
|
||||
|
|
|
@ -99,9 +99,16 @@ public abstract class ByteBufferIndexInput extends IndexInput implements RandomA
|
|||
}
|
||||
}
|
||||
|
||||
// the unused parameter is just to silence javac about unused variables
|
||||
AlreadyClosedException alreadyClosed(RuntimeException unused) {
|
||||
return new AlreadyClosedException("Already closed: " + this);
|
||||
AlreadyClosedException alreadyClosed(NullPointerException npe) {
|
||||
// we use NPE to signal if this input is closed (to not have checks everywhere). If NPE happens,
|
||||
// we check the "is closed" condition explicitly by checking that our "buffers" are null or
|
||||
// the guard was invalidated.
|
||||
if (this.buffers == null || this.curBuf == null || guard.isInvalidated()) {
|
||||
return new AlreadyClosedException("Already closed: " + this);
|
||||
}
|
||||
// otherwise rethrow unmodified NPE (as it possibly a bug with passing a null parameter to the
|
||||
// IndexInput method):
|
||||
throw npe;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -459,7 +466,7 @@ public abstract class ByteBufferIndexInput extends IndexInput implements RandomA
|
|||
|
||||
/** Builds the actual sliced IndexInput (may apply extra offset in subclasses). * */
|
||||
protected ByteBufferIndexInput buildSlice(String sliceDescription, long offset, long length) {
|
||||
if (buffers == null) {
|
||||
if (buffers == null || guard.isInvalidated()) {
|
||||
throw alreadyClosed(null);
|
||||
}
|
||||
|
||||
|
|
|
@ -102,9 +102,17 @@ abstract class MemorySegmentIndexInput extends IndexInput implements RandomAcces
|
|||
}
|
||||
}
|
||||
|
||||
// the unused parameter is just to silence javac about unused variables
|
||||
AlreadyClosedException alreadyClosed(RuntimeException unused) {
|
||||
return new AlreadyClosedException("Already closed: " + this);
|
||||
AlreadyClosedException alreadyClosed(RuntimeException e) {
|
||||
// we use NPE to signal if this input is closed (to not have checks everywhere). If NPE happens,
|
||||
// we check the "is closed" condition explicitly by checking that our "curSegment" is null.
|
||||
// if it is an IllegalStateException, it can only come from MemorySegment API (other thread has
|
||||
// closed input)
|
||||
if (this.curSegment == null || e instanceof IllegalStateException) {
|
||||
return new AlreadyClosedException("Already closed: " + this);
|
||||
}
|
||||
// otherwise rethrow unmodified NPE/ISE (as it possibly a bug with passing a null parameter to
|
||||
// the IndexInput method):
|
||||
throw e;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -100,9 +100,17 @@ abstract class MemorySegmentIndexInput extends IndexInput implements RandomAcces
|
|||
}
|
||||
}
|
||||
|
||||
// the unused parameter is just to silence javac about unused variables
|
||||
AlreadyClosedException alreadyClosed(RuntimeException unused) {
|
||||
return new AlreadyClosedException("Already closed: " + this);
|
||||
AlreadyClosedException alreadyClosed(RuntimeException e) {
|
||||
// we use NPE to signal if this input is closed (to not have checks everywhere). If NPE happens,
|
||||
// we check the "is closed" condition explicitly by checking that our "curSegment" is null.
|
||||
// if it is an IllegalStateException, it can only come from MemorySegment API (other thread has
|
||||
// closed input)
|
||||
if (this.curSegment == null || e instanceof IllegalStateException) {
|
||||
return new AlreadyClosedException("Already closed: " + this);
|
||||
}
|
||||
// otherwise rethrow unmodified NPE/ISE (as it possibly a bug with passing a null parameter to
|
||||
// the IndexInput method):
|
||||
throw e;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -100,9 +100,17 @@ abstract class MemorySegmentIndexInput extends IndexInput implements RandomAcces
|
|||
}
|
||||
}
|
||||
|
||||
// the unused parameter is just to silence javac about unused variables
|
||||
AlreadyClosedException alreadyClosed(RuntimeException unused) {
|
||||
return new AlreadyClosedException("Already closed: " + this);
|
||||
AlreadyClosedException alreadyClosed(RuntimeException e) {
|
||||
// we use NPE to signal if this input is closed (to not have checks everywhere). If NPE happens,
|
||||
// we check the "is closed" condition explicitly by checking that our "curSegment" is null.
|
||||
// if it is an IllegalStateException, it can only come from MemorySegment API (other thread has
|
||||
// closed input)
|
||||
if (this.curSegment == null || e instanceof IllegalStateException) {
|
||||
return new AlreadyClosedException("Already closed: " + this);
|
||||
}
|
||||
// otherwise rethrow unmodified NPE/ISE (as it possibly a bug with passing a null parameter to
|
||||
// the IndexInput method):
|
||||
throw e;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -104,4 +104,17 @@ public class TestMmapDirectory extends BaseDirectoryTestCase {
|
|||
dir.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void testNullParamsIndexInput() throws Exception {
|
||||
try (Directory mmapDir = getDirectory(createTempDir("testNullParamsIndexInput"))) {
|
||||
try (IndexOutput out = mmapDir.createOutput("bytes", newIOContext(random()))) {
|
||||
out.alignFilePointer(16);
|
||||
}
|
||||
try (IndexInput in = mmapDir.openInput("bytes", IOContext.DEFAULT)) {
|
||||
assertThrows(NullPointerException.class, () -> in.readBytes(null, 0, 1));
|
||||
assertThrows(NullPointerException.class, () -> in.readFloats(null, 0, 1));
|
||||
assertThrows(NullPointerException.class, () -> in.readLongs(null, 0, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue