Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.management.ManagementFactory;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.NoSuchFileException;
Expand Down Expand Up @@ -80,6 +86,56 @@ public static void main(String[] args) {
new GraalPythonMain().launch(args);
}

@Override
protected String decodeArgument(byte[] argument) {
Charset charset = Charset.defaultCharset();
String decoded = new String(argument, charset);
if (decoded.indexOf('\uFFFD') < 0) {
return decoded;
}
return decodeArgument(argument, charset);
}

/*
* Match documented Unix sys.argv behavior:
* https://docs.python.org/3.12/library/sys.html#sys.argv
* "When you need original bytes, you can get it by `[os.fsencode(arg) for arg in sys.argv]`."
*/
private static String decodeArgument(byte[] argument, Charset charset) {
CharsetDecoder decoder = charset.newDecoder().onMalformedInput(CodingErrorAction.REPORT).onUnmappableCharacter(CodingErrorAction.REPORT);
StringBuilder builder = new StringBuilder(argument.length);
ByteBuffer in = ByteBuffer.wrap(argument);
CharBuffer out = CharBuffer.allocate(Math.max(1, (int) Math.ceil(argument.length * decoder.maxCharsPerByte())));
while (true) {
CoderResult result = decoder.decode(in, out, true);
appendDecodedChars(builder, out);
if (result.isUnderflow()) {
break;
} else if (result.isOverflow()) {
continue;
} else if (result.isError()) {
int errorLength = result.length();
for (int i = 0; i < errorLength && in.hasRemaining(); i++) {
builder.append((char) (0xDC00 + (in.get() & 0xff)));
}
}
}
while (true) {
CoderResult result = decoder.flush(out);
appendDecodedChars(builder, out);
if (result.isUnderflow()) {
break;
}
}
return builder.toString();
}

private static void appendDecodedChars(StringBuilder builder, CharBuffer out) {
out.flip();
builder.append(out);
out.clear();
}

private static final String LANGUAGE_ID = "python";

private static final String J_PYENVCFG = "pyvenv.cfg";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2018, 2025, Oracle and/or its affiliates.
# Copyright (c) 2018, 2026, Oracle and/or its affiliates.
# Copyright (C) 1996-2017 Python Software Foundation
#
# Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
Expand Down Expand Up @@ -75,6 +75,17 @@ def test_check_output(self):
[sys.executable, "-c", "print('BDFL')"])
self.assertIn(b'BDFL', output)

@unittest.skipIf(sys.platform == 'win32', "POSIX argv bytes specific")
def test_surrogateescape_non_utf8_argv(self):
code = (
"import os, sys; "
"assert os.fsencode(sys.argv[-1]) == b'\\x8av'; "
"print(repr(sys.argv[-1]))"
)
cmd = f"{shlex.quote(sys.executable)} -c {shlex.quote(code)} \"$(printf '\\212v')\""
output = subprocess.check_output(cmd, shell=True, stderr=subprocess.PIPE, text=True)
self.assertEqual("'\\udc8av'\n", output)

def test_check_output_nonzero(self):
# check_call() function with non-zero return code
with self.assertRaises(subprocess.CalledProcessError) as c:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
Expand Down Expand Up @@ -1006,9 +1006,9 @@ public Void visit(TypeVarTuple node) {
return null;
}

/*-
// Validation of sequences
*/
/*-
// Validation of sequences
*/

// Equivalent of validate_stmts
private void validateStmts(StmtTy[] stmts) {
Expand Down
Loading