Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
2cf4de5f
Commit
2cf4de5f
authored
Jul 06, 2013
by
Raymond Hettinger
Browse files
Options
Browse Files
Download
Plain Diff
merge
parents
e6f57a4f
69fb3aeb
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
802 additions
and
239 deletions
+802
-239
Doc/c-api/memory.rst
Doc/c-api/memory.rst
+170
-1
Doc/whatsnew/3.4.rst
Doc/whatsnew/3.4.rst
+4
-14
Include/objimpl.h
Include/objimpl.h
+28
-34
Include/pymem.h
Include/pymem.h
+74
-20
Misc/NEWS
Misc/NEWS
+7
-0
Modules/_testcapimodule.c
Modules/_testcapimodule.c
+163
-0
Objects/object.c
Objects/object.c
+0
-20
Objects/obmalloc.c
Objects/obmalloc.c
+355
-149
PCbuild/python.vcxproj
PCbuild/python.vcxproj
+1
-1
No files found.
Doc/c-api/memory.rst
View file @
2cf4de5f
...
...
@@ -84,6 +84,48 @@ the C library allocator as shown in the previous example, the allocated memory
for the I/O buffer escapes completely the Python memory manager.
Raw Memory Interface
====================
The following function sets are wrappers to the system allocator. These
functions are thread-safe, the :term:`GIL <global interpreter lock>` does not
need to be held.
The default raw memory block allocator uses the following functions:
:c:func:`malloc`, :c:func:`realloc` and :c:func:`free`; call ``malloc(1)`` when
requesting zero bytes.
.. versionadded:: 3.4
.. c:function:: void* PyMem_RawMalloc(size_t n)
Allocates *n* bytes and returns a pointer of type :c:type:`void\*` to the
allocated memory, or *NULL* if the request fails. Requesting zero bytes
returns a distinct non-*NULL* pointer if possible, as if
``PyMem_RawMalloc(1)`` had been called instead. The memory will not have
been initialized in any way.
.. c:function:: void* PyMem_RawRealloc(void *p, size_t n)
Resizes the memory block pointed to by *p* to *n* bytes. The contents will
be unchanged to the minimum of the old and the new sizes. If *p* is *NULL*,
the call is equivalent to ``PyMem_RawMalloc(n)``; else if *n* is equal to
zero, the memory block is resized but is not freed, and the returned pointer
is non-*NULL*. Unless *p* is *NULL*, it must have been returned by a
previous call to :c:func:`PyMem_RawMalloc` or :c:func:`PyMem_RawRealloc`. If
the request fails, :c:func:`PyMem_RawRealloc` returns *NULL* and *p* remains
a valid pointer to the previous memory area.
.. c:function:: void PyMem_RawFree(void *p)
Frees the memory block pointed to by *p*, which must have been returned by a
previous call to :c:func:`PyMem_RawMalloc` or :c:func:`PyMem_RawRealloc`.
Otherwise, or if ``PyMem_Free(p)`` has been called before, undefined
behavior occurs. If *p* is *NULL*, no operation is performed.
.. _memoryinterface:
Memory Interface
...
...
@@ -91,8 +133,16 @@ Memory Interface
The following function sets, modeled after the ANSI C standard, but specifying
behavior when requesting zero bytes, are available for allocating and releasing
memory from the Python heap:
memory from the Python heap.
The default memory block allocator uses the following functions:
:c:func:`malloc`, :c:func:`realloc` and :c:func:`free`; call ``malloc(1)`` when
requesting zero bytes.
.. warning::
The :term:`GIL <global interpreter lock>` must be held when using these
functions.
.. c:function:: void* PyMem_Malloc(size_t n)
...
...
@@ -155,6 +205,125 @@ versions and is therefore deprecated in extension modules.
:c:func:`PyMem_NEW`, :c:func:`PyMem_RESIZE`, :c:func:`PyMem_DEL`.
Customize Memory Allocators
===========================
.. versionadded:: 3.4
.. c:type:: PyMemAllocator
Structure used to describe a memory block allocator. The structure has
four fields:
+----------------------------------------------------------+---------------------------------------+
| Field | Meaning |
+==========================================================+=======================================+
| ``void *ctx`` | user context passed as first argument |
+----------------------------------------------------------+---------------------------------------+
| ``void* malloc(void *ctx, size_t size)`` | allocate a memory block |
+----------------------------------------------------------+---------------------------------------+
| ``void* realloc(void *ctx, void *ptr, size_t new_size)`` | allocate or resize a memory block |
+----------------------------------------------------------+---------------------------------------+
| ``void free(void *ctx, void *ptr)`` | free a memory block |
+----------------------------------------------------------+---------------------------------------+
.. c:type:: PyMemAllocatorDomain
Enum used to identify an allocator domain. Domains:
* :c:data:`PYMEM_DOMAIN_RAW`: functions :c:func:`PyMem_RawMalloc`,
:c:func:`PyMem_RawRealloc` and :c:func:`PyMem_RawFree`
* :c:data:`PYMEM_DOMAIN_MEM`: functions :c:func:`PyMem_Malloc`,
:c:func:`PyMem_Realloc` and :c:func:`PyMem_Free`
* :c:data:`PYMEM_DOMAIN_OBJ`: functions :c:func:`PyObject_Malloc`,
:c:func:`PyObject_Realloc` and :c:func:`PyObject_Free`
.. c:function:: void PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator)
Get the memory block allocator of the specified domain.
.. c:function:: void PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator)
Set the memory block allocator of the specified domain.
The new allocator must return a distinct non-NULL pointer when requesting
zero bytes.
For the :c:data:`PYMEM_DOMAIN_RAW` domain, the allocator must be
thread-safe: the :term:`GIL <global interpreter lock>` is not held when the
allocator is called.
If the new allocator is not a hook (does not call the previous allocator),
the :c:func:`PyMem_SetupDebugHooks` function must be called to reinstall the
debug hooks on top on the new allocator.
.. c:function:: void PyMem_SetupDebugHooks(void)
Setup hooks to detect bugs in the following Python memory allocator
functions:
- :c:func:`PyMem_RawMalloc`, :c:func:`PyMem_RawRealloc`,
:c:func:`PyMem_RawFree`
- :c:func:`PyMem_Malloc`, :c:func:`PyMem_Realloc`, :c:func:`PyMem_Free`
- :c:func:`PyObject_Malloc`, :c:func:`PyObject_Realloc`,
:c:func:`PyObject_Free`
Newly allocated memory is filled with the byte ``0xCB``, freed memory is
filled with the byte ``0xDB``. Additionnal checks:
- detect API violations, ex: :c:func:`PyObject_Free` called on a buffer
allocated by :c:func:`PyMem_Malloc`
- detect write before the start of the buffer (buffer underflow)
- detect write after the end of the buffer (buffer overflow)
The function does nothing if Python is not compiled is debug mode.
Customize PyObject Arena Allocator
==================================
Python has a *pymalloc* allocator for allocations smaller than 512 bytes. This
allocator is optimized for small objects with a short lifetime. It uses memory
mappings called "arenas" with a fixed size of 256 KB. It falls back to
:c:func:`PyMem_Malloc` and :c:func:`PyMem_Realloc` for allocations larger than
512 bytes. *pymalloc* is the default allocator used by
:c:func:`PyObject_Malloc`.
The default arena allocator uses the following functions:
* :c:func:`VirtualAlloc` and :c:func:`VirtualFree` on Windows,
* :c:func:`mmap` and :c:func:`munmap` if available,
* :c:func:`malloc` and :c:func:`free` otherwise.
.. versionadded:: 3.4
.. c:type:: PyObjectArenaAllocator
Structure used to describe an arena allocator. The structure has
three fields:
+--------------------------------------------------+---------------------------------------+
| Field | Meaning |
+==================================================+=======================================+
| ``void *ctx`` | user context passed as first argument |
+--------------------------------------------------+---------------------------------------+
| ``void* alloc(void *ctx, size_t size)`` | allocate an arena of size bytes |
+--------------------------------------------------+---------------------------------------+
| ``void free(void *ctx, size_t size, void *ptr)`` | free an arena |
+--------------------------------------------------+---------------------------------------+
.. c:function:: PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator)
Get the arena allocator.
.. c:function:: PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator)
Set the arena allocator.
.. _memoryexamples:
Examples
...
...
Doc/whatsnew/3.4.rst
View file @
2cf4de5f
...
...
@@ -112,21 +112,11 @@ Security improvements:
Please read on for a comprehensive list of user-facing changes.
.. PEP-sized items next.
.. _pep-4XX:
.. PEP 4XX: Example PEP
.. ====================
.. (Implemented by Foo Bar.)
.. .. seealso::
:pep:`4XX` - Example PEP
PEP written by Example Author
PEP 445: Add new APIs to customize Python memory allocators
===========================================================
The :pep:`445` adds new Application Programming Interfaces (API) to customize
Python memory allocators.
...
...
Include/objimpl.h
View file @
2cf4de5f
...
...
@@ -94,9 +94,9 @@ PyObject_{New, NewVar, Del}.
the object gets initialized via PyObject_{Init, InitVar} after obtaining
the raw memory.
*/
PyAPI_FUNC
(
void
*
)
PyObject_Malloc
(
size_t
);
PyAPI_FUNC
(
void
*
)
PyObject_Realloc
(
void
*
,
size_t
);
PyAPI_FUNC
(
void
)
PyObject_Free
(
void
*
);
PyAPI_FUNC
(
void
*
)
PyObject_Malloc
(
size_t
size
);
PyAPI_FUNC
(
void
*
)
PyObject_Realloc
(
void
*
ptr
,
size_t
new_size
);
PyAPI_FUNC
(
void
)
PyObject_Free
(
void
*
ptr
);
/* This function returns the number of allocated memory blocks, regardless of size */
PyAPI_FUNC
(
Py_ssize_t
)
_Py_GetAllocatedBlocks
(
void
);
...
...
@@ -106,41 +106,15 @@ PyAPI_FUNC(Py_ssize_t) _Py_GetAllocatedBlocks(void);
#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_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
);
PyAPI_FUNC
(
void
)
_PyObject_DebugCheckAddressApi
(
char
api
,
const
void
*
p
);
PyAPI_FUNC
(
void
*
)
_PyMem_DebugMalloc
(
size_t
nbytes
);
PyAPI_FUNC
(
void
*
)
_PyMem_DebugRealloc
(
void
*
p
,
size_t
nbytes
);
PyAPI_FUNC
(
void
)
_PyMem_DebugFree
(
void
*
p
);
#define PyObject_MALLOC _PyObject_DebugMalloc
#define PyObject_Malloc _PyObject_DebugMalloc
#define PyObject_REALLOC _PyObject_DebugRealloc
#define PyObject_Realloc _PyObject_DebugRealloc
#define PyObject_FREE _PyObject_DebugFree
#define PyObject_Free _PyObject_DebugFree
#else
/* WITH_PYMALLOC && ! PYMALLOC_DEBUG */
#endif
/* Macros */
#define PyObject_MALLOC PyObject_Malloc
#define PyObject_REALLOC PyObject_Realloc
#define PyObject_FREE PyObject_Free
#endif
#else
/* ! WITH_PYMALLOC */
#define PyObject_MALLOC PyMem_MALLOC
#define PyObject_REALLOC PyMem_REALLOC
#define PyObject_FREE PyMem_FREE
#endif
/* WITH_PYMALLOC */
#define PyObject_Del PyObject_Free
#define PyObject_DEL PyObject_FREE
#define PyObject_DEL PyObject_Free
/*
* Generic object allocator interface
...
...
@@ -224,6 +198,26 @@ PyAPI_FUNC(PyVarObject *) _PyObject_NewVar(PyTypeObject *, Py_ssize_t);
constructor you would start directly with PyObject_Init/InitVar
*/
#ifndef Py_LIMITED_API
typedef
struct
{
/* user context passed as the first argument to the 2 functions */
void
*
ctx
;
/* allocate an arena of size bytes */
void
*
(
*
alloc
)
(
void
*
ctx
,
size_t
size
);
/* free an arena */
void
(
*
free
)
(
void
*
ctx
,
void
*
ptr
,
size_t
size
);
}
PyObjectArenaAllocator
;
/* Get the arena allocator. */
PyAPI_FUNC
(
void
)
PyObject_GetArenaAllocator
(
PyObjectArenaAllocator
*
allocator
);
/* Set the arena allocator. */
PyAPI_FUNC
(
void
)
PyObject_SetArenaAllocator
(
PyObjectArenaAllocator
*
allocator
);
#endif
/*
* Garbage Collection Support
* ==========================
...
...
Include/pymem.h
View file @
2cf4de5f
...
...
@@ -11,6 +11,11 @@
extern
"C"
{
#endif
PyAPI_FUNC
(
void
*
)
PyMem_RawMalloc
(
size_t
size
);
PyAPI_FUNC
(
void
*
)
PyMem_RawRealloc
(
void
*
ptr
,
size_t
new_size
);
PyAPI_FUNC
(
void
)
PyMem_RawFree
(
void
*
ptr
);
/* BEWARE:
Each interface exports both functions and macros. Extension modules should
...
...
@@ -49,21 +54,11 @@ extern "C" {
performed on failure (no exception is set, no warning is printed, etc).
*/
PyAPI_FUNC
(
void
*
)
PyMem_Malloc
(
size_t
);
PyAPI_FUNC
(
void
*
)
PyMem_Realloc
(
void
*
,
size_t
);
PyAPI_FUNC
(
void
)
PyMem_Free
(
void
*
);
/* Starting from Python 1.6, the wrappers Py_{Malloc,Realloc,Free} are
no longer supported. They used to call PyErr_NoMemory() on failure. */
PyAPI_FUNC
(
void
*
)
PyMem_Malloc
(
size_t
size
);
PyAPI_FUNC
(
void
*
)
PyMem_Realloc
(
void
*
ptr
,
size_t
new_size
);
PyAPI_FUNC
(
void
)
PyMem_Free
(
void
*
ptr
);
/* Macros. */
#ifdef PYMALLOC_DEBUG
/* Redirect all memory operations to Python's debugging allocator. */
#define PyMem_MALLOC _PyMem_DebugMalloc
#define PyMem_REALLOC _PyMem_DebugRealloc
#define PyMem_FREE _PyMem_DebugFree
#else
/* ! PYMALLOC_DEBUG */
/* PyMem_MALLOC(0) means malloc(1). Some systems would return NULL
for malloc(0), which would be treated as an error. Some platforms
...
...
@@ -71,13 +66,9 @@ PyAPI_FUNC(void) PyMem_Free(void *);
pymalloc. To solve these problems, allocate an extra byte. */
/* Returns NULL to indicate error if a negative size or size larger than
Py_ssize_t can represent is supplied. Helps prevents security holes. */
#define PyMem_MALLOC(n) ((size_t)(n) > (size_t)PY_SSIZE_T_MAX ? NULL \
: malloc((n) ? (n) : 1))
#define PyMem_REALLOC(p, n) ((size_t)(n) > (size_t)PY_SSIZE_T_MAX ? NULL \
: realloc((p), (n) ? (n) : 1))
#define PyMem_FREE free
#endif
/* PYMALLOC_DEBUG */
#define PyMem_MALLOC(n) PyMem_Malloc(n)
#define PyMem_REALLOC(p, n) PyMem_Realloc(p, n)
#define PyMem_FREE(p) PyMem_Free(p)
/*
* Type-oriented memory interface
...
...
@@ -115,6 +106,69 @@ PyAPI_FUNC(void) PyMem_Free(void *);
#define PyMem_Del PyMem_Free
#define PyMem_DEL PyMem_FREE
#ifndef Py_LIMITED_API
typedef
enum
{
/* PyMem_RawMalloc(), PyMem_RawRealloc() and PyMem_RawFree() */
PYMEM_DOMAIN_RAW
,
/* PyMem_Malloc(), PyMem_Realloc() and PyMem_Free() */
PYMEM_DOMAIN_MEM
,
/* PyObject_Malloc(), PyObject_Realloc() and PyObject_Free() */
PYMEM_DOMAIN_OBJ
}
PyMemAllocatorDomain
;
typedef
struct
{
/* user context passed as the first argument to the 3 functions */
void
*
ctx
;
/* allocate a memory block */
void
*
(
*
malloc
)
(
void
*
ctx
,
size_t
size
);
/* allocate or resize a memory block */
void
*
(
*
realloc
)
(
void
*
ctx
,
void
*
ptr
,
size_t
new_size
);
/* release a memory block */
void
(
*
free
)
(
void
*
ctx
,
void
*
ptr
);
}
PyMemAllocator
;
/* Get the memory block allocator of the specified domain. */
PyAPI_FUNC
(
void
)
PyMem_GetAllocator
(
PyMemAllocatorDomain
domain
,
PyMemAllocator
*
allocator
);
/* Set the memory block allocator of the specified domain.
The new allocator must return a distinct non-NULL pointer when requesting
zero bytes.
For the PYMEM_DOMAIN_RAW domain, the allocator must be thread-safe: the GIL
is not held when the allocator is called.
If the new allocator is not a hook (don't call the previous allocator), the
PyMem_SetupDebugHooks() function must be called to reinstall the debug hooks
on top on the new allocator. */
PyAPI_FUNC
(
void
)
PyMem_SetAllocator
(
PyMemAllocatorDomain
domain
,
PyMemAllocator
*
allocator
);
/* Setup hooks to detect bugs in the following Python memory allocator
functions:
- PyMem_RawMalloc(), PyMem_RawRealloc(), PyMem_RawFree()
- PyMem_Malloc(), PyMem_Realloc(), PyMem_Free()
- PyObject_Malloc(), PyObject_Realloc() and PyObject_Free()
Newly allocated memory is filled with the byte 0xCB, freed memory is filled
with the byte 0xDB. Additionnal checks:
- detect API violations, ex: PyObject_Free() called on a buffer allocated
by PyMem_Malloc()
- detect write before the start of the buffer (buffer underflow)
- detect write after the end of the buffer (buffer overflow)
The function does nothing if Python is not compiled is debug mode. */
PyAPI_FUNC
(
void
)
PyMem_SetupDebugHooks
(
void
);
#endif
#ifdef __cplusplus
}
#endif
...
...
Misc/NEWS
View file @
2cf4de5f
...
...
@@ -10,6 +10,13 @@ What's New in Python 3.4.0 Alpha 1?
Core and Builtins
-----------------
- Issue #17206: On Windows, increase the stack size from 2 MB to 4.2 MB to fix
a stack overflow in the marshal module (fix a crash in test_marshal).
Patch written by Jeremy Kloth.
- Issue #3329: Implement the PEP 445: Add new APIs to customize Python memory
allocators.
- Issue #18328: Reorder ops in PyThreadState_Delete*() functions. Now the
tstate is first removed from TLS and then deallocated.
...
...
Modules/_testcapimodule.c
View file @
2cf4de5f
...
...
@@ -2511,6 +2511,161 @@ test_decref_doesnt_leak(PyObject *ob)
Py_RETURN_NONE
;
}
static
PyObject
*
test_pymem_alloc0
(
PyObject
*
self
)
{
void
*
ptr
;
ptr
=
PyMem_Malloc
(
0
);
if
(
ptr
==
NULL
)
{
PyErr_SetString
(
PyExc_RuntimeError
,
"PyMem_Malloc(0) returns NULL"
);
return
NULL
;
}
PyMem_Free
(
ptr
);
ptr
=
PyObject_Malloc
(
0
);
if
(
ptr
==
NULL
)
{
PyErr_SetString
(
PyExc_RuntimeError
,
"PyObject_Malloc(0) returns NULL"
);
return
NULL
;
}
PyObject_Free
(
ptr
);
Py_RETURN_NONE
;
}
typedef
struct
{
PyMemAllocator
alloc
;
size_t
malloc_size
;
void
*
realloc_ptr
;
size_t
realloc_new_size
;
void
*
free_ptr
;
}
alloc_hook_t
;
static
void
*
hook_malloc
(
void
*
ctx
,
size_t
size
)
{
alloc_hook_t
*
hook
=
(
alloc_hook_t
*
)
ctx
;
hook
->
malloc_size
=
size
;
return
hook
->
alloc
.
malloc
(
hook
->
alloc
.
ctx
,
size
);
}
static
void
*
hook_realloc
(
void
*
ctx
,
void
*
ptr
,
size_t
new_size
)
{
alloc_hook_t
*
hook
=
(
alloc_hook_t
*
)
ctx
;
hook
->
realloc_ptr
=
ptr
;
hook
->
realloc_new_size
=
new_size
;
return
hook
->
alloc
.
realloc
(
hook
->
alloc
.
ctx
,
ptr
,
new_size
);
}
static
void
hook_free
(
void
*
ctx
,
void
*
ptr
)
{
alloc_hook_t
*
hook
=
(
alloc_hook_t
*
)
ctx
;
hook
->
free_ptr
=
ptr
;
hook
->
alloc
.
free
(
hook
->
alloc
.
ctx
,
ptr
);
}
static
PyObject
*
test_setallocators
(
PyMemAllocatorDomain
domain
)
{
PyObject
*
res
=
NULL
;
const
char
*
error_msg
;
alloc_hook_t
hook
;
PyMemAllocator
alloc
;
size_t
size
,
size2
;
void
*
ptr
,
*
ptr2
;
hook
.
malloc_size
=
0
;
hook
.
realloc_ptr
=
NULL
;
hook
.
realloc_new_size
=
0
;
hook
.
free_ptr
=
NULL
;
alloc
.
ctx
=
&
hook
;
alloc
.
malloc
=
&
hook_malloc
;
alloc
.
realloc
=
&
hook_realloc
;
alloc
.
free
=
&
hook_free
;
PyMem_GetAllocator
(
domain
,
&
hook
.
alloc
);
PyMem_SetAllocator
(
domain
,
&
alloc
);
size
=
42
;
switch
(
domain
)
{
case
PYMEM_DOMAIN_RAW
:
ptr
=
PyMem_RawMalloc
(
size
);
break
;
case
PYMEM_DOMAIN_MEM
:
ptr
=
PyMem_Malloc
(
size
);
break
;
case
PYMEM_DOMAIN_OBJ
:
ptr
=
PyObject_Malloc
(
size
);
break
;
default:
ptr
=
NULL
;
break
;
}
if
(
ptr
==
NULL
)
{
error_msg
=
"malloc failed"
;
goto
fail
;
}
if
(
hook
.
malloc_size
!=
size
)
{
error_msg
=
"malloc invalid size"
;
goto
fail
;
}
size2
=
200
;
switch
(
domain
)
{
case
PYMEM_DOMAIN_RAW
:
ptr2
=
PyMem_RawRealloc
(
ptr
,
size2
);
break
;
case
PYMEM_DOMAIN_MEM
:
ptr2
=
PyMem_Realloc
(
ptr
,
size2
);
break
;
case
PYMEM_DOMAIN_OBJ
:
ptr2
=
PyObject_Realloc
(
ptr
,
size2
);
break
;
}
if
(
ptr2
==
NULL
)
{
error_msg
=
"realloc failed"
;
goto
fail
;
}
if
(
hook
.
realloc_ptr
!=
ptr
||
hook
.
realloc_new_size
!=
size2
)
{
error_msg
=
"realloc invalid parameters"
;
goto
fail
;
}
switch
(
domain
)
{
case
PYMEM_DOMAIN_RAW
:
PyMem_RawFree
(
ptr2
);
break
;
case
PYMEM_DOMAIN_MEM
:
PyMem_Free
(
ptr2
);
break
;
case
PYMEM_DOMAIN_OBJ
:
PyObject_Free
(
ptr2
);
break
;
}
if
(
hook
.
free_ptr
!=
ptr2
)
{
error_msg
=
"free invalid pointer"
;
goto
fail
;
}
Py_INCREF
(
Py_None
);
res
=
Py_None
;
goto
finally
;
fail:
PyErr_SetString
(
PyExc_RuntimeError
,
error_msg
);
finally:
PyMem_SetAllocator
(
domain
,
&
hook
.
alloc
);
return
res
;
}
static
PyObject
*
test_pymem_setrawallocators
(
PyObject
*
self
)
{
return
test_setallocators
(
PYMEM_DOMAIN_RAW
);
}
static
PyObject
*
test_pymem_setallocators
(
PyObject
*
self
)
{
return
test_setallocators
(
PYMEM_DOMAIN_MEM
);
}
static
PyObject
*
test_pyobject_setallocators
(
PyObject
*
self
)
{
return
test_setallocators
(
PYMEM_DOMAIN_OBJ
);
}
static
PyMethodDef
TestMethods
[]
=
{
{
"raise_exception"
,
raise_exception
,
METH_VARARGS
},
{
"raise_memoryerror"
,
(
PyCFunction
)
raise_memoryerror
,
METH_NOARGS
},
...
...
@@ -2611,6 +2766,14 @@ static PyMethodDef TestMethods[] = {
{
"pytime_object_to_time_t"
,
test_pytime_object_to_time_t
,
METH_VARARGS
},
{
"pytime_object_to_timeval"
,
test_pytime_object_to_timeval
,
METH_VARARGS
},
{
"pytime_object_to_timespec"
,
test_pytime_object_to_timespec
,
METH_VARARGS
},
{
"test_pymem"
,
(
PyCFunction
)
test_pymem_alloc0
,
METH_NOARGS
},
{
"test_pymem_alloc0"
,
(
PyCFunction
)
test_pymem_setrawallocators
,
METH_NOARGS
},
{
"test_pymem_setallocators"
,
(
PyCFunction
)
test_pymem_setallocators
,
METH_NOARGS
},
{
"test_pyobject_setallocators"
,
(
PyCFunction
)
test_pyobject_setallocators
,
METH_NOARGS
},
{
NULL
,
NULL
}
/* sentinel */
};
...
...
Objects/object.c
View file @
2cf4de5f
...
...
@@ -1859,26 +1859,6 @@ PyTypeObject *_PyCapsule_hack = &PyCapsule_Type;
Py_ssize_t
(
*
_Py_abstract_hack
)(
PyObject
*
)
=
PyObject_Size
;
/* Python's malloc wrappers (see pymem.h) */
void
*
PyMem_Malloc
(
size_t
nbytes
)
{
return
PyMem_MALLOC
(
nbytes
);
}
void
*
PyMem_Realloc
(
void
*
p
,
size_t
nbytes
)
{
return
PyMem_REALLOC
(
p
,
nbytes
);
}
void
PyMem_Free
(
void
*
p
)
{
PyMem_FREE
(
p
);
}
void
_PyObject_DebugTypeStats
(
FILE
*
out
)
{
...
...
Objects/obmalloc.c
View file @
2cf4de5f
#include "Python.h"
/* Python's malloc wrappers (see pymem.h) */
#ifdef PYMALLOC_DEBUG
/* WITH_PYMALLOC && PYMALLOC_DEBUG */
/* Forward declaration */
static
void
*
_PyMem_DebugMalloc
(
void
*
ctx
,
size_t
size
);
static
void
_PyMem_DebugFree
(
void
*
ctx
,
void
*
p
);
static
void
*
_PyMem_DebugRealloc
(
void
*
ctx
,
void
*
ptr
,
size_t
size
);
static
void
_PyObject_DebugDumpAddress
(
const
void
*
p
);
static
void
_PyMem_DebugCheckAddress
(
char
api_id
,
const
void
*
p
);
#endif
#ifdef WITH_PYMALLOC
#ifdef HAVE_MMAP
#include <sys/mman.h>
#ifdef MAP_ANONYMOUS
#define ARENAS_USE_MMAP
#endif
#ifdef MS_WINDOWS
# include <windows.h>
#elif defined(HAVE_MMAP)
# include <sys/mman.h>
# ifdef MAP_ANONYMOUS
# define ARENAS_USE_MMAP
# endif
#endif
/* Forward declaration */
static
void
*
_PyObject_Malloc
(
void
*
ctx
,
size_t
size
);
static
void
_PyObject_Free
(
void
*
ctx
,
void
*
p
);
static
void
*
_PyObject_Realloc
(
void
*
ctx
,
void
*
ptr
,
size_t
size
);
#endif
static
void
*
_PyMem_RawMalloc
(
void
*
ctx
,
size_t
size
)
{
/* PyMem_Malloc(0) means malloc(1). Some systems would return NULL
for malloc(0), which would be treated as an error. Some platforms would
return a pointer with no memory behind it, which would break pymalloc.
To solve these problems, allocate an extra byte. */
if
(
size
==
0
)
size
=
1
;
return
malloc
(
size
);
}
static
void
*
_PyMem_RawRealloc
(
void
*
ctx
,
void
*
ptr
,
size_t
size
)
{
if
(
size
==
0
)
size
=
1
;
return
realloc
(
ptr
,
size
);
}
static
void
_PyMem_RawFree
(
void
*
ctx
,
void
*
ptr
)
{
free
(
ptr
);
}
#ifdef MS_WINDOWS
#include <windows.h>
static
void
*
_PyObject_ArenaVirtualAlloc
(
void
*
ctx
,
size_t
size
)
{
return
VirtualAlloc
(
NULL
,
size
,
MEM_COMMIT
|
MEM_RESERVE
,
PAGE_READWRITE
);
}
static
void
_PyObject_ArenaVirtualFree
(
void
*
ctx
,
void
*
ptr
,
size_t
size
)
{
VirtualFree
(
ptr
,
0
,
MEM_RELEASE
);
}
#elif defined(ARENAS_USE_MMAP)
static
void
*
_PyObject_ArenaMmap
(
void
*
ctx
,
size_t
size
)
{
void
*
ptr
;
ptr
=
mmap
(
NULL
,
size
,
PROT_READ
|
PROT_WRITE
,
MAP_PRIVATE
|
MAP_ANONYMOUS
,
-
1
,
0
);
if
(
ptr
==
MAP_FAILED
)
return
NULL
;
assert
(
ptr
!=
NULL
);
return
ptr
;
}
static
void
_PyObject_ArenaMunmap
(
void
*
ctx
,
void
*
ptr
,
size_t
size
)
{
munmap
(
ptr
,
size
);
}
#else
static
void
*
_PyObject_ArenaMalloc
(
void
*
ctx
,
size_t
size
)
{
return
malloc
(
size
);
}
static
void
_PyObject_ArenaFree
(
void
*
ctx
,
void
*
ptr
,
size_t
size
)
{
free
(
ptr
);
}
#endif
#define PYRAW_FUNCS _PyMem_RawMalloc, _PyMem_RawRealloc, _PyMem_RawFree
#ifdef WITH_PYMALLOC
#define PYOBJECT_FUNCS _PyObject_Malloc, _PyObject_Realloc, _PyObject_Free
#else
#define PYOBJECT_FUNCS PYRAW_FUNCS
#endif
#ifdef PYMALLOC_DEBUG
typedef
struct
{
/* We tag each block with an API ID in order to tag API violations */
char
api_id
;
PyMemAllocator
alloc
;
}
debug_alloc_api_t
;
static
struct
{
debug_alloc_api_t
raw
;
debug_alloc_api_t
mem
;
debug_alloc_api_t
obj
;
}
_PyMem_Debug
=
{
{
'r'
,
{
NULL
,
PYRAW_FUNCS
}},
{
'm'
,
{
NULL
,
PYRAW_FUNCS
}},
{
'o'
,
{
NULL
,
PYOBJECT_FUNCS
}}
};
#define PYDEBUG_FUNCS _PyMem_DebugMalloc, _PyMem_DebugRealloc, _PyMem_DebugFree
#endif
static
PyMemAllocator
_PyMem_Raw
=
{
#ifdef PYMALLOC_DEBUG
&
_PyMem_Debug
.
raw
,
PYDEBUG_FUNCS
#else
NULL
,
PYRAW_FUNCS
#endif
};
static
PyMemAllocator
_PyMem
=
{
#ifdef PYMALLOC_DEBUG
&
_PyMem_Debug
.
mem
,
PYDEBUG_FUNCS
#else
NULL
,
PYRAW_FUNCS
#endif
};
static
PyMemAllocator
_PyObject
=
{
#ifdef PYMALLOC_DEBUG
&
_PyMem_Debug
.
obj
,
PYDEBUG_FUNCS
#else
NULL
,
PYOBJECT_FUNCS
#endif
};
#undef PYRAW_FUNCS
#undef PYOBJECT_FUNCS
#undef PYDEBUG_FUNCS
static
PyObjectArenaAllocator
_PyObject_Arena
=
{
NULL
,
#ifdef MS_WINDOWS
_PyObject_ArenaVirtualAlloc
,
_PyObject_ArenaVirtualFree
#elif defined(ARENAS_USE_MMAP)
_PyObject_ArenaMmap
,
_PyObject_ArenaMunmap
#else
_PyObject_ArenaMalloc
,
_PyObject_ArenaFree
#endif
};
void
PyMem_SetupDebugHooks
(
void
)
{
#ifdef PYMALLOC_DEBUG
PyMemAllocator
alloc
;
alloc
.
malloc
=
_PyMem_DebugMalloc
;
alloc
.
realloc
=
_PyMem_DebugRealloc
;
alloc
.
free
=
_PyMem_DebugFree
;
if
(
_PyMem_Raw
.
malloc
!=
_PyMem_DebugMalloc
)
{
alloc
.
ctx
=
&
_PyMem_Debug
.
raw
;
PyMem_GetAllocator
(
PYMEM_DOMAIN_RAW
,
&
_PyMem_Debug
.
raw
.
alloc
);
PyMem_SetAllocator
(
PYMEM_DOMAIN_RAW
,
&
alloc
);
}
if
(
_PyMem
.
malloc
!=
_PyMem_DebugMalloc
)
{
alloc
.
ctx
=
&
_PyMem_Debug
.
mem
;
PyMem_GetAllocator
(
PYMEM_DOMAIN_MEM
,
&
_PyMem_Debug
.
mem
.
alloc
);
PyMem_SetAllocator
(
PYMEM_DOMAIN_MEM
,
&
alloc
);
}
if
(
_PyObject
.
malloc
!=
_PyMem_DebugMalloc
)
{
alloc
.
ctx
=
&
_PyMem_Debug
.
obj
;
PyMem_GetAllocator
(
PYMEM_DOMAIN_OBJ
,
&
_PyMem_Debug
.
obj
.
alloc
);
PyMem_SetAllocator
(
PYMEM_DOMAIN_OBJ
,
&
alloc
);
}
#endif
}
void
PyMem_GetAllocator
(
PyMemAllocatorDomain
domain
,
PyMemAllocator
*
allocator
)
{
switch
(
domain
)
{
case
PYMEM_DOMAIN_RAW
:
*
allocator
=
_PyMem_Raw
;
break
;
case
PYMEM_DOMAIN_MEM
:
*
allocator
=
_PyMem
;
break
;
case
PYMEM_DOMAIN_OBJ
:
*
allocator
=
_PyObject
;
break
;
default:
/* unknown domain */
allocator
->
ctx
=
NULL
;
allocator
->
malloc
=
NULL
;
allocator
->
realloc
=
NULL
;
allocator
->
free
=
NULL
;
}
}
void
PyMem_SetAllocator
(
PyMemAllocatorDomain
domain
,
PyMemAllocator
*
allocator
)
{
switch
(
domain
)
{
case
PYMEM_DOMAIN_RAW
:
_PyMem_Raw
=
*
allocator
;
break
;
case
PYMEM_DOMAIN_MEM
:
_PyMem
=
*
allocator
;
break
;
case
PYMEM_DOMAIN_OBJ
:
_PyObject
=
*
allocator
;
break
;
/* ignore unknown domain */
}
}
void
PyObject_GetArenaAllocator
(
PyObjectArenaAllocator
*
allocator
)
{
*
allocator
=
_PyObject_Arena
;
}
void
PyObject_SetArenaAllocator
(
PyObjectArenaAllocator
*
allocator
)
{
_PyObject_Arena
=
*
allocator
;
}
void
*
PyMem_RawMalloc
(
size_t
size
)
{
/*
* Limit ourselves to PY_SSIZE_T_MAX bytes to prevent security holes.
* Most python internals blindly use a signed Py_ssize_t to track
* things without checking for overflows or negatives.
* As size_t is unsigned, checking for size < 0 is not required.
*/
if
(
size
>
(
size_t
)
PY_SSIZE_T_MAX
)
return
NULL
;
return
_PyMem_Raw
.
malloc
(
_PyMem_Raw
.
ctx
,
size
);
}
void
*
PyMem_RawRealloc
(
void
*
ptr
,
size_t
new_size
)
{
/* see PyMem_RawMalloc() */
if
(
new_size
>
(
size_t
)
PY_SSIZE_T_MAX
)
return
NULL
;
return
_PyMem_Raw
.
realloc
(
_PyMem_Raw
.
ctx
,
ptr
,
new_size
);
}
void
PyMem_RawFree
(
void
*
ptr
)
{
_PyMem_Raw
.
free
(
_PyMem_Raw
.
ctx
,
ptr
);
}
void
*
PyMem_Malloc
(
size_t
size
)
{
/* see PyMem_RawMalloc() */
if
(
size
>
(
size_t
)
PY_SSIZE_T_MAX
)
return
NULL
;
return
_PyMem
.
malloc
(
_PyMem
.
ctx
,
size
);
}
void
*
PyMem_Realloc
(
void
*
ptr
,
size_t
new_size
)
{
/* see PyMem_RawMalloc() */
if
(
new_size
>
(
size_t
)
PY_SSIZE_T_MAX
)
return
NULL
;
return
_PyMem
.
realloc
(
_PyMem
.
ctx
,
ptr
,
new_size
);
}
void
PyMem_Free
(
void
*
ptr
)
{
_PyMem
.
free
(
_PyMem
.
ctx
,
ptr
);
}
void
*
PyObject_Malloc
(
size_t
size
)
{
/* see PyMem_RawMalloc() */
if
(
size
>
(
size_t
)
PY_SSIZE_T_MAX
)
return
NULL
;
return
_PyObject
.
malloc
(
_PyObject
.
ctx
,
size
);
}
void
*
PyObject_Realloc
(
void
*
ptr
,
size_t
new_size
)
{
/* see PyMem_RawMalloc() */
if
(
new_size
>
(
size_t
)
PY_SSIZE_T_MAX
)
return
NULL
;
return
_PyObject
.
realloc
(
_PyObject
.
ctx
,
ptr
,
new_size
);
}
void
PyObject_Free
(
void
*
ptr
)
{
_PyObject
.
free
(
_PyObject
.
ctx
,
ptr
);
}
#ifdef WITH_PYMALLOC
#ifdef WITH_VALGRIND
#include <valgrind/valgrind.h>
...
...
@@ -549,7 +857,6 @@ new_arena(void)
struct
arena_object
*
arenaobj
;
uint
excess
;
/* number of bytes above pool alignment */
void
*
address
;
int
err
;
#ifdef PYMALLOC_DEBUG
if
(
Py_GETENV
(
"PYTHONMALLOCSTATS"
))
...
...
@@ -571,7 +878,7 @@ new_arena(void)
return
NULL
;
/* overflow */
#endif
nbytes
=
numarenas
*
sizeof
(
*
arenas
);
arenaobj
=
(
struct
arena_object
*
)
r
ealloc
(
arenas
,
nbytes
);
arenaobj
=
(
struct
arena_object
*
)
PyMem_R
ealloc
(
arenas
,
nbytes
);
if
(
arenaobj
==
NULL
)
return
NULL
;
arenas
=
arenaobj
;
...
...
@@ -602,19 +909,8 @@ new_arena(void)
arenaobj
=
unused_arena_objects
;
unused_arena_objects
=
arenaobj
->
nextarena
;
assert
(
arenaobj
->
address
==
0
);
#ifdef MS_WINDOWS
address
=
(
void
*
)
VirtualAlloc
(
NULL
,
ARENA_SIZE
,
MEM_COMMIT
|
MEM_RESERVE
,
PAGE_READWRITE
);
err
=
(
address
==
NULL
);
#elif defined(ARENAS_USE_MMAP)
address
=
mmap
(
NULL
,
ARENA_SIZE
,
PROT_READ
|
PROT_WRITE
,
MAP_PRIVATE
|
MAP_ANONYMOUS
,
-
1
,
0
);
err
=
(
address
==
MAP_FAILED
);
#else
address
=
malloc
(
ARENA_SIZE
);
err
=
(
address
==
0
);
#endif
if
(
err
)
{
address
=
_PyObject_Arena
.
alloc
(
_PyObject_Arena
.
ctx
,
ARENA_SIZE
);
if
(
address
==
NULL
)
{
/* The allocation failed: return NULL after putting the
* arenaobj back.
*/
...
...
@@ -777,9 +1073,8 @@ int Py_ADDRESS_IN_RANGE(void *P, poolp pool) Py_NO_INLINE;
* Unless the optimizer reorders everything, being too smart...
*/
#undef PyObject_Malloc
void
*
PyObject_Malloc
(
size_t
nbytes
)
static
void
*
_PyObject_Malloc
(
void
*
ctx
,
size_t
nbytes
)
{
block
*
bp
;
poolp
pool
;
...
...
@@ -795,17 +1090,6 @@ PyObject_Malloc(size_t nbytes)
goto
redirect
;
#endif
/*
* Limit ourselves to PY_SSIZE_T_MAX bytes to prevent security holes.
* Most python internals blindly use a signed Py_ssize_t to track
* things without checking for overflows or negatives.
* As size_t is unsigned, checking for nbytes < 0 is not required.
*/
if
(
nbytes
>
PY_SSIZE_T_MAX
)
{
_Py_AllocatedBlocks
--
;
return
NULL
;
}
/*
* This implicitly redirects malloc(0).
*/
...
...
@@ -978,10 +1262,8 @@ redirect:
* last chance to serve the request) or when the max memory limit
* has been reached.
*/
if
(
nbytes
==
0
)
nbytes
=
1
;
{
void
*
result
=
m
alloc
(
nbytes
);
void
*
result
=
PyMem_M
alloc
(
nbytes
);
if
(
!
result
)
_Py_AllocatedBlocks
--
;
return
result
;
...
...
@@ -990,9 +1272,8 @@ redirect:
/* free */
#undef PyObject_Free
void
PyObject_Free
(
void
*
p
)
static
void
_PyObject_Free
(
void
*
ctx
,
void
*
p
)
{
poolp
pool
;
block
*
lastfree
;
...
...
@@ -1101,13 +1382,8 @@ PyObject_Free(void *p)
unused_arena_objects
=
ao
;
/* Free the entire arena. */
#ifdef MS_WINDOWS
VirtualFree
((
void
*
)
ao
->
address
,
0
,
MEM_RELEASE
);
#elif defined(ARENAS_USE_MMAP)
munmap
((
void
*
)
ao
->
address
,
ARENA_SIZE
);
#else
free
((
void
*
)
ao
->
address
);
#endif
_PyObject_Arena
.
free
(
_PyObject_Arena
.
ctx
,
(
void
*
)
ao
->
address
,
ARENA_SIZE
);
ao
->
address
=
0
;
/* mark unassociated */
--
narenas_currently_allocated
;
...
...
@@ -1216,7 +1492,7 @@ PyObject_Free(void *p)
redirect:
#endif
/* We didn't allocate this address. */
f
ree
(
p
);
PyMem_F
ree
(
p
);
}
/* realloc. If p is NULL, this acts like malloc(nbytes). Else if nbytes==0,
...
...
@@ -1224,9 +1500,8 @@ redirect:
* return a non-NULL result.
*/
#undef PyObject_Realloc
void
*
PyObject_Realloc
(
void
*
p
,
size_t
nbytes
)
static
void
*
_PyObject_Realloc
(
void
*
ctx
,
void
*
p
,
size_t
nbytes
)
{
void
*
bp
;
poolp
pool
;
...
...
@@ -1236,16 +1511,7 @@ PyObject_Realloc(void *p, size_t nbytes)
#endif
if
(
p
==
NULL
)
return
PyObject_Malloc
(
nbytes
);
/*
* Limit ourselves to PY_SSIZE_T_MAX bytes to prevent security holes.
* Most python internals blindly use a signed Py_ssize_t to track
* things without checking for overflows or negatives.
* As size_t is unsigned, checking for nbytes < 0 is not required.
*/
if
(
nbytes
>
PY_SSIZE_T_MAX
)
return
NULL
;
return
_PyObject_Malloc
(
ctx
,
nbytes
);
#ifdef WITH_VALGRIND
/* Treat running_on_valgrind == -1 the same as 0 */
...
...
@@ -1273,10 +1539,10 @@ PyObject_Realloc(void *p, size_t nbytes)
}
size
=
nbytes
;
}
bp
=
PyObject_Malloc
(
nbytes
);
bp
=
_PyObject_Malloc
(
ctx
,
nbytes
);
if
(
bp
!=
NULL
)
{
memcpy
(
bp
,
p
,
size
);
PyObject_Free
(
p
);
_PyObject_Free
(
ctx
,
p
);
}
return
bp
;
}
...
...
@@ -1294,14 +1560,14 @@ PyObject_Realloc(void *p, size_t nbytes)
* at p. Instead we punt: let C continue to manage this block.
*/
if
(
nbytes
)
return
r
ealloc
(
p
,
nbytes
);
return
PyMem_R
ealloc
(
p
,
nbytes
);
/* C doesn't define the result of realloc(p, 0) (it may or may not
* return NULL then), but Python's docs promise that nbytes==0 never
* returns NULL. We don't pass 0 to realloc(), to avoid that endcase
* to begin with. Even then, we can't be sure that realloc() won't
* return NULL.
*/
bp
=
r
ealloc
(
p
,
1
);
bp
=
PyMem_R
ealloc
(
p
,
1
);
return
bp
?
bp
:
p
;
}
...
...
@@ -1311,24 +1577,6 @@ PyObject_Realloc(void *p, size_t nbytes)
/* pymalloc not enabled: Redirect the entry points to malloc. These will
* only be used by extensions that are compiled with pymalloc enabled. */
void
*
PyObject_Malloc
(
size_t
n
)
{
return
PyMem_MALLOC
(
n
);
}
void
*
PyObject_Realloc
(
void
*
p
,
size_t
n
)
{
return
PyMem_REALLOC
(
p
,
n
);
}
void
PyObject_Free
(
void
*
p
)
{
PyMem_FREE
(
p
);
}
Py_ssize_t
_Py_GetAllocatedBlocks
(
void
)
{
...
...
@@ -1354,10 +1602,6 @@ _Py_GetAllocatedBlocks(void)
#define DEADBYTE 0xDB
/* dead (newly freed) memory */
#define FORBIDDENBYTE 0xFB
/* untouchable bytes at each end of a block */
/* We tag each block with an API ID in order to tag API violations */
#define _PYMALLOC_MEM_ID 'm'
/* the PyMem_Malloc() API */
#define _PYMALLOC_OBJ_ID 'o'
/* The PyObject_Malloc() API */
static
size_t
serialno
=
0
;
/* incremented on each debug {m,re}alloc */
/* serialno is always incremented via calling this routine. The point is
...
...
@@ -1440,58 +1684,18 @@ p[2*S: 2*S+n]
p[2*S+n: 2*S+n+S]
Copies of FORBIDDENBYTE. Used to catch over- writes and reads.
p[2*S+n+S: 2*S+n+2*S]
A serial number, incremented by 1 on each call to _Py
Object
_DebugMalloc
and _Py
Object
_DebugRealloc.
A serial number, incremented by 1 on each call to _Py
Mem
_DebugMalloc
and _Py
Mem
_DebugRealloc.
This is a big-endian size_t.
If "bad memory" is detected later, the serial number gives an
excellent way to set a breakpoint on the next run, to capture the
instant at which this block was passed out.
*/
/* debug replacements for the PyMem_* memory API */
void
*
_PyMem_DebugMalloc
(
size_t
nbytes
)
{
return
_PyObject_DebugMallocApi
(
_PYMALLOC_MEM_ID
,
nbytes
);
}
void
*
_PyMem_DebugRealloc
(
void
*
p
,
size_t
nbytes
)
{
return
_PyObject_DebugReallocApi
(
_PYMALLOC_MEM_ID
,
p
,
nbytes
);
}
void
_PyMem_DebugFree
(
void
*
p
)
{
_PyObject_DebugFreeApi
(
_PYMALLOC_MEM_ID
,
p
);
}
/* debug replacements for the PyObject_* memory API */
void
*
_PyObject_DebugMalloc
(
size_t
nbytes
)
{
return
_PyObject_DebugMallocApi
(
_PYMALLOC_OBJ_ID
,
nbytes
);
}
void
*
_PyObject_DebugRealloc
(
void
*
p
,
size_t
nbytes
)
{
return
_PyObject_DebugReallocApi
(
_PYMALLOC_OBJ_ID
,
p
,
nbytes
);
}
void
_PyObject_DebugFree
(
void
*
p
)
{
_PyObject_DebugFreeApi
(
_PYMALLOC_OBJ_ID
,
p
);
}
void
_PyObject_DebugCheckAddress
(
const
void
*
p
)
{
_PyObject_DebugCheckAddressApi
(
_PYMALLOC_OBJ_ID
,
p
);
}
/* generic debug memory api, with an "id" to identify the API in use */
void
*
_PyObject_DebugMallocApi
(
char
id
,
size_t
nbytes
)
static
void
*
_PyMem_DebugMalloc
(
void
*
ctx
,
size_t
nbytes
)
{
debug_alloc_api_t
*
api
=
(
debug_alloc_api_t
*
)
ctx
;
uchar
*
p
;
/* base address of malloc'ed block */
uchar
*
tail
;
/* p + 2*SST + nbytes == pointer to tail pad bytes */
size_t
total
;
/* nbytes + 4*SST */
...
...
@@ -1502,14 +1706,14 @@ _PyObject_DebugMallocApi(char id, size_t nbytes)
/* overflow: can't represent total as a size_t */
return
NULL
;
p
=
(
uchar
*
)
PyObject_Malloc
(
total
);
p
=
(
uchar
*
)
api
->
alloc
.
malloc
(
api
->
alloc
.
ctx
,
total
);
if
(
p
==
NULL
)
return
NULL
;
/* at p, write size (SST bytes), id (1 byte), pad (SST-1 bytes) */
write_size_t
(
p
,
nbytes
);
p
[
SST
]
=
(
uchar
)
id
;
memset
(
p
+
SST
+
1
,
FORBIDDENBYTE
,
SST
-
1
);
p
[
SST
]
=
(
uchar
)
api
->
api_
id
;
memset
(
p
+
SST
+
1
,
FORBIDDENBYTE
,
SST
-
1
);
if
(
nbytes
>
0
)
memset
(
p
+
2
*
SST
,
CLEANBYTE
,
nbytes
);
...
...
@@ -1527,25 +1731,27 @@ _PyObject_DebugMallocApi(char id, size_t nbytes)
Then fills the original bytes with DEADBYTE.
Then calls the underlying free.
*/
void
_Py
Object_DebugFreeApi
(
char
api
,
void
*
p
)
static
void
_Py
Mem_DebugFree
(
void
*
ctx
,
void
*
p
)
{
debug_alloc_api_t
*
api
=
(
debug_alloc_api_t
*
)
ctx
;
uchar
*
q
=
(
uchar
*
)
p
-
2
*
SST
;
/* address returned from malloc */
size_t
nbytes
;
if
(
p
==
NULL
)
return
;
_Py
Object_DebugCheckAddressApi
(
api
,
p
);
_Py
Mem_DebugCheckAddress
(
api
->
api_id
,
p
);
nbytes
=
read_size_t
(
q
);
nbytes
+=
4
*
SST
;
if
(
nbytes
>
0
)
memset
(
q
,
DEADBYTE
,
nbytes
);
PyObject_Free
(
q
);
api
->
alloc
.
free
(
api
->
alloc
.
ctx
,
q
);
}
void
*
_Py
Object_DebugReallocApi
(
char
api
,
void
*
p
,
size_t
nbytes
)
static
void
*
_Py
Mem_DebugRealloc
(
void
*
ctx
,
void
*
p
,
size_t
nbytes
)
{
debug_alloc_api_t
*
api
=
(
debug_alloc_api_t
*
)
ctx
;
uchar
*
q
=
(
uchar
*
)
p
;
uchar
*
tail
;
size_t
total
;
/* nbytes + 4*SST */
...
...
@@ -1553,9 +1759,9 @@ _PyObject_DebugReallocApi(char api, void *p, size_t nbytes)
int
i
;
if
(
p
==
NULL
)
return
_Py
Object_DebugMallocApi
(
api
,
nbytes
);
return
_Py
Mem_DebugMalloc
(
ctx
,
nbytes
);
_Py
Object_DebugCheckAddressApi
(
api
,
p
);
_Py
Mem_DebugCheckAddress
(
api
->
api_id
,
p
);
bumpserialno
();
original_nbytes
=
read_size_t
(
q
-
2
*
SST
);
total
=
nbytes
+
4
*
SST
;
...
...
@@ -1572,12 +1778,12 @@ _PyObject_DebugReallocApi(char api, void *p, size_t nbytes)
* case we didn't get the chance to mark the old memory with DEADBYTE,
* but we live with that.
*/
q
=
(
uchar
*
)
PyObject_Realloc
(
q
-
2
*
SST
,
total
);
q
=
(
uchar
*
)
api
->
alloc
.
realloc
(
api
->
alloc
.
ctx
,
q
-
2
*
SST
,
total
);
if
(
q
==
NULL
)
return
NULL
;
write_size_t
(
q
,
nbytes
);
assert
(
q
[
SST
]
==
(
uchar
)
api
);
assert
(
q
[
SST
]
==
(
uchar
)
api
->
api_id
);
for
(
i
=
1
;
i
<
SST
;
++
i
)
assert
(
q
[
SST
+
i
]
==
FORBIDDENBYTE
);
q
+=
2
*
SST
;
...
...
@@ -1599,8 +1805,8 @@ _PyObject_DebugReallocApi(char api, void *p, size_t nbytes)
* and call Py_FatalError to kill the program.
* The API id, is also checked.
*/
void
_Py
Object_DebugCheckAddressApi
(
char
api
,
const
void
*
p
)
static
void
_Py
Mem_DebugCheckAddress
(
char
api
,
const
void
*
p
)
{
const
uchar
*
q
=
(
const
uchar
*
)
p
;
char
msgbuf
[
64
];
...
...
@@ -1652,7 +1858,7 @@ error:
}
/* Display info to stderr about the memory block at p. */
void
static
void
_PyObject_DebugDumpAddress
(
const
void
*
p
)
{
const
uchar
*
q
=
(
const
uchar
*
)
p
;
...
...
PCbuild/python.vcxproj
View file @
2cf4de5f
...
...
@@ -243,7 +243,7 @@
<Link>
<OutputFile>
$(OutDir)python_d.exe
</OutputFile>
<SubSystem>
Console
</SubSystem>
<StackReserveSize>
2100000
</StackReserveSize>
<StackReserveSize>
4194304
</StackReserveSize>
<BaseAddress>
0x1d000000
</BaseAddress>
</Link>
</ItemDefinitionGroup>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment