JDK-8244703 : "platform encoding not initialized" exceptions with debugger, JNI
  • Type: Bug
  • Component: core-svc
  • Sub-Component: debugger
  • Affected Version: 11.0.6,11.0.7,14
  • Priority: P2
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_10
  • CPU: x86_64
  • Submitted: 2020-05-10
  • Updated: 2020-06-10
  • Resolved: 2020-05-28
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 11 JDK 15
11.0.9-oracleFixed 15 b26Fixed
Related Reports
Relates :  
Relates :  
Description
ADDITIONAL SYSTEM INFORMATION :
OpenJDK 14.0.1
Windows 10

A DESCRIPTION OF THE PROBLEM :
It appears that attaching a debugger to a JVM that's been launched via JNI will cause "platform encoding not initialized" exceptions if the JVM being used is from an OpenJDK 14 location other than the one that the Windows 10 PATH variables are pointing to and the Java code calls Graphics2D.drawString().

I'm attaching sample Java code and a C++ Windows console app that runs the Java code via JNI. If you install a copy of OpenJDK in a location other than the standard, PATH-informed one and run the Java code from it, it'll fail if you attempt to attach a debugger (via the -agentlib:jdwp etc. parameter) but succeed if you don't try to attach a debugger. If you initialize JNI from the jvm.dll that's in the standard installation location, it'll succeed in either case.

The sample code is a much simplified version of code we use in an application that behaves correctly with all other versions of OpenJDK that we've used, up to version 13. It's just V14 that has this problem, as far as we've been able to ascertain.

REGRESSION : Last worked in version 13

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1) Create an OpenJDK 14 installation in a folder other than the one that Windows 10 PATH variables point to
2) create Java code that calls Graphics2D.drawString()
3) In a C++ app, call JNI_CreateJavaVM to create a new VM from the jvm.dll in your custom installation
4) use the resulting JNIEnv to run the Java code mentioned in step 2

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
drawString() should display text
ACTUAL -
a long string of exceptions, with "platform encoding not initialized" appearing to be at the core, and drawing fails.

---------- BEGIN SOURCE ----------
Here's a simple Java class that launches a Swing window that displays some text when you click on a button:

//**************** TextTest.java ******************//
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;

import javax.swing.*;


public class TextTest implements ActionListener 
{

public static void main(String[] args) 
{
   RunTest();
}

public static void RunTest()
{
   TextTest mainClass = new TextTest();
   mainClass.Go();
}

TextTest()
{
}

void Go()
{
   final int buttonHeight = 30;
	
   frame = new JFrame();
   frame.setDefaultCloseOperation( JFrame.DO_NOTHING_ON_CLOSE ); //EXIT_ON_CLOSE );
   frame.setSize( canvasWidth, canvasHeight + buttonHeight );
   frame.getContentPane().setLayout( null );

   textButton = new JButton( "Show Text" );
   textButton.addActionListener( this );
   frame.getContentPane().add( textButton );
   textButton.setBounds( 0, 0, 200, buttonHeight );

   frame.getContentPane().add( canvas );
   canvas.setBounds( 0, buttonHeight, canvasWidth, canvasHeight );
	
   frame.setVisible( true );
   canvas.repaint();

   image = new BufferedImage( canvasWidth, canvasHeight, BufferedImage.TYPE_INT_ARGB );
}

public void actionPerformed( ActionEvent event )
{
   onButtonClicked();
}

public void onButtonClicked()
{
   if ( textOnFlag )
   {
      textOnFlag = false;
      textButton.setText( "Show Text" );
   }
   else
   {
      textOnFlag = true;
      textButton.setText( "Hide Text" );	
   }
   canvas.repaint();
}

public void PaintCanvas( Graphics2D g )
{
   Graphics2D ig = image.createGraphics();
   PaintBufferedImage( ig );
	
   g.drawImage( image, 0, 0, null );
}
	
public void PaintBufferedImage( Graphics2D g )
{
   if ( textOnFlag )
      g.setBackground( new Color(235,255,235) );
   else
      g.setBackground( new Color(128,128,255) );
   g.clearRect( 0, 0, canvasWidth, canvasHeight );

   if ( textOnFlag )
   {
      g.setColor(new Color(5,5,5) );
      g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
      int fontHeight = 15;
      Font labelFont = new Font( "SansSerif", Font.BOLD, fontHeight );
      g.setFont( labelFont );
      g.drawString( "Text!", 12, (canvasHeight - fontHeight) / 2 );
   }
}

class MyDrawPanel extends JPanel
{
   MyDrawPanel(TextTest p)
   {
      parent = p;
   }
	
   public void paintComponent( Graphics g )
   {
      parent.PaintCanvas( (Graphics2D)g );
   }

   TextTest parent;
}

protected final int canvasWidth = 500, canvasHeight = 300;

protected JFrame frame;
protected JButton textButton;
protected MyDrawPanel canvas = new MyDrawPanel(this);
protected boolean textOnFlag = false;
protected BufferedImage image = null;
}
//**************** END TextTest.java ******************//


... and here's a Windows console app that runs TextTest via JNI:


//**************** JavaTester.cpp ******************//
#include <windows.h>
#include <jni.h>
#include <libloaderapi.h>

int main()
{
   const int numArgs = 2;
   JavaVMInitArgs vmArgs;
   JavaVMOption * options = new JavaVMOption[numArgs];

   // folder where TextTest.class is located
   options[0].optionString = (char*)"-Djava.class.path=D:";

   if ( numArgs > 1 )
      options[1].optionString = (char*)"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=9009";

   vmArgs.version = JNI_VERSION_10;
   vmArgs.nOptions = numArgs;
   vmArgs.options = options;
   vmArgs.ignoreUnrecognized = false;

   char jvmPath[512] = "C:\\OpenJDK14\\bin\\server\\jvm.dll";   // custom installation
//   char jvmPath[512] = "C:\\Program Files\\Java\\jdk-14.0.1\\bin\\server\\jvm.dll";  // standard installation
   HMODULE hmod = LoadLibraryA( jvmPath );
   if ( ! hmod )
      return 1;

   typedef void createJVMFunctionPtr(JavaVM**, void**, void*);
   createJVMFunctionPtr * createJVMFunction = (createJVMFunctionPtr*)GetProcAddress( hmod, "JNI_CreateJavaVM" );
   if ( ! createJVMFunction )
      return 2;

   JavaVM * jvm = nullptr;
   JNIEnv * env = nullptr;
   createJVMFunction( &jvm, (void**)&env, &vmArgs );

   if ( ! jvm )
      return 3;
   if ( ! env )
      return 4;

   jclass cls = env->FindClass( "TextTest" );
   jmethodID mid = env->GetStaticMethodID( cls, "RunTest", "()V" );
   env->CallStaticVoidMethod( cls, mid );

   // kludge to keep the swing window from disappearing for 30 seconds
   Sleep( 30000 );

   jvm->DetachCurrentThread();

   return 0;
}

//**************** END JavaTester.cpp ******************//

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
haven't found one

FREQUENCY : always



Comments
Fix request (11u) -- will label after testing completed. I would like to downport this for parity with 11.0.9-oracle. I skipped the change to the makefile. The makefile was renamed, and the original makefile already includes WIN_JAVA_LIB. http://mail.openjdk.java.net/pipermail/jdk-updates-dev/2020-June/003265.html
09-06-2020

URL: https://hg.openjdk.java.net/jdk/jdk/rev/8e28aae50680 User: amenkov Date: 2020-05-28 18:42:27 +0000
28-05-2020

This is regression from JDK-8222529. jdwp now linked to java.dll and hotspot loads agents (including jdwp) before any other libs. hotspot loads java.dll from jdk the VM belongs too, but jdwp just uses Windows DLL dependency, so Windows loads java.dll when jdwp.dll is loading by using standard Windows rules. As a result we have 2 java.dll loaded - from PATH and from JDK directory.
20-05-2020

I suspect JDK-8222529 may be the issue, it has created a dependency on java.dll. Need to check JDK 12 vs. JDK 13 to be sure. I've set the fixVersion to 15 for now as it does appear to be a regression.
15-05-2020

When the test program (in cpp) is run, it invokes JavaVM in the custom location (OpenJDK14) and the platform encoding is initialized, more specifically, java.dll in that custom location. However, at the time of AWT initializes Win32FontManager, it invokes JNU_NewStringPlatform entry in java.dll on the PATH, i.e., c:/Program Files/Java/jdk-14/bin, which does not seem correct. I am not familiar with how debugger works, so I would like someone more familiar in this field look into this. Transferring to "core-svc/debugger" component.
14-05-2020

Reproduced with Oracle JDK 14.0.1. Here is the exeption: --- Exception in thread "AWT-EventQueue-0" java.lang.InternalError: java.lang.reflect.InvocationTargetException at java.desktop/sun.font.FontManagerFactory$1.run(FontManagerFactory.java:86) at java.base/java.security.AccessController.doPrivileged(AccessController.java:312) at java.desktop/sun.font.FontManagerFactory.getInstance(FontManagerFactory.java:74) at java.desktop/sun.font.SunFontManager.getInstance(SunFontManager.java:247) at java.desktop/sun.font.FontDesignMetrics.getMetrics(FontDesignMetrics.java:261) at java.desktop/sun.swing.SwingUtilities2.getFontMetrics(SwingUtilities2.java:1243) at java.desktop/javax.swing.JComponent.getFontMetrics(JComponent.java:1646) at java.desktop/sun.swing.SwingUtilities2.getFontMetrics(SwingUtilities2.java:356) at java.desktop/sun.swing.SwingUtilities2.getFontMetrics(SwingUtilities2.java:328) at java.desktop/javax.swing.plaf.basic.BasicButtonUI.paint(BasicButtonUI.java:263) at java.desktop/javax.swing.plaf.metal.MetalButtonUI.update(MetalButtonUI.java:175) at java.desktop/javax.swing.JComponent.paintComponent(JComponent.java:797) at java.desktop/javax.swing.JComponent.paint(JComponent.java:1074) at java.desktop/javax.swing.JComponent.paintToOffscreen(JComponent.java:5255) at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBufferedImpl(RepaintManager.java:1643) at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1618) at java.desktop/javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1556) at java.desktop/javax.swing.RepaintManager.paint(RepaintManager.java:1323) at java.desktop/javax.swing.JComponent._paintImmediately(JComponent.java:5203) at java.desktop/javax.swing.JComponent.paintImmediately(JComponent.java:5013) at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:865) at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:848) at java.base/java.security.AccessController.doPrivileged(AccessController.java:391) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85) at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:848) at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:823) at java.desktop/javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:772) at java.desktop/javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1884) at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:316) at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715) at java.base/java.security.AccessController.doPrivileged(AccessController.java:391) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85) at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740) at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203) at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124) at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90) Caused by: java.lang.reflect.InvocationTargetException at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500) at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481) at java.desktop/sun.font.FontManagerFactory$1.run(FontManagerFactory.java:84) ... 40 more Caused by: java.lang.InternalError: platform encoding not initialized at java.desktop/sun.awt.Win32FontManager.getFontPath(Native Method) at java.desktop/sun.font.SunFontManager.getPlatformFontPath(SunFontManager.java:3051) at java.desktop/sun.font.SunFontManager.getPlatformFontDirs(SunFontManager.java:2936) at java.desktop/sun.awt.Win32FontManager.getDefaultPlatformFont(Win32FontManager.java:218) at java.desktop/sun.font.SunFontManager$2.run(SunFontManager.java:374) at java.base/java.security.AccessController.doPrivileged(AccessController.java:312) at java.desktop/sun.font.SunFontManager.<init>(SunFontManager.java:317) at java.desktop/sun.awt.Win32FontManager.<init>(Win32FontManager.java:87) ... 46 more ---
13-05-2020

The reproducer uses JNI CreateJavaVM directly, no java launcher in the picture. Need to track down why the jnu encoding is not initialised.
13-05-2020

This isn't a JavaFX program, it's a Swing program. However, the problem isn't in Swing. The "platform encoding not initialized" error message is coming from the JNI launcher.
12-05-2020