Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for #678 #1712

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft

Conversation

zkxvh
Copy link

@zkxvh zkxvh commented Jan 9, 2025

Fix for SIGSEGV in Tree.cellDataProc(...) when calling TreeItem.setImage(...).

Fixes #678

Reproducing the crash:

The cause of the crash is described here:
#678 (comment) In short, the crash happens due to read accesses to an already disposed renderer.
The sequence of action leading to the crash was:

  • in a Tree with SWT.VIRTUAL a TreeItem is rendered for the first time or after clear()
    • Tree.cellDataProc() is executed for the item and one of the renderers
      • Tree.checkData(item) is called for the item
        • SWT.SetData event is created and sent for the item
          • TreeItem.setImage() is executed by the event handler for SWT.SetData``
          • Tree.createRenderers() executes and disposes the current renderer
      • further actions in Tree.cellDataProc() that access the already-disposed renderer (they think it's alive)

How it's fixed: in Tree.cellDataProc() wrap Tree.checkData(item) into Display.asyncExec().

Why fixed this way:

  1. on one hand, Tree.cellDataProc() is a cell data function which is not supposed to change tree structure. Violation of this leads to C memory errors.
  2. On the other hand, SWT.SetData event handlers are written by swt users and therefore can contain any code.

Using Display.asyncExec() to postpone SWT.SetData event handlers until Tree.cellDataProc() is finished seems like the most simple and bullet-proof solution to #678 and all similar bugs.

@iloveeclipse
Copy link
Member

Could you please add the executable snippet that demonstrates the crash to the eclipse.platform.swt/tests/org.eclipse.swt.tests.gtk/ManualTests ?

I've tried two snippets on the ticket but none of them crashed on my RHEL 9.2 / gtk3-3.24.31-2.el9.x86_64.

Copy link
Contributor

github-actions bot commented Jan 9, 2025

Test Results

   483 files   -  3     483 suites   - 3   10m 10s ⏱️ +19s
 4 288 tests  - 19   4 275 ✅  - 19   12 💤  - 1  1 ❌ +1 
16 375 runs   - 37  16 268 ✅  - 36  106 💤  - 2  1 ❌ +1 

For more details on these failures, see this check.

Results for commit 72c21ef. ± Comparison against base commit d7febc4.

This pull request removes 19 tests.
org.eclipse.swt.tests.gtk.Test_GtkConverter ‑ test_HeuristicASCII_dollarSign
org.eclipse.swt.tests.gtk.Test_GtkConverter ‑ test_HeuristicASCII_emptyString
org.eclipse.swt.tests.gtk.Test_GtkConverter ‑ test_HeuristicASCII_letterA
org.eclipse.swt.tests.gtk.Test_GtkConverter ‑ test_HeuristicASCII_letters
org.eclipse.swt.tests.gtk.Test_GtkConverter ‑ test_HeuristicUTF16LE_null
org.eclipse.swt.tests.gtk.Test_GtkConverter ‑ test_HeuristicUTF16_AsciiLetters
org.eclipse.swt.tests.gtk.Test_GtkConverter ‑ test_HeuristicUTF16_Asciiletter
org.eclipse.swt.tests.gtk.Test_GtkConverter ‑ test_HeuristicUTF16_LotsOfLetters
org.eclipse.swt.tests.gtk.Test_GtkConverter ‑ test_HeuristicUTF16_letter
org.eclipse.swt.tests.gtk.Test_GtkConverter ‑ test_HeuristicUTF16_letters
…

@zkxvh
Copy link
Author

zkxvh commented Jan 10, 2025

Could you please add the executable snippet that demonstrates the crash to the eclipse.platform.swt/tests/org.eclipse.swt.tests.gtk/ManualTests ?

I've tried two snippets on the ticket but none of them crashed on my RHEL 9.2 / gtk3-3.24.31-2.el9.x86_64.

I don't know how to reliably reproduce a jvm crash for this bug.

The bug itself is a so called use-after-free, i.e. in Tree.cellDataProc() the memory for the renderer is at first freed inside Tree.checkData(item) call and then accessed again in OS.g_object_set (cell, OS.gicon, ptr [0], 0) and other places.

The crash happens when in between the memory release and the access the freed memory is allocated again and modified in specific way by some other native code.

For example, if the value of some pointer accessed inside OS.g_object_set (cell, OS.gicon, ptr [0], 0) gets rewritten to point to inaccessible memory address, then the app would crash.

The problem is that this "some other native code", on which depends if and how the freed memory is modified, is impossible to predict - because it's native code of the JVM and system libraries, both of which are super complicated.

Even on my own computer I don't get crash every time I run the snippet.

I suppose #1611 offers the highest chance for the app crash.

For now IMO the easiest way to make sure that in Tree.cellDataProc() the renderer is released first and accessed later is debugging.

BTW in C/C++ there are tools to detect errors of this type.
One of them - valgrind - works with java.
I tried it, it detects that OS.g_object_set (cell, OS.gicon, ptr [0], 0) accesses freed memory, but the output is not very useful because valgrind doesn't support native code generated by the JVM:

==16395== 1 errors in context 3 of 977:
==16395== Invalid read of size 8
==16395==    at 0x2AFCDD59: g_type_check_instance_is_fundamentally_a (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.8000.0)
==16395==    by 0x2AFBA8E9: g_object_set (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.8000.0)
==16395==    by 0x2FE4B773: Java_org_eclipse_swt_internal_gtk_OS_g_1object_1set__J_3BJJ (in /home/user/.swt/lib/linux/x86_64/libswt-pi3-gtk-4966r5.so)
==16395==    by 0x156D85D9: ???
==16395==    by 0x156D425F: ???
==16395==    by 0x156D432E: ???
==16395==    by 0x156CBCC8: ???
==16395==    by 0x56EB5D1: JavaCalls::call_helper(JavaValue*, methodHandle const&, JavaCallArguments*, JavaThread*) (javaCalls.cpp:429)
==16395==    by 0x578129B: jni_invoke_nonstatic(JNIEnv_*, JavaValue*, _jobject*, JNICallType, _jmethodID*, JNI_ArgumentPusher*, JavaThread*) [clone .constprop.1] (jni.cpp
:956)
==16395==    by 0x5788B9F: jni_CallLongMethodV (jni.cpp:1238)
==16395==    by 0x2FA3F689: callback (in /home/user/.swt/lib/linux/x86_64/libswt-gtk-4966r5.so)
==16395==    by 0x2FA48FBF: fn20_5 (in /home/user/.swt/lib/linux/x86_64/libswt-gtk-4966r5.so)
==16395==  Address 0x33c21a90 is 272 bytes inside a block of size 320 free'd
==16395==    at 0x484988F: free (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==16395==    by 0x2AFCB103: g_type_free_instance (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.8000.0)
==16395==    by 0x2AFB5624: g_object_unref (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.8000.0)
==16395==    by 0x30157B4E: ??? (in /usr/lib/x86_64-linux-gnu/libgtk-3.so.0.2409.32)
==16395==    by 0x30155662: ??? (in /usr/lib/x86_64-linux-gnu/libgtk-3.so.0.2409.32)
==16395==    by 0x2FE476D3: Java_org_eclipse_swt_internal_gtk_GTK_gtk_1tree_1view_1column_1clear (in /home/user/.swt/lib/linux/x86_64/libswt-pi3-gtk-4966r5.so)
==16395==    by 0x156D85D9: ???
==16395==    by 0x156D425F: ???
==16395==    by 0x156D425F: ???
==16395==    by 0x156D425F: ???
==16395==    by 0x156D425F: ???
==16395==    by 0x156D425F: ???
==16395==  Block was alloc'd at
==16395==    at 0x484D953: calloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==16395==    by 0x308997A1: g_malloc0 (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.8000.0)
==16395==    by 0x2AFD1E8B: g_type_create_instance (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.8000.0)
==16395==    by 0x2AFB7A63: ??? (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.8000.0)
==16395==    by 0x2AFB9015: g_object_new_with_properties (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.8000.0)
==16395==    by 0x2AFB9F70: g_object_new (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.8000.0)
==16395==    by 0x2FE42E66: Java_org_eclipse_swt_internal_gtk_GTK_gtk_1cell_1renderer_1text_1new (in /home/user/.swt/lib/linux/x86_64/libswt-pi3-gtk-4966r5.so)
==16395==    by 0x156D85D9: ???
==16395==    by 0x156D432E: ???
==16395==    by 0x156D425F: ???
==16395==    by 0x156D425F: ???
==16395==    by 0x156D425F: ???

@iloveeclipse
Copy link
Member

Would be still good to provide best snippet that could produce the crash in same PR.

@zkxvh zkxvh force-pushed the set-data-asyncexec branch from 72c21ef to 04e2d7a Compare January 10, 2025 11:46
Fix for `SIGSEGV` in `Tree.cellDataProc(...)` when calling
`TreeItem.setImage(...)`.

Fixes eclipse-platform#678

Reproducing the crash:
- eclipse-platform#678 (comment)
- eclipse-platform#1611
- eclipse-platform#678 (comment)

The cause of the crash is described here:
eclipse-platform#678 (comment)
In short, the crash happens due to read accesses to an already disposed
renderer.
The sequence of action leading to the crash was:
- in a `Tree` with `SWT.VIRTUAL` a `TreeItem` is rendered for the first
time or after `clear()`
  - `Tree.cellDataProc()` is executed for the item and one of the
renderers
    - `Tree.checkData(item)` is called for the item
      - `SWT.SetData` event is created and sent for the item
        - `TreeItem.setImage() is executed by the event handler for
`SWT.SetData``
         - `Tree.createRenderers()` executes and disposes the current
renderer
    - further actions in `Tree.cellDataProc()` that access the
already-disposed renderer (they think it's alive)

How it's fixed: in `Tree.cellDataProc()` wrap `Tree.checkData(item)`
into `Display.asyncExec()`.

Why fixed this way:
1. on one hand, `Tree.cellDataProc()` is a [cell data
function](https://docs.gtk.org/gtk3/treeview-tutorial.html#cell-data-functions)
which is not supposed to change tree structure. Violation of this leads
to C memory errors.
2. On the other hand, `SWT.SetData` event handlers are written by swt
users and therefore can contain any code.

Using `Display.asyncExec()` to postpone `SWT.SetData` event handlers
until `Tree.cellDataProc()` is finished seems like the most simple and
bullet-proof solution to eclipse-platform#678 and all similar bugs.
@zkxvh zkxvh force-pushed the set-data-asyncexec branch from 04e2d7a to de2db35 Compare January 10, 2025 11:47
@zkxvh
Copy link
Author

zkxvh commented Jan 10, 2025

added the snippet as Issue678_JvmCrashOnTreeItemSetImage.java

@zkxvh zkxvh marked this pull request as draft January 10, 2025 13:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

SIGSEGV in Tree.cellDataProc when calling TreeItem.setImage
2 participants