mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
8349254: Disable "best-fit" mapping on Windows environment variables
Reviewed-by: jlu, jpai
This commit is contained in:
parent
32dc41c9f7
commit
642816538f
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2025, 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
|
||||
@ -83,6 +83,9 @@ static jboolean relaunch = JNI_FALSE;
|
||||
* Prototypes for internal functions.
|
||||
*/
|
||||
static jboolean expand(JLI_List args, const char *str, const char *var_name);
|
||||
#ifdef _WIN32
|
||||
static char * winGetEnv(const char * var_name);
|
||||
#endif
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JLI_InitArgProcessing(jboolean hasJavaArgs, jboolean disableArgFile) {
|
||||
@ -465,8 +468,6 @@ int isTerminalOpt(char *arg) {
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
JLI_AddArgsFromEnvVar(JLI_List args, const char *var_name) {
|
||||
char *env = getenv(var_name);
|
||||
|
||||
if (firstAppArgIndex == 0) {
|
||||
// Not 'java', return
|
||||
return JNI_FALSE;
|
||||
@ -476,12 +477,25 @@ JLI_AddArgsFromEnvVar(JLI_List args, const char *var_name) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if (NULL == env) {
|
||||
return JNI_FALSE;
|
||||
#ifdef _WIN32
|
||||
char *env = winGetEnv(var_name);
|
||||
#else
|
||||
char *env = getenv(var_name);
|
||||
#endif
|
||||
|
||||
jboolean ret = JNI_FALSE;
|
||||
|
||||
if (NULL != env) {
|
||||
JLI_ReportMessage(ARG_INFO_ENVVAR, var_name, env);
|
||||
ret = expand(args, env, var_name);
|
||||
}
|
||||
|
||||
JLI_ReportMessage(ARG_INFO_ENVVAR, var_name, env);
|
||||
return expand(args, env, var_name);
|
||||
#ifdef _WIN32
|
||||
if (NULL != env) {
|
||||
JLI_MemFree(env);
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -583,6 +597,39 @@ static jboolean expand(JLI_List args, const char *str, const char *var_name) {
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
/*
|
||||
* getenv() without best-fit mapping. The return value is constructed by converting
|
||||
* _wgetenv()'s return encoded in wide char to ANSI code page without best-fit map.
|
||||
*/
|
||||
static char * winGetEnv(const char * var_name) {
|
||||
char * mbEnvVar = NULL;
|
||||
|
||||
int wcCount = MultiByteToWideChar(CP_ACP, 0, var_name, -1, NULL, 0);
|
||||
if (wcCount > 0) {
|
||||
LPWSTR wcVarName = JLI_MemAlloc(wcCount * sizeof(wchar_t));
|
||||
if (MultiByteToWideChar(CP_ACP, 0, var_name, -1, wcVarName, wcCount) != 0) {
|
||||
LPWSTR wcEnvVar = _wgetenv(wcVarName);
|
||||
if (wcEnvVar != NULL) {
|
||||
int mbSize = WideCharToMultiByte(CP_ACP,
|
||||
WC_NO_BEST_FIT_CHARS | WC_COMPOSITECHECK | WC_DEFAULTCHAR,
|
||||
wcEnvVar, -1, NULL, 0, NULL, NULL);
|
||||
if (mbSize > 0) {
|
||||
mbEnvVar = JLI_MemAlloc(mbSize);
|
||||
if (WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS | WC_COMPOSITECHECK | WC_DEFAULTCHAR,
|
||||
wcEnvVar, -1, mbEnvVar, mbSize, NULL, NULL) == 0) {
|
||||
JLI_MemFree(mbEnvVar);
|
||||
mbEnvVar = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
JLI_MemFree(wcVarName);
|
||||
}
|
||||
return mbEnvVar;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_ARGFILE
|
||||
/*
|
||||
* Stand-alone sanity test, build with following command line
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2025, 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
|
||||
@ -28,46 +28,6 @@
|
||||
#include "jni_util.h"
|
||||
#include <windows.h>
|
||||
|
||||
static jstring
|
||||
environmentBlock9x(JNIEnv *env)
|
||||
{
|
||||
int i;
|
||||
jmethodID String_init_ID;
|
||||
jbyteArray bytes;
|
||||
jbyte *blockA;
|
||||
jclass string_class;
|
||||
|
||||
string_class = JNU_ClassString(env);
|
||||
CHECK_NULL_RETURN(string_class, NULL);
|
||||
|
||||
String_init_ID =
|
||||
(*env)->GetMethodID(env, string_class, "<init>", "([B)V");
|
||||
CHECK_NULL_RETURN(String_init_ID, NULL);
|
||||
|
||||
blockA = (jbyte *) GetEnvironmentStringsA();
|
||||
if (blockA == NULL) {
|
||||
/* Both GetEnvironmentStringsW and GetEnvironmentStringsA
|
||||
* failed. Out of memory is our best guess. */
|
||||
JNU_ThrowOutOfMemoryError(env, "GetEnvironmentStrings failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Don't search for "\0\0", since an empty environment block may
|
||||
legitimately consist of a single "\0". */
|
||||
for (i = 0; blockA[i];)
|
||||
while (blockA[i++])
|
||||
;
|
||||
|
||||
if ((bytes = (*env)->NewByteArray(env, i)) == NULL) {
|
||||
FreeEnvironmentStringsA(blockA);
|
||||
return NULL;
|
||||
}
|
||||
(*env)->SetByteArrayRegion(env, bytes, 0, i, blockA);
|
||||
FreeEnvironmentStringsA(blockA);
|
||||
return (*env)->NewObject(env, string_class,
|
||||
String_init_ID, bytes);
|
||||
}
|
||||
|
||||
/* Returns a Windows style environment block, discarding final trailing NUL */
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_java_lang_ProcessEnvironment_environmentBlock(JNIEnv *env, jclass klass)
|
||||
@ -75,8 +35,11 @@ Java_java_lang_ProcessEnvironment_environmentBlock(JNIEnv *env, jclass klass)
|
||||
int i;
|
||||
jstring envblock;
|
||||
jchar *blockW = (jchar *) GetEnvironmentStringsW();
|
||||
if (blockW == NULL)
|
||||
return environmentBlock9x(env);
|
||||
if (blockW == NULL) {
|
||||
/* Out of memory is our best guess. */
|
||||
JNU_ThrowOutOfMemoryError(env, "GetEnvironmentStrings failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Don't search for "\u0000\u0000", since an empty environment
|
||||
block may legitimately consist of a single "\u0000". */
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2024, 2025, 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
|
||||
@ -23,9 +23,10 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8337506
|
||||
* @summary Verify Command Line arguments are not mapped with
|
||||
* "best-fit" mappings on Windows
|
||||
* @bug 8337506 8349254
|
||||
* @summary Verify command line arguments, including ones from
|
||||
* "JDK_JAVA_OPTIONS" environment variables are not mapped
|
||||
* with "best-fit" mappings on Windows
|
||||
* @requires (os.family == "windows")
|
||||
* @library /test/lib
|
||||
* @run junit DisableBestFitMappingTest
|
||||
@ -34,9 +35,9 @@ import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
@ -49,10 +50,12 @@ public class DisableBestFitMappingTest {
|
||||
Charset.forName(System.getProperty("native.encoding")).newEncoder();
|
||||
private static final String REPLACEMENT =
|
||||
NATIVE_ENC.charset().decode(ByteBuffer.wrap(NATIVE_ENC.replacement())).toString();
|
||||
private static final String TEST_ENV_VAR = "JDK_JAVA_OPTIONS";
|
||||
private static final String TEST_PROP_KEY = "testProp";
|
||||
private static final int EXIT_SUCCESS = 0;
|
||||
private static final int EXIT_FAILURE = -1;
|
||||
|
||||
static Stream<Arguments> CMD_ARGS() {
|
||||
static Stream<Arguments> TEST_ARGS() {
|
||||
return Stream.of(
|
||||
Arguments.of("aa\uff02 \uff02bb", "aa" + REPLACEMENT + " " + REPLACEMENT + "bb"),
|
||||
Arguments.of("aa\uff01bb", "aa" + REPLACEMENT + "bb"),
|
||||
@ -61,23 +64,41 @@ public class DisableBestFitMappingTest {
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("CMD_ARGS")
|
||||
void testDisableBestFitMapping(String arg, String expected) throws Exception {
|
||||
@MethodSource("TEST_ARGS")
|
||||
void testCommandLineArgument(String arg, String expected) throws Exception {
|
||||
// Only execute if the arg cannot be encoded
|
||||
assumeFalse(NATIVE_ENC.canEncode(arg),
|
||||
"native.encoding (%s) can encode the argument '%s'. Test ignored."
|
||||
.formatted(NATIVE_ENC.charset(), arg));
|
||||
|
||||
var result= ProcessTools.executeTestJava(
|
||||
DisableBestFitMappingTest.class.getSimpleName(), arg, expected);
|
||||
var result = ProcessTools.executeTestJava(
|
||||
DisableBestFitMappingTest.class.getSimpleName(), expected, arg);
|
||||
result.asLines().forEach(System.out::println);
|
||||
assertEquals(EXIT_SUCCESS, result.getExitValue(),
|
||||
"Disabling best-fit mapping failed");
|
||||
"Command line argument mapping failed");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("TEST_ARGS")
|
||||
void testEnvironmentVariable(String propVal, String expected) throws Exception {
|
||||
// Only execute if the arg from the environment variable cannot be encoded
|
||||
assumeFalse(NATIVE_ENC.canEncode(propVal),
|
||||
"native.encoding (%s) can encode the argument '%s'. Test ignored."
|
||||
.formatted(NATIVE_ENC.charset(), propVal));
|
||||
|
||||
var pb = ProcessTools.createTestJavaProcessBuilder(
|
||||
DisableBestFitMappingTest.class.getSimpleName(), expected);
|
||||
pb.environment().put(TEST_ENV_VAR, "-D" + TEST_PROP_KEY + "=\"" + propVal + "\"");
|
||||
var result = ProcessTools.executeProcess(pb);
|
||||
result.asLines().forEach(System.out::println);
|
||||
assertEquals(EXIT_SUCCESS, result.getExitValue(),
|
||||
"Argument from JDK_JAVA_OPTIONS mapping failed");
|
||||
}
|
||||
|
||||
public static void main(String... args) {
|
||||
System.out.println(args[0]);
|
||||
System.out.println(args[1]);
|
||||
System.exit(args[0].equals(args[1]) ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
var expected = args[0];
|
||||
var actual = args.length > 1 ? args[1] : System.getProperty(TEST_PROP_KEY);
|
||||
System.out.printf("expected: %s, actual: %s%n", expected, actual);
|
||||
System.exit(expected.equals(actual) ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user