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

Skip to content

Commit 2e71d01

Browse files
author
Victor Stinner
committed
Merged revisions 81250-81253 via svnmerge from
svn+ssh://[email protected]/python/branches/py3k ........ r81250 | victor.stinner | 2010-05-17 03:13:37 +0200 (lun., 17 mai 2010) | 2 lines Issue #6697: Fix a crash if code of "python -c code" contains surrogates ........ r81251 | victor.stinner | 2010-05-17 03:26:01 +0200 (lun., 17 mai 2010) | 3 lines PyObject_Dump() encodes unicode objects to utf8 with backslashreplace (instead of strict) error handler to escape surrogates ........ r81252 | victor.stinner | 2010-05-17 10:58:51 +0200 (lun., 17 mai 2010) | 6 lines handle_system_exit() flushs files to warranty the output order PyObject_Print() writes into the C object stderr, whereas PySys_WriteStderr() writes into the Python object sys.stderr. Each object has its own buffer, so call sys.stderr.flush() and fflush(stderr). ........ r81253 | victor.stinner | 2010-05-17 11:33:42 +0200 (lun., 17 mai 2010) | 6 lines Fix refleak in internal_print() introduced by myself in r81251 _PyUnicode_AsDefaultEncodedString() uses a magical PyUnicode attribute to automatically destroy PyUnicode_EncodeUTF8() result when the unicode string is destroyed. ........
1 parent 6763514 commit 2e71d01

5 files changed

Lines changed: 58 additions & 6 deletions

File tree

Lib/test/test_sys.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ def test_excepthook(self):
7979
# Python/pythonrun.c::PyErr_PrintEx() is tricky.
8080

8181
def test_exit(self):
82+
import subprocess
83+
8284
self.assertRaises(TypeError, sys.exit, 42, 42)
8385

8486
# call without argument
@@ -133,11 +135,29 @@ def test_exit(self):
133135
self.fail("no exception")
134136

135137
# test that the exit machinery handles SystemExits properly
136-
import subprocess
137138
rc = subprocess.call([sys.executable, "-c",
138139
"raise SystemExit(47)"])
139140
self.assertEqual(rc, 47)
140141

142+
def check_exit_message(code, expected):
143+
process = subprocess.Popen([sys.executable, "-c", code],
144+
stderr=subprocess.PIPE)
145+
stdout, stderr = process.communicate()
146+
self.assertEqual(process.returncode, 1)
147+
self.assertTrue(stderr.startswith(expected), stderr)
148+
149+
# test that stderr buffer if flushed before the exit message is written
150+
# into stderr
151+
check_exit_message(
152+
r'import sys; sys.stderr.write("unflushed,"); sys.exit("message")',
153+
b"unflushed,message")
154+
155+
# test that the exit message is written with backslashreplace error
156+
# handler to stderr
157+
check_exit_message(
158+
r'import sys; sys.exit("surrogates:\uDCFF")',
159+
b"surrogates:\\udcff")
160+
141161
def test_getdefaultencoding(self):
142162
self.assertRaises(TypeError, sys.getdefaultencoding, 42)
143163
# can't check more than the type, as the user might have changed it
@@ -403,6 +423,24 @@ def __hash__(self):
403423

404424
self.assertRaises(TypeError, sys.intern, S("abc"))
405425

426+
def test_main_invalid_unicode(self):
427+
import locale
428+
non_decodable = b"\xff"
429+
encoding = locale.getpreferredencoding()
430+
try:
431+
non_decodable.decode(encoding)
432+
except UnicodeDecodeError:
433+
pass
434+
else:
435+
self.skipTest('%r is decodable with encoding %s'
436+
% (non_decodable, encoding))
437+
code = b'print("' + non_decodable + b'")'
438+
p = subprocess.Popen([sys.executable, "-c", code], stderr=subprocess.PIPE)
439+
stdout, stderr = p.communicate()
440+
self.assertEqual(p.returncode, 1)
441+
self.assert_(stderr.startswith(b"UnicodeEncodeError: "
442+
b"'utf-8' codec can't encode character '\\udcff' in "
443+
b"position 7: surrogates not allowed"), stderr)
406444

407445
def test_sys_flags(self):
408446
self.assertTrue(sys.flags)

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ What's New in Python 3.1.3?
1212
Core and Builtins
1313
-----------------
1414

15+
- PyObject_Dump() encodes unicode objects to utf8 with backslashreplace
16+
(instead of strict) error handler to escape surrogates
17+
1518
- Issue #8124: PySys_WriteStdout() and PySys_WriteStderr() don't execute
1619
indirectly Python signal handlers anymore because mywrite() ignores
1720
exceptions (KeyboardInterrupt)

Modules/main.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -516,18 +516,22 @@ Py_Main(int argc, wchar_t **argv)
516516
}
517517

518518
if (command) {
519+
char *commandStr;
519520
PyObject *commandObj = PyUnicode_FromWideChar(
520521
command, wcslen(command));
521522
free(command);
522-
if (commandObj != NULL) {
523-
sts = PyRun_SimpleStringFlags(
524-
_PyUnicode_AsString(commandObj), &cf) != 0;
523+
if (commandObj != NULL)
524+
commandStr = _PyUnicode_AsString(commandObj);
525+
else
526+
commandStr = NULL;
527+
if (commandStr != NULL) {
528+
sts = PyRun_SimpleStringFlags(commandStr, &cf) != 0;
529+
Py_DECREF(commandObj);
525530
}
526531
else {
527532
PyErr_Print();
528533
sts = 1;
529534
}
530-
Py_DECREF(commandObj);
531535
} else if (module) {
532536
sts = RunModule(module, 1);
533537
}

Objects/object.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,12 +303,15 @@ internal_print(PyObject *op, FILE *fp, int flags, int nesting)
303303
}
304304
else if (PyUnicode_Check(s)) {
305305
PyObject *t;
306-
t = _PyUnicode_AsDefaultEncodedString(s, NULL);
306+
t = PyUnicode_EncodeUTF8(PyUnicode_AS_UNICODE(s),
307+
PyUnicode_GET_SIZE(s),
308+
"backslashreplace");
307309
if (t == NULL)
308310
ret = 0;
309311
else {
310312
fwrite(PyBytes_AS_STRING(t), 1,
311313
PyBytes_GET_SIZE(t), fp);
314+
Py_DECREF(t);
312315
}
313316
}
314317
else {

Python/pythonrun.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,7 +1353,11 @@ handle_system_exit(void)
13531353
if (PyLong_Check(value))
13541354
exitcode = (int)PyLong_AsLong(value);
13551355
else {
1356+
PyObject *sys_stderr = PySys_GetObject("stderr");
1357+
if (sys_stderr != NULL)
1358+
PyObject_CallMethod(sys_stderr, "flush", NULL);
13561359
PyObject_Print(value, stderr, Py_PRINT_RAW);
1360+
fflush(stderr);
13571361
PySys_WriteStderr("\n");
13581362
exitcode = 1;
13591363
}

0 commit comments

Comments
 (0)