Skip to content
Permalink
Browse files
8231558: [macos] Platform.exit causes assertion error on macOS 10.15 …
…or later

Reviewed-by: pbansal, aghaisas
  • Loading branch information
kevinrushforth committed Jul 1, 2021
1 parent 61aff1c commit 6403d6745578887b7f2ccc10ac02e7cdd04d09c1
Show file tree
Hide file tree
Showing 7 changed files with 208 additions and 4 deletions.
@@ -42,7 +42,7 @@ - (id)initWithEnv:(JNIEnv*)env accessible:(jobject)acc

- (void)dealloc
{
GET_MAIN_JENV;
GET_MAIN_JENV_NOWARN;
if (env != NULL) {
(*env)->DeleteGlobalRef(env, jAccessible);
GLASS_CHECK_EXCEPTION(env);
@@ -218,11 +218,19 @@ do {
}


// retrieve main thread Java env asserting the call originated on main thread
// Retrieve Java env, asserting the call originated on main thread.
// Warn if the JVM has already been detached.
#define GET_MAIN_JENV \
assert(pthread_main_np() == 1); \
if (jEnv == NULL) \
GLASS_CALLSTACK("Java has been detached already, but someone is still trying to use it at ") \
JNIEnv *env = jEnv;

// Retrieve Java env, asserting the call originated on main thread.
// This variant is silent if the JVM has been detached, making it suitable
// for use by dealloc methods, which are called by the auto-release mechanism.
#define GET_MAIN_JENV_NOWARN \
assert(pthread_main_np() == 1); \
JNIEnv *env = jEnv;

#endif
@@ -137,7 +137,7 @@ - (id)initWithJavajdelegate:(jobject)jdelegate jtitle:(jstring)jtitle

- (void)dealloc
{
GET_MAIN_JENV;
GET_MAIN_JENV_NOWARN;

if (env != NULL)
{
@@ -201,7 +201,8 @@ - (void)dealloc

[GlassTouches stopTracking:self];

GET_MAIN_JENV;
GET_MAIN_JENV_NOWARN;

if (env != NULL)
{
(*env)->DeleteGlobalRef(env, self->jView);
@@ -66,4 +66,6 @@ public class Constants {
static final int ERROR_STARTUP_FAILED = 27;

static final int ERROR_ASSERTION_FAILURE = 28;

static final int ERROR_TIMEOUT = 29;
}
@@ -0,0 +1,98 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

package test.launchertest;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.layout.StackPane;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.Stage;

import static test.launchertest.Constants.*;

/**
* Test application that calls Platform.exit while Stage is still showing
* the Scene.
*
* This is launched by PlatformExitTest.
*/
public class PlatformExitApp extends Application {

// Timeout in milliseconds (must be at least 15 seconds)
private static final int TIMEOUT = 20000;

public static void sleep(long msec) {
try {
Thread.sleep(msec);
} catch (InterruptedException ex) {
ex.printStackTrace();
System.exit(ERROR_UNEXPECTED_EXCEPTION);
}
}

public static void setupTimeoutThread() {
// Timeout thread
Thread th = new Thread(() -> {
sleep(TIMEOUT);
System.exit(ERROR_TIMEOUT);
});
th.setDaemon(true);
th.start();
}

@Override public void start(Stage stage) throws Exception {
StackPane root = new StackPane();
Scene scene = new Scene(root, 400, 300);

final Label label = new Label("Hello");

root.getChildren().add(label);

stage.setScene(scene);
stage.show();

// Show window for 1 second before calling Platform.exit
Thread thr = new Thread(() -> {
sleep(1000);
Platform.exit();
});
thr.start();
}

/**
* @param args the command line arguments
*/
public static void main(String[] args) {
setupTimeoutThread();
Application.launch(args);

// Short delay to allow any pending output to be flushed
sleep(500);
System.exit(ERROR_NONE);
}

}
@@ -0,0 +1,95 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

package test.launchertest;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import junit.framework.AssertionFailedError;
import org.junit.Test;
import test.util.Util;

import static test.launchertest.Constants.*;

/**
* Unit test for Platform.exit
*/
public class PlatformExitTest {

private static final String className = PlatformExitTest.class.getName();
private static final String pkgName = className.substring(0, className.lastIndexOf("."));
private static final String testAppName = pkgName + "." + "PlatformExitApp";

@Test (timeout = 15000)
public void testPlatformExit() throws Exception {

final ArrayList<String> cmd =
Util.createApplicationLaunchCommand(testAppName, null, null);

ProcessBuilder builder = new ProcessBuilder(cmd);
builder.redirectErrorStream(true);
Process process = builder.start();
final InputStream in = process.getInputStream();

// Wait for the process to exit
int retVal = process.waitFor();
switch (retVal) {
case 0:// SUCCESS
case ERROR_NONE:
break;

case 1:
throw new AssertionFailedError(testAppName
+ ": unable to launch java application");

case ERROR_TIMEOUT:
throw new AssertionFailedError(testAppName
+ ": application timeout");

case ERROR_UNEXPECTED_EXCEPTION:
throw new AssertionFailedError(testAppName
+ ": unexpected exception");

default:
throw new AssertionFailedError(testAppName
+ ": Unexpected error exit: " + retVal);
}

// Read the output of the forked process and check for warning string
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
stringBuilder = stringBuilder.append(line).append("\n");
}
if (stringBuilder.indexOf("Java has been detached") >= 0) {
System.err.println(stringBuilder);
throw new AssertionFailedError(testAppName + ": tried to use JNI after Java was detached");
}
}

}

1 comment on commit 6403d67

@openjdk-notifier
Copy link

@openjdk-notifier openjdk-notifier bot commented on 6403d67 Jul 1, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.