Skip to content
Closed
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
9 changes: 9 additions & 0 deletions Lib/test/test_cmd_line_script.py
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,15 @@ def test_issue20884(self):
self.assertEqual(b"", out)
self.assertEqual(b"", err)

def test_issue32381(self):

@aeros aeros Jul 11, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Instead of test_issue32381, I would recommend renaming the method to something more descriptive of the issue itself, such as test_windows_non_ascii_path.

Suggested change
def test_issue32381(self):
# tests bpo-32381
def test_windows_non_ascii_path(self):

# On Windows, a .pyc file with a non-ASCII path could not be reopened.
with support.temp_dir() as script_dir:
script_name = _make_test_script(script_dir, 'ߢߢscript')
py_compile.compile(script_name, doraise=True)
pyc_file = support.make_legacy_pyc(script_name)
self._check_script(pyc_file, pyc_file, pyc_file, script_dir, None,
importlib.machinery.SourcelessFileLoader)

@contextlib.contextmanager
def setup_test_pkg(self, *args):
with support.temp_dir() as script_dir, \
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
``.pyc`` files with non-ASCII paths can now be reopened on Windows.
13 changes: 6 additions & 7 deletions Python/fileutils.c
Original file line number Diff line number Diff line change
Expand Up @@ -1365,7 +1365,7 @@ _Py_wfopen(const wchar_t *path, const wchar_t *mode)
return f;
}

/* Wrapper to fopen().
/* Open a file.

The file descriptor is created non-inheritable.

Expand All @@ -1377,14 +1377,13 @@ _Py_fopen(const char *pathname, const char *mode)
return NULL;
}

FILE *f = fopen(pathname, mode);
if (f == NULL)
return NULL;
if (make_non_inheritable(fileno(f)) < 0) {
fclose(f);
PyObject *path = PyUnicode_DecodeFSDefault(pathname);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The change should be conditionally defined just for Windows. In the Unix world a path is just a sequence of bytes, with only ASCII slash and null reserved.

@aeros aeros Jul 11, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Agreed with @eryksun. Performing the change across all OS's wouldn't be necessary, since this is a windows specific issue.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thank you, @eryksun, for the comment. One issue is the fact that _Py_fopen_obj() calls set_inheritable() with raise == 1, but _Py_fopen() currently uses make_non_inheritable(), which calls set_inheritable() with raise == 0. I think, for non-Windows, the make_non_inheritable() call in _Py_fopen() should be replaced with set_inheritable(fileno(f), 0, 1, NULL).

@eryksun eryksun Jul 11, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It's a problem that _Py_fopen doesn't require the GIL to be held, but _Py_fopen_obj requires it. It may be better to modify PyRun_SimpleFileExFlags instead of tinkering with _Py_fopen.

(Another issue is with pymain_run_startup, which gets the ANSI encoded PYTHONSTARTUP filename via _Py_GetEnv and passes it to _Py_fopen. This is a problem for users with arbitrary Unicode usernames if the startup file is in their profile directory. In Windows we need to pass the filename from the native wide-character environment to _Py_wfopen.)

if (path == NULL) {
return NULL;
}
return f;
FILE *ret = _Py_fopen_obj(path, mode);
Py_DECREF(path);
return ret;
}

/* Open a file. Call _wfopen() on Windows, or encode the path to the filesystem
Expand Down