mirror of https://github.com/apache/lucene.git
LUCENE-6577: Give earlier and better error message for invalid CRC
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1685927 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
5a0c012250
commit
f047b54425
|
@ -85,6 +85,9 @@ New Features
|
|||
quite slow and are only fast in specific cases. (Adrien Grand,
|
||||
Robert Muir, Mike McCandless)
|
||||
|
||||
* LUCENE-6577: Give earlier and better error message for invalid CRC.
|
||||
(Robert Muir)
|
||||
|
||||
API Changes
|
||||
|
||||
* LUCENE-6508: Simplify Lock api, there is now just
|
||||
|
|
|
@ -307,7 +307,7 @@ public final class CodecUtil {
|
|||
public static void writeFooter(IndexOutput out) throws IOException {
|
||||
out.writeInt(FOOTER_MAGIC);
|
||||
out.writeInt(0);
|
||||
out.writeLong(out.getChecksum());
|
||||
writeCRC(out);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -330,7 +330,7 @@ public final class CodecUtil {
|
|||
public static long checkFooter(ChecksumIndexInput in) throws IOException {
|
||||
validateFooter(in);
|
||||
long actualChecksum = in.getChecksum();
|
||||
long expectedChecksum = in.readLong();
|
||||
long expectedChecksum = readCRC(in);
|
||||
if (expectedChecksum != actualChecksum) {
|
||||
throw new CorruptIndexException("checksum failed (hardware problem?) : expected=" + Long.toHexString(expectedChecksum) +
|
||||
" actual=" + Long.toHexString(actualChecksum), in);
|
||||
|
@ -399,7 +399,7 @@ public final class CodecUtil {
|
|||
public static long retrieveChecksum(IndexInput in) throws IOException {
|
||||
in.seek(in.length() - footerLength());
|
||||
validateFooter(in);
|
||||
return in.readLong();
|
||||
return readCRC(in);
|
||||
}
|
||||
|
||||
private static void validateFooter(IndexInput in) throws IOException {
|
||||
|
@ -436,4 +436,30 @@ public final class CodecUtil {
|
|||
in.seek(in.length() - footerLength());
|
||||
return checkFooter(in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads CRC32 value as a 64-bit long from the input.
|
||||
* @throws CorruptIndexException if CRC is formatted incorrectly (wrong bits set)
|
||||
* @throws IOException if an i/o error occurs
|
||||
*/
|
||||
public static long readCRC(IndexInput input) throws IOException {
|
||||
long value = input.readLong();
|
||||
if ((value & 0xFFFFFFFF00000000L) != 0) {
|
||||
throw new CorruptIndexException("Illegal CRC-32 checksum: " + value, input);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes CRC32 value as a 64-bit long to the output.
|
||||
* @throws IllegalStateException if CRC is formatted incorrectly (wrong bits set)
|
||||
* @throws IOException if an i/o error occurs
|
||||
*/
|
||||
public static void writeCRC(IndexOutput output) throws IOException {
|
||||
long value = output.getChecksum();
|
||||
if ((value & 0xFFFFFFFF00000000L) != 0) {
|
||||
throw new IllegalStateException("Illegal CRC-32 checksum: " + value + " (resource=" + output + ")");
|
||||
}
|
||||
output.writeLong(value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,9 @@ package org.apache.lucene.index;
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.apache.lucene.codecs.CodecUtil;
|
||||
import org.apache.lucene.store.BufferedChecksumIndexInput;
|
||||
import org.apache.lucene.store.ChecksumIndexInput;
|
||||
|
@ -252,4 +255,86 @@ public class TestCodecUtil extends LuceneTestCase {
|
|||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
public void testReadBogusCRC() throws Exception {
|
||||
RAMFile file = new RAMFile();
|
||||
IndexOutput output = new RAMOutputStream(file, false);
|
||||
output.writeLong(-1L); // bad
|
||||
output.writeLong(1L << 32); // bad
|
||||
output.writeLong(-(1L << 32)); // bad
|
||||
output.writeLong((1L << 32) - 1); // ok
|
||||
output.close();
|
||||
IndexInput input = new RAMInputStream("file", file);
|
||||
// read 3 bogus values
|
||||
for (int i = 0; i < 3; i++) {
|
||||
try {
|
||||
CodecUtil.readCRC(input);
|
||||
fail("didn't get expected exception");
|
||||
} catch (CorruptIndexException expected) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
// good value
|
||||
CodecUtil.readCRC(input);
|
||||
}
|
||||
|
||||
public void testWriteBogusCRC() throws Exception {
|
||||
RAMFile file = new RAMFile();
|
||||
final IndexOutput output = new RAMOutputStream(file, false);
|
||||
AtomicLong fakeChecksum = new AtomicLong();
|
||||
// wrap the index input where we control the checksum for mocking
|
||||
IndexOutput fakeOutput = new IndexOutput("fake") {
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
output.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFilePointer() {
|
||||
return output.getFilePointer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getChecksum() throws IOException {
|
||||
return fakeChecksum.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeByte(byte b) throws IOException {
|
||||
output.writeByte(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBytes(byte[] b, int offset, int length) throws IOException {
|
||||
output.writeBytes(b, offset, length);
|
||||
}
|
||||
};
|
||||
|
||||
fakeChecksum.set(-1L); // bad
|
||||
try {
|
||||
CodecUtil.writeCRC(fakeOutput);
|
||||
fail("didn't get expected exception");
|
||||
} catch (IllegalStateException expected) {
|
||||
// expected exception
|
||||
}
|
||||
|
||||
fakeChecksum.set(1L << 32); // bad
|
||||
try {
|
||||
CodecUtil.writeCRC(fakeOutput);
|
||||
fail("didn't get expected exception");
|
||||
} catch (IllegalStateException expected) {
|
||||
// expected exception
|
||||
}
|
||||
|
||||
fakeChecksum.set(-(1L << 32)); // bad
|
||||
try {
|
||||
CodecUtil.writeCRC(fakeOutput);
|
||||
fail("didn't get expected exception");
|
||||
} catch (IllegalStateException expected) {
|
||||
// expected exception
|
||||
}
|
||||
|
||||
fakeChecksum.set((1L << 32) - 1); // ok
|
||||
CodecUtil.writeCRC(fakeOutput);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue