You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ro...@apache.org on 2026/10/22 13:41:25 UTC

(lucene) branch branch_10x updated: Throw proper CorruptIndexException in stored fields reader (#16891)

This is an automated email from the ASF dual-hosted git repository.

romseygeek pushed a commit to branch branch_10x
in repository https://gitbox.apache.org/repos/asf/lucene.git


The following commit(s) were added to refs/heads/branch_10x by this push:
     new f8964e2bdbe Throw proper CorruptIndexException in stored fields reader (#16891)
f8964e2bdbe is described below

commit f8964e2bdbe3e2fcd5873f795cce6d7bc0e84624
Author: Alan Woodward <ro...@apache.org>
AuthorDate: Thu Oct 22 14:37:52 2026 +0100

    Throw proper CorruptIndexException in stored fields reader (#16891)
    
    Lucene90StoredFieldsReader would throw an AssertionError when it hit
    corrupt data, which in most client applications will cause a JVM
    shutdown. Replace this with a CorruptIndexException which can be
    handled more gracefully, and will identify which file contains the
    error.
---
 .../Lucene90CompressingStoredFieldsReader.java     | 18 ++++++++------
 .../TestCompressingStoredFieldsFormat.java         | 29 ++++++++++++++++++++++
 2 files changed, 40 insertions(+), 7 deletions(-)

diff --git a/lucene/core/src/java/org/apache/lucene/codecs/lucene90/compressing/Lucene90CompressingStoredFieldsReader.java b/lucene/core/src/java/org/apache/lucene/codecs/lucene90/compressing/Lucene90CompressingStoredFieldsReader.java
index af20a351b4b..f1a4dd4aab6 100644
--- a/lucene/core/src/java/org/apache/lucene/codecs/lucene90/compressing/Lucene90CompressingStoredFieldsReader.java
+++ b/lucene/core/src/java/org/apache/lucene/codecs/lucene90/compressing/Lucene90CompressingStoredFieldsReader.java
@@ -286,7 +286,8 @@ public final class Lucene90CompressingStoredFieldsReader extends StoredFieldsRea
     return original == this && mergeFieldsStream != fieldsStream ? mergeFieldsStream : null;
   }
 
-  private static void readField(DataInput in, StoredFieldVisitor visitor, FieldInfo info, int bits)
+  static void readField(
+      DataInput in, StoredFieldVisitor visitor, FieldInfo info, int bits, DataInput source)
       throws IOException {
     switch (bits & TYPE_MASK) {
       case BYTE_ARR:
@@ -309,11 +310,11 @@ public final class Lucene90CompressingStoredFieldsReader extends StoredFieldsRea
         visitor.doubleField(info, readZDouble(in));
         break;
       default:
-        throw new AssertionError("Unknown type flag: " + Integer.toHexString(bits));
+        throw new CorruptIndexException("Unknown type flag: " + Integer.toHexString(bits), source);
     }
   }
 
-  private static void skipField(DataInput in, int bits) throws IOException {
+  static void skipField(DataInput in, int bits, DataInput source) throws IOException {
     switch (bits & TYPE_MASK) {
       case BYTE_ARR:
       case STRING:
@@ -333,7 +334,7 @@ public final class Lucene90CompressingStoredFieldsReader extends StoredFieldsRea
         readZDouble(in);
         break;
       default:
-        throw new AssertionError("Unknown type flag: " + Integer.toHexString(bits));
+        throw new CorruptIndexException("Unknown type flag: " + Integer.toHexString(bits), source);
     }
   }
 
@@ -699,20 +700,23 @@ public final class Lucene90CompressingStoredFieldsReader extends StoredFieldsRea
       final long infoAndBits = doc.in.readVLong();
       final int fieldNumber = (int) (infoAndBits >>> TYPE_BITS);
       final FieldInfo fieldInfo = fieldInfos.fieldInfo(fieldNumber);
+      if (fieldInfo == null) {
+        throw new CorruptIndexException(
+            "Unknown field number: " + fieldNumber + ", docID=" + docID, fieldsStream);
+      }
 
       final int bits = (int) (infoAndBits & TYPE_MASK);
-      assert bits <= NUMERIC_DOUBLE : "bits=" + Integer.toHexString(bits);
 
       switch (visitor.needsField(fieldInfo)) {
         case YES:
-          readField(doc.in, visitor, fieldInfo, bits);
+          readField(doc.in, visitor, fieldInfo, bits, fieldsStream);
           break;
         case NO:
           if (fieldIDX
               == doc.numStoredFields - 1) { // don't skipField on last field value; treat like STOP
             return;
           }
-          skipField(doc.in, bits);
+          skipField(doc.in, bits, fieldsStream);
           break;
         case STOP:
           return;
diff --git a/lucene/core/src/test/org/apache/lucene/codecs/lucene90/compressing/TestCompressingStoredFieldsFormat.java b/lucene/core/src/test/org/apache/lucene/codecs/lucene90/compressing/TestCompressingStoredFieldsFormat.java
index 9c6140801a9..6a3f8dfc3f3 100644
--- a/lucene/core/src/test/org/apache/lucene/codecs/lucene90/compressing/TestCompressingStoredFieldsFormat.java
+++ b/lucene/core/src/test/org/apache/lucene/codecs/lucene90/compressing/TestCompressingStoredFieldsFormat.java
@@ -17,11 +17,15 @@
 package org.apache.lucene.codecs.lucene90.compressing;
 
 import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
 import java.util.Random;
 import org.apache.lucene.codecs.Codec;
 import org.apache.lucene.document.Document;
+import org.apache.lucene.document.DocumentStoredFieldVisitor;
 import org.apache.lucene.document.StoredField;
 import org.apache.lucene.index.CodecReader;
+import org.apache.lucene.index.CorruptIndexException;
 import org.apache.lucene.index.DirectoryReader;
 import org.apache.lucene.index.IndexWriter;
 import org.apache.lucene.index.IndexWriterConfig;
@@ -29,7 +33,10 @@ import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.NoMergePolicy;
 import org.apache.lucene.store.ByteArrayDataInput;
 import org.apache.lucene.store.ByteArrayDataOutput;
+import org.apache.lucene.store.ByteBuffersDataInput;
+import org.apache.lucene.store.ByteBuffersIndexInput;
 import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.IndexInput;
 import org.apache.lucene.tests.analysis.MockAnalyzer;
 import org.apache.lucene.tests.codecs.compressing.CompressingCodec;
 import org.apache.lucene.tests.index.BaseStoredFieldsFormatTestCase;
@@ -49,6 +56,28 @@ public class TestCompressingStoredFieldsFormat extends BaseStoredFieldsFormatTes
     }
   }
 
+  public void testUnknownTypeFlagIsCorruptIndex() throws Exception {
+    IndexInput source =
+        new ByteBuffersIndexInput(
+            new ByteBuffersDataInput(List.of(ByteBuffer.allocate(1))), "test.fdt");
+    ByteArrayDataInput in = new ByteArrayDataInput(new byte[8]);
+    for (int bits : new int[] {6, 7}) {
+      CorruptIndexException readException =
+          expectThrows(
+              CorruptIndexException.class,
+              () ->
+                  Lucene90CompressingStoredFieldsReader.readField(
+                      in, new DocumentStoredFieldVisitor(), null, bits, source));
+      assertTrue(readException.getMessage().contains("test.fdt"));
+
+      CorruptIndexException skipException =
+          expectThrows(
+              CorruptIndexException.class,
+              () -> Lucene90CompressingStoredFieldsReader.skipField(in, bits, source));
+      assertTrue(skipException.getMessage().contains("test.fdt"));
+    }
+  }
+
   public void testZFloat() throws Exception {
     byte[] buffer = new byte[5]; // we never need more than 5 bytes
     ByteArrayDataOutput out = new ByteArrayDataOutput(buffer);