Skip to content

Commit

Permalink
Synchronize usages of ImageIO.read(...)
Browse files Browse the repository at this point in the history
ImageIO.read(...) is not really thread-safe, as calling it on several threads at the same time can cause NullPointerExceptions and ConcurrentModificationExceptions, as reported in https://bugs.openjdk.java.net/browse/JDK-8058973 and https://bugs.openjdk.java.net/browse/JDK-6986863.

This commit changes all usages of this method to synchronize on ImageIO.class, so the method is never run asynchronously.
  • Loading branch information
alexanderhenne committed Mar 7, 2018
1 parent ff27750 commit 8dc25ae
Show file tree
Hide file tree
Showing 29 changed files with 203 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,10 @@ public BufferedImage getIcon(int itemId) throws IOException
}

InputStream in = response.body().byteStream();
BufferedImage imageIcon = ImageIO.read(in);
return imageIcon;
synchronized (ImageIO.class)
{
return ImageIO.read(in);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ public BufferedImage getSkillImage(Skill skill)
{
String skillIconPath = "/skill_icons/" + skill.getName().toLowerCase() + ".png";
log.debug("Loading skill icon from {}", skillIconPath);
skillImage = ImageIO.read(SkillIconManager.class.getResourceAsStream(skillIconPath));
synchronized (ImageIO.class)
{
skillImage = ImageIO.read(SkillIconManager.class.getResourceAsStream(skillIconPath));
}
imgCache[skillIdx] = skillImage;
}
catch (IOException e)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,11 @@ public class AccountPlugin extends Plugin
{
try
{
LOGIN_IMAGE = ImageIO.read(AccountPlugin.class.getResourceAsStream("login_icon.png"));
LOGOUT_IMAGE = ImageIO.read(AccountPlugin.class.getResourceAsStream("logout_icon.png"));
synchronized (ImageIO.class)
{
LOGIN_IMAGE = ImageIO.read(AccountPlugin.class.getResourceAsStream("login_icon.png"));
LOGOUT_IMAGE = ImageIO.read(AccountPlugin.class.getResourceAsStream("logout_icon.png"));
}
}
catch (IOException e)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,11 @@ protected void startUp() throws Exception
{
font = FontManager.getRunescapeFont()
.deriveFont(Font.BOLD, 24);
clockImage = ImageIO.read(getClass().getResourceAsStream("clock.png"));

synchronized (ImageIO.class)
{
clockImage = ImageIO.read(getClass().getResourceAsStream("clock.png"));
}
}

@Subscribe
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,12 @@ public class ConfigPanel extends PluginPanel
{
try
{
CONFIG_ICON = ImageIO.read(ConfigPanel.class.getResourceAsStream("config_icon.png"));
UNCHECK_ICON = ImageIO.read(ConfigPanel.class.getResourceAsStream("disabled.png"));
CHECK_ICON = ImageIO.read(ConfigPanel.class.getResourceAsStream("enabled.png"));
synchronized (ImageIO.class)
{
CONFIG_ICON = ImageIO.read(ConfigPanel.class.getResourceAsStream("config_icon.png"));
UNCHECK_ICON = ImageIO.read(ConfigPanel.class.getResourceAsStream("disabled.png"));
CHECK_ICON = ImageIO.read(ConfigPanel.class.getResourceAsStream("enabled.png"));
}
}
catch (IOException e)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
package net.runelite.client.plugins.config;

import com.google.common.eventbus.Subscribe;
import java.awt.image.BufferedImage;
import java.util.concurrent.ScheduledExecutorService;
import javax.imageio.ImageIO;
import javax.inject.Inject;
Expand Down Expand Up @@ -68,9 +69,15 @@ protected void startUp() throws Exception
{
configPanel = new ConfigPanel(pluginManager, configManager, executorService, runeLiteConfig);

BufferedImage icon;
synchronized (ImageIO.class)
{
icon = ImageIO.read(getClass().getResourceAsStream("config_icon.png"));
}

navButton = new NavigationButton(
"Configuration",
ImageIO.read(getClass().getResourceAsStream("config_icon.png")),
icon,
() -> configPanel);

ui.getPluginToolbar().addNavigation(navButton);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,13 @@ private JPanel createBoundsDebugMultiButton()

try
{
bBox2DIcon = new ImageIcon(ImageIO.read(DevToolsPlugin.class.getResourceAsStream("2D_bounding_box.png")));
bBox3DIcon = new ImageIcon(ImageIO.read(DevToolsPlugin.class.getResourceAsStream("3D_bounding_box.png")));
clickBoxIcon = new ImageIcon(ImageIO.read(DevToolsPlugin.class.getResourceAsStream("2D_clickbox_geometry.png")));
bBox3DMousoverIcon = new ImageIcon(ImageIO.read(DevToolsPlugin.class.getResourceAsStream("mouseover_3D_bounding_box.png")));
synchronized (ImageIO.class)
{
bBox2DIcon = new ImageIcon(ImageIO.read(DevToolsPlugin.class.getResourceAsStream("2D_bounding_box.png")));
bBox3DIcon = new ImageIcon(ImageIO.read(DevToolsPlugin.class.getResourceAsStream("3D_bounding_box.png")));
clickBoxIcon = new ImageIcon(ImageIO.read(DevToolsPlugin.class.getResourceAsStream("2D_clickbox_geometry.png")));
bBox3DMousoverIcon = new ImageIcon(ImageIO.read(DevToolsPlugin.class.getResourceAsStream("mouseover_3D_bounding_box.png")));
}
}
catch (IOException ex)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
package net.runelite.client.plugins.devtools;

import java.awt.Font;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.inject.Inject;
import net.runelite.api.widgets.Widget;
Expand Down Expand Up @@ -67,9 +68,16 @@ public class DevToolsPlugin extends Plugin
protected void startUp() throws Exception
{
final DevToolsPanel panel = injector.getInstance(DevToolsPanel.class);

BufferedImage icon;
synchronized (ImageIO.class)
{
icon = ImageIO.read(getClass().getResourceAsStream("devtools_icon.png"));
}

navButton = new NavigationButton(
"Developer Tools",
ImageIO.read(getClass().getResourceAsStream("devtools_icon.png")),
icon,
() -> panel);

ui.getPluginToolbar().addNavigation(navButton);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,10 @@ else if (o2.getType() == FeedItemType.BLOG_POST)
{
try
{
RUNELITE_ICON = ImageIO.read(FeedPanel.class.getResourceAsStream("runelite.png"));
synchronized (ImageIO.class)
{
RUNELITE_ICON = ImageIO.read(FeedPanel.class.getResourceAsStream("runelite.png"));
}
}
catch (IOException e)
{
Expand All @@ -104,7 +107,10 @@ else if (o2.getType() == FeedItemType.BLOG_POST)

try
{
OSRS_ICON = ImageIO.read(FeedPanel.class.getResourceAsStream("osrs.png"));
synchronized (ImageIO.class)
{
OSRS_ICON = ImageIO.read(FeedPanel.class.getResourceAsStream("osrs.png"));
}
}
catch (IOException e)
{
Expand Down Expand Up @@ -184,7 +190,12 @@ public void onResponse(Call call, Response response) throws IOException
return;
}

avatar.setIcon(new ImageIcon(ImageIO.read(responseBody.byteStream())));
BufferedImage icon;
synchronized (ImageIO.class)
{
icon = ImageIO.read(responseBody.byteStream());
}
avatar.setIcon(new ImageIcon(icon));
}
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.google.common.base.Suppliers;
import com.google.common.eventbus.Subscribe;
import com.google.inject.Provides;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.ScheduledExecutorService;
Expand Down Expand Up @@ -87,9 +88,15 @@ protected void startUp() throws Exception
{
feedPanel = new FeedPanel(config, feedSupplier, linkBrowser);

BufferedImage icon;
synchronized (ImageIO.class)
{
icon = ImageIO.read(getClass().getResourceAsStream("icon.png"));
}

navButton = new NavigationButton(
"News Feed",
ImageIO.read(getClass().getResourceAsStream("icon.png")),
icon,
() -> feedPanel);

ui.getPluginToolbar().addNavigation(navButton);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;

@Slf4j
public class FightCaveOverlay extends Overlay
Expand Down Expand Up @@ -110,8 +109,10 @@ private BufferedImage getImage(String path)
BufferedImage image = null;
try
{
InputStream in = FightCaveOverlay.class.getResourceAsStream(path);
image = ImageIO.read(in);
synchronized (ImageIO.class)
{
image = ImageIO.read(FightCaveOverlay.class.getResourceAsStream(path));
}
}
catch (IOException e)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,11 @@ GrandExchangeConfig provideConfig(ConfigManager configManager)
protected void startUp() throws IOException
{
panel = injector.getInstance(GrandExchangePanel.class);
BufferedImage icon = ImageIO.read(getClass().getResourceAsStream("ge_icon.png"));
BufferedImage icon;
synchronized (ImageIO.class)
{
icon = ImageIO.read(getClass().getResourceAsStream("ge_icon.png"));
}
button = new NavigationButton("GE Offers", icon, () -> panel);
ui.getPluginToolbar().addNavigation(button);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,12 @@ void init()
// Search Box
try
{
search = new ImageIcon(ImageIO.read(GrandExchangePlugin.class.getResourceAsStream("search.png")));
BufferedImage icon;
synchronized (ImageIO.class)
{
icon = ImageIO.read(GrandExchangePlugin.class.getResourceAsStream("search.png"));
}
search = new ImageIcon(icon);
}
catch (IOException e)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.ArrayList;
Expand Down Expand Up @@ -118,10 +119,15 @@ public HiscorePanel()
inputPanel.setLayout(new BorderLayout(7, 7));
inputPanel.setBorder(subPanelBorder);

Icon search = null;
Icon search;
try
{
search = new ImageIcon(ImageIO.read(HiscorePanel.class.getResourceAsStream("search.png")));
BufferedImage icon;
synchronized (ImageIO.class)
{
icon = ImageIO.read(HiscorePanel.class.getResourceAsStream("search.png"));
}
search = new ImageIcon(icon);
}
catch (IOException ex)
{
Expand Down Expand Up @@ -217,13 +223,18 @@ public HiscorePanel()
{
try
{
Icon icon = new ImageIcon(ImageIO.read(HiscorePanel.class.getResourceAsStream(
endpoint.name().toLowerCase() + ".png")));
Icon selected = new ImageIcon(ImageIO.read(HiscorePanel.class.getResourceAsStream(
endpoint.name().toLowerCase() + "_selected.png")));
BufferedImage iconImage;
BufferedImage selectedImage;
synchronized (ImageIO.class)
{
iconImage = ImageIO.read(HiscorePanel.class.getResourceAsStream(
endpoint.name().toLowerCase() + ".png"));
selectedImage = ImageIO.read(HiscorePanel.class.getResourceAsStream(
endpoint.name().toLowerCase() + "_selected.png"));
}
JToggleButton button = new JToggleButton();
button.setIcon(icon);
button.setSelectedIcon(selected);
button.setIcon(new ImageIcon(iconImage));
button.setSelectedIcon(new ImageIcon(selectedImage));
button.setPreferredSize(new Dimension(24, 24));
button.setBackground(Color.WHITE);
button.setFocusPainted(false);
Expand Down Expand Up @@ -344,7 +355,12 @@ private JPanel makeSkillPanel(String skillName, HiscoreSkill skill)

try
{
label.setIcon(new ImageIcon(ImageIO.read(HiscorePanel.class.getResourceAsStream(skillIcon))));
BufferedImage icon;
synchronized (ImageIO.class)
{
icon = ImageIO.read(HiscorePanel.class.getResourceAsStream(skillIcon));
}
label.setIcon(new ImageIcon(icon));
}
catch (IOException ex)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

import com.google.common.eventbus.Subscribe;
import com.google.inject.Provides;
import java.awt.image.BufferedImage;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.ScheduledExecutorService;
import javax.imageio.ImageIO;
Expand Down Expand Up @@ -73,9 +74,16 @@ HiscoreConfig provideConfig(ConfigManager configManager)
protected void startUp() throws Exception
{
hiscorePanel = injector.getInstance(HiscorePanel.class);

BufferedImage icon;
synchronized (ImageIO.class)
{
icon = ImageIO.read(getClass().getResourceAsStream("hiscore.gif"));
}

navButton = new NavigationButton(
"Hiscore",
ImageIO.read(getClass().getResourceAsStream("hiscore.gif")),
icon,
() -> hiscorePanel);

ui.getPluginToolbar().addNavigation(navButton);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
*/
package net.runelite.client.plugins.info;

import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.inject.Inject;
import net.runelite.client.plugins.Plugin;
Expand All @@ -48,9 +49,15 @@ protected void startUp() throws Exception
final InfoPanel panel = injector.getInstance(InfoPanel.class);
panel.init();

BufferedImage icon;
synchronized (ImageIO.class)
{
icon = ImageIO.read(getClass().getResourceAsStream("info_icon.png"));
}

navButton = new NavigationButton(
"Info",
ImageIO.read(getClass().getResourceAsStream("info_icon.png")),
icon,
() -> panel
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,10 @@ private static BufferedImage getImage(String name)
{
try
{
return ImageIO.read(Book.class.getResourceAsStream("items/" + name + ".png"));
synchronized (ImageIO.class)
{
return ImageIO.read(Book.class.getResourceAsStream("items/" + name + ".png"));
}
}
catch (IOException | IllegalArgumentException e)
{
Expand Down
Loading

0 comments on commit 8dc25ae

Please sign in to comment.