Skip to content

Commit 645ed62

Browse files
authored
bpo-43774: Remove unused PYMALLOC_DEBUG macro (GH-25711)
Enhance also the documentation of debug hooks on memory allocators.
1 parent b1f413e commit 645ed62

File tree

8 files changed

+135
-143
lines changed

8 files changed

+135
-143
lines changed

Doc/c-api/init_config.rst

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -229,17 +229,20 @@ PyPreConfig
229229
Name of the Python memory allocators:
230230
231231
* ``PYMEM_ALLOCATOR_NOT_SET`` (``0``): don't change memory allocators
232-
(use defaults)
233-
* ``PYMEM_ALLOCATOR_DEFAULT`` (``1``): default memory allocators
234-
* ``PYMEM_ALLOCATOR_DEBUG`` (``2``): default memory allocators with
235-
debug hooks
236-
* ``PYMEM_ALLOCATOR_MALLOC`` (``3``): force usage of ``malloc()``
232+
(use defaults).
233+
* ``PYMEM_ALLOCATOR_DEFAULT`` (``1``): :ref:`default memory allocators
234+
<default-memory-allocators>`.
235+
* ``PYMEM_ALLOCATOR_DEBUG`` (``2``): :ref:`default memory allocators
236+
<default-memory-allocators>` with :ref:`debug hooks
237+
<pymem-debug-hooks>`.
238+
* ``PYMEM_ALLOCATOR_MALLOC`` (``3``): use ``malloc()`` of the C library.
237239
* ``PYMEM_ALLOCATOR_MALLOC_DEBUG`` (``4``): force usage of
238-
``malloc()`` with debug hooks
240+
``malloc()`` with :ref:`debug hooks <pymem-debug-hooks>`.
239241
* ``PYMEM_ALLOCATOR_PYMALLOC`` (``5``): :ref:`Python pymalloc memory
240-
allocator <pymalloc>`
242+
allocator <pymalloc>`.
241243
* ``PYMEM_ALLOCATOR_PYMALLOC_DEBUG`` (``6``): :ref:`Python pymalloc
242-
memory allocator <pymalloc>` with debug hooks
244+
memory allocator <pymalloc>` with :ref:`debug hooks
245+
<pymem-debug-hooks>`.
243246
244247
``PYMEM_ALLOCATOR_PYMALLOC`` and ``PYMEM_ALLOCATOR_PYMALLOC_DEBUG`` are
245248
not supported if Python is :option:`configured using --without-pymalloc

Doc/c-api/memory.rst

Lines changed: 111 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,8 @@ Legend:
389389
* ``malloc``: system allocators from the standard C library, C functions:
390390
:c:func:`malloc`, :c:func:`calloc`, :c:func:`realloc` and :c:func:`free`.
391391
* ``pymalloc``: :ref:`pymalloc memory allocator <pymalloc>`.
392-
* "+ debug": with debug hooks installed by :c:func:`PyMem_SetupDebugHooks`.
392+
* "+ debug": with :ref:`debug hooks on the Python memory allocators
393+
<pymem-debug-hooks>`.
393394
* "Debug build": :ref:`Python build in debug mode <debug-build>`.
394395
395396
.. _customize-memory-allocators:
@@ -478,45 +479,113 @@ Customize Memory Allocators
478479
479480
.. c:function:: void PyMem_SetupDebugHooks(void)
480481
481-
Setup hooks to detect bugs in the Python memory allocator functions.
482+
Setup :ref:`debug hooks in the Python memory allocators <pymem-debug-hooks>`
483+
to detect memory errors.
484+
485+
486+
.. _pymem-debug-hooks:
487+
488+
Debug hooks on the Python memory allocators
489+
===========================================
490+
491+
When :ref:`Python is built is debug mode <debug-build>`, the
492+
:c:func:`PyMem_SetupDebugHooks` function is called at the :ref:`Python
493+
preinitialization <c-preinit>` to setup debug hooks on Python memory allocators
494+
to detect memory errors.
495+
496+
The :envvar:`PYTHONMALLOC` environment variable can be used to install debug
497+
hooks on a Python compiled in release mode (ex: ``PYTHONMALLOC=debug``).
498+
499+
The :c:func:`PyMem_SetupDebugHooks` function can be used to set debug hooks
500+
after calling :c:func:`PyMem_SetAllocator`.
501+
502+
These debug hooks fill dynamically allocated memory blocks with special,
503+
recognizable bit patterns. Newly allocated memory is filled with the byte
504+
``0xCD`` (``PYMEM_CLEANBYTE``), freed memory is filled with the byte ``0xDD``
505+
(``PYMEM_DEADBYTE``). Memory blocks are surrounded by "forbidden bytes"
506+
filled with the byte ``0xFD`` (``PYMEM_FORBIDDENBYTE``). Strings of these bytes
507+
are unlikely to be valid addresses, floats, or ASCII strings.
508+
509+
Runtime checks:
510+
511+
- Detect API violations. For example, detect if :c:func:`PyObject_Free` is
512+
called on a memory block allocated by :c:func:`PyMem_Malloc`.
513+
- Detect write before the start of the buffer (buffer underflow).
514+
- Detect write after the end of the buffer (buffer overflow).
515+
- Check that the :term:`GIL <global interpreter lock>` is held when
516+
allocator functions of :c:data:`PYMEM_DOMAIN_OBJ` (ex:
517+
:c:func:`PyObject_Malloc`) and :c:data:`PYMEM_DOMAIN_MEM` (ex:
518+
:c:func:`PyMem_Malloc`) domains are called.
519+
520+
On error, the debug hooks use the :mod:`tracemalloc` module to get the
521+
traceback where a memory block was allocated. The traceback is only displayed
522+
if :mod:`tracemalloc` is tracing Python memory allocations and the memory block
523+
was traced.
524+
525+
Let *S* = ``sizeof(size_t)``. ``2*S`` bytes are added at each end of each block
526+
of *N* bytes requested. The memory layout is like so, where p represents the
527+
address returned by a malloc-like or realloc-like function (``p[i:j]`` means
528+
the slice of bytes from ``*(p+i)`` inclusive up to ``*(p+j)`` exclusive; note
529+
that the treatment of negative indices differs from a Python slice):
530+
531+
``p[-2*S:-S]``
532+
Number of bytes originally asked for. This is a size_t, big-endian (easier
533+
to read in a memory dump).
534+
``p[-S]``
535+
API identifier (ASCII character):
536+
537+
* ``'r'`` for :c:data:`PYMEM_DOMAIN_RAW`.
538+
* ``'m'`` for :c:data:`PYMEM_DOMAIN_MEM`.
539+
* ``'o'`` for :c:data:`PYMEM_DOMAIN_OBJ`.
540+
541+
``p[-S+1:0]``
542+
Copies of PYMEM_FORBIDDENBYTE. Used to catch under- writes and reads.
543+
544+
``p[0:N]``
545+
The requested memory, filled with copies of PYMEM_CLEANBYTE, used to catch
546+
reference to uninitialized memory. When a realloc-like function is called
547+
requesting a larger memory block, the new excess bytes are also filled with
548+
PYMEM_CLEANBYTE. When a free-like function is called, these are
549+
overwritten with PYMEM_DEADBYTE, to catch reference to freed memory. When
550+
a realloc- like function is called requesting a smaller memory block, the
551+
excess old bytes are also filled with PYMEM_DEADBYTE.
552+
553+
``p[N:N+S]``
554+
Copies of PYMEM_FORBIDDENBYTE. Used to catch over- writes and reads.
555+
556+
``p[N+S:N+2*S]``
557+
Only used if the ``PYMEM_DEBUG_SERIALNO`` macro is defined (not defined by
558+
default).
559+
560+
A serial number, incremented by 1 on each call to a malloc-like or
561+
realloc-like function. Big-endian ``size_t``. If "bad memory" is detected
562+
later, the serial number gives an excellent way to set a breakpoint on the
563+
next run, to capture the instant at which this block was passed out. The
564+
static function bumpserialno() in obmalloc.c is the only place the serial
565+
number is incremented, and exists so you can set such a breakpoint easily.
566+
567+
A realloc-like or free-like function first checks that the PYMEM_FORBIDDENBYTE
568+
bytes at each end are intact. If they've been altered, diagnostic output is
569+
written to stderr, and the program is aborted via Py_FatalError(). The other
570+
main failure mode is provoking a memory error when a program reads up one of
571+
the special bit patterns and tries to use it as an address. If you get in a
572+
debugger then and look at the object, you're likely to see that it's entirely
573+
filled with PYMEM_DEADBYTE (meaning freed memory is getting used) or
574+
PYMEM_CLEANBYTE (meaning uninitialized memory is getting used).
482575
483-
Newly allocated memory is filled with the byte ``0xCD`` (``CLEANBYTE``),
484-
freed memory is filled with the byte ``0xDD`` (``DEADBYTE``). Memory blocks
485-
are surrounded by "forbidden bytes" (``FORBIDDENBYTE``: byte ``0xFD``).
486-
487-
Runtime checks:
488-
489-
- Detect API violations, ex: :c:func:`PyObject_Free` called on a buffer
490-
allocated by :c:func:`PyMem_Malloc`
491-
- Detect write before the start of the buffer (buffer underflow)
492-
- Detect write after the end of the buffer (buffer overflow)
493-
- Check that the :term:`GIL <global interpreter lock>` is held when
494-
allocator functions of :c:data:`PYMEM_DOMAIN_OBJ` (ex:
495-
:c:func:`PyObject_Malloc`) and :c:data:`PYMEM_DOMAIN_MEM` (ex:
496-
:c:func:`PyMem_Malloc`) domains are called
497-
498-
On error, the debug hooks use the :mod:`tracemalloc` module to get the
499-
traceback where a memory block was allocated. The traceback is only
500-
displayed if :mod:`tracemalloc` is tracing Python memory allocations and the
501-
memory block was traced.
502-
503-
These hooks are :ref:`installed by default <default-memory-allocators>` if
504-
:ref:`Python is built in debug mode <debug-build>`.
505-
The :envvar:`PYTHONMALLOC` environment variable can be used to install
506-
debug hooks on a Python compiled in release mode.
507-
508-
.. versionchanged:: 3.6
509-
This function now also works on Python compiled in release mode.
510-
On error, the debug hooks now use :mod:`tracemalloc` to get the traceback
511-
where a memory block was allocated. The debug hooks now also check
512-
if the GIL is held when functions of :c:data:`PYMEM_DOMAIN_OBJ` and
513-
:c:data:`PYMEM_DOMAIN_MEM` domains are called.
576+
.. versionchanged:: 3.6
577+
The :c:func:`PyMem_SetupDebugHooks` function now also works on Python
578+
compiled in release mode. On error, the debug hooks now use
579+
:mod:`tracemalloc` to get the traceback where a memory block was allocated.
580+
The debug hooks now also check if the GIL is held when functions of
581+
:c:data:`PYMEM_DOMAIN_OBJ` and :c:data:`PYMEM_DOMAIN_MEM` domains are
582+
called.
514583
515-
.. versionchanged:: 3.8
516-
Byte patterns ``0xCB`` (``CLEANBYTE``), ``0xDB`` (``DEADBYTE``) and
517-
``0xFB`` (``FORBIDDENBYTE``) have been replaced with ``0xCD``, ``0xDD``
518-
and ``0xFD`` to use the same values than Windows CRT debug ``malloc()``
519-
and ``free()``.
584+
.. versionchanged:: 3.8
585+
Byte patterns ``0xCB`` (``PYMEM_CLEANBYTE``), ``0xDB`` (``PYMEM_DEADBYTE``)
586+
and ``0xFB`` (``PYMEM_FORBIDDENBYTE``) have been replaced with ``0xCD``,
587+
``0xDD`` and ``0xFD`` to use the same values than Windows CRT debug
588+
``malloc()`` and ``free()``.
520589
521590
522591
.. _pymalloc:
@@ -539,6 +608,10 @@ The arena allocator uses the following functions:
539608
* :c:func:`mmap` and :c:func:`munmap` if available,
540609
* :c:func:`malloc` and :c:func:`free` otherwise.
541610
611+
This allocator is disabled if Python is configured with the
612+
:option:`--without-pymalloc` option. It can also be disabled at runtime using
613+
the :envvar:`PYTHONMALLOC` environment variable (ex: ``PYTHONMALLOC=malloc``).
614+
542615
Customize pymalloc Arena Allocator
543616
----------------------------------
544617

Doc/using/cmdline.rst

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -799,17 +799,13 @@ conflict.
799799
:c:data:`PYMEM_DOMAIN_MEM` and :c:data:`PYMEM_DOMAIN_OBJ` domains and use
800800
the :c:func:`malloc` function for the :c:data:`PYMEM_DOMAIN_RAW` domain.
801801

802-
Install debug hooks:
802+
Install :ref:`debug hooks <pymem-debug-hooks>`:
803803

804804
* ``debug``: install debug hooks on top of the :ref:`default memory
805805
allocators <default-memory-allocators>`.
806806
* ``malloc_debug``: same as ``malloc`` but also install debug hooks.
807807
* ``pymalloc_debug``: same as ``pymalloc`` but also install debug hooks.
808808

809-
See the :ref:`default memory allocators <default-memory-allocators>` and the
810-
:c:func:`PyMem_SetupDebugHooks` function (install debug hooks on Python
811-
memory allocators).
812-
813809
.. versionchanged:: 3.7
814810
Added the ``"default"`` allocator.
815811

Include/Python.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,6 @@
7272
# endif
7373
#endif
7474

75-
/* Debug-mode build with pymalloc implies PYMALLOC_DEBUG.
76-
* PYMALLOC_DEBUG is in error if pymalloc is not in use.
77-
*/
78-
#if defined(Py_DEBUG) && defined(WITH_PYMALLOC) && !defined(PYMALLOC_DEBUG)
79-
#define PYMALLOC_DEBUG
80-
#endif
81-
#if defined(PYMALLOC_DEBUG) && !defined(WITH_PYMALLOC)
82-
#error "PYMALLOC_DEBUG requires WITH_PYMALLOC"
83-
#endif
8475
#include "pymath.h"
8576
#include "pymem.h"
8677

Include/objimpl.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ Functions and macros for modules that implement new object types.
4848
4949
Note that objects created with PyObject_{New, NewVar} are allocated using the
5050
specialized Python allocator (implemented in obmalloc.c), if WITH_PYMALLOC is
51-
enabled. In addition, a special debugging allocator is used if PYMALLOC_DEBUG
52-
is also #defined.
51+
enabled. In addition, a special debugging allocator is used if Py_DEBUG
52+
macro is also defined.
5353
5454
In case a specific form of memory management is needed (for example, if you
5555
must use the platform malloc heap(s), or shared memory, or C++ local storage or

Include/pymem.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ extern "C" {
2525
heap used by the Python DLL; it could be a disaster if you free()'ed that
2626
directly in your own extension. Using PyMem_Free instead ensures Python
2727
can return the memory to the proper heap. As another example, in
28-
PYMALLOC_DEBUG mode, Python wraps all calls to all PyMem_ and PyObject_
29-
memory functions in special debugging wrappers that add additional
28+
a debug build (Py_DEBUG macro), Python wraps all calls to all PyMem_ and
29+
PyObject_ memory functions in special debugging wrappers that add additional
3030
debugging info to dynamic memory blocks. The system routines have no idea
3131
what to do with that stuff, and the Python wrappers have no idea what to do
3232
with raw blocks obtained directly by the system routines then.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Remove the now unused ``PYMALLOC_DEBUG`` macro. Debug hooks on memory
2+
allocators are now installed by default if Python is built in debug mode (if
3+
``Py_DEBUG`` macro is defined). Moreover, they can now be used on Python
4+
build in release mode (ex: using ``PYTHONMALLOC=debug`` environment
5+
variable).

Misc/SpecialBuilds.txt

Lines changed: 3 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -77,90 +77,14 @@ envvar PYTHONDUMPREFS
7777
combinerefs.py, were new in Python 2.3b1.
7878

7979

80-
PYMALLOC_DEBUG
81-
--------------
82-
83-
When pymalloc is enabled (WITH_PYMALLOC is defined), calls to the PyObject_
84-
memory routines are handled by Python's own small-object allocator, while calls
85-
to the PyMem_ memory routines are directed to the system malloc/ realloc/free.
86-
If PYMALLOC_DEBUG is also defined, calls to both PyObject_ and PyMem_ memory
87-
routines are directed to a special debugging mode of Python's small-object
88-
allocator.
89-
90-
This mode fills dynamically allocated memory blocks with special, recognizable
91-
bit patterns, and adds debugging info on each end of dynamically allocated
92-
memory blocks. The special bit patterns are:
93-
94-
#define CLEANBYTE 0xCB /* clean (newly allocated) memory */
95-
#define DEADBYTE 0xDB /* dead (newly freed) memory */
96-
#define FORBIDDENBYTE 0xFB /* forbidden -- untouchable bytes */
97-
98-
Strings of these bytes are unlikely to be valid addresses, floats, or 7-bit
99-
ASCII strings.
100-
101-
Let S = sizeof(size_t). 2*S bytes are added at each end of each block of N bytes
102-
requested. The memory layout is like so, where p represents the address
103-
returned by a malloc-like or realloc-like function (p[i:j] means the slice of
104-
bytes from *(p+i) inclusive up to *(p+j) exclusive; note that the treatment of
105-
negative indices differs from a Python slice):
106-
107-
p[-2*S:-S]
108-
Number of bytes originally asked for. This is a size_t, big-endian (easier
109-
to read in a memory dump).
110-
p[-S]
111-
API ID. See PEP 445. This is a character, but seems undocumented.
112-
p[-S+1:0]
113-
Copies of FORBIDDENBYTE. Used to catch under- writes and reads.
114-
p[0:N]
115-
The requested memory, filled with copies of CLEANBYTE, used to catch
116-
reference to uninitialized memory. When a realloc-like function is called
117-
requesting a larger memory block, the new excess bytes are also filled with
118-
CLEANBYTE. When a free-like function is called, these are overwritten with
119-
DEADBYTE, to catch reference to freed memory. When a realloc- like function
120-
is called requesting a smaller memory block, the excess old bytes are also
121-
filled with DEADBYTE.
122-
p[N:N+S]
123-
Copies of FORBIDDENBYTE. Used to catch over- writes and reads.
124-
p[N+S:N+2*S]
125-
A serial number, incremented by 1 on each call to a malloc-like or
126-
realloc-like function. Big-endian size_t. If "bad memory" is detected
127-
later, the serial number gives an excellent way to set a breakpoint on the
128-
next run, to capture the instant at which this block was passed out. The
129-
static function bumpserialno() in obmalloc.c is the only place the serial
130-
number is incremented, and exists so you can set such a breakpoint easily.
131-
132-
A realloc-like or free-like function first checks that the FORBIDDENBYTEs at
133-
each end are intact. If they've been altered, diagnostic output is written to
134-
stderr, and the program is aborted via Py_FatalError(). The other main failure
135-
mode is provoking a memory error when a program reads up one of the special bit
136-
patterns and tries to use it as an address. If you get in a debugger then and
137-
look at the object, you're likely to see that it's entirely filled with 0xDB
138-
(meaning freed memory is getting used) or 0xCB (meaning uninitialized memory is
139-
getting used).
140-
141-
Note that PYMALLOC_DEBUG requires WITH_PYMALLOC. Py_DEBUG implies
142-
PYMALLOC_DEBUG (if WITH_PYMALLOC is enabled).
143-
144-
Special gimmicks:
145-
146-
envvar PYTHONMALLOCSTATS
147-
If this envvar exists, a report of pymalloc summary statistics is printed to
148-
stderr whenever a new arena is allocated, and also by Py_FinalizeEx().
149-
150-
Changed in 2.5: The number of extra bytes allocated is 4*sizeof(size_t).
151-
Before it was 16 on all boxes, reflecting that Python couldn't make use of
152-
allocations >= 2**32 bytes even on 64-bit boxes before 2.5.
153-
154-
15580
Py_DEBUG
15681
--------
15782

15883
This is what is generally meant by "a debug build" of Python.
15984

160-
Py_DEBUG implies LLTRACE, Py_REF_DEBUG, and PYMALLOC_DEBUG (if
161-
WITH_PYMALLOC is enabled). In addition, C assert()s are enabled (via the C way:
162-
by not defining NDEBUG), and some routines do additional sanity checks inside
163-
"#ifdef Py_DEBUG" blocks.
85+
Py_DEBUG implies LLTRACE and Py_REF_DEBUG. In addition, C assert()s are enabled
86+
(via the C way: by not defining NDEBUG), and some routines do additional sanity
87+
checks inside "#ifdef Py_DEBUG" blocks.
16488

16589

16690
LLTRACE

0 commit comments

Comments
 (0)