JDK-8241370 : Crash in JPEGImageLoader after fix for JDK-8212034
  • Type: Bug
  • Component: javafx
  • Sub-Component: graphics
  • Affected Version: 8u261,openjfx15
  • Priority: P2
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2020-03-20
  • Updated: 2020-06-22
  • Resolved: 2020-04-03
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 Other
8u261Fixed openjfx11.0.8Fixed
Related Reports
Relates :  
After the fix for JDK-8212034 (memory leaks in jpegLoader.c), many web sites that load images, including the default https://www.oracle.com/java/ site, will crash in "com.sun.javafx.iio.jpeg.JPEGImageLoader.initDecompressor".

Here is the simplest test case I could find that crashes:

$ java HelloWebView https://www.oracle.com/a/ocom/img/ch10-java-home-banner.jpg

# A fatal error has been detected by the Java Runtime Environment:
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffed7dcbfba, pid=23776, tid=21224
# JRE version: OpenJDK Runtime Environment (14.0+36) (build 14+36-1461)
# Java VM: OpenJDK 64-Bit Server VM (14+36-1461, mixed mode, sharing, tiered, compressed oops, g1 gc, windows-amd64)
# Problematic frame:
# C  0x00007ffed7dcbfba

The crash is here:

Current thread (0x000001cc40753800):  JavaThread "JavaFX Application Thread" [_thread_in_native, id=21224, stack(0x000000c9b0700000,0x000000c9b0800000)]

Stack: [0x000000c9b0700000,0x000000c9b0800000],  sp=0x000000c9b07fcea0,  free space=1011k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C  0x00007ffed7dcbfba

Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j  com.sun.javafx.iio.jpeg.JPEGImageLoader.initDecompressor(Ljava/io/InputStream;)J+0 javafx.graphics
j  com.sun.javafx.iio.jpeg.JPEGImageLoader.<init>(Ljava/io/InputStream;)V+45 javafx.graphics
j  com.sun.javafx.iio.jpeg.JPEGImageLoaderFactory.createImageLoader(Ljava/io/InputStream;)Lcom/sun/javafx/iio/ImageLoader;+5 javafx.graphics

I have attached the crash log.

This works fine if I locally revert the fix for JDK-8212034
Changeset: 5906521c Author: Ambarish Rapte <arapte@openjdk.org> Date: 2020-04-03 04:06:16 +0000 URL: https://git.openjdk.java.net/jfx/commit/5906521c

It never gets to any subsequent call to initDecompressor(), so that isn't the issue. The error code that is executed when setjmp returns now calls disposeIIO, which in turn calls imageio_dispose. This will free cinfo->err and set it to NULL, and the subsequent call to (*cinfo->err->format_message) is guaranteed to crash. So this is a use-after-free case introduced with the fix for JDK-8212034. The simplest fix might be to move the call to disposeIIO after the block where it is used. If you do go with this latter approach, rather than reverting the call as I initially suggested, you will need to make sure that dispose can't be called a second time (e.g., from the JPEGImageLoader::disposeNative JNI method), since it isn't safe to call it more than once.

When image is loaded in WebView usinga url, WebView attempts to load a image frames with partial image data. JDK-8153148 -> WCImageDecoderImpl.addImageData() -> calls loadFrames() with partial image data. Call to jpeg_read_header() may fail when the partial image data has incomplete header information. In the given case the jpeg_read_header() call fails and code execution flow enters the 'if (setjmp(jerr->setjmp_buffer)) {}' block and results in call to disposeIIO(env, data); After receiving more image data, the method initDecompressor() is executed again and it results in the crash. Fix: 1. Revert the change that Kevin has mentioned above OR/And 2. When initDecompressor() is called next time, jpeg library should be initialized properly and should not result in crash. It may be a case that an existing issue is unearthed by the JDK-8212034 fix. The issue does not occur if the url image is loaded using ImageView, as it starts decoding the image only after receiving all image data.

[~arapte] I think this change is the source of the bug: @@ -1382,13 +1392,14 @@ if (setjmp(jerr->setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error while reading the header. */ - RELEASE_ARRAYS(env, data, src->next_input_byte); + disposeIIO(env, data); if (!(*env)->ExceptionOccurred(env)) { char buffer[JMSG_LENGTH_MAX]; (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo, buffer); ThrowByName(env, "java/io/IOException", buffer); } In looking at it more closely, this part of the fix doesn't look correct to me. If I revert just this part, calling RELEASE_ARRAYS rather than disposeIIO, the crash goes away. Of course more analysis is needed.

I updated the title and description to reflect the actual cause of the regression.

It crashes on all three platforms (Windows, Mac, Linux).