Merge Python 3.4.0rc1 release branch.

This commit is contained in:
Larry Hastings 2014-02-11 00:15:46 -08:00
commit 3f99504c08
22 changed files with 198 additions and 64 deletions

View file

@ -118,6 +118,8 @@ d047928ae3f6314a13b6137051315453d0ae89b6 v3.3.2
fd53c500f8b80f54f3ecedec9da2e8c7e52a6888 v3.3.3rc1 fd53c500f8b80f54f3ecedec9da2e8c7e52a6888 v3.3.3rc1
d32442c0e60dfbd71234e807d3d1dedd227495a9 v3.3.3rc2 d32442c0e60dfbd71234e807d3d1dedd227495a9 v3.3.3rc2
c3896275c0f61b2510a6c7e6c458a750359a91b8 v3.3.3 c3896275c0f61b2510a6c7e6c458a750359a91b8 v3.3.3
fa92f5f940c6c0d839d7f0611e4b717606504a3c v3.3.4rc1
7ff62415e4263c432c8acf6e424224209211eadb v3.3.4
46535f65e7f3bcdcf176f36d34bc1fed719ffd2b v3.4.0a1 46535f65e7f3bcdcf176f36d34bc1fed719ffd2b v3.4.0a1
9265a2168e2cb2a84785d8717792acc661e6b692 v3.4.0a2 9265a2168e2cb2a84785d8717792acc661e6b692 v3.4.0a2
dd9cdf90a5073510877e9dd5112f8e6cf20d5e89 v3.4.0a3 dd9cdf90a5073510877e9dd5112f8e6cf20d5e89 v3.4.0a3

View file

@ -282,3 +282,4 @@ whatsnew/changelog,,:PythonCmd,"With Tk < 8.5 _tkinter.c:PythonCmd() raised Unic
whatsnew/changelog,,::,": Fix FTP tests for IPv6, bind to ""::1"" instead of ""localhost""." whatsnew/changelog,,::,": Fix FTP tests for IPv6, bind to ""::1"" instead of ""localhost""."
whatsnew/changelog,,::,": Use ""127.0.0.1"" or ""::1"" instead of ""localhost"" as much as" whatsnew/changelog,,::,": Use ""127.0.0.1"" or ""::1"" instead of ""localhost"" as much as"
whatsnew/changelog,,:password,user:password whatsnew/changelog,,:password,user:password
whatsnew/changelog,,:gz,w:gz

1 c-api/arg :ref PyArg_ParseTuple(args, "O|O:ref", &object, &callback)
282 whatsnew/changelog :: : Fix FTP tests for IPv6, bind to "::1" instead of "localhost".
283 whatsnew/changelog :: : Use "127.0.0.1" or "::1" instead of "localhost" as much as
284 whatsnew/changelog :password user:password
285 whatsnew/changelog :gz w:gz

View file

@ -364,6 +364,9 @@ Some smaller changes made to the core Python language are:
Contributed by Victor Stinner, Kang-Hao (Kenny) Lu and Serhiy Storchaka in Contributed by Victor Stinner, Kang-Hao (Kenny) Lu and Serhiy Storchaka in
:issue:`12892`. :issue:`12892`.
* :class:`bytes`.join() and :class:`bytearray`.join() now accept arbitrary
buffer objects as arguments. (Contributed by Antoine Pitrou in
:issue:`15958`.)
New Modules New Modules
@ -1609,6 +1612,19 @@ Porting to Python 3.4
This section lists previously described changes and other bugfixes This section lists previously described changes and other bugfixes
that may require changes to your code. that may require changes to your code.
Changes in 'python' command behavior
------------------------------------
* In a posix shell, setting the :envvar:`PATH` environment variable to
an empty value is equivalent to not setting it at all. However, setting
:envvar:`PYTHONPATH` to an empty value was *not* equivalent to not setting it
at all: setting :envvar:`PYTHONPATH` to an empty value was equivalent to
setting it to ``.``, which leads to confusion when reasoning by analogy to
how :envvar:`PATH` works. The behavior now conforms to the posix convention
for :envvar:`PATH`.
Changes in the Python API Changes in the Python API
------------------------- -------------------------
@ -1704,6 +1720,11 @@ Changes in the Python API
informative :exc:`ValueError` rather than the previous more mysterious informative :exc:`ValueError` rather than the previous more mysterious
:exc:`AttributeError` (:issue:`9177`). :exc:`AttributeError` (:issue:`9177`).
* :meth:`slice.indices` no longer produces an :exc:`OverflowError` for huge
values. As a consequence of this fix, :meth:`slice.indices` now raises a
:exc:`ValueError` if given a negative length; previously it returned nonsense
values (:issue:`14794`).
Changes in the C API Changes in the C API
-------------------- --------------------

View file

@ -25,6 +25,7 @@ PyAPI_FUNC(const char *) PyModule_GetFilename(PyObject *);
PyAPI_FUNC(PyObject *) PyModule_GetFilenameObject(PyObject *); PyAPI_FUNC(PyObject *) PyModule_GetFilenameObject(PyObject *);
#ifndef Py_LIMITED_API #ifndef Py_LIMITED_API
PyAPI_FUNC(void) _PyModule_Clear(PyObject *); PyAPI_FUNC(void) _PyModule_Clear(PyObject *);
PyAPI_FUNC(void) _PyModule_ClearDict(PyObject *);
#endif #endif
PyAPI_FUNC(struct PyModuleDef*) PyModule_GetDef(PyObject*); PyAPI_FUNC(struct PyModuleDef*) PyModule_GetDef(PyObject*);
PyAPI_FUNC(void*) PyModule_GetState(PyObject*); PyAPI_FUNC(void*) PyModule_GetState(PyObject*);

View file

@ -33,7 +33,6 @@ typedef struct _is {
int codecs_initialized; int codecs_initialized;
int fscodec_initialized; int fscodec_initialized;
#ifdef HAVE_DLOPEN #ifdef HAVE_DLOPEN
int dlopenflags; int dlopenflags;
#endif #endif
@ -41,6 +40,7 @@ typedef struct _is {
int tscdump; int tscdump;
#endif #endif
PyObject *builtins_copy;
} PyInterpreterState; } PyInterpreterState;
#endif #endif

View file

@ -96,6 +96,7 @@ class BaseEventLoop(events.AbstractEventLoop):
self._default_executor = None self._default_executor = None
self._internal_fds = 0 self._internal_fds = 0
self._running = False self._running = False
self._clock_resolution = time.get_clock_info('monotonic').resolution
def _make_socket_transport(self, sock, protocol, waiter=None, *, def _make_socket_transport(self, sock, protocol, waiter=None, *,
extra=None, server=None): extra=None, server=None):
@ -643,10 +644,10 @@ class BaseEventLoop(events.AbstractEventLoop):
self._process_events(event_list) self._process_events(event_list)
# Handle 'later' callbacks that are ready. # Handle 'later' callbacks that are ready.
now = self.time() end_time = self.time() + self._clock_resolution
while self._scheduled: while self._scheduled:
handle = self._scheduled[0] handle = self._scheduled[0]
if handle._when > now: if handle._when >= end_time:
break break
handle = heapq.heappop(self._scheduled) handle = heapq.heappop(self._scheduled)
self._ready.append(handle) self._ready.append(handle)

View file

@ -191,6 +191,7 @@ class TestLoop(base_events.BaseEventLoop):
self._gen = gen() self._gen = gen()
next(self._gen) next(self._gen)
self._time = 0 self._time = 0
self._clock_resolution = 1e-9
self._timers = [] self._timers = []
self._selector = TestSelector() self._selector = TestSelector()

View file

@ -111,6 +111,8 @@ class _SimpleBinder:
except tkinter.TclError as e: except tkinter.TclError as e:
if e.args[0] == APPLICATION_GONE: if e.args[0] == APPLICATION_GONE:
pass pass
else:
raise
# An int in range(1 << len(_modifiers)) represents a combination of modifiers # An int in range(1 << len(_modifiers)) represents a combination of modifiers
# (if the least significent bit is on, _modifiers[0] is on, and so on). # (if the least significent bit is on, _modifiers[0] is on, and so on).
@ -244,6 +246,8 @@ class _ComplexBinder:
except tkinter.TclError as e: except tkinter.TclError as e:
if e.args[0] == APPLICATION_GONE: if e.args[0] == APPLICATION_GONE:
break break
else:
raise
# define the list of event types to be handled by MultiEvent. the order is # define the list of event types to be handled by MultiEvent. the order is
# compatible with the definition of event type constants. # compatible with the definition of event type constants.
@ -411,6 +415,8 @@ def MultiCallCreator(widget):
except tkinter.TclError as e: except tkinter.TclError as e:
if e.args[0] == APPLICATION_GONE: if e.args[0] == APPLICATION_GONE:
break break
else:
raise
_multicall_dict[widget] = MultiCall _multicall_dict[widget] = MultiCall
return MultiCall return MultiCall

View file

@ -875,4 +875,3 @@ What's New in IDLEfork 0.9 Alpha 1?
-------------------------------------------------------------------- --------------------------------------------------------------------
Refer to HISTORY.txt for additional information on earlier releases. Refer to HISTORY.txt for additional information on earlier releases.
-------------------------------------------------------------------- --------------------------------------------------------------------

View file

@ -62,6 +62,7 @@ SMTP_PORT = 25
SMTP_SSL_PORT = 465 SMTP_SSL_PORT = 465
CRLF = "\r\n" CRLF = "\r\n"
bCRLF = b"\r\n" bCRLF = b"\r\n"
_MAXLINE = 8192 # more than 8 times larger than RFC 821, 4.5.3
OLDSTYLE_AUTH = re.compile(r"auth=(.*)", re.I) OLDSTYLE_AUTH = re.compile(r"auth=(.*)", re.I)
@ -365,7 +366,7 @@ class SMTP:
self.file = self.sock.makefile('rb') self.file = self.sock.makefile('rb')
while 1: while 1:
try: try:
line = self.file.readline() line = self.file.readline(_MAXLINE + 1)
except OSError as e: except OSError as e:
self.close() self.close()
raise SMTPServerDisconnected("Connection unexpectedly closed: " raise SMTPServerDisconnected("Connection unexpectedly closed: "
@ -375,6 +376,8 @@ class SMTP:
raise SMTPServerDisconnected("Connection unexpectedly closed") raise SMTPServerDisconnected("Connection unexpectedly closed")
if self.debuglevel > 0: if self.debuglevel > 0:
print('reply:', repr(line), file=stderr) print('reply:', repr(line), file=stderr)
if len(line) > _MAXLINE:
raise SMTPResponseException(500, "Line too long.")
resp.append(line[4:].strip(b' \t\r\n')) resp.append(line[4:].strip(b' \t\r\n'))
code = line[:3] code = line[:3]
# Check that the error code is syntactically correct. # Check that the error code is syntactically correct.

View file

@ -738,6 +738,9 @@ _PLATFORM_DEFAULT_CLOSE_FDS = object()
class Popen(object): class Popen(object):
_child_created = False # Set here since __del__ checks it
def __init__(self, args, bufsize=-1, executable=None, def __init__(self, args, bufsize=-1, executable=None,
stdin=None, stdout=None, stderr=None, stdin=None, stdout=None, stderr=None,
preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS, preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS,
@ -748,7 +751,6 @@ class Popen(object):
"""Create new Popen instance.""" """Create new Popen instance."""
_cleanup() _cleanup()
self._child_created = False
self._input = None self._input = None
self._communication_started = False self._communication_started = False
if bufsize is None: if bufsize is None:
@ -890,11 +892,8 @@ class Popen(object):
# Wait for the process to terminate, to avoid zombies. # Wait for the process to terminate, to avoid zombies.
self.wait() self.wait()
def __del__(self, _maxsize=sys.maxsize, _active=_active): def __del__(self, _maxsize=sys.maxsize):
# If __init__ hasn't had a chance to execute (e.g. if it if not self._child_created:
# was passed an undeclared keyword argument), we don't
# have a _child_created attribute at all.
if not getattr(self, '_child_created', False):
# We didn't get to successfully create a child process. # We didn't get to successfully create a child process.
return return
# In case the child hasn't been waited on, check if it's done. # In case the child hasn't been waited on, check if it's done.
@ -1446,7 +1445,7 @@ class Popen(object):
_WTERMSIG=os.WTERMSIG, _WIFEXITED=os.WIFEXITED, _WTERMSIG=os.WTERMSIG, _WIFEXITED=os.WIFEXITED,
_WEXITSTATUS=os.WEXITSTATUS): _WEXITSTATUS=os.WEXITSTATUS):
# This method is called (indirectly) by __del__, so it cannot # This method is called (indirectly) by __del__, so it cannot
# refer to anything outside of its local scope.""" # refer to anything outside of its local scope.
if _WIFSIGNALED(sts): if _WIFSIGNALED(sts):
self.returncode = -_WTERMSIG(sts) self.returncode = -_WTERMSIG(sts)
elif _WIFEXITED(sts): elif _WIFEXITED(sts):

View file

@ -21,8 +21,13 @@ class MockFile:
""" """
def __init__(self, lines): def __init__(self, lines):
self.lines = lines self.lines = lines
def readline(self): def readline(self, limit=-1):
return self.lines.pop(0) + b'\r\n' result = self.lines.pop(0) + b'\r\n'
if limit >= 0:
# Re-insert the line, removing the \r\n we added.
self.lines.insert(0, result[limit:-2])
result = result[:limit]
return result
def close(self): def close(self):
pass pass

View file

@ -1176,15 +1176,17 @@ class EventLoopTestsMixin:
loop = self.loop loop = self.loop
yield from asyncio.sleep(1e-2, loop=loop) yield from asyncio.sleep(1e-2, loop=loop)
yield from asyncio.sleep(1e-4, loop=loop) yield from asyncio.sleep(1e-4, loop=loop)
yield from asyncio.sleep(1e-6, loop=loop)
yield from asyncio.sleep(1e-8, loop=loop)
yield from asyncio.sleep(1e-10, loop=loop)
self.loop.run_until_complete(wait()) self.loop.run_until_complete(wait())
# The ideal number of call is 6, but on some platforms, the selector # The ideal number of call is 12, but on some platforms, the selector
# may sleep at little bit less than timeout depending on the resolution # may sleep at little bit less than timeout depending on the resolution
# of the clock used by the kernel. Tolerate 2 useless calls on these # of the clock used by the kernel. Tolerate a few useless calls on
# platforms. # these platforms.
self.assertLessEqual(self.loop._run_once_counter, 8, self.assertLessEqual(self.loop._run_once_counter, 20,
{'time_info': time.get_clock_info('time'), {'clock_resolution': self.loop._clock_resolution,
'monotonic_info': time.get_clock_info('monotonic'),
'selector': self.loop._selector.__class__.__name__}) 'selector': self.loop._selector.__class__.__name__})

View file

@ -16,6 +16,7 @@ import unittest
import warnings import warnings
from operator import neg from operator import neg
from test.support import TESTFN, unlink, run_unittest, check_warnings from test.support import TESTFN, unlink, run_unittest, check_warnings
from test.script_helper import assert_python_ok
try: try:
import pty, signal import pty, signal
except ImportError: except ImportError:
@ -1592,6 +1593,34 @@ class TestSorted(unittest.TestCase):
data = 'The quick Brown fox Jumped over The lazy Dog'.split() data = 'The quick Brown fox Jumped over The lazy Dog'.split()
self.assertRaises(TypeError, sorted, data, None, lambda x,y: 0) self.assertRaises(TypeError, sorted, data, None, lambda x,y: 0)
class ShutdownTest(unittest.TestCase):
def test_cleanup(self):
# Issue #19255: builtins are still available at shutdown
code = """if 1:
import builtins
import sys
class C:
def __del__(self):
print("before")
# Check that builtins still exist
len(())
print("after")
c = C()
# Make this module survive until builtins and sys are cleaned
builtins.here = sys.modules[__name__]
sys.here = sys.modules[__name__]
# Create a reference loop so that this module needs to go
# through a GC phase.
here = sys.modules[__name__]
"""
rc, out, err = assert_python_ok("-c", code)
self.assertEqual(["before", "after"], out.decode().splitlines())
def load_tests(loader, tests, pattern): def load_tests(loader, tests, pattern):
from doctest import DocTestSuite from doctest import DocTestSuite
tests.addTest(DocTestSuite(builtins)) tests.addTest(DocTestSuite(builtins))

View file

@ -2691,7 +2691,8 @@ class CTextIOWrapperTest(TextIOWrapperTest):
class PyTextIOWrapperTest(TextIOWrapperTest): class PyTextIOWrapperTest(TextIOWrapperTest):
io = pyio io = pyio
shutdown_error = "LookupError: unknown encoding: ascii" #shutdown_error = "LookupError: unknown encoding: ascii"
shutdown_error = "TypeError: 'NoneType' object is not iterable"
class IncrementalNewlineDecoderTest(unittest.TestCase): class IncrementalNewlineDecoderTest(unittest.TestCase):

View file

@ -563,6 +563,33 @@ class BadHELOServerTests(unittest.TestCase):
HOST, self.port, 'localhost', 3) HOST, self.port, 'localhost', 3)
@unittest.skipUnless(threading, 'Threading required for this test.')
class TooLongLineTests(unittest.TestCase):
respdata = b'250 OK' + (b'.' * smtplib._MAXLINE * 2) + b'\n'
def setUp(self):
self.old_stdout = sys.stdout
self.output = io.StringIO()
sys.stdout = self.output
self.evt = threading.Event()
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.settimeout(15)
self.port = support.bind_port(self.sock)
servargs = (self.evt, self.respdata, self.sock)
threading.Thread(target=server, args=servargs).start()
self.evt.wait()
self.evt.clear()
def tearDown(self):
self.evt.wait()
sys.stdout = self.old_stdout
def testLineTooLong(self):
self.assertRaises(smtplib.SMTPResponseException, smtplib.SMTP,
HOST, self.port, 'localhost', 3)
sim_users = {'Mr.A@somewhere.com':'John A', sim_users = {'Mr.A@somewhere.com':'John A',
'Ms.B@xn--fo-fka.com':'Sally B', 'Ms.B@xn--fo-fka.com':'Sally B',
'Mrs.C@somewhereesle.com':'Ruth C', 'Mrs.C@somewhereesle.com':'Ruth C',
@ -888,7 +915,8 @@ class SMTPSimTests(unittest.TestCase):
def test_main(verbose=None): def test_main(verbose=None):
support.run_unittest(GeneralTests, DebuggingServerTests, support.run_unittest(GeneralTests, DebuggingServerTests,
NonConnectingTests, NonConnectingTests,
BadHELOServerTests, SMTPSimTests) BadHELOServerTests, SMTPSimTests,
TooLongLineTests)
if __name__ == '__main__': if __name__ == '__main__':
test_main() test_main()

View file

@ -22,6 +22,11 @@ Release date: 2014-02-10
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #19255: The builtins module is restored to initial value before
cleaning other modules. The sys and builtins modules are cleaned last.
- Issue #20588: Make Python-ast.c C89 compliant.
- Issue #20437: Fixed 22 potential bugs when deleting objects references. - Issue #20437: Fixed 22 potential bugs when deleting objects references.
- Issue #20500: Displaying an exception at interpreter shutdown no longer - Issue #20500: Displaying an exception at interpreter shutdown no longer

View file

@ -298,6 +298,14 @@ PyModule_GetState(PyObject* m)
void void
_PyModule_Clear(PyObject *m) _PyModule_Clear(PyObject *m)
{
PyObject *d = ((PyModuleObject *)m)->md_dict;
if (d != NULL)
_PyModule_ClearDict(d);
}
void
_PyModule_ClearDict(PyObject *d)
{ {
/* To make the execution order of destructors for global /* To make the execution order of destructors for global
objects a bit more predictable, we first zap all objects objects a bit more predictable, we first zap all objects
@ -308,11 +316,6 @@ _PyModule_Clear(PyObject *m)
Py_ssize_t pos; Py_ssize_t pos;
PyObject *key, *value; PyObject *key, *value;
PyObject *d;
d = ((PyModuleObject *)m)->md_dict;
if (d == NULL)
return;
/* First, clear only names starting with a single underscore */ /* First, clear only names starting with a single underscore */
pos = 0; pos = 0;

View file

@ -1203,10 +1203,14 @@ PyObject* PyAST_mod2obj(mod_ty t)
mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode) mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode)
{ {
mod_ty res; mod_ty res;
PyObject *req_type[] = {(PyObject*)Module_type, (PyObject*)Expression_type, PyObject *req_type[3];
(PyObject*)Interactive_type};
char *req_name[] = {"Module", "Expression", "Interactive"}; char *req_name[] = {"Module", "Expression", "Interactive"};
int isinstance; int isinstance;
req_type[0] = (PyObject*)Module_type;
req_type[1] = (PyObject*)Expression_type;
req_type[2] = (PyObject*)Interactive_type;
assert(0 <= mode && mode <= 2); assert(0 <= mode && mode <= 2);
if (!init_types()) if (!init_types())

View file

@ -7023,10 +7023,14 @@ PyObject* PyAST_mod2obj(mod_ty t)
mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode) mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode)
{ {
mod_ty res; mod_ty res;
PyObject *req_type[] = {(PyObject*)Module_type, (PyObject*)Expression_type, PyObject *req_type[3];
(PyObject*)Interactive_type};
char *req_name[] = {"Module", "Expression", "Interactive"}; char *req_name[] = {"Module", "Expression", "Interactive"};
int isinstance; int isinstance;
req_type[0] = (PyObject*)Module_type;
req_type[1] = (PyObject*)Expression_type;
req_type[2] = (PyObject*)Interactive_type;
assert(0 <= mode && mode <= 2); assert(0 <= mode && mode <= 2);
if (!init_types()) if (!init_types())

View file

@ -49,9 +49,13 @@ class fs_unicode_converter(CConverter):
void void
_PyImport_Init(void) _PyImport_Init(void)
{ {
PyInterpreterState *interp = PyThreadState_Get()->interp;
initstr = PyUnicode_InternFromString("__init__"); initstr = PyUnicode_InternFromString("__init__");
if (initstr == NULL) if (initstr == NULL)
Py_FatalError("Can't initialize import variables"); Py_FatalError("Can't initialize import variables");
interp->builtins_copy = PyDict_Copy(interp->builtins);
if (interp->builtins_copy == NULL)
Py_FatalError("Can't backup builtins dict");
} }
void void
@ -397,8 +401,8 @@ PyImport_Cleanup(void)
PyObject *key, *value, *dict; PyObject *key, *value, *dict;
PyInterpreterState *interp = PyThreadState_GET()->interp; PyInterpreterState *interp = PyThreadState_GET()->interp;
PyObject *modules = interp->modules; PyObject *modules = interp->modules;
PyObject *builtins = interp->builtins;
PyObject *weaklist = NULL; PyObject *weaklist = NULL;
char **p;
if (modules == NULL) if (modules == NULL)
return; /* Already done */ return; /* Already done */
@ -411,31 +415,22 @@ PyImport_Cleanup(void)
/* XXX Perhaps these precautions are obsolete. Who knows? */ /* XXX Perhaps these precautions are obsolete. Who knows? */
value = PyDict_GetItemString(modules, "builtins"); if (Py_VerboseFlag)
if (value != NULL && PyModule_Check(value)) { PySys_WriteStderr("# clear builtins._\n");
dict = PyModule_GetDict(value); PyDict_SetItemString(interp->builtins, "_", Py_None);
for (p = sys_deletes; *p != NULL; p++) {
if (Py_VerboseFlag) if (Py_VerboseFlag)
PySys_WriteStderr("# clear builtins._\n"); PySys_WriteStderr("# clear sys.%s\n", *p);
PyDict_SetItemString(dict, "_", Py_None); PyDict_SetItemString(interp->sysdict, *p, Py_None);
} }
value = PyDict_GetItemString(modules, "sys"); for (p = sys_files; *p != NULL; p+=2) {
if (value != NULL && PyModule_Check(value)) { if (Py_VerboseFlag)
char **p; PySys_WriteStderr("# restore sys.%s\n", *p);
PyObject *v; value = PyDict_GetItemString(interp->sysdict, *(p+1));
dict = PyModule_GetDict(value); if (value == NULL)
for (p = sys_deletes; *p != NULL; p++) { value = Py_None;
if (Py_VerboseFlag) PyDict_SetItemString(interp->sysdict, *p, value);
PySys_WriteStderr("# clear sys.%s\n", *p);
PyDict_SetItemString(dict, *p, Py_None);
}
for (p = sys_files; *p != NULL; p+=2) {
if (Py_VerboseFlag)
PySys_WriteStderr("# restore sys.%s\n", *p);
v = PyDict_GetItemString(dict, *(p+1));
if (v == NULL)
v = Py_None;
PyDict_SetItemString(dict, *p, v);
}
} }
/* We prepare a list which will receive (name, weakref) tuples of /* We prepare a list which will receive (name, weakref) tuples of
@ -473,11 +468,15 @@ PyImport_Cleanup(void)
/* Clear the modules dict. */ /* Clear the modules dict. */
PyDict_Clear(modules); PyDict_Clear(modules);
/* Replace the interpreter's reference to builtins with an empty dict /* Restore the original builtins dict, to ensure that any
(module globals still have a reference to the original builtins). */ user data gets cleared. */
builtins = interp->builtins; dict = PyDict_Copy(interp->builtins);
interp->builtins = PyDict_New(); if (dict == NULL)
Py_DECREF(builtins); PyErr_Clear();
PyDict_Clear(interp->builtins);
if (PyDict_Update(interp->builtins, interp->builtins_copy))
PyErr_Clear();
Py_XDECREF(dict);
/* Clear module dict copies stored in the interpreter state */ /* Clear module dict copies stored in the interpreter state */
_PyState_ClearModules(); _PyState_ClearModules();
/* Collect references */ /* Collect references */
@ -488,7 +487,15 @@ PyImport_Cleanup(void)
/* Now, if there are any modules left alive, clear their globals to /* Now, if there are any modules left alive, clear their globals to
minimize potential leaks. All C extension modules actually end minimize potential leaks. All C extension modules actually end
up here, since they are kept alive in the interpreter state. */ up here, since they are kept alive in the interpreter state.
The special treatment of "builtins" here is because even
when it's not referenced as a module, its dictionary is
referenced by almost every module's __builtins__. Since
deleting a module clears its dictionary (even if there are
references left to it), we need to delete the "builtins"
module last. Likewise, we don't delete sys until the very
end because it is implicitly referenced (e.g. by print). */
if (weaklist != NULL) { if (weaklist != NULL) {
Py_ssize_t i, n; Py_ssize_t i, n;
n = PyList_GET_SIZE(weaklist); n = PyList_GET_SIZE(weaklist);
@ -498,17 +505,27 @@ PyImport_Cleanup(void)
PyObject *mod = PyWeakref_GET_OBJECT(PyTuple_GET_ITEM(tup, 1)); PyObject *mod = PyWeakref_GET_OBJECT(PyTuple_GET_ITEM(tup, 1));
if (mod == Py_None) if (mod == Py_None)
continue; continue;
Py_INCREF(mod);
assert(PyModule_Check(mod)); assert(PyModule_Check(mod));
dict = PyModule_GetDict(mod);
if (dict == interp->builtins || dict == interp->sysdict)
continue;
Py_INCREF(mod);
if (Py_VerboseFlag && PyUnicode_Check(name)) if (Py_VerboseFlag && PyUnicode_Check(name))
PySys_FormatStderr("# cleanup[3] wiping %U\n", PySys_FormatStderr("# cleanup[3] wiping %U\n", name);
name, mod);
_PyModule_Clear(mod); _PyModule_Clear(mod);
Py_DECREF(mod); Py_DECREF(mod);
} }
Py_DECREF(weaklist); Py_DECREF(weaklist);
} }
/* Next, delete sys and builtins (in that order) */
if (Py_VerboseFlag)
PySys_FormatStderr("# cleanup[3] wiping sys\n");
_PyModule_ClearDict(interp->sysdict);
if (Py_VerboseFlag)
PySys_FormatStderr("# cleanup[3] wiping builtins\n");
_PyModule_ClearDict(interp->builtins);
/* Clear and delete the modules directory. Actual modules will /* Clear and delete the modules directory. Actual modules will
still be there only if imported during the execution of some still be there only if imported during the execution of some
destructor. */ destructor. */

View file

@ -72,6 +72,7 @@ PyInterpreterState_New(void)
interp->modules_by_index = NULL; interp->modules_by_index = NULL;
interp->sysdict = NULL; interp->sysdict = NULL;
interp->builtins = NULL; interp->builtins = NULL;
interp->builtins_copy = NULL;
interp->tstate_head = NULL; interp->tstate_head = NULL;
interp->codec_search_path = NULL; interp->codec_search_path = NULL;
interp->codec_search_cache = NULL; interp->codec_search_cache = NULL;
@ -115,6 +116,7 @@ PyInterpreterState_Clear(PyInterpreterState *interp)
Py_CLEAR(interp->modules_by_index); Py_CLEAR(interp->modules_by_index);
Py_CLEAR(interp->sysdict); Py_CLEAR(interp->sysdict);
Py_CLEAR(interp->builtins); Py_CLEAR(interp->builtins);
Py_CLEAR(interp->builtins_copy);
Py_CLEAR(interp->importlib); Py_CLEAR(interp->importlib);
} }