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:
Robert Muir 2015-06-17 02:49:35 +00:00
parent 5a0c012250
commit f047b54425
3 changed files with 117 additions and 3 deletions

View File

@ -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

View File

@ -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);
}
}

View File

@ -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);
}
}