This commit is contained in:
Guido van Rossum 2012-06-22 15:18:38 -07:00
commit 8e0d25504c
41 changed files with 2413 additions and 173 deletions

View File

@ -247,6 +247,30 @@ Directory and files operations
.. versionadded:: 3.3
.. function:: which(cmd, mode=os.F_OK | os.X_OK, path=None)
Return the path to an executable which would be run if the given *cmd*
was called. If no *cmd* would be called, return ``None``.
*mode* is a permission mask passed a to :func:`os.access`, by default
determining if the file exists and executable.
When no *path* is specified, the results of :func:`os.environ` are
used, returning either the "PATH" value or a fallback of :attr:`os.defpath`.
On Windows, the current directory is always prepended to the *path*
whether or not you use the default or provide your own, which
is the behavior the command shell uses when finding executables.
Additionaly, when finding the *cmd* in the *path*, the
``PATHEXT`` environment variable is checked. For example, if you
call ``shutil.which("python")``, :func:`which` will search
``PATHEXT`` to know that it should look for ``python.exe`` within
the *path* directories.
>>> print(shutil.which("python"))
'c:\\python33\\python.exe'
.. versionadded:: 3.3
.. exception:: Error

View File

@ -59,6 +59,22 @@ Functions, Constants, and Exceptions
.. versionchanged:: 3.3
:exc:`SSLError` used to be a subtype of :exc:`socket.error`.
.. attribute:: library
A string mnemonic designating the OpenSSL submodule in which the error
occurred, such as ``SSL``, ``PEM`` or ``X509``. The range of possible
values depends on the OpenSSL version.
.. versionadded:: 3.3
.. attribute:: reason
A string mnemonic designating the reason this error occurred, for
example ``CERTIFICATE_VERIFY_FAILED``. The range of possible
values depends on the OpenSSL version.
.. versionadded:: 3.3
.. exception:: SSLZeroReturnError
A subclass of :exc:`SSLError` raised when trying to read or write and

View File

@ -106,6 +106,22 @@ always available.
This function should be used for internal and specialized purposes only.
.. function:: _debugmallocstats()
Print low-level information to stderr about the state of CPython's memory
allocator.
If Python is configured --with-pydebug, it also performs some expensive
internal consistency checks.
.. versionadded:: 3.3
.. impl-detail::
This function is specific to CPython. The exact output format is not
defined here, and may change.
.. data:: dllhandle
Integer specifying the handle of the Python DLL. Availability: Windows.

View File

@ -545,7 +545,7 @@ The module defines the following functions and data items:
+-------+-------------------+---------------------------------+
| N/A | :attr:`tm_zone` | abbreviation of timezone name |
+-------+-------------------+---------------------------------+
| N/A | :attr:`tm_gmtoff` | offset from UTC in seconds |
| N/A | :attr:`tm_gmtoff` | offset east of UTC in seconds |
+-------+-------------------+---------------------------------+
Note that unlike the C structure, the month value is a range of [1, 12], not

View File

@ -111,6 +111,7 @@ PyAPI_FUNC(int) PyDict_DelItemString(PyObject *dp, const char *key);
#ifndef Py_LIMITED_API
int _PyObjectDict_SetItem(PyTypeObject *tp, PyObject **dictptr, PyObject *name, PyObject *value);
PyObject *_PyDict_LoadGlobal(PyDictObject *, PyDictObject *, PyObject *);
PyAPI_FUNC(void) _PyDict_DebugMallocStats(FILE *out);
#endif
#ifdef __cplusplus

View File

@ -110,6 +110,8 @@ PyAPI_FUNC(double) _PyFloat_Unpack8(const unsigned char *p, int le);
/* free list api */
PyAPI_FUNC(int) PyFloat_ClearFreeList(void);
PyAPI_FUNC(void) _PyFloat_DebugMallocStats(FILE* out);
/* Format the object based on the format_spec, as defined in PEP 3101
(Advanced String Formatting). */
PyAPI_FUNC(int) _PyFloat_FormatAdvancedWriter(

View File

@ -79,6 +79,8 @@ PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *);
PyAPI_FUNC(int) PyFrame_ClearFreeList(void);
PyAPI_FUNC(void) _PyFrame_DebugMallocStats(FILE *out);
/* Return the line of code the frame is currently executing. */
PyAPI_FUNC(int) PyFrame_GetLineNumber(PyFrameObject *);

View File

@ -64,6 +64,7 @@ PyAPI_FUNC(PyObject *) PyList_AsTuple(PyObject *);
PyAPI_FUNC(PyObject *) _PyList_Extend(PyListObject *, PyObject *);
PyAPI_FUNC(int) PyList_ClearFreeList(void);
PyAPI_FUNC(void) _PyList_DebugMallocStats(FILE *out);
#endif
/* Macro, trading safety for speed */

View File

@ -82,6 +82,11 @@ typedef struct {
PyAPI_FUNC(int) PyCFunction_ClearFreeList(void);
#ifndef Py_LIMITED_API
PyAPI_FUNC(void) _PyCFunction_DebugMallocStats(FILE *out);
PyAPI_FUNC(void) _PyMethod_DebugMallocStats(FILE *out);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -977,6 +977,14 @@ PyAPI_DATA(PyObject *) _PyTrash_delete_later;
else \
_PyTrash_deposit_object((PyObject*)op);
#ifndef Py_LIMITED_API
PyAPI_FUNC(void)
_PyDebugAllocatorStats(FILE *out, const char *block_name, int num_blocks,
size_t sizeof_block);
PyAPI_FUNC(void)
_PyObject_DebugTypeStats(FILE *out);
#endif /* ifndef Py_LIMITED_API */
#ifdef __cplusplus
}
#endif

View File

@ -101,13 +101,15 @@ PyAPI_FUNC(void) PyObject_Free(void *);
/* Macros */
#ifdef WITH_PYMALLOC
#ifndef Py_LIMITED_API
PyAPI_FUNC(void) _PyObject_DebugMallocStats(FILE *out);
#endif /* #ifndef Py_LIMITED_API */
#ifdef PYMALLOC_DEBUG /* WITH_PYMALLOC && PYMALLOC_DEBUG */
PyAPI_FUNC(void *) _PyObject_DebugMalloc(size_t nbytes);
PyAPI_FUNC(void *) _PyObject_DebugRealloc(void *p, size_t nbytes);
PyAPI_FUNC(void) _PyObject_DebugFree(void *p);
PyAPI_FUNC(void) _PyObject_DebugDumpAddress(const void *p);
PyAPI_FUNC(void) _PyObject_DebugCheckAddress(const void *p);
PyAPI_FUNC(void) _PyObject_DebugMallocStats(void);
PyAPI_FUNC(void *) _PyObject_DebugMallocApi(char api, size_t nbytes);
PyAPI_FUNC(void *) _PyObject_DebugReallocApi(char api, void *p, size_t nbytes);
PyAPI_FUNC(void) _PyObject_DebugFreeApi(char api, void *p);

View File

@ -101,6 +101,7 @@ PyAPI_FUNC(PyObject *) PySet_Pop(PyObject *set);
PyAPI_FUNC(int) _PySet_Update(PyObject *set, PyObject *iterable);
PyAPI_FUNC(int) PySet_ClearFreeList(void);
PyAPI_FUNC(void) _PySet_DebugMallocStats(FILE *out);
#endif
#ifdef __cplusplus

View File

@ -63,6 +63,9 @@ PyAPI_FUNC(void) _PyTuple_MaybeUntrack(PyObject *);
#endif
PyAPI_FUNC(int) PyTuple_ClearFreeList(void);
#ifndef Py_LIMITED_API
PyAPI_FUNC(void) _PyTuple_DebugMallocStats(FILE *out);
#endif /* Py_LIMITED_API */
#ifdef __cplusplus
}

View File

@ -1510,13 +1510,13 @@ class datetime(date):
# implied by tm_isdst.
delta = local - datetime(*_time.gmtime(ts)[:6])
dst = _time.daylight and localtm.tm_isdst > 0
gmtoff = _time.altzone if dst else _time.timezone
if delta == timedelta(seconds=-gmtoff):
gmtoff = -(_time.altzone if dst else _time.timezone)
if delta == timedelta(seconds=gmtoff):
tz = timezone(delta, _time.tzname[dst])
else:
tz = timezone(delta)
else:
tz = timezone(timedelta(seconds=-gmtoff), zone)
tz = timezone(timedelta(seconds=gmtoff), zone)
elif not isinstance(tz, tzinfo):
raise TypeError("tz argument must be an instance of tzinfo")

View File

@ -36,7 +36,7 @@ __all__ = ["copyfileobj", "copyfile", "copymode", "copystat", "copy", "copy2",
"register_archive_format", "unregister_archive_format",
"get_unpack_formats", "register_unpack_format",
"unregister_unpack_format", "unpack_archive",
"ignore_patterns", "chown"]
"ignore_patterns", "chown", "which"]
# disk_usage is added later, if available on the platform
class Error(EnvironmentError):
@ -961,3 +961,50 @@ def get_terminal_size(fallback=(80, 24)):
lines = size.lines
return os.terminal_size((columns, lines))
def which(cmd, mode=os.F_OK | os.X_OK, path=None):
"""Given a file, mode, and a path string, return the path whichs conform
to the given mode on the path."""
# Check that a given file can be accessed with the correct mode.
# Additionally check that `file` is not a directory, as on Windows
# directories pass the os.access check.
def _access_check(fn, mode):
if (os.path.exists(fn) and os.access(fn, mode)
and not os.path.isdir(fn)):
return True
return False
# Short circuit. If we're given a full path which matches the mode
# and it exists, we're done here.
if _access_check(cmd, mode):
return cmd
path = (path or os.environ.get("PATH", os.defpath)).split(os.pathsep)
if sys.platform == "win32":
# The current directory takes precedence on Windows.
if not os.curdir in path:
path.insert(0, os.curdir)
# PATHEXT is necessary to check on Windows.
pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
# See if the given file matches any of the expected path extensions.
# This will allow us to short circuit when given "python.exe".
matches = [cmd for ext in pathext if cmd.lower().endswith(ext.lower())]
# If it does match, only test that one, otherwise we have to try others.
files = [cmd + ext.lower() for ext in pathext] if not matches else [cmd]
else:
# On other platforms you don't have things like PATHEXT to tell you
# what file suffixes are executable, so just pass on cmd as-is.
files = [cmd]
seen = set()
for dir in path:
dir = os.path.normcase(dir)
if not dir in seen:
seen.add(dir)
for thefile in files:
name = os.path.join(dir, thefile)
if _access_check(name, mode):
return name
return None

View File

@ -3278,16 +3278,18 @@ class TestDateTimeTZ(TestDateTime, TZInfoBase, unittest.TestCase):
self.assertEqual(dt.astimezone(None), dt)
self.assertEqual(dt.astimezone(), dt)
# Note that offset in TZ variable has the opposite sign to that
# produced by %z directive.
@support.run_with_tz('EST+05EDT,M3.2.0,M11.1.0')
def test_astimezone_default_eastern(self):
dt = self.theclass(2012, 11, 4, 6, 30, tzinfo=timezone.utc)
local = dt.astimezone()
self.assertEqual(dt, local)
self.assertEqual(local.strftime("%z %Z"), "+0500 EST")
self.assertEqual(local.strftime("%z %Z"), "-0500 EST")
dt = self.theclass(2012, 11, 4, 5, 30, tzinfo=timezone.utc)
local = dt.astimezone()
self.assertEqual(dt, local)
self.assertEqual(local.strftime("%z %Z"), "+0400 EDT")
self.assertEqual(local.strftime("%z %Z"), "-0400 EDT")
def test_aware_subtract(self):
cls = self.theclass

View File

@ -222,36 +222,38 @@ class SkipitemTest(unittest.TestCase):
in Python/getargs.c, but neglected to update our poor friend
skipitem() in the same file. (If so, shame on you!)
This function brute-force tests all** ASCII characters (1 to 127
inclusive) as format units, checking to see that
PyArg_ParseTupleAndKeywords() return consistent errors both when
the unit is attempted to be used and when it is skipped. If the
format unit doesn't exist, we'll get one of two specific error
messages (one for used, one for skipped); if it does exist we
*won't* get that error--we'll get either no error or some other
error. If we get the "does not exist" error for one test and
not for the other, there's a mismatch, and the test fails.
With a few exceptions**, this function brute-force tests all
printable ASCII*** characters (32 to 126 inclusive) as format units,
checking to see that PyArg_ParseTupleAndKeywords() return consistent
errors both when the unit is attempted to be used and when it is
skipped. If the format unit doesn't exist, we'll get one of two
specific error messages (one for used, one for skipped); if it does
exist we *won't* get that error--we'll get either no error or some
other error. If we get the specific "does not exist" error for one
test and not for the other, there's a mismatch, and the test fails.
** Some format units have special funny semantics and it would
be difficult to accomodate them here. Since these are all
well-established and properly skipped in skipitem() we can
get away with not testing them--this test is really intended
to catch *new* format units.
*** Python C source files must be ASCII. Therefore it's impossible
to have non-ASCII format units.
** Okay, it actually skips some ASCII characters. Some characters
have special funny semantics, and it would be difficult to
accomodate them here.
"""
empty_tuple = ()
tuple_1 = (0,)
dict_b = {'b':1}
keywords = ["a", "b"]
# Python C source files must be ASCII,
# therefore we'll never have a format unit > 127
for i in range(1, 128):
for i in range(32, 127):
c = chr(i)
# skip non-printable characters, no one is insane enough to define
# one as a format unit
# skip parentheses, the error reporting is inconsistent about them
# skip 'e', it's always a two-character code
# skip '|' and '$', they don't represent arguments anyway
if (not c.isprintable()) or (c in '()e|$'):
if c in '()e|$':
continue
# test the format unit when not skipped

View File

@ -10,7 +10,7 @@ import shutil
import importlib
import unittest
from test.support import run_unittest, create_empty_file
from test.support import run_unittest, create_empty_file, verbose
from reprlib import repr as r # Don't shadow builtin repr
from reprlib import Repr
from reprlib import recursive_repr
@ -248,6 +248,8 @@ class LongReprTest(unittest.TestCase):
# (see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx#maxpath)
self.skipTest("test paths too long (%d characters) for Windows' 260 character limit"
% cached_path_len)
elif os.name == 'nt' and verbose:
print("len(cached_path_len) =", len(cached_path_len))
def test_module(self):
self._check_path_limitations(self.pkgname)

View File

@ -1128,6 +1128,59 @@ class TestShutil(unittest.TestCase):
self.assertEqual(['foo'], os.listdir(rv))
class TestWhich(unittest.TestCase):
def setUp(self):
self.temp_dir = tempfile.mkdtemp()
# Give the temp_file an ".exe" suffix for all.
# It's needed on Windows and not harmful on other platforms.
self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
suffix=".exe")
os.chmod(self.temp_file.name, stat.S_IXUSR)
self.addCleanup(self.temp_file.close)
self.dir, self.file = os.path.split(self.temp_file.name)
def test_basic(self):
# Given an EXE in a directory, it should be returned.
rv = shutil.which(self.file, path=self.dir)
self.assertEqual(rv, self.temp_file.name)
def test_full_path_short_circuit(self):
# When given the fully qualified path to an executable that exists,
# it should be returned.
rv = shutil.which(self.temp_file.name, path=self.temp_dir)
self.assertEqual(self.temp_file.name, rv)
def test_non_matching_mode(self):
# Set the file read-only and ask for writeable files.
os.chmod(self.temp_file.name, stat.S_IREAD)
rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
self.assertIsNone(rv)
def test_relative(self):
old_cwd = os.getcwd()
base_dir, tail_dir = os.path.split(self.dir)
os.chdir(base_dir)
try:
rv = shutil.which(self.file, path=tail_dir)
self.assertEqual(rv, os.path.join(tail_dir, self.file))
finally:
os.chdir(old_cwd)
def test_nonexistent_file(self):
# Return None when no matching executable file is found on the path.
rv = shutil.which("foo.exe", path=self.dir)
self.assertIsNone(rv)
@unittest.skipUnless(sys.platform == "win32",
"pathext check is Windows-only")
def test_pathext_checking(self):
# Ask for the file without the ".exe" extension, then ensure that
# it gets found properly with the extension.
rv = shutil.which(self.temp_file.name[:-4], path=self.dir)
self.assertEqual(self.temp_file.name, rv)
class TestMove(unittest.TestCase):
def setUp(self):
@ -1460,7 +1513,7 @@ class TermsizeTests(unittest.TestCase):
def test_main():
support.run_unittest(TestShutil, TestMove, TestCopyFile,
TermsizeTests)
TermsizeTests, TestWhich)
if __name__ == '__main__':
test_main()

View File

@ -552,7 +552,7 @@ class ContextTests(unittest.TestCase):
with self.assertRaises(FileNotFoundError) as cm:
ctx.load_dh_params(WRONGCERT)
self.assertEqual(cm.exception.errno, errno.ENOENT)
with self.assertRaisesRegex(ssl.SSLError, "PEM routines"):
with self.assertRaises(ssl.SSLError) as cm:
ctx.load_dh_params(CERTFILE)
@skip_if_broken_ubuntu_ssl
@ -590,6 +590,47 @@ class ContextTests(unittest.TestCase):
self.assertRaises(ValueError, ctx.set_ecdh_curve, b"foo")
class SSLErrorTests(unittest.TestCase):
def test_str(self):
# The str() of a SSLError doesn't include the errno
e = ssl.SSLError(1, "foo")
self.assertEqual(str(e), "foo")
self.assertEqual(e.errno, 1)
# Same for a subclass
e = ssl.SSLZeroReturnError(1, "foo")
self.assertEqual(str(e), "foo")
self.assertEqual(e.errno, 1)
def test_lib_reason(self):
# Test the library and reason attributes
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
with self.assertRaises(ssl.SSLError) as cm:
ctx.load_dh_params(CERTFILE)
self.assertEqual(cm.exception.library, 'PEM')
self.assertEqual(cm.exception.reason, 'NO_START_LINE')
s = str(cm.exception)
self.assertTrue(s.startswith("[PEM: NO_START_LINE] no start line"), s)
def test_subclass(self):
# Check that the appropriate SSLError subclass is raised
# (this only tests one of them)
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
with socket.socket() as s:
s.bind(("127.0.0.1", 0))
s.listen(5)
with socket.socket() as c:
c.connect(s.getsockname())
c.setblocking(False)
c = ctx.wrap_socket(c, False, do_handshake_on_connect=False)
with self.assertRaises(ssl.SSLWantReadError) as cm:
c.do_handshake()
s = str(cm.exception)
self.assertTrue(s.startswith("The operation did not complete (read)"), s)
# For compatibility
self.assertEqual(cm.exception.errno, ssl.SSL_ERROR_WANT_READ)
class NetworkedTests(unittest.TestCase):
def test_connect(self):
@ -1931,7 +1972,7 @@ def test_main(verbose=False):
if not os.path.exists(filename):
raise support.TestFailed("Can't read certificate file %r" % filename)
tests = [ContextTests, BasicSocketTests]
tests = [ContextTests, BasicSocketTests, SSLErrorTests]
if support.is_resource_enabled('network'):
tests.append(NetworkedTests)

View File

@ -603,6 +603,12 @@ class SysModuleTest(unittest.TestCase):
self.assertEqual(sys.implementation.name,
sys.implementation.name.lower())
def test_debugmallocstats(self):
# Test sys._debugmallocstats()
from test.script_helper import assert_python_ok
args = ['-c', 'import sys; sys._debugmallocstats()']
ret, out, err = assert_python_ok(*args)
self.assertIn(b"free PyDictObjects", err)
class SizeofTest(unittest.TestCase):

View File

@ -42,6 +42,14 @@ Library
- Issue: #15138: base64.urlsafe_{en,de}code() are now 3-4x faster.
- Issue #444582: Add shutil.which, for finding programs on the system path.
Original patch by Erik Demaine, with later iterations by Jan Killian
and Brian Curtin.
- Issue #14837: SSL errors now have ``library`` and ``reason`` attributes
describing precisely what happened and in which OpenSSL submodule. The
str() of a SSLError is also enhanced accordingly.
- Issue #9527: datetime.astimezone() method will now supply a class
timezone instance corresponding to the system local timezone when
called with no arguments.
@ -149,6 +157,9 @@ Library
- Issue #14963: Convert contextlib.ExitStack.__exit__ to use an iterative
algorithm (Patch by Alon Horev)
- Issue #14785: Add sys._debugmallocstats() to help debug low-level memory
allocation issues
C-API
-----

View File

@ -809,14 +809,16 @@ new_timezone(PyObject *offset, PyObject *name)
}
if (GET_TD_MICROSECONDS(offset) != 0 || GET_TD_SECONDS(offset) % 60 != 0) {
PyErr_Format(PyExc_ValueError, "offset must be a timedelta"
" representing a whole number of minutes");
" representing a whole number of minutes,"
" not %R.", offset);
return NULL;
}
if ((GET_TD_DAYS(offset) == -1 && GET_TD_SECONDS(offset) == 0) ||
GET_TD_DAYS(offset) < -1 || GET_TD_DAYS(offset) >= 1) {
PyErr_Format(PyExc_ValueError, "offset must be a timedelta"
" strictly between -timedelta(hours=24) and"
" timedelta(hours=24).");
" timedelta(hours=24),"
" not %R.", offset);
return NULL;
}
@ -4686,12 +4688,11 @@ datetime_replace(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
}
static PyObject *
local_timezone(PyObject *utc_time)
local_timezone(PyDateTime_DateTime *utc_time)
{
PyObject *result = NULL;
struct tm *timep;
time_t timestamp;
long offset;
PyObject *delta;
PyObject *one_second;
PyObject *seconds;
@ -4716,21 +4717,18 @@ local_timezone(PyObject *utc_time)
return NULL;
timep = localtime(&timestamp);
#ifdef HAVE_STRUCT_TM_TM_ZONE
offset = timep->tm_gmtoff;
zone = timep->tm_zone;
delta = new_delta(0, -offset, 0, 0);
delta = new_delta(0, timep->tm_gmtoff, 0, 1);
#else /* HAVE_STRUCT_TM_TM_ZONE */
{
PyObject *local_time;
Py_INCREF(utc_time->tzinfo);
local_time = new_datetime(timep->tm_year + 1900, timep->tm_mon + 1,
timep->tm_mday, timep->tm_hour, timep->tm_min,
timep->tm_sec, utc_time->tzinfo);
if (local_time == NULL) {
Py_DECREF(utc_time->tzinfo);
timep->tm_sec, DATE_GET_MICROSECOND(utc_time),
utc_time->tzinfo);
if (local_time == NULL)
goto error;
}
delta = datetime_subtract(local_time, utc_time);
delta = datetime_subtract(local_time, (PyObject*)utc_time);
/* XXX: before relying on tzname, we should compare delta
to the offset implied by timezone/altzone */
if (daylight && timep->tm_isdst >= 0)
@ -4752,10 +4750,10 @@ local_timezone(PyObject *utc_time)
return result;
}
static PyObject *
static PyDateTime_DateTime *
datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
{
PyObject *result;
PyDateTime_DateTime *result;
PyObject *offset;
PyObject *temp;
PyObject *tzinfo = Py_None;
@ -4775,7 +4773,7 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
/* Conversion to self's own time zone is a NOP. */
if (self->tzinfo == tzinfo) {
Py_INCREF(self);
return (PyObject *)self;
return self;
}
/* Convert self to UTC. */
@ -4791,14 +4789,14 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
}
/* result = self - offset */
result = add_datetime_timedelta(self,
(PyDateTime_Delta *)offset, -1);
result = (PyDateTime_DateTime *)add_datetime_timedelta(self,
(PyDateTime_Delta *)offset, -1);
Py_DECREF(offset);
if (result == NULL)
return NULL;
/* Attach new tzinfo and let fromutc() do the rest. */
temp = ((PyDateTime_DateTime *)result)->tzinfo;
temp = result->tzinfo;
if (tzinfo == Py_None) {
tzinfo = local_timezone(result);
if (tzinfo == NULL) {
@ -4808,11 +4806,12 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
}
else
Py_INCREF(tzinfo);
((PyDateTime_DateTime *)result)->tzinfo = tzinfo;
result->tzinfo = tzinfo;
Py_DECREF(temp);
temp = result;
result = _PyObject_CallMethodId(tzinfo, &PyId_fromutc, "O", temp);
temp = (PyObject *)result;
result = (PyDateTime_DateTime *)
_PyObject_CallMethodId(tzinfo, &PyId_fromutc, "O", temp);
Py_DECREF(temp);
return result;

View File

@ -76,6 +76,16 @@ enum py_ssl_version {
PY_SSL_VERSION_TLS1
};
struct py_ssl_error_code {
const char *mnemonic;
int library, reason;
};
struct py_ssl_library_code {
const char *library;
int code;
};
/* Include symbols from _socket module */
#include "socketmodule.h"
@ -97,6 +107,9 @@ static PySocketModule_APIObject PySocketModule;
#include "openssl/err.h"
#include "openssl/rand.h"
/* Include generated data (error codes) */
#include "_ssl_data.h"
/* SSL error object */
static PyObject *PySSLErrorObject;
static PyObject *PySSLZeroReturnErrorObject;
@ -105,6 +118,11 @@ static PyObject *PySSLWantWriteErrorObject;
static PyObject *PySSLSyscallErrorObject;
static PyObject *PySSLEOFErrorObject;
/* Error mappings */
static PyObject *err_codes_to_names;
static PyObject *err_names_to_codes;
static PyObject *lib_codes_to_names;
#ifdef WITH_THREAD
/* serves as a flag to see whether we've initialized the SSL thread support. */
@ -202,22 +220,134 @@ typedef enum {
#define ERRSTR1(x,y,z) (x ":" y ": " z)
#define ERRSTR(x) ERRSTR1("_ssl.c", STRINGIFY2(__LINE__), x)
/* XXX It might be helpful to augment the error message generated
below with the name of the SSL function that generated the error.
I expect it's obvious most of the time.
*/
/*
* SSL errors.
*/
PyDoc_STRVAR(SSLError_doc,
"An error occurred in the SSL implementation.");
PyDoc_STRVAR(SSLZeroReturnError_doc,
"SSL/TLS session closed cleanly.");
PyDoc_STRVAR(SSLWantReadError_doc,
"Non-blocking SSL socket needs to read more data\n"
"before the requested operation can be completed.");
PyDoc_STRVAR(SSLWantWriteError_doc,
"Non-blocking SSL socket needs to write more data\n"
"before the requested operation can be completed.");
PyDoc_STRVAR(SSLSyscallError_doc,
"System error when attempting SSL operation.");
PyDoc_STRVAR(SSLEOFError_doc,
"SSL/TLS connection terminated abruptly.");
static PyObject *
SSLError_str(PyOSErrorObject *self)
{
if (self->strerror != NULL && PyUnicode_Check(self->strerror)) {
Py_INCREF(self->strerror);
return self->strerror;
}
else
return PyObject_Str(self->args);
}
static PyType_Slot sslerror_type_slots[] = {
{Py_tp_base, NULL}, /* Filled out in module init as it's not a constant */
{Py_tp_doc, SSLError_doc},
{Py_tp_str, SSLError_str},
{0, 0},
};
static PyType_Spec sslerror_type_spec = {
"ssl.SSLError",
sizeof(PyOSErrorObject),
0,
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
sslerror_type_slots
};
static void
fill_and_set_sslerror(PyObject *type, int ssl_errno, const char *errstr,
int lineno, unsigned long errcode)
{
PyObject *err_value = NULL, *reason_obj = NULL, *lib_obj = NULL;
PyObject *init_value, *msg, *key;
_Py_IDENTIFIER(reason);
_Py_IDENTIFIER(library);
if (errcode != 0) {
int lib, reason;
lib = ERR_GET_LIB(errcode);
reason = ERR_GET_REASON(errcode);
key = Py_BuildValue("ii", lib, reason);
if (key == NULL)
goto fail;
reason_obj = PyDict_GetItem(err_codes_to_names, key);
Py_DECREF(key);
if (reason_obj == NULL) {
/* XXX if reason < 100, it might reflect a library number (!!) */
PyErr_Clear();
}
key = PyLong_FromLong(lib);
if (key == NULL)
goto fail;
lib_obj = PyDict_GetItem(lib_codes_to_names, key);
Py_DECREF(key);
if (lib_obj == NULL) {
PyErr_Clear();
}
if (errstr == NULL)
errstr = ERR_reason_error_string(errcode);
}
if (errstr == NULL)
errstr = "unknown error";
if (reason_obj && lib_obj)
msg = PyUnicode_FromFormat("[%S: %S] %s (_ssl.c:%d)",
lib_obj, reason_obj, errstr, lineno);
else if (lib_obj)
msg = PyUnicode_FromFormat("[%S] %s (_ssl.c:%d)",
lib_obj, errstr, lineno);
else
msg = PyUnicode_FromFormat("%s (_ssl.c:%d)", errstr, lineno);
if (msg == NULL)
goto fail;
init_value = Py_BuildValue("iN", ssl_errno, msg);
err_value = PyObject_CallObject(type, init_value);
Py_DECREF(init_value);
if (err_value == NULL)
goto fail;
if (reason_obj == NULL)
reason_obj = Py_None;
if (_PyObject_SetAttrId(err_value, &PyId_reason, reason_obj))
goto fail;
if (lib_obj == NULL)
lib_obj = Py_None;
if (_PyObject_SetAttrId(err_value, &PyId_library, lib_obj))
goto fail;
PyErr_SetObject(type, err_value);
fail:
Py_XDECREF(err_value);
}
static PyObject *
PySSL_SetError(PySSLSocket *obj, int ret, char *filename, int lineno)
{
PyObject *v;
PyObject *type = PySSLErrorObject;
char buf[2048];
char *errstr;
char *errstr = NULL;
int err;
enum py_ssl_error p = PY_SSL_ERROR_NONE;
unsigned long e = 0;
assert(ret <= 0);
e = ERR_peek_last_error();
if (obj->ssl != NULL) {
err = SSL_get_error(obj->ssl, ret);
@ -248,7 +378,6 @@ PySSL_SetError(PySSLSocket *obj, int ret, char *filename, int lineno)
break;
case SSL_ERROR_SYSCALL:
{
unsigned long e = ERR_get_error();
if (e == 0) {
PySocketSockObject *s
= (PySocketSockObject *) PyWeakref_GetObject(obj->Socket);
@ -260,9 +389,9 @@ PySSL_SetError(PySSLSocket *obj, int ret, char *filename, int lineno)
/* underlying BIO reported an I/O error */
Py_INCREF(s);
ERR_clear_error();
v = s->errorhandler();
s->errorhandler();
Py_DECREF(s);
return v;
return NULL;
} else { /* possible? */
p = PY_SSL_ERROR_SYSCALL;
type = PySSLSyscallErrorObject;
@ -270,60 +399,43 @@ PySSL_SetError(PySSLSocket *obj, int ret, char *filename, int lineno)
}
} else {
p = PY_SSL_ERROR_SYSCALL;
/* XXX Protected by global interpreter lock */
errstr = ERR_error_string(e, NULL);
}
break;
}
case SSL_ERROR_SSL:
{
unsigned long e = ERR_get_error();
p = PY_SSL_ERROR_SSL;
if (e != 0)
/* XXX Protected by global interpreter lock */
errstr = ERR_error_string(e, NULL);
else { /* possible? */
if (e == 0)
/* possible? */
errstr = "A failure in the SSL library occurred";
}
break;
}
default:
p = PY_SSL_ERROR_INVALID_ERROR_CODE;
errstr = "Invalid error code";
}
} else {
errstr = ERR_error_string(ERR_peek_last_error(), NULL);
}
PyOS_snprintf(buf, sizeof(buf), "_ssl.c:%d: %s", lineno, errstr);
fill_and_set_sslerror(type, p, errstr, lineno, e);
ERR_clear_error();
v = Py_BuildValue("(is)", p, buf);
if (v != NULL) {
PyErr_SetObject(type, v);
Py_DECREF(v);
}
return NULL;
}
static PyObject *
_setSSLError (char *errstr, int errcode, char *filename, int lineno) {
char buf[2048];
PyObject *v;
if (errstr == NULL) {
if (errstr == NULL)
errcode = ERR_peek_last_error();
errstr = ERR_error_string(errcode, NULL);
}
PyOS_snprintf(buf, sizeof(buf), "_ssl.c:%d: %s", lineno, errstr);
else
errcode = 0;
fill_and_set_sslerror(PySSLErrorObject, errcode, errstr, lineno, errcode);
ERR_clear_error();
v = Py_BuildValue("(is)", errcode, buf);
if (v != NULL) {
PyErr_SetObject(PySSLErrorObject, v);
Py_DECREF(v);
}
return NULL;
}
/*
* SSL objects
*/
static PySSLSocket *
newPySSLSocket(SSL_CTX *ctx, PySocketSockObject *sock,
enum py_ssl_server_or_client socket_type,
@ -2520,27 +2632,6 @@ parse_openssl_version(unsigned long libver,
*major = libver & 0xFF;
}
PyDoc_STRVAR(SSLError_doc,
"An error occurred in the SSL implementation.");
PyDoc_STRVAR(SSLZeroReturnError_doc,
"SSL/TLS session closed cleanly.");
PyDoc_STRVAR(SSLWantReadError_doc,
"Non-blocking SSL socket needs to read more data\n"
"before the requested operation can be completed.");
PyDoc_STRVAR(SSLWantWriteError_doc,
"Non-blocking SSL socket needs to write more data\n"
"before the requested operation can be completed.");
PyDoc_STRVAR(SSLSyscallError_doc,
"System error when attempting SSL operation.");
PyDoc_STRVAR(SSLEOFError_doc,
"SSL/TLS connection terminated abruptly.");
PyMODINIT_FUNC
PyInit__ssl(void)
{
@ -2548,6 +2639,8 @@ PyInit__ssl(void)
unsigned long libver;
unsigned int major, minor, fix, patch, status;
PySocketModule_APIObject *socket_api;
struct py_ssl_error_code *errcode;
struct py_ssl_library_code *libcode;
if (PyType_Ready(&PySSLContext_Type) < 0)
return NULL;
@ -2577,12 +2670,11 @@ PyInit__ssl(void)
OpenSSL_add_all_algorithms();
/* Add symbols to module dict */
PySSLErrorObject = PyErr_NewExceptionWithDoc("ssl.SSLError",
SSLError_doc,
PyExc_OSError,
NULL);
sslerror_type_slots[0].pfunc = PyExc_OSError;
PySSLErrorObject = PyType_FromSpec(&sslerror_type_spec);
if (PySSLErrorObject == NULL)
return NULL;
PySSLZeroReturnErrorObject = PyErr_NewExceptionWithDoc(
"ssl.SSLZeroReturnError", SSLZeroReturnError_doc,
PySSLErrorObject, NULL);
@ -2705,6 +2797,50 @@ PyInit__ssl(void)
Py_INCREF(r);
PyModule_AddObject(m, "HAS_NPN", r);
/* Mappings for error codes */
err_codes_to_names = PyDict_New();
err_names_to_codes = PyDict_New();
if (err_codes_to_names == NULL || err_names_to_codes == NULL)
return NULL;
errcode = error_codes;
while (errcode->mnemonic != NULL) {
PyObject *mnemo, *key;
mnemo = PyUnicode_FromString(errcode->mnemonic);
key = Py_BuildValue("ii", errcode->library, errcode->reason);
if (mnemo == NULL || key == NULL)
return NULL;
if (PyDict_SetItem(err_codes_to_names, key, mnemo))
return NULL;
if (PyDict_SetItem(err_names_to_codes, mnemo, key))
return NULL;
Py_DECREF(key);
Py_DECREF(mnemo);
errcode++;
}
if (PyModule_AddObject(m, "err_codes_to_names", err_codes_to_names))
return NULL;
if (PyModule_AddObject(m, "err_names_to_codes", err_names_to_codes))
return NULL;
lib_codes_to_names = PyDict_New();
if (lib_codes_to_names == NULL)
return NULL;
libcode = library_codes;
while (libcode->library != NULL) {
PyObject *mnemo, *key;
key = PyLong_FromLong(libcode->code);
mnemo = PyUnicode_FromString(libcode->library);
if (key == NULL || mnemo == NULL)
return NULL;
if (PyDict_SetItem(lib_codes_to_names, key, mnemo))
return NULL;
Py_DECREF(key);
Py_DECREF(mnemo);
libcode++;
}
if (PyModule_AddObject(m, "lib_codes_to_names", lib_codes_to_names))
return NULL;
/* OpenSSL version */
/* SSLeay() gives us the version of the library linked against,
which could be different from the headers version.

1653
Modules/_ssl_data.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,7 @@ typedef struct {
PyObject_HEAD
PyThread_type_lock lock_lock;
PyObject *in_weakreflist;
char locked; /* for sanity checking */
} lockobject;
static void
@ -32,9 +33,8 @@ lock_dealloc(lockobject *self)
PyObject_ClearWeakRefs((PyObject *) self);
if (self->lock_lock != NULL) {
/* Unlock the lock so it's safe to free it */
PyThread_acquire_lock(self->lock_lock, 0);
PyThread_release_lock(self->lock_lock);
if (self->locked)
PyThread_release_lock(self->lock_lock);
PyThread_free_lock(self->lock_lock);
}
PyObject_Del(self);
@ -62,9 +62,13 @@ acquire_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds)
do {
Py_BEGIN_ALLOW_THREADS
r = PyThread_acquire_lock_timed(lock, microseconds, 1);
Py_END_ALLOW_THREADS
/* first a simple non-blocking try without releasing the GIL */
r = PyThread_acquire_lock_timed(lock, 0, 0);
if (r == PY_LOCK_FAILURE && microseconds != 0) {
Py_BEGIN_ALLOW_THREADS
r = PyThread_acquire_lock_timed(lock, microseconds, 1);
Py_END_ALLOW_THREADS
}
if (r == PY_LOCK_INTR) {
/* Run signal handlers if we were interrupted. Propagate
@ -135,6 +139,8 @@ lock_PyThread_acquire_lock(lockobject *self, PyObject *args, PyObject *kwds)
return NULL;
}
if (r == PY_LOCK_ACQUIRED)
self->locked = 1;
return PyBool_FromLong(r == PY_LOCK_ACQUIRED);
}
@ -153,13 +159,13 @@ static PyObject *
lock_PyThread_release_lock(lockobject *self)
{
/* Sanity check: the lock must be locked */
if (PyThread_acquire_lock(self->lock_lock, 0)) {
PyThread_release_lock(self->lock_lock);
if (!self->locked) {
PyErr_SetString(ThreadError, "release unlocked lock");
return NULL;
}
PyThread_release_lock(self->lock_lock);
self->locked = 0;
Py_INCREF(Py_None);
return Py_None;
}
@ -175,11 +181,7 @@ but it needn't be locked by the same thread that unlocks it.");
static PyObject *
lock_locked_lock(lockobject *self)
{
if (PyThread_acquire_lock(self->lock_lock, 0)) {
PyThread_release_lock(self->lock_lock);
return PyBool_FromLong(0L);
}
return PyBool_FromLong(1L);
return PyBool_FromLong((long)self->locked);
}
PyDoc_STRVAR(locked_doc,
@ -313,14 +315,7 @@ rlock_acquire(rlockobject *self, PyObject *args, PyObject *kwds)
self->rlock_count = count;
Py_RETURN_TRUE;
}
if (self->rlock_count > 0 ||
!PyThread_acquire_lock(self->rlock_lock, 0)) {
if (microseconds == 0) {
Py_RETURN_FALSE;
}
r = acquire_timed(self->rlock_lock, microseconds);
}
r = acquire_timed(self->rlock_lock, microseconds);
if (r == PY_LOCK_ACQUIRED) {
assert(self->rlock_count == 0);
self->rlock_owner = tid;
@ -548,6 +543,7 @@ newlockobject(void)
if (self == NULL)
return NULL;
self->lock_lock = PyThread_allocate_lock();
self->locked = 0;
self->in_weakreflist = NULL;
if (self->lock_lock == NULL) {
Py_DECREF(self);

View File

@ -400,6 +400,15 @@ PyMethod_Fini(void)
(void)PyMethod_ClearFreeList();
}
/* Print summary info about the state of the optimized allocator */
void
_PyMethod_DebugMallocStats(FILE *out)
{
_PyDebugAllocatorStats(out,
"free PyMethodObject",
numfree, sizeof(PyMethodObject));
}
/* ------------------------------------------------------------------------
* instance method
*/

View File

@ -255,6 +255,15 @@ PyDict_ClearFreeList(void)
return ret;
}
/* Print summary info about the state of the optimized allocator */
void
_PyDict_DebugMallocStats(FILE *out)
{
_PyDebugAllocatorStats(out,
"free PyDictObject", numfree, sizeof(PyDictObject));
}
void
PyDict_Fini(void)
{

View File

@ -1933,6 +1933,16 @@ PyFloat_Fini(void)
(void)PyFloat_ClearFreeList();
}
/* Print summary info about the state of the optimized allocator */
void
_PyFloat_DebugMallocStats(FILE *out)
{
_PyDebugAllocatorStats(out,
"free PyFloatObject",
numfree, sizeof(PyFloatObject));
}
/*----------------------------------------------------------------------------
* _PyFloat_{Pack,Unpack}{4,8}. See floatobject.h.
*/

View File

@ -955,3 +955,13 @@ PyFrame_Fini(void)
Py_XDECREF(builtin_object);
builtin_object = NULL;
}
/* Print summary info about the state of the optimized allocator */
void
_PyFrame_DebugMallocStats(FILE *out)
{
_PyDebugAllocatorStats(out,
"free PyFrameObject",
numfree, sizeof(PyFrameObject));
}

View File

@ -117,6 +117,15 @@ PyList_Fini(void)
PyList_ClearFreeList();
}
/* Print summary info about the state of the optimized allocator */
void
_PyList_DebugMallocStats(FILE *out)
{
_PyDebugAllocatorStats(out,
"free PyListObject",
numfree, sizeof(PyListObject));
}
PyObject *
PyList_New(Py_ssize_t size)
{

View File

@ -338,6 +338,15 @@ PyCFunction_Fini(void)
(void)PyCFunction_ClearFreeList();
}
/* Print summary info about the state of the optimized allocator */
void
_PyCFunction_DebugMallocStats(FILE *out)
{
_PyDebugAllocatorStats(out,
"free PyCFunction",
numfree, sizeof(PyCFunction));
}
/* PyCFunction_New() is now just a macro that calls PyCFunction_NewEx(),
but it's part of the API so we need to keep a function around that
existing C extensions can call.

View File

@ -1852,6 +1852,18 @@ PyMem_Free(void *p)
PyMem_FREE(p);
}
void
_PyObject_DebugTypeStats(FILE *out)
{
_PyCFunction_DebugMallocStats(out);
_PyDict_DebugMallocStats(out);
_PyFloat_DebugMallocStats(out);
_PyFrame_DebugMallocStats(out);
_PyList_DebugMallocStats(out);
_PyMethod_DebugMallocStats(out);
_PySet_DebugMallocStats(out);
_PyTuple_DebugMallocStats(out);
}
/* These methods are used to control infinite recursion in repr, str, print,
etc. Container objects that may recursively contain themselves,

View File

@ -523,12 +523,10 @@ static struct arena_object* usable_arenas = NULL;
/* Number of arenas allocated that haven't been free()'d. */
static size_t narenas_currently_allocated = 0;
#ifdef PYMALLOC_DEBUG
/* Total number of times malloc() called to allocate an arena. */
static size_t ntimes_arena_allocated = 0;
/* High water mark (max value ever seen) for narenas_currently_allocated. */
static size_t narenas_highwater = 0;
#endif
/* Allocate a new arena. If we run out of memory, return NULL. Else
* allocate a new arena, and return the address of an arena_object
@ -545,7 +543,7 @@ new_arena(void)
#ifdef PYMALLOC_DEBUG
if (Py_GETENV("PYTHONMALLOCSTATS"))
_PyObject_DebugMallocStats();
_PyObject_DebugMallocStats(stderr);
#endif
if (unused_arena_objects == NULL) {
uint i;
@ -613,11 +611,9 @@ new_arena(void)
arenaobj->address = (uptr)address;
++narenas_currently_allocated;
#ifdef PYMALLOC_DEBUG
++ntimes_arena_allocated;
if (narenas_currently_allocated > narenas_highwater)
narenas_highwater = narenas_currently_allocated;
#endif
arenaobj->freepools = NULL;
/* pool_address <- first pool-aligned address in the arena
nfreepools <- number of whole pools that fit after alignment */
@ -1723,17 +1719,19 @@ _PyObject_DebugDumpAddress(const void *p)
}
}
#endif /* PYMALLOC_DEBUG */
static size_t
printone(const char* msg, size_t value)
printone(FILE *out, const char* msg, size_t value)
{
int i, k;
char buf[100];
size_t origvalue = value;
fputs(msg, stderr);
fputs(msg, out);
for (i = (int)strlen(msg); i < 35; ++i)
fputc(' ', stderr);
fputc('=', stderr);
fputc(' ', out);
fputc('=', out);
/* Write the value with commas. */
i = 22;
@ -1754,17 +1752,33 @@ printone(const char* msg, size_t value)
while (i >= 0)
buf[i--] = ' ';
fputs(buf, stderr);
fputs(buf, out);
return origvalue;
}
/* Print summary info to stderr about the state of pymalloc's structures.
void
_PyDebugAllocatorStats(FILE *out,
const char *block_name, int num_blocks, size_t sizeof_block)
{
char buf1[128];
char buf2[128];
PyOS_snprintf(buf1, sizeof(buf1),
"%d %ss * %zd bytes each",
num_blocks, block_name, sizeof_block);
PyOS_snprintf(buf2, sizeof(buf2),
"%48s ", buf1);
(void)printone(out, buf2, num_blocks * sizeof_block);
}
#ifdef WITH_PYMALLOC
/* Print summary info to "out" about the state of pymalloc's structures.
* In Py_DEBUG mode, also perform some expensive internal consistency
* checks.
*/
void
_PyObject_DebugMallocStats(void)
_PyObject_DebugMallocStats(FILE *out)
{
uint i;
const uint numclasses = SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT;
@ -1793,7 +1807,7 @@ _PyObject_DebugMallocStats(void)
size_t total;
char buf[128];
fprintf(stderr, "Small block threshold = %d, in %u size classes.\n",
fprintf(out, "Small block threshold = %d, in %u size classes.\n",
SMALL_REQUEST_THRESHOLD, numclasses);
for (i = 0; i < numclasses; ++i)
@ -1847,10 +1861,10 @@ _PyObject_DebugMallocStats(void)
}
assert(narenas == narenas_currently_allocated);
fputc('\n', stderr);
fputc('\n', out);
fputs("class size num pools blocks in use avail blocks\n"
"----- ---- --------- ------------- ------------\n",
stderr);
out);
for (i = 0; i < numclasses; ++i) {
size_t p = numpools[i];
@ -1861,7 +1875,7 @@ _PyObject_DebugMallocStats(void)
assert(b == 0 && f == 0);
continue;
}
fprintf(stderr, "%5u %6u "
fprintf(out, "%5u %6u "
"%11" PY_FORMAT_SIZE_T "u "
"%15" PY_FORMAT_SIZE_T "u "
"%13" PY_FORMAT_SIZE_T "u\n",
@ -1871,35 +1885,36 @@ _PyObject_DebugMallocStats(void)
pool_header_bytes += p * POOL_OVERHEAD;
quantization += p * ((POOL_SIZE - POOL_OVERHEAD) % size);
}
fputc('\n', stderr);
(void)printone("# times object malloc called", serialno);
(void)printone("# arenas allocated total", ntimes_arena_allocated);
(void)printone("# arenas reclaimed", ntimes_arena_allocated - narenas);
(void)printone("# arenas highwater mark", narenas_highwater);
(void)printone("# arenas allocated current", narenas);
fputc('\n', out);
#ifdef PYMALLOC_DEBUG
(void)printone(out, "# times object malloc called", serialno);
#endif
(void)printone(out, "# arenas allocated total", ntimes_arena_allocated);
(void)printone(out, "# arenas reclaimed", ntimes_arena_allocated - narenas);
(void)printone(out, "# arenas highwater mark", narenas_highwater);
(void)printone(out, "# arenas allocated current", narenas);
PyOS_snprintf(buf, sizeof(buf),
"%" PY_FORMAT_SIZE_T "u arenas * %d bytes/arena",
narenas, ARENA_SIZE);
(void)printone(buf, narenas * ARENA_SIZE);
(void)printone(out, buf, narenas * ARENA_SIZE);
fputc('\n', stderr);
fputc('\n', out);
total = printone("# bytes in allocated blocks", allocated_bytes);
total += printone("# bytes in available blocks", available_bytes);
total = printone(out, "# bytes in allocated blocks", allocated_bytes);
total += printone(out, "# bytes in available blocks", available_bytes);
PyOS_snprintf(buf, sizeof(buf),
"%u unused pools * %d bytes", numfreepools, POOL_SIZE);
total += printone(buf, (size_t)numfreepools * POOL_SIZE);
total += printone(out, buf, (size_t)numfreepools * POOL_SIZE);
total += printone("# bytes lost to pool headers", pool_header_bytes);
total += printone("# bytes lost to quantization", quantization);
total += printone("# bytes lost to arena alignment", arena_alignment);
(void)printone("Total", total);
total += printone(out, "# bytes lost to pool headers", pool_header_bytes);
total += printone(out, "# bytes lost to quantization", quantization);
total += printone(out, "# bytes lost to arena alignment", arena_alignment);
(void)printone(out, "Total", total);
}
#endif /* PYMALLOC_DEBUG */
#endif /* #ifdef WITH_PYMALLOC */
#ifdef Py_USING_MEMORY_DEBUGGER
/* Make this function last so gcc won't inline it since the definition is

View File

@ -1133,6 +1133,16 @@ PySet_Fini(void)
Py_CLEAR(emptyfrozenset);
}
/* Print summary info about the state of the optimized allocator */
void
_PySet_DebugMallocStats(FILE *out)
{
_PyDebugAllocatorStats(out,
"free PySetObject",
numfree, sizeof(PySetObject));
}
static PyObject *
set_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{

View File

@ -45,6 +45,22 @@ show_track(void)
}
#endif
/* Print summary info about the state of the optimized allocator */
void
_PyTuple_DebugMallocStats(FILE *out)
{
#if PyTuple_MAXSAVESIZE > 0
int i;
char buf[128];
for (i = 1; i < PyTuple_MAXSAVESIZE; i++) {
PyOS_snprintf(buf, sizeof(buf),
"free %d-sized PyTupleObject", i);
_PyDebugAllocatorStats(out,
buf,
numfree[i], _PyObject_VAR_SIZE(&PyTuple_Type, i));
}
#endif
}
PyObject *
PyTuple_New(register Py_ssize_t size)

View File

@ -12,6 +12,9 @@
<ClCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG</PreprocessorDefinitions>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemGroup>
<BuildMacro Include="PyDebugExt">

View File

@ -642,7 +642,7 @@ Py_Finalize(void)
#endif /* Py_TRACE_REFS */
#ifdef PYMALLOC_DEBUG
if (Py_GETENV("PYTHONMALLOCSTATS"))
_PyObject_DebugMallocStats();
_PyObject_DebugMallocStats(stderr);
#endif
call_ll_exitfuncs();

View File

@ -997,6 +997,27 @@ a 11-tuple where the entries in the tuple are counts of:\n\
extern "C" {
#endif
static PyObject *
sys_debugmallocstats(PyObject *self, PyObject *args)
{
#ifdef WITH_PYMALLOC
_PyObject_DebugMallocStats(stderr);
fputc('\n', stderr);
#endif
_PyObject_DebugTypeStats(stderr);
Py_RETURN_NONE;
}
PyDoc_STRVAR(debugmallocstats_doc,
"_debugmallocstats()\n\
\n\
Print summary info to stderr about the state of\n\
pymalloc's structures.\n\
\n\
In Py_DEBUG mode, also perform some expensive internal consistency\n\
checks.\n\
");
#ifdef Py_TRACE_REFS
/* Defined in objects.c because it uses static globals if that file */
extern PyObject *_Py_GetObjects(PyObject *, PyObject *);
@ -1093,6 +1114,8 @@ static PyMethodDef sys_methods[] = {
{"settrace", sys_settrace, METH_O, settrace_doc},
{"gettrace", sys_gettrace, METH_NOARGS, gettrace_doc},
{"call_tracing", sys_call_tracing, METH_VARARGS, call_tracing_doc},
{"_debugmallocstats", sys_debugmallocstats, METH_VARARGS,
debugmallocstats_doc},
{NULL, NULL} /* sentinel */
};

View File

@ -9,6 +9,12 @@
"""
import sys, os, time, difflib, optparse
from datetime import datetime, timezone
def file_mtime(path):
t = datetime.fromtimestamp(os.stat(path).st_mtime,
timezone.utc)
return t.astimezone().isoformat()
def main():
@ -30,10 +36,12 @@ def main():
n = options.lines
fromfile, tofile = args
fromdate = time.ctime(os.stat(fromfile).st_mtime)
todate = time.ctime(os.stat(tofile).st_mtime)
fromlines = open(fromfile, 'U').readlines()
tolines = open(tofile, 'U').readlines()
fromdate = file_mtime(fromfile)
todate = file_mtime(tofile)
with open(fromfile, 'U') as ff:
fromlines = ff.readlines()
with open(tofile, 'U') as tf:
tolines = tf.readlines()
if options.u:
diff = difflib.unified_diff(fromlines, tolines, fromfile, tofile, fromdate, todate, n=n)

View File

@ -0,0 +1,68 @@
#! /usr/bin/env python3
"""
This script should be called *manually* when we want to upgrade SSLError
`library` and `reason` mnemnonics to a more recent OpenSSL version.
It takes two arguments:
- the path to the OpenSSL include files' directory
(e.g. openssl-1.0.1-beta3/include/openssl/)
- the path to the C file to be generated
(probably Modules/_ssl_data.h)
"""
import datetime
import os
import re
import sys
def parse_error_codes(h_file, prefix):
pat = re.compile(r"#define\W+(%s([\w]+))\W+(\d+)\b" % re.escape(prefix))
codes = []
with open(h_file, "r", encoding="latin1") as f:
for line in f:
match = pat.search(line)
if match:
code, name, num = match.groups()
num = int(num)
codes.append((code, name, num))
return codes
if __name__ == "__main__":
openssl_inc = sys.argv[1]
outfile = sys.argv[2]
use_stdout = outfile == '-'
f = sys.stdout if use_stdout else open(outfile, "w")
error_libraries = (
# (library code, mnemonic, error prefix, header file)
('ERR_LIB_PEM', 'PEM', 'PEM_R_', 'pem.h'),
('ERR_LIB_SSL', 'SSL', 'SSL_R_', 'ssl.h'),
('ERR_LIB_X509', 'X509', 'X509_R_', 'x509.h'),
)
def w(l):
f.write(l + "\n")
w("/* File generated by Tools/ssl/make_ssl_data.py */")
w("/* Generated on %s */" % datetime.datetime.now().isoformat())
w("")
w("static struct py_ssl_library_code library_codes[] = {")
for libcode, mnemo, _, _ in error_libraries:
w(' {"%s", %s},' % (mnemo, libcode))
w(' { NULL }')
w('};')
w("")
w("static struct py_ssl_error_code error_codes[] = {")
for libcode, _, prefix, h_file in error_libraries:
codes = parse_error_codes(os.path.join(openssl_inc, h_file), prefix)
for code, name, num in sorted(codes):
w(' #ifdef %s' % (code))
w(' {"%s", %s, %s},' % (name, libcode, code))
w(' #else')
w(' {"%s", %s, %d},' % (name, libcode, num))
w(' #endif')
w(' { NULL }')
w('};')
if not use_stdout:
f.close()