Commit 266772ab authored by Christian Heimes's avatar Christian Heimes

merge

parents af01f668 712cb734
...@@ -36,6 +36,7 @@ import _testcapi ...@@ -36,6 +36,7 @@ import _testcapi
from collections import deque, UserList from collections import deque, UserList
from itertools import cycle, count from itertools import cycle, count
from test import support from test import support
from test.script_helper import assert_python_ok
import codecs import codecs
import io # C implementation of io import io # C implementation of io
...@@ -2589,8 +2590,46 @@ class TextIOWrapperTest(unittest.TestCase): ...@@ -2589,8 +2590,46 @@ class TextIOWrapperTest(unittest.TestCase):
encoding='quopri_codec') encoding='quopri_codec')
self.assertRaises(TypeError, t.read) self.assertRaises(TypeError, t.read)
def _check_create_at_shutdown(self, **kwargs):
# Issue #20037: creating a TextIOWrapper at shutdown
# shouldn't crash the interpreter.
iomod = self.io.__name__
code = """if 1:
import codecs
import {iomod} as io
# Avoid looking up codecs at shutdown
codecs.lookup('utf-8')
class C:
def __init__(self):
self.buf = io.BytesIO()
def __del__(self):
io.TextIOWrapper(self.buf, **{kwargs})
print("ok")
c = C()
""".format(iomod=iomod, kwargs=kwargs)
return assert_python_ok("-c", code)
def test_create_at_shutdown_without_encoding(self):
rc, out, err = self._check_create_at_shutdown()
if err:
# Can error out with a RuntimeError if the module state
# isn't found.
self.assertIn("RuntimeError: could not find io module state",
err.decode())
else:
self.assertEqual("ok", out.decode().strip())
def test_create_at_shutdown_with_encoding(self):
rc, out, err = self._check_create_at_shutdown(encoding='utf-8',
errors='strict')
self.assertFalse(err)
self.assertEqual("ok", out.decode().strip())
class CTextIOWrapperTest(TextIOWrapperTest): class CTextIOWrapperTest(TextIOWrapperTest):
io = io
def test_initialization(self): def test_initialization(self):
r = self.BytesIO(b"\xc3\xa9\n\n") r = self.BytesIO(b"\xc3\xa9\n\n")
...@@ -2634,7 +2673,7 @@ class CTextIOWrapperTest(TextIOWrapperTest): ...@@ -2634,7 +2673,7 @@ class CTextIOWrapperTest(TextIOWrapperTest):
class PyTextIOWrapperTest(TextIOWrapperTest): class PyTextIOWrapperTest(TextIOWrapperTest):
pass io = pyio
class IncrementalNewlineDecoderTest(unittest.TestCase): class IncrementalNewlineDecoderTest(unittest.TestCase):
......
...@@ -41,6 +41,7 @@ import socket ...@@ -41,6 +41,7 @@ import socket
import struct import struct
import sys import sys
import tempfile import tempfile
from test.script_helper import assert_python_ok
from test.support import (captured_stdout, run_with_locale, run_unittest, from test.support import (captured_stdout, run_with_locale, run_unittest,
patch, requires_zlib, TestHandler, Matcher) patch, requires_zlib, TestHandler, Matcher)
import textwrap import textwrap
...@@ -3397,6 +3398,25 @@ class ModuleLevelMiscTest(BaseTest): ...@@ -3397,6 +3398,25 @@ class ModuleLevelMiscTest(BaseTest):
logging.setLoggerClass(logging.Logger) logging.setLoggerClass(logging.Logger)
self.assertEqual(logging.getLoggerClass(), logging.Logger) self.assertEqual(logging.getLoggerClass(), logging.Logger)
def test_logging_at_shutdown(self):
# Issue #20037
code = """if 1:
import logging
class A:
def __del__(self):
try:
raise ValueError("some error")
except Exception:
logging.exception("exception in __del__")
a = A()"""
rc, out, err = assert_python_ok("-c", code)
err = err.decode()
self.assertIn("exception in __del__", err)
self.assertIn("ValueError: some error", err)
class LogRecordTest(BaseTest): class LogRecordTest(BaseTest):
def test_str_rep(self): def test_str_rep(self):
r = logging.makeLogRecord({}) r = logging.makeLogRecord({})
......
...@@ -44,6 +44,9 @@ Core and Builtins ...@@ -44,6 +44,9 @@ Core and Builtins
Library Library
------- -------
- Issue #20037: Avoid crashes when opening a text file late at interpreter
shutdown.
- Issue #19967: Thanks to the PEP 442, asyncio.Future now uses a - Issue #19967: Thanks to the PEP 442, asyncio.Future now uses a
destructor to log uncaught exceptions, instead of the dedicated destructor to log uncaught exceptions, instead of the dedicated
_TracebackLogger class. _TracebackLogger class.
......
...@@ -539,6 +539,20 @@ _PyIO_ConvertSsize_t(PyObject *obj, void *result) { ...@@ -539,6 +539,20 @@ _PyIO_ConvertSsize_t(PyObject *obj, void *result) {
} }
_PyIO_State *
_PyIO_get_module_state(void)
{
PyObject *mod = PyState_FindModule(&_PyIO_Module);
_PyIO_State *state;
if (mod == NULL || (state = IO_MOD_STATE(mod)) == NULL) {
PyErr_SetString(PyExc_RuntimeError,
"could not find io module state "
"(interpreter shutdown?)");
return NULL;
}
return state;
}
PyObject * PyObject *
_PyIO_get_locale_module(_PyIO_State *state) _PyIO_get_locale_module(_PyIO_State *state)
{ {
......
...@@ -135,8 +135,9 @@ typedef struct { ...@@ -135,8 +135,9 @@ typedef struct {
} _PyIO_State; } _PyIO_State;
#define IO_MOD_STATE(mod) ((_PyIO_State *)PyModule_GetState(mod)) #define IO_MOD_STATE(mod) ((_PyIO_State *)PyModule_GetState(mod))
#define IO_STATE IO_MOD_STATE(PyState_FindModule(&_PyIO_Module)) #define IO_STATE() _PyIO_get_module_state()
extern _PyIO_State *_PyIO_get_module_state(void);
extern PyObject *_PyIO_get_locale_module(_PyIO_State *); extern PyObject *_PyIO_get_locale_module(_PyIO_State *);
extern PyObject *_PyIO_str_close; extern PyObject *_PyIO_str_close;
......
...@@ -91,7 +91,9 @@ bufferediobase_readinto(PyObject *self, PyObject *args) ...@@ -91,7 +91,9 @@ bufferediobase_readinto(PyObject *self, PyObject *args)
static PyObject * static PyObject *
bufferediobase_unsupported(const char *message) bufferediobase_unsupported(const char *message)
{ {
PyErr_SetString(IO_STATE->unsupported_operation, message); _PyIO_State *state = IO_STATE();
if (state != NULL)
PyErr_SetString(state->unsupported_operation, message);
return NULL; return NULL;
} }
......
...@@ -493,8 +493,10 @@ err_closed(void) ...@@ -493,8 +493,10 @@ err_closed(void)
static PyObject * static PyObject *
err_mode(char *action) err_mode(char *action)
{ {
PyErr_Format(IO_STATE->unsupported_operation, _PyIO_State *state = IO_STATE();
"File not open for %s", action); if (state != NULL)
PyErr_Format(state->unsupported_operation,
"File not open for %s", action);
return NULL; return NULL;
} }
......
...@@ -69,7 +69,9 @@ _Py_IDENTIFIER(read); ...@@ -69,7 +69,9 @@ _Py_IDENTIFIER(read);
static PyObject * static PyObject *
iobase_unsupported(const char *message) iobase_unsupported(const char *message)
{ {
PyErr_SetString(IO_STATE->unsupported_operation, message); _PyIO_State *state = IO_STATE();
if (state != NULL)
PyErr_SetString(state->unsupported_operation, message);
return NULL; return NULL;
} }
......
...@@ -45,7 +45,9 @@ PyDoc_STRVAR(textiobase_doc, ...@@ -45,7 +45,9 @@ PyDoc_STRVAR(textiobase_doc,
static PyObject * static PyObject *
_unsupported(const char *message) _unsupported(const char *message)
{ {
PyErr_SetString(IO_STATE->unsupported_operation, message); _PyIO_State *state = IO_STATE();
if (state != NULL)
PyErr_SetString(state->unsupported_operation, message);
return NULL; return NULL;
} }
...@@ -852,7 +854,7 @@ textiowrapper_init(textio *self, PyObject *args, PyObject *kwds) ...@@ -852,7 +854,7 @@ textiowrapper_init(textio *self, PyObject *args, PyObject *kwds)
char *errors = NULL; char *errors = NULL;
char *newline = NULL; char *newline = NULL;
int line_buffering = 0, write_through = 0; int line_buffering = 0, write_through = 0;
_PyIO_State *state = IO_STATE; _PyIO_State *state = NULL;
PyObject *res; PyObject *res;
int r; int r;
...@@ -891,6 +893,9 @@ textiowrapper_init(textio *self, PyObject *args, PyObject *kwds) ...@@ -891,6 +893,9 @@ textiowrapper_init(textio *self, PyObject *args, PyObject *kwds)
if (encoding == NULL) { if (encoding == NULL) {
/* Try os.device_encoding(fileno) */ /* Try os.device_encoding(fileno) */
PyObject *fileno; PyObject *fileno;
state = IO_STATE();
if (state == NULL)
goto error;
fileno = _PyObject_CallMethodId(buffer, &PyId_fileno, NULL); fileno = _PyObject_CallMethodId(buffer, &PyId_fileno, NULL);
/* Ignore only AttributeError and UnsupportedOperation */ /* Ignore only AttributeError and UnsupportedOperation */
if (fileno == NULL) { if (fileno == NULL) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment