Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0ad59d4

Browse files
committed
Issue #5604: non-ASCII characters in module name passed to
imp.find_module() were converted to UTF-8 while the path is converted to the default filesystem encoding, causing nonsense. Thanks to Andrew Svetlov. (This time to the right branch. Will block duplicate merge to 3.0.2.)
1 parent eaaec27 commit 0ad59d4

4 files changed

Lines changed: 117 additions & 16 deletions

File tree

Lib/test/test_imp.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import imp
2+
import locale
3+
import os
4+
import os.path
25
import sys
36
import unittest
47
from test import support
@@ -75,6 +78,74 @@ def test_issue3594(self):
7578
support.unlink(temp_mod_name + '.pyc')
7679
support.unlink(temp_mod_name + '.pyo')
7780

81+
def test_issue5604(self):
82+
# Test cannot cover imp.load_compiled function.
83+
# Martin von Loewis note what shared library cannot have non-ascii
84+
# character because init_xxx function cannot be compiled
85+
# and issue never happens for dynamic modules.
86+
# But sources modified to follow generic way for processing pathes.
87+
88+
locale_encoding = locale.getpreferredencoding()
89+
90+
# covers utf-8 and Windows ANSI code pages
91+
# one non-space symbol from every page
92+
# (http://en.wikipedia.org/wiki/Code_page)
93+
known_locales = {
94+
'utf-8' : b'\xe4',
95+
'cp1250' : b'\x8C',
96+
'cp1251' : b'\xc0',
97+
'cp1252' : b'\xc0',
98+
'cp1253' : b'\xc1',
99+
'cp1254' : b'\xc0',
100+
'cp1255' : b'\xe0',
101+
'cp1256' : b'\xe0',
102+
'cp1257' : b'\xc0',
103+
'cp1258' : b'\xc0',
104+
}
105+
106+
special_char = known_locales.get(locale_encoding)
107+
if special_char:
108+
encoded_char = special_char.decode(locale_encoding)
109+
temp_mod_name = 'test_imp_helper_' + encoded_char
110+
test_package_name = 'test_imp_helper_package_' + encoded_char
111+
init_file_name = os.path.join(test_package_name, '__init__.py')
112+
try:
113+
with open(temp_mod_name + '.py', 'w') as file:
114+
file.write('a = 1\n')
115+
file, filename, info = imp.find_module(temp_mod_name)
116+
self.assertNotEquals(None, file)
117+
self.assertTrue(filename[:-3].endswith(temp_mod_name))
118+
self.assertEquals('.py', info[0])
119+
self.assertEquals('U', info[1])
120+
self.assertEquals(imp.PY_SOURCE, info[2])
121+
122+
mod = imp.load_module(temp_mod_name, file, filename, info)
123+
self.assertEquals(1, mod.a)
124+
file.close()
125+
126+
mod = imp.load_source(temp_mod_name, temp_mod_name + '.py')
127+
self.assertEquals(1, mod.a)
128+
129+
mod = imp.load_compiled(temp_mod_name, temp_mod_name + '.pyc')
130+
self.assertEquals(1, mod.a)
131+
132+
if not os.path.exists(test_package_name):
133+
os.mkdir(test_package_name)
134+
with open(init_file_name, 'w') as file:
135+
file.write('b = 2\n')
136+
package = imp.load_package(test_package_name, test_package_name)
137+
self.assertEquals(2, package.b)
138+
finally:
139+
support.unlink(temp_mod_name + '.py')
140+
support.unlink(temp_mod_name + '.pyc')
141+
support.unlink(temp_mod_name + '.pyo')
142+
143+
support.unlink(init_file_name + '.py')
144+
support.unlink(init_file_name + '.pyc')
145+
support.unlink(init_file_name + '.pyo')
146+
support.rmtree(test_package_name)
147+
148+
78149
def test_reload(self):
79150
import marshal
80151
imp.reload(marshal)

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,7 @@ Nathan Sullivan
688688
Mark Summerfield
689689
Hisao Suzuki
690690
Kalle Svensson
691+
Andrew Svetlov
691692
Paul Swartz
692693
Thenault Sylvain
693694
Geoff Talvola

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ What's New in Python 3.1 alpha 2?
1212
Core and Builtins
1313
-----------------
1414

15+
- Issue #5604: non-ASCII characters in module name passed to
16+
imp.find_module() were converted to UTF-8 while the path is
17+
converted to the default filesystem encoding, causing nonsense.
18+
1519
- Issue #5126: str.isprintable() returned False for space characters.
1620

1721
- Issue #4688: Add a heuristic so that tuples and dicts containing only

Python/import.c

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3040,15 +3040,20 @@ imp_load_compiled(PyObject *self, PyObject *args)
30403040
PyObject *fob = NULL;
30413041
PyObject *m;
30423042
FILE *fp;
3043-
if (!PyArg_ParseTuple(args, "ss|O:load_compiled",
3044-
&name, &pathname, &fob))
3043+
if (!PyArg_ParseTuple(args, "ses|O:load_compiled",
3044+
&name,
3045+
Py_FileSystemDefaultEncoding, &pathname,
3046+
&fob))
30453047
return NULL;
30463048
fp = get_file(pathname, fob, "rb");
3047-
if (fp == NULL)
3049+
if (fp == NULL) {
3050+
PyMem_Free(pathname);
30483051
return NULL;
3052+
}
30493053
m = load_compiled_module(name, pathname, fp);
30503054
if (fob == NULL)
30513055
fclose(fp);
3056+
PyMem_Free(pathname);
30523057
return m;
30533058
}
30543059

@@ -3062,15 +3067,20 @@ imp_load_dynamic(PyObject *self, PyObject *args)
30623067
PyObject *fob = NULL;
30633068
PyObject *m;
30643069
FILE *fp = NULL;
3065-
if (!PyArg_ParseTuple(args, "ss|O:load_dynamic",
3066-
&name, &pathname, &fob))
3070+
if (!PyArg_ParseTuple(args, "ses|O:load_dynamic",
3071+
&name,
3072+
Py_FileSystemDefaultEncoding, &pathname,
3073+
&fob))
30673074
return NULL;
30683075
if (fob) {
30693076
fp = get_file(pathname, fob, "r");
3070-
if (fp == NULL)
3077+
if (fp == NULL) {
3078+
PyMem_Free(pathname);
30713079
return NULL;
3080+
}
30723081
}
30733082
m = _PyImport_LoadDynamicModule(name, pathname, fp);
3083+
PyMem_Free(pathname);
30743084
return m;
30753085
}
30763086

@@ -3084,12 +3094,16 @@ imp_load_source(PyObject *self, PyObject *args)
30843094
PyObject *fob = NULL;
30853095
PyObject *m;
30863096
FILE *fp;
3087-
if (!PyArg_ParseTuple(args, "ss|O:load_source",
3088-
&name, &pathname, &fob))
3097+
if (!PyArg_ParseTuple(args, "ses|O:load_source",
3098+
&name,
3099+
Py_FileSystemDefaultEncoding, &pathname,
3100+
&fob))
30893101
return NULL;
30903102
fp = get_file(pathname, fob, "r");
3091-
if (fp == NULL)
3103+
if (fp == NULL) {
3104+
PyMem_Free(pathname);
30923105
return NULL;
3106+
}
30933107
m = load_source_module(name, pathname, fp);
30943108
if (fob == NULL)
30953109
fclose(fp);
@@ -3102,13 +3116,15 @@ imp_load_module(PyObject *self, PyObject *args)
31023116
char *name;
31033117
PyObject *fob;
31043118
char *pathname;
3119+
PyObject * ret;
31053120
char *suffix; /* Unused */
31063121
char *mode;
31073122
int type;
31083123
FILE *fp;
31093124

3110-
if (!PyArg_ParseTuple(args, "sOs(ssi):load_module",
3111-
&name, &fob, &pathname,
3125+
if (!PyArg_ParseTuple(args, "sOes(ssi):load_module",
3126+
&name, &fob,
3127+
Py_FileSystemDefaultEncoding, &pathname,
31123128
&suffix, &mode, &type))
31133129
return NULL;
31143130
if (*mode) {
@@ -3119,27 +3135,36 @@ imp_load_module(PyObject *self, PyObject *args)
31193135
if (!(*mode == 'r' || *mode == 'U') || strchr(mode, '+')) {
31203136
PyErr_Format(PyExc_ValueError,
31213137
"invalid file open mode %.200s", mode);
3138+
PyMem_Free(pathname);
31223139
return NULL;
31233140
}
31243141
}
31253142
if (fob == Py_None)
31263143
fp = NULL;
31273144
else {
31283145
fp = get_file(NULL, fob, mode);
3129-
if (fp == NULL)
3146+
if (fp == NULL) {
3147+
PyMem_Free(pathname);
31303148
return NULL;
3131-
}
3132-
return load_module(name, fp, pathname, type, NULL);
3149+
}
3150+
}
3151+
ret = load_module(name, fp, pathname, type, NULL);
3152+
PyMem_Free(pathname);
3153+
return ret;
31333154
}
31343155

31353156
static PyObject *
31363157
imp_load_package(PyObject *self, PyObject *args)
31373158
{
31383159
char *name;
31393160
char *pathname;
3140-
if (!PyArg_ParseTuple(args, "ss:load_package", &name, &pathname))
3161+
PyObject * ret;
3162+
if (!PyArg_ParseTuple(args, "ses:load_package",
3163+
&name, Py_FileSystemDefaultEncoding, &pathname))
31413164
return NULL;
3142-
return load_package(name, pathname);
3165+
ret = load_package(name, pathname);
3166+
PyMem_Free(pathname);
3167+
return ret;
31433168
}
31443169

31453170
static PyObject *

0 commit comments

Comments
 (0)