Skip to content

Commit 1858dc1

Browse files
Karmjerboaa
authored andcommitted
8336382: Fix error reporting in loading AWT
Reviewed-by: prr, aivanov, serb
1 parent 22069ff commit 1858dc1

File tree

3 files changed

+156
-12
lines changed

3 files changed

+156
-12
lines changed

src/java.desktop/unix/native/libawt/awt/awt_LoadLibrary.c

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@
4343
#define VERBOSE_AWT_DEBUG
4444
#endif
4545

46+
#define CHECK_EXCEPTION_FATAL(env, message) \
47+
if ((*env)->ExceptionCheck(env)) { \
48+
(*env)->ExceptionDescribe(env); \
49+
(*env)->FatalError(env, message); \
50+
}
51+
4652
static void *awtHandle = NULL;
4753

4854
typedef jint JNICALL JNI_OnLoad_type(JavaVM *vm, void *reserved);
@@ -61,16 +67,13 @@ JNIEXPORT jboolean JNICALL AWTIsHeadless() {
6167
env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
6268
graphicsEnvClass = (*env)->FindClass(env,
6369
"java/awt/GraphicsEnvironment");
64-
if (graphicsEnvClass == NULL) {
65-
return JNI_TRUE;
66-
}
70+
CHECK_EXCEPTION_FATAL(env, "FindClass java/awt/GraphicsEnvironment failed");
6771
headlessFn = (*env)->GetStaticMethodID(env,
6872
graphicsEnvClass, "isHeadless", "()Z");
69-
if (headlessFn == NULL) {
70-
return JNI_TRUE;
71-
}
73+
CHECK_EXCEPTION_FATAL(env, "GetStaticMethodID isHeadless failed");
7274
isHeadless = (*env)->CallStaticBooleanMethod(env, graphicsEnvClass,
7375
headlessFn);
76+
// If an exception occurred, we assume headless mode and carry on.
7477
if ((*env)->ExceptionCheck(env)) {
7578
(*env)->ExceptionClear(env);
7679
return JNI_TRUE;
@@ -79,12 +82,6 @@ JNIEXPORT jboolean JNICALL AWTIsHeadless() {
7982
return isHeadless;
8083
}
8184

82-
#define CHECK_EXCEPTION_FATAL(env, message) \
83-
if ((*env)->ExceptionCheck(env)) { \
84-
(*env)->ExceptionClear(env); \
85-
(*env)->FatalError(env, message); \
86-
}
87-
8885
/*
8986
* Pathnames to the various awt toolkits
9087
*/
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
import jdk.internal.org.objectweb.asm.ClassReader;
24+
import jdk.internal.org.objectweb.asm.ClassVisitor;
25+
import jdk.internal.org.objectweb.asm.ClassWriter;
26+
import jdk.internal.org.objectweb.asm.MethodVisitor;
27+
import jdk.internal.org.objectweb.asm.Opcodes;
28+
29+
import java.lang.instrument.ClassFileTransformer;
30+
import java.lang.instrument.Instrumentation;
31+
import java.security.ProtectionDomain;
32+
33+
/**
34+
* This agent removes the isHeadless method from java.awt.GraphicsEnvironment.
35+
*/
36+
public class HeadlessMalfunctionAgent {
37+
38+
public static void premain(String agentArgs, Instrumentation inst) {
39+
inst.addTransformer(new ClassFileTransformer() {
40+
41+
@Override
42+
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
43+
ProtectionDomain pd, byte[] cb) {
44+
if ("java/awt/GraphicsEnvironment".equals(className)) {
45+
System.out.println("Transforming java.awt.GraphicsEnvironment.");
46+
try {
47+
final ClassReader cr = new ClassReader(cb);
48+
final ClassWriter cw = new ClassWriter(cr, 0);
49+
cr.accept(new ClassVisitor(Opcodes.ASM9, cw) {
50+
51+
@Override
52+
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature,
53+
String[] exceptions) {
54+
if ("isHeadless".equals(name) && "()Z".equals(descriptor)) {
55+
System.out.println("isHeadless removed from java.awt.GraphicsEnvironment.");
56+
// WHACK! Remove the isHeadless method.
57+
return null;
58+
}
59+
return super.visitMethod(access, name, descriptor, signature, exceptions);
60+
}
61+
}, 0);
62+
return cw.toByteArray();
63+
} catch (Exception e) {
64+
e.printStackTrace();
65+
}
66+
}
67+
return null;
68+
}
69+
});
70+
}
71+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
import jdk.test.lib.JDKToolFinder;
25+
import jdk.test.lib.process.OutputAnalyzer;
26+
import jdk.test.lib.process.ProcessTools;
27+
28+
import java.nio.file.Files;
29+
import java.nio.file.Path;
30+
31+
/*
32+
* @test
33+
* @bug 8336382
34+
* @summary Test that in absence of isHeadless method, the JDK throws a meaningful error message.
35+
* @library /test/lib
36+
* @modules java.base/jdk.internal.org.objectweb.asm
37+
* @build HeadlessMalfunctionAgent
38+
* @run driver jdk.test.lib.helpers.ClassFileInstaller
39+
* HeadlessMalfunctionAgent
40+
* HeadlessMalfunctionAgent$1
41+
* HeadlessMalfunctionAgent$1$1
42+
* @run driver HeadlessMalfunctionTest
43+
*/
44+
public class HeadlessMalfunctionTest {
45+
46+
public static void main(String[] args) throws Exception {
47+
// Package agent
48+
Files.writeString(Path.of("MANIFEST.MF"), "Premain-Class: HeadlessMalfunctionAgent\n");
49+
final ProcessBuilder pbJar = new ProcessBuilder()
50+
.command(JDKToolFinder.getJDKTool("jar"), "cmf", "MANIFEST.MF", "agent.jar",
51+
"HeadlessMalfunctionAgent.class",
52+
"HeadlessMalfunctionAgent$1.class",
53+
"HeadlessMalfunctionAgent$1$1.class");
54+
ProcessTools.executeProcess(pbJar).shouldHaveExitValue(0);
55+
56+
// Run test
57+
final ProcessBuilder pbJava = ProcessTools.createTestJavaProcessBuilder(
58+
"--add-opens",
59+
"java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED",
60+
"-javaagent:agent.jar",
61+
"HeadlessMalfunctionTest$Runner"
62+
);
63+
final OutputAnalyzer output = ProcessTools.executeProcess(pbJava);
64+
// Unpatched JDK logs: "FATAL ERROR in native method: Could not allocate library name"
65+
output.shouldContain("FATAL ERROR in native method: GetStaticMethodID isHeadless failed");
66+
output.shouldNotHaveExitValue(0);
67+
}
68+
69+
public static class Runner {
70+
public static void main(String[] args) {
71+
System.out.println(java.awt.GraphicsEnvironment
72+
.getLocalGraphicsEnvironment()
73+
.getMaximumWindowBounds());
74+
}
75+
}
76+
}

0 commit comments

Comments
 (0)