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

finalize() called while instance is still reachable on stack

XMLWordPrintable

    • gc
    • generic
    • generic

      ADDITIONAL SYSTEM INFORMATION :
      Debian bullseye openjdk release 11.0.13+8-1~deb11u1 on amd64.

      A DESCRIPTION OF THE PROBLEM :
      We have a project which contains a substantial quantity of native code (actually a Rust library exposed to Java via JNI bindings) which a user was hitting use-after-frees when calling it from Kotlin. Upon investigation, its clear that finalize() methods are being called while the object is still reachable on stack (while a native method is being called which references the object).

      Relevant Java snippets showing the error:

      Persist.java:bindings.LDKPersist instance:update_persisted_channel (roughly line 119) (top-level entry point into the bug)

                                      ChannelMonitor data_hu_conv = null; if (data < 0 || data > 4096) { data_hu_conv = new ChannelMonitor(null, data); }
      System.out.println("Got monitor in update_persisted_chan : " + data_hu_conv + " (ptr " + data + ")");
      try {
                                      MonitorUpdateId update_id_hu_conv = null; if (update_id < 0 || update_id > 4096) { update_id_hu_conv = new MonitorUpdateId(null, update_id); }
                                      update_id_hu_conv.ptrs_to.add(this);
                                      Result_NoneChannelMonitorUpdateErrZ ret = arg.update_persisted_channel(channel_id_hu_conv, update_hu_conv, data_hu_conv, update_id_hu_conv);
      System.out.println("Done persisting! (monitor ptr " + data + ")");
                                      long result = ret == null ? 0 : ret.clone_ptr();
                                      return result;
      } catch (Exception e) {
      System.out.println("WTF");
      }

      ChannelMonitor.java's finzlie() override (the thing being free'd too early):
              protected void finalize() throws Throwable {
                      super.finalize();
                      System.out.println("Freeing monitor " + this);
                      if (ptr != 0) { bindings.ChannelMonitor_free(ptr); }
              }

      Relevant output from runtime:

      Cloned everything, now calling java update_persisted_channel with mon 107958298379521...
      Got monitor in update_persisted_chan : org.ldk.structs.ChannelMonitor@6ebd9f7e (ptr 107958298379521)
      start persist...
      Freeing monitor org.ldk.structs.ChannelMonitor@6ebd9f7e
      Freeing channel monitor! 107958298379521

      note how the ChannelMonitor from Persist.java is clearly still reachable on the thread's stack (we don't ever hit the catch there - there is no exception, and the "Done persisting" print is never reached), but the instance @6ebd9f7e is finalize()d

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Place an object on the stack, call a Kotlin JVM function, call a native method (to hit ASAN user-after-free detection, the bug may exist with or without native code), watch finalize() get called while the object is still reachable on stack.


      ---------- BEGIN SOURCE ----------
      Kotlin project at https://github.com/BlueWallet/HelloLightning/tree/master/src/main note that some effort is required to call the triggering function at https://github.com/BlueWallet/HelloLightning/blob/master/src/main/kotlin/RnLdkFunctions.kt#L176. VM access with installed/running/crashing code can be provided on request. It is easiest to trigger the crash by spawning a new thread which calls `System.gc(); System.runFinalization();` in a loop.

      The underlying Java is available at https://github.com/lightningdevkit/ldk-garbagecollected/tree/main/src note that this is auto-generated code and the above code snippets (with minor modifications) are from https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/ChannelMonitor.java and https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Persist.java
      ---------- END SOURCE ----------

            Unassigned Unassigned
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            6 Start watching this issue

              Created:
              Updated:
              Resolved: