Search code examples
javauser-interfacecrashtooltipjvm-crash

Java TrayIcon.setToolTip() crashes JVM on String with 128 characters


while running my mp3 player, it crashed on some songs. Looking into that, it turns out it's not the player itself, but the java TrayIcon class, when I call setToolTip(str) with str.length() == 128.

I wrote a short example to prove what happens:

package jc.javaexceptions;

import java.awt.AWTException;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.lang.reflect.InvocationTargetException;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;



public class Tray_setToolTip {

    // testing switches

    // if set to true, shows chrash screen
    // if set to false, app crashes quietly
    static private final boolean    SHOW_GUI_FAIL                   = true;

    // does not play a role if run in- or outside EDT
    static private final boolean    RUN_IN_SWING_DISPATCH_THREAD    = true;

    /**
     * Demonstrates, how setting a 128-char ToolTipText to a TrayIcon will crash the JVM
     */
    public static void main(final String[] args) throws AWTException, InvocationTargetException, InterruptedException {
        if (SHOW_GUI_FAIL) {
            final JFrame f = new JFrame("Test Window, fails at 128 chars ToolTipText length");
            f.setBounds(200, 200, 400, 400);
            f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
            f.setVisible(true);
        }

        // create tray image
        final int SIZE = 16;
        final BufferedImage bi = new BufferedImage(SIZE, SIZE, BufferedImage.TYPE_INT_ARGB);
        final Graphics g = bi.getGraphics();
        g.setColor(Color.CYAN);
        g.fillRect(0, 0, SIZE, SIZE);
        g.setColor(Color.RED);
        g.drawLine(0, 0, SIZE, SIZE);
        g.drawLine(0, SIZE, SIZE, 0);

        // set up tray and tray icon
        final TrayIcon trayIcon = new TrayIcon(bi);
        final SystemTray tray = SystemTray.getSystemTray();
        trayIcon.addMouseListener(new MouseAdapter() {
            @Override public void mouseClicked(final MouseEvent pE) {
                tray.remove(trayIcon);
                System.exit(0);
            }
        });
        tray.add(trayIcon);

        // works fine
        System.out.println("1 OK");
        trayIcon.setToolTip("Funny Test!"); // -> OK

        setTTT(trayIcon, 127); // try 127 -> OK
        setTTT(trayIcon, 129); // try 129 -> OK
        setTTT(trayIcon, 128); // try 128 -> CRASH // <--------------------------- CRASH

        // will not be reached!
        System.out.println("End reached!");
    }

    static private void setTTT(final TrayIcon pTrayIcon, final int pStringLength) throws InvocationTargetException, InterruptedException {
        System.out.println("Tray_setToolTip.setTTT(" + pStringLength + ")");

        // construct bad-ass string
        final StringBuilder sb = new StringBuilder();
        for (int i = 0; i < pStringLength; i++) {
            sb.append("1");
        }
        final String str = sb.toString();
        System.out.println("\tString len=" + str.length());

        if (RUN_IN_SWING_DISPATCH_THREAD) {
            //          SwingUtilities.invokeLater(() -> pTrayIcon.setToolTip(str)); // cannot use invokeLater(), would allow the output of "End reached!"
            SwingUtilities.invokeAndWait(() -> pTrayIcon.setToolTip(str));
        } else {
            pTrayIcon.setToolTip(str);
        }
        System.out.println("\tOK");

        try {
            Thread.sleep(1000);
        } catch (final InterruptedException e) {
            e.printStackTrace();
        }
    }

}

Soooo... does this happen on your PCs too? Or just on mine? I run Oracle jdk-8u40-windows-x64 on an up-to-date Windows 7...

If it turns out this is a Java intrinsic bug, how should I proceed further?


Solution

  • Ah yes. Been fixed already. Had my Eclipse stuck on an old version of Java, current (1.8.0_151-b12) runs it without any problems.

    Silly meeee