Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8244703

"platform encoding not initialized" exceptions with debugger, JNI

XMLWordPrintable

    • b26
    • x86_64
    • windows_10

        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


              amenkov Alex Menkov
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              12 Start watching this issue

                Created:
                Updated:
                Resolved: