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

Skip to content

Commit 9a5499b

Browse files
committed
#3705: Command-line arguments were not correctly decoded when the
terminal does not use UTF8. Now the code propagates the unicode string as far as possible, and avoids the conversion to char* which implicitely uses utf-8. Reviewed by Benjamin.
1 parent d3013ff commit 9a5499b

4 files changed

Lines changed: 35 additions & 25 deletions

File tree

Lib/test/test_cmd_line.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,12 @@ def test_run_code(self):
135135
self.exit_code('-c', 'pass'),
136136
0)
137137

138+
# Test handling of non-ascii data
139+
command = "assert(ord('\xe9') == 0xe9)"
140+
self.assertEqual(
141+
self.exit_code('-c', command),
142+
0)
143+
138144

139145
def test_main():
140146
test.support.run_unittest(CmdLineTest)

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ What's New in Python 3.0 release candiate 3?
1313
Core and Builtins
1414
-----------------
1515

16+
- Issue #3705: Command-line arguments were not correctly decoded when the
17+
terminal does not use UTF8.
18+
1619
Library
1720
-------
1821

Modules/main.c

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ Py_Main(int argc, wchar_t **argv)
287287
{
288288
int c;
289289
int sts;
290-
char *command = NULL;
290+
wchar_t *command = NULL;
291291
wchar_t *filename = NULL;
292292
wchar_t *module = NULL;
293293
FILE *fp = stdin;
@@ -299,7 +299,6 @@ Py_Main(int argc, wchar_t **argv)
299299
int version = 0;
300300
int saw_unbuffered_flag = 0;
301301
PyCompilerFlags cf;
302-
char *oldloc;
303302

304303
cf.cf_flags = 0;
305304

@@ -310,30 +309,19 @@ Py_Main(int argc, wchar_t **argv)
310309

311310
while ((c = _PyOS_GetOpt(argc, argv, PROGRAM_OPTS)) != EOF) {
312311
if (c == 'c') {
313-
size_t r1, r2;
314-
oldloc = setlocale(LC_ALL, NULL);
315-
setlocale(LC_ALL, "");
316-
r1 = wcslen(_PyOS_optarg);
317-
r2 = wcstombs(NULL, _PyOS_optarg, r1);
318-
if (r2 == (size_t) -1)
319-
Py_FatalError(
320-
"cannot convert character encoding of -c argument");
321-
if (r2 > r1)
322-
r1 = r2;
323-
r1 += 2;
312+
size_t len;
324313
/* -c is the last option; following arguments
325314
that look like options are left for the
326315
command to interpret. */
327-
command = (char *)malloc(r1);
316+
317+
len = wcslen(_PyOS_optarg) + 1 + 1;
318+
command = (wchar_t *)malloc(sizeof(wchar_t) * len);
328319
if (command == NULL)
329320
Py_FatalError(
330321
"not enough memory to copy -c argument");
331-
r2 = wcstombs(command, _PyOS_optarg, r1);
332-
if (r2 > r1-1)
333-
Py_FatalError(
334-
"not enough memory to copy -c argument");
335-
strcat(command, "\n");
336-
setlocale(LC_ALL, oldloc);
322+
wcscpy(command, _PyOS_optarg);
323+
command[len - 2] = '\n';
324+
command[len - 1] = 0;
337325
break;
338326
}
339327

@@ -543,8 +531,18 @@ Py_Main(int argc, wchar_t **argv)
543531
}
544532

545533
if (command) {
546-
sts = PyRun_SimpleStringFlags(command, &cf) != 0;
534+
PyObject *commandObj = PyUnicode_FromWideChar(
535+
command, wcslen(command));
547536
free(command);
537+
if (commandObj != NULL) {
538+
sts = PyRun_SimpleStringFlags(
539+
_PyUnicode_AsString(commandObj), &cf) != 0;
540+
}
541+
else {
542+
PyErr_Print();
543+
sts = 1;
544+
}
545+
Py_DECREF(commandObj);
548546
} else if (module) {
549547
sts = RunModule(module, 1);
550548
}

Python/import.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2793,6 +2793,7 @@ call_find_module(char *name, PyObject *path)
27932793
{
27942794
extern int fclose(FILE *);
27952795
PyObject *fob, *ret;
2796+
PyObject *pathobj;
27962797
struct filedescr *fdp;
27972798
char pathname[MAXPATHLEN+1];
27982799
FILE *fp = NULL;
@@ -2836,9 +2837,9 @@ call_find_module(char *name, PyObject *path)
28362837
fob = Py_None;
28372838
Py_INCREF(fob);
28382839
}
2839-
ret = Py_BuildValue("Os(ssi)",
2840-
fob, pathname, fdp->suffix, fdp->mode, fdp->type);
2841-
Py_DECREF(fob);
2840+
pathobj = PyUnicode_DecodeFSDefault(pathname);
2841+
ret = Py_BuildValue("NN(ssi)",
2842+
fob, pathobj, fdp->suffix, fdp->mode, fdp->type);
28422843
PyMem_FREE(found_encoding);
28432844

28442845
return ret;
@@ -2849,7 +2850,9 @@ imp_find_module(PyObject *self, PyObject *args)
28492850
{
28502851
char *name;
28512852
PyObject *path = NULL;
2852-
if (!PyArg_ParseTuple(args, "s|O:find_module", &name, &path))
2853+
if (!PyArg_ParseTuple(args, "es|O:find_module",
2854+
Py_FileSystemDefaultEncoding, &name,
2855+
&path))
28532856
return NULL;
28542857
return call_find_module(name, path);
28552858
}

0 commit comments

Comments
 (0)