You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by us...@apache.org on 2020/09/10 09:57:11 UTC

[lucene-solr] branch branch_8x updated: LUCENE-9517: Don't subclass Deflater and instead create a patch for setDictionary() using a functional interface (#1850) (backport: forbiddenApis/base.txt changed for Java 8, private static method in interface changed)

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

uschindler pushed a commit to branch branch_8x
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git


The following commit(s) were added to refs/heads/branch_8x by this push:
     new b313618  LUCENE-9517: Don't subclass Deflater and instead create a patch for setDictionary() using a functional interface (#1850) (backport: forbiddenApis/base.txt changed for Java 8, private static method in interface changed)
b313618 is described below

commit b313618cc1d104ae8994aad9aa71565562407ee1
Author: Uwe Schindler <us...@apache.org>
AuthorDate: Thu Sep 10 11:12:59 2020 +0200

    LUCENE-9517: Don't subclass Deflater and instead create a patch for setDictionary() using a functional interface (#1850)
    (backport: forbiddenApis/base.txt changed for Java 8, private static method in interface changed)
---
 .../codecs/lucene87/BugfixDeflater_JDK8252739.java | 46 +++++++++++-----------
 .../DeflateWithPresetDictCompressionMode.java      |  6 ++-
 lucene/tools/forbiddenApis/base.txt                |  3 ++
 3 files changed, 29 insertions(+), 26 deletions(-)

diff --git a/lucene/core/src/java/org/apache/lucene/codecs/lucene87/BugfixDeflater_JDK8252739.java b/lucene/core/src/java/org/apache/lucene/codecs/lucene87/BugfixDeflater_JDK8252739.java
index 23a5f50..8dc2152 100644
--- a/lucene/core/src/java/org/apache/lucene/codecs/lucene87/BugfixDeflater_JDK8252739.java
+++ b/lucene/core/src/java/org/apache/lucene/codecs/lucene87/BugfixDeflater_JDK8252739.java
@@ -21,50 +21,48 @@ import java.util.zip.DataFormatException;
 import java.util.zip.Deflater;
 import java.util.zip.Inflater;
 
+import org.apache.lucene.util.SuppressForbidden;
+
 /**
  * This class is a workaround for JDK bug
  * <a href="https://bugs.openjdk.java.net/browse/JDK-8252739">JDK-8252739</a>.
  */
-final class BugfixDeflater_JDK8252739 extends Deflater {
+@FunctionalInterface
+interface BugfixDeflater_JDK8252739 {
   
   public static final boolean IS_BUGGY_JDK = detectBuggyJDK();
 
   /**
-   * Creates a {@link Deflater} instance, which works around JDK-8252739.
+   * Creates a bugfix for {@link Deflater} instances, which works around JDK-8252739.
    * <p>
-   * Use this whenever you intend to call {@link #setDictionary(byte[], int, int)}
+   * Use this whenever you intend to call {@link Deflater#setDictionary(byte[], int, int)}
    * on a {@code Deflater}.
    * */
-  public static Deflater createDeflaterInstance(int level, boolean nowrap, int dictLength) {
+  @SuppressForbidden(reason = "Works around bug, so it must call forbidden method")
+  public static BugfixDeflater_JDK8252739 createBugfix(Deflater deflater, int dictLength) {
     if (dictLength < 0) {
       throw new IllegalArgumentException("dictLength must be >= 0");
     }
     if (IS_BUGGY_JDK) {
-      return new BugfixDeflater_JDK8252739(level, nowrap, dictLength);
+      final byte[] dictBytesScratch = new byte[dictLength];
+      return (dictBytes, off, len) -> {
+        if (off > 0) {
+          System.arraycopy(dictBytes, off, dictBytesScratch, 0, len);
+          deflater.setDictionary(dictBytesScratch, 0, len);
+        } else {
+          deflater.setDictionary(dictBytes, off, len);
+        }
+      };
     } else {
-      return new Deflater(level, nowrap);
+      return deflater::setDictionary;
     }
   }
   
+  /** Call this method as a workaround */
+  void setDictionary(byte[] dictBytes, int off, int len);
   
-  private final byte[] dictBytesScratch;
-
-  private BugfixDeflater_JDK8252739(int level, boolean nowrap, int dictLength) {
-    super(level, nowrap);
-    this.dictBytesScratch = new byte[dictLength];
-  }
-  
-  @Override
-  public void setDictionary(byte[] dictBytes, int off, int len) {
-    if (off > 0) {
-      System.arraycopy(dictBytes, off, dictBytesScratch, 0, len);
-      super.setDictionary(dictBytesScratch, 0, len);
-    } else {
-      super.setDictionary(dictBytes, off, len);
-    }
-  }
-
-  private static boolean detectBuggyJDK() {
+  @SuppressForbidden(reason = "Detector for the bug, so it must call buggy method")
+  static boolean detectBuggyJDK() {
     final byte[] testData = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
     final byte[] compressed = new byte[32]; // way enough space
     final Deflater deflater = new Deflater(6, true);
diff --git a/lucene/core/src/java/org/apache/lucene/codecs/lucene87/DeflateWithPresetDictCompressionMode.java b/lucene/core/src/java/org/apache/lucene/codecs/lucene87/DeflateWithPresetDictCompressionMode.java
index 91c1480..4269740 100644
--- a/lucene/core/src/java/org/apache/lucene/codecs/lucene87/DeflateWithPresetDictCompressionMode.java
+++ b/lucene/core/src/java/org/apache/lucene/codecs/lucene87/DeflateWithPresetDictCompressionMode.java
@@ -157,11 +157,13 @@ public final class DeflateWithPresetDictCompressionMode extends CompressionMode
 
     private final int dictLength, blockLength;
     final Deflater compressor;
+    final BugfixDeflater_JDK8252739 deflaterBugfix;
     byte[] compressed;
     boolean closed;
 
     DeflateWithPresetDictCompressor(int level, int dictLength, int blockLength) {
-      compressor = BugfixDeflater_JDK8252739.createDeflaterInstance(level, true, dictLength);
+      compressor = new Deflater(level, true);
+      deflaterBugfix = BugfixDeflater_JDK8252739.createBugfix(compressor, dictLength);
       compressed = new byte[64];
       this.dictLength = dictLength;
       this.blockLength = blockLength;
@@ -208,7 +210,7 @@ public final class DeflateWithPresetDictCompressionMode extends CompressionMode
       // And then sub blocks
       for (int start = off + dictLength; start < end; start += blockLength) {
         compressor.reset();
-        compressor.setDictionary(bytes, off, dictLength);
+        deflaterBugfix.setDictionary(bytes, off, dictLength);
         doCompress(bytes, start, Math.min(blockLength, off + len - start), out);
       }
     }
diff --git a/lucene/tools/forbiddenApis/base.txt b/lucene/tools/forbiddenApis/base.txt
index 6ff080b..b0a2128 100644
--- a/lucene/tools/forbiddenApis/base.txt
+++ b/lucene/tools/forbiddenApis/base.txt
@@ -62,3 +62,6 @@ java.lang.Double#<init>(java.lang.String)
 @defaultMessage Java deserialization is unsafe when the data is untrusted. The java developer is powerless: no checks or casts help, exploitation can happen in places such as clinit or finalize!
 java.io.ObjectInputStream
 java.io.ObjectOutputStream
+
+@defaultMessage Don't set a dictionary on a Deflater using a method that takes an offset or ByteBuffer (JDK-8252739)
+java.util.zip.Deflater#setDictionary(byte[],int,int)