Skip to content

Commit 791cd97

Browse files
Use the system encoding to generate the *.argfile (#458)
1 parent de77ff3 commit 791cd97

File tree

2 files changed

+81
-11
lines changed

2 files changed

+81
-11
lines changed

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchRequestHandler.java

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2018-2021 Microsoft Corporation and others.
2+
* Copyright (c) 2018-2022 Microsoft Corporation and others.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -16,6 +16,7 @@
1616
import java.net.MalformedURLException;
1717
import java.net.URISyntaxException;
1818
import java.nio.charset.Charset;
19+
import java.nio.charset.CharsetEncoder;
1920
import java.nio.file.Path;
2021
import java.nio.file.Paths;
2122
import java.util.ArrayList;
@@ -134,11 +135,50 @@ protected CompletableFuture<Response> handleLaunchCommand(Arguments arguments, R
134135
}
135136
} else if (launchArguments.shortenCommandLine == ShortenApproach.ARGFILE) {
136137
try {
137-
Path tempfile = LaunchUtils.generateArgfile(launchArguments.vmArgs, launchArguments.classPaths, launchArguments.modulePaths);
138-
launchArguments.vmArgs = " \"@" + tempfile.toAbsolutePath().toString() + "\"";
139-
launchArguments.classPaths = new String[0];
140-
launchArguments.modulePaths = new String[0];
141-
context.setArgsfile(tempfile);
138+
/**
139+
* See the JDK spec https://docs.oracle.com/en/java/javase/18/docs/specs/man/java.html#java-command-line-argument-files.
140+
* The argument file must contain only ASCII characters or characters in system default encoding that's ASCII friendly.
141+
*/
142+
Charset systemCharset = LaunchUtils.getSystemCharset();
143+
CharsetEncoder encoder = systemCharset.newEncoder();
144+
String vmArgsForShorten = null;
145+
String[] classPathsForShorten = null;
146+
String[] modulePathsForShorten = null;
147+
if (StringUtils.isNotBlank(launchArguments.vmArgs)) {
148+
if (!encoder.canEncode(launchArguments.vmArgs)) {
149+
logger.warning(String.format("Cannot generate the 'vmArgs' argument into the argfile because it contains characters "
150+
+ "that cannot be encoded in the system charset '%s'.", systemCharset.displayName()));
151+
} else {
152+
vmArgsForShorten = launchArguments.vmArgs;
153+
}
154+
}
155+
156+
if (ArrayUtils.isNotEmpty(launchArguments.classPaths)) {
157+
if (!encoder.canEncode(String.join(File.pathSeparator, launchArguments.classPaths))) {
158+
logger.warning(String.format("Cannot generate the '-cp' argument into the argfile because it contains characters "
159+
+ "that cannot be encoded in the system charset '%s'.", systemCharset.displayName()));
160+
} else {
161+
classPathsForShorten = launchArguments.classPaths;
162+
}
163+
}
164+
165+
if (ArrayUtils.isNotEmpty(launchArguments.modulePaths)) {
166+
if (!encoder.canEncode(String.join(File.pathSeparator, launchArguments.modulePaths))) {
167+
logger.warning(String.format("Cannot generate the '--module-path' argument into the argfile because it contains characters "
168+
+ "that cannot be encoded in the system charset '%s'.", systemCharset.displayName()));
169+
} else {
170+
modulePathsForShorten = launchArguments.modulePaths;
171+
}
172+
}
173+
174+
if (vmArgsForShorten != null || classPathsForShorten != null || modulePathsForShorten != null) {
175+
Path tempfile = LaunchUtils.generateArgfile(vmArgsForShorten, classPathsForShorten, modulePathsForShorten, systemCharset);
176+
launchArguments.vmArgs = (vmArgsForShorten == null ? launchArguments.vmArgs : "")
177+
+ " \"@" + tempfile.toAbsolutePath().toString() + "\"";
178+
launchArguments.classPaths = (classPathsForShorten == null ? launchArguments.classPaths : new String[0]);
179+
launchArguments.modulePaths = (modulePathsForShorten == null ? launchArguments.modulePaths : new String[0]);
180+
context.setArgsfile(tempfile);
181+
}
142182
} catch (IOException e) {
143183
logger.log(Level.SEVERE, String.format("Failed to create a temp argfile: %s", e.toString()), e);
144184
}

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchUtils.java

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import java.io.IOException;
1818
import java.io.InputStreamReader;
1919
import java.math.BigInteger;
20+
import java.nio.charset.Charset;
2021
import java.nio.file.Files;
2122
import java.nio.file.Path;
2223
import java.nio.file.Paths;
@@ -36,16 +37,45 @@
3637
import java.util.logging.Logger;
3738
import java.util.stream.Collectors;
3839

39-
import com.microsoft.java.debug.core.Configuration;
40-
import com.microsoft.java.debug.core.adapter.AdapterUtils;
41-
4240
import org.apache.commons.lang3.ArrayUtils;
4341
import org.apache.commons.lang3.StringUtils;
4442
import org.apache.commons.lang3.SystemUtils;
4543

44+
import com.microsoft.java.debug.core.Configuration;
45+
import com.microsoft.java.debug.core.adapter.AdapterUtils;
46+
4647
public class LaunchUtils {
4748
private static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME);
4849
private static Set<Path> tempFilesInUse = new HashSet<>();
50+
private static final Charset SYSTEM_CHARSET;
51+
52+
static {
53+
Charset result = null;
54+
try {
55+
// JEP 400: Java 17+ populates this system property.
56+
String encoding = System.getProperty("native.encoding"); //$NON-NLS-1$
57+
if (encoding != null && !encoding.isBlank()) {
58+
result = Charset.forName(encoding);
59+
} else {
60+
// JVM internal property, works on older JVM's too
61+
encoding = System.getProperty("sun.jnu.encoding"); //$NON-NLS-1$
62+
if (encoding != null && !encoding.isBlank()) {
63+
result = Charset.forName(encoding);
64+
}
65+
}
66+
} catch (Exception e) {
67+
logger.log(Level.SEVERE, "Error occurs during resolving system encoding", e);
68+
}
69+
if (result == null) {
70+
// This is always UTF-8 on Java >= 18.
71+
result = Charset.defaultCharset();
72+
}
73+
SYSTEM_CHARSET = result;
74+
}
75+
76+
public static Charset getSystemCharset() {
77+
return SYSTEM_CHARSET;
78+
}
4979

5080
/**
5181
* Generate the classpath parameters to a temporary classpath.jar.
@@ -82,7 +112,7 @@ public static synchronized Path generateClasspathJar(String[] classPaths) throws
82112
* @return the file path of the generated argfile
83113
* @throws IOException Some errors occur during generating the argfile
84114
*/
85-
public static synchronized Path generateArgfile(String vmArgs, String[] classPaths, String[] modulePaths) throws IOException {
115+
public static synchronized Path generateArgfile(String vmArgs, String[] classPaths, String[] modulePaths, Charset encoding) throws IOException {
86116
String argfile = "";
87117
if (StringUtils.isNotBlank(vmArgs)) {
88118
argfile += vmArgs;
@@ -100,7 +130,7 @@ public static synchronized Path generateArgfile(String vmArgs, String[] classPat
100130
String baseName = "cp_" + getMd5(argfile);
101131
cleanupTempFiles(baseName, ".argfile");
102132
Path tempfile = createTempFile(baseName, ".argfile");
103-
Files.write(tempfile, argfile.getBytes());
133+
Files.writeString(tempfile, argfile, encoding);
104134
lockTempLaunchFile(tempfile);
105135

106136
return tempfile;

0 commit comments

Comments
 (0)