Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8248910

NPE when freeing the memory for a slice from a buffer

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Won't Fix
    • Icon: P4 P4
    • 16
    • 16
    • core-libs
    • None
    • generic
    • generic

      Simple test case:

      $ cat FreeBuffer.java
      import sun.nio.ch.Util;
      import java.nio.ByteBuffer;

      public class FreeBuffer {

          public static void main(String[] args) {
              // Get a buffer with a capacity of 100, and then get its slice object.
              // The slice cleaner is empty.
              // And there is no reference to the allocated buffer.
              ByteBuffer slice = ByteBuffer.allocateDirect(100).slice();

              // Release this slice and it will be in the cache.
              Util.releaseTemporaryDirectBuffer(slice);

              // Get a buffer with a capacity of 1000.
              // At this time, the slice in the cache will be freed by Util.free().
              // But the cleaner of this slice is empty.
              Util.getTemporaryDirectBuffer(1000);
          }

      }

      $ javac --add-exports=java.base/sun.nio.ch=ALL-UNNAMED FreeBuffer.java

      $ java FreeBuffer
      Exception in thread "main" java.lang.NullPointerException: Cannot invoke "jdk.internal.ref.Cleaner.clean()" because the return value of "sun.nio.ch.DirectBuffer.cleaner()" is null
              at java.base/sun.nio.ch.Util.free(Util.java:328)
              at java.base/sun.nio.ch.Util.getTemporaryDirectBuffer(Util.java:241)
              at FreeBuffer.main(FreeBuffer.java:18)

      Proposed fix:
      diff -r a37f2e2b6fee src/java.base/share/classes/sun/nio/ch/Util.java
      --- a/src/java.base/share/classes/sun/nio/ch/Util.java Mon Jul 06 23:11:37 2020 -0700
      +++ b/src/java.base/share/classes/sun/nio/ch/Util.java Tue Jul 07 15:20:18 2020 +0800
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      @@ -40,6 +40,7 @@
       import jdk.internal.access.foreign.MemorySegmentProxy;
       import jdk.internal.misc.TerminatingThreadLocal;
       import jdk.internal.misc.Unsafe;
      +import jdk.internal.ref.Cleaner;
       import sun.security.action.GetPropertyAction;

       public class Util {
      @@ -322,10 +323,14 @@
           }

           /**
      - * Frees the memory for the given direct buffer
      + * Frees the memory for the given direct buffer if the buffer has cleaner.
      + * When the buffer has no cleaner, it will be recycled at GC time.
            */
           private static void free(ByteBuffer buf) {
      - ((DirectBuffer)buf).cleaner().clean();
      + Cleaner cleaner = ((DirectBuffer)buf).cleaner();
      + if (cleaner != null) {
      + cleaner.clean();
      + }
           }

            fyang Fei Yang
            fyang Fei Yang
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: