Calling instance methods inherited from MediaStream triggers stack overflow #291

Closed
opened 2025-10-29 13:55:47 +01:00 by Nyeksenn · 6 comments
Nyeksenn commented 2025-10-29 13:55:47 +01:00 (Migrated from github.com)

I am currently implementing a class which is derived from org.gnome.gtk.MediaStream.
MediaStream itself is marked as abstract, but none of the instance methods are.
Therefore I can call them in my Java Code. I think this should not be possible because
all of these methods have to be override. Otherwise, I can call them and upon doing so trigger
a stack overflow.

Uncaught exception:
java.lang.StackOverflowError 
{0x0000000616f6ac78} - klass: 'java/lang/StackOverflowError'
 - ---- fields (total size 5 words):
 - private transient 'depth' 'I' @12  1024 (0x00000400)
 - private transient 'backtrace' 'Ljava/lang/Object;' @16  a 'java/lang/Object'[7] {0x0000000616f6aca0} (0xc2ded594)
 - private 'detailMessage' 'Ljava/lang/String;' @20  null (0x00000000)
 - private 'cause' 'Ljava/lang/Throwable;' @24  null (0x00000000)
 - private 'stackTrace' '[Ljava/lang/StackTraceElement;' @28  null (0x00000000)
 - private 'suppressedExceptions' 'Ljava/util/List;' @32  null (0x00000000)
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  Internal Error (upcallLinker.cpp:146), pid=10756, tid=10757
#  Error: ShouldNotReachHere()
#
# JRE version: OpenJDK Runtime Environment Temurin-23+37 (23.0+37) (build 23+37)
# Java VM: OpenJDK 64-Bit Server VM Temurin-23+37 (23+37, mixed mode, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, linux-amd64)
# Problematic frame:
# V  [libjvm.so+0xfa6b13]  UpcallLinker::handle_uncaught_exception(oopDesc*)+0x43

java-gi version 0.12.2

I am currently implementing a class which is derived from org.gnome.gtk.MediaStream. MediaStream itself is marked as abstract, but none of the instance methods are. Therefore I can call them in my Java Code. I think this should not be possible because all of these methods have to be override. Otherwise, I can call them and upon doing so trigger a stack overflow. ```bash Uncaught exception: java.lang.StackOverflowError {0x0000000616f6ac78} - klass: 'java/lang/StackOverflowError' - ---- fields (total size 5 words): - private transient 'depth' 'I' @12 1024 (0x00000400) - private transient 'backtrace' 'Ljava/lang/Object;' @16 a 'java/lang/Object'[7] {0x0000000616f6aca0} (0xc2ded594) - private 'detailMessage' 'Ljava/lang/String;' @20 null (0x00000000) - private 'cause' 'Ljava/lang/Throwable;' @24 null (0x00000000) - private 'stackTrace' '[Ljava/lang/StackTraceElement;' @28 null (0x00000000) - private 'suppressedExceptions' 'Ljava/util/List;' @32 null (0x00000000) # # A fatal error has been detected by the Java Runtime Environment: # # Internal Error (upcallLinker.cpp:146), pid=10756, tid=10757 # Error: ShouldNotReachHere() # # JRE version: OpenJDK Runtime Environment Temurin-23+37 (23.0+37) (build 23+37) # Java VM: OpenJDK 64-Bit Server VM Temurin-23+37 (23+37, mixed mode, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, linux-amd64) # Problematic frame: # V [libjvm.so+0xfa6b13] UpcallLinker::handle_uncaught_exception(oopDesc*)+0x43 ``` java-gi version 0.12.2
Nyeksenn commented 2025-10-29 15:39:42 +01:00 (Migrated from github.com)

Closing this because I couldn't read.
One has to call asParent() instead of super

Closing this because I couldn't read. One has to call asParent() instead of super
Nyeksenn commented 2025-10-29 15:53:07 +01:00 (Migrated from github.com)

I just found out, that the issue is still valid because calling asParent().play() also causes the overflow.
This method should probably be abstract.

I just found out, that the issue is still valid because calling `asParent().play()` also causes the overflow. This method should probably be abstract.
jwharm commented 2025-10-29 20:02:57 +01:00 (Migrated from github.com)

Thanks for logging these issues, I appreciate the feedback!

GObject-introspection doesn't specify whether a virtual method is abstract or not, and many (but not all) have default implementations.
There is an open issue for this: https://gitlab.gnome.org/GNOME/gobject-introspection/-/issues/411

Using asParent() should have resolved the stack overflow though. Can you provide a short snippet showing how you use asParent()?

Thanks for logging these issues, I appreciate the feedback! GObject-introspection doesn't specify whether a virtual method is abstract or not, and many (but not all) have default implementations. There is an open issue for this: https://gitlab.gnome.org/GNOME/gobject-introspection/-/issues/411 Using `asParent()` should have resolved the stack overflow though. Can you provide a short snippet showing how you use `asParent()`?
Nyeksenn commented 2025-10-29 20:36:49 +01:00 (Migrated from github.com)

Thanks for the quick replies. I am currently building a Subsonic API compatible music player so I am
poking at a lot of functions. The following reliably produces a stack overflow:

    @Override
    public boolean play() {
        asParent().setPlaying(true);
        logger.info("Play was called");
        return true;
    }

I know this snippet is nonsensical but the GTK docs of MediaStream aren't great and I just did a bunch of experimentation
with the code.

Thanks for the quick replies. I am currently building a Subsonic API compatible music player so I am poking at a lot of functions. The following reliably produces a stack overflow: ```java @Override public boolean play() { asParent().setPlaying(true); logger.info("Play was called"); return true; } ``` I know this snippet is nonsensical but the GTK docs of `MediaStream` aren't great and I just did a bunch of experimentation with the code.
jwharm commented 2025-10-30 22:17:41 +01:00 (Migrated from github.com)

asParent() sets a flag so that when a virtual method is invoked (from Java), it will call the virtual method of the parent class instead of the overridden method. It affects Java code, not native code.

The reproducer results in a stack overflow because:

  1. setPlaying(true) calls the C function gtk_media_stream_set_playing
  2. gtk_media_stream_set_playing calls the C function gtk_media_stream_play
  3. gtk_media_stream_play calls the virtual method play
  4. The play virtual method points to our Java play() method, and we go back to step 1.

Crucially, step 4 happens in native code, so it's not affected by the call to asParent() in Java.

I haven't tried it, but I'm very certain that all other Gtk language bindings, and even a C application, would exhibit the same stack overflow in this case.

For a working sample on how to create a GtkMediaStream subclass, see this example.

`asParent()` sets a flag so that when a virtual method is invoked (from Java), it will call the virtual method of the parent class instead of the overridden method. It affects Java code, not native code. The reproducer results in a stack overflow because: 1. `setPlaying(true)` calls the C function `gtk_media_stream_set_playing` 2. `gtk_media_stream_set_playing` calls the C function `gtk_media_stream_play` 3. `gtk_media_stream_play` calls the virtual method `play` 4. The `play` virtual method points to our Java `play()` method, and we go back to step 1. Crucially, step 4 happens [in native code](https://gitlab.gnome.org/GNOME/gtk/-/blob/main/gtk/gtkmediastream.c#L512), so it's not affected by the call to `asParent()` in Java. I haven't tried it, but I'm very certain that all other Gtk language bindings, and even a C application, would exhibit the same stack overflow in this case. For a working sample on how to create a GtkMediaStream subclass, see [this example](https://github.com/jwharm/java-gi-examples/tree/main/MediaStream).
Nyeksenn commented 2025-11-03 07:50:17 +01:00 (Migrated from github.com)

Thanks, that makes complete sense. Closing this.

Thanks, that makes complete sense. Closing this.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
java-gi/java-gi#291
No description provided.