Skip to content

Commit 115e2b1

Browse files
committed
WIP edit on debugging and cPyRefs.c
1 parent f1e8732 commit 115e2b1

File tree

4 files changed

+102
-37
lines changed

4 files changed

+102
-37
lines changed

HISTORY.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Other
2929

3030
- Python versions supported: 3.9, 3.10, 3.11, 3.12, 3.13.
3131
- Development Status :: 5 - Production/Stable
32+
- Documentation word count has gone up 50%+ from 41,000 to 66,000.
3233

3334
..
3435
.. todo::

doc/sphinx/source/debugging/debug_python.rst

Lines changed: 77 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ Building and Using a Debug Version of Python
1919
There is a spectrum of debug builds of Python that you can create. This chapter describes how to create them.
2020

2121

22+
.. index::
23+
single: Debugging; Building Python
24+
2225
--------------------------------------------
2326
Building a Standard Debug Version of Python
2427
--------------------------------------------
@@ -33,6 +36,9 @@ Download and unpack the Python source. Then in the source directory create a deb
3336
make
3437
make test
3538
39+
.. index::
40+
single: Debugging; Python Build Macros
41+
3642
-----------------------
3743
Specifying Macros
3844
-----------------------
@@ -54,38 +60,20 @@ However the python documentation suggests the alternative way of specifying them
5460
5561
I don't know why one way would be regarded as better than the other.
5662

63+
.. index::
64+
pair: Debugging; Py_DEBUG
65+
pair: Debugging; Py_REF_DEBUG
66+
pair: Debugging; Py_TRACE_REFS
67+
pair: Debugging; WITH_PYMALLOC
68+
pair: Debugging; PYMALLOC_DEBUG
69+
pair: Debugging; LLTRACE
70+
5771
---------------------------
5872
The Debug Builds
5973
---------------------------
6074

61-
The builds are controlled by the following macros:
62-
63-
=================== ======================================================= ==============
64-
Macro Description Must Rebuild
65-
Extensions?
66-
=================== ======================================================= ==============
67-
``Py_DEBUG`` A standard debug build. ``Py_DEBUG`` sets Yes
68-
``LLTRACE``, ``Py_REF_DEBUG``, ``Py_TRACE_REFS``, and
69-
``PYMALLOC_DEBUG`` (if ``WITH_PYMALLOC`` is enabled).
70-
``Py_REF_DEBUG`` Turn on aggregate reference counting which will be No
71-
displayed in the interactive interpreter when
72-
invoked with ``-X showrefcount`` on the command line.
73-
If you are not keeping references to objects and the
74-
count is increasing there is probably a leak.
75-
Also adds ``sys.gettotalrefcount()`` to the ``sys``
76-
module and this returns the total number of references.
77-
``Py_TRACE_REFS`` Turns on reference tracing. Yes
78-
Sets ``Py_REF_DEBUG``.
79-
``WITH_PYMALLOC`` Enables Pythons small memory allocator. For Valgrind No
80-
this must be disabled, if using Pythons malloc
81-
debugger (using ``PYMALLOC_DEBUG``) this must be
82-
enabled.
83-
See: :ref:`debug-version-of-python-memory_alloc-label`
84-
``PYMALLOC_DEBUG`` Enables Python's malloc debugger that annotates No
85-
memory blocks. Requires ``WITH_PYMALLOC``.
86-
See: :ref:`debug-version-of-python-memory_alloc-label`
87-
=================== ======================================================= ==============
88-
75+
The builds are controlled by the following macros.
76+
The third column shows if CPython C extensions have to be rebuilt against that version of Python:
8977

9078
.. list-table:: Debug Macros
9179
:widths: 20 70 10
@@ -98,8 +86,30 @@ Macro Description Must
9886
- A standard debug build. ``Py_DEBUG`` sets ``LLTRACE``, ``Py_REF_DEBUG``, ``Py_TRACE_REFS``, and
9987
``PYMALLOC_DEBUG`` (if ``WITH_PYMALLOC`` is enabled).
10088
- Yes
101-
102-
89+
* - ``Py_REF_DEBUG``
90+
- Turn on aggregate reference counting which will be
91+
displayed in the interactive interpreter when
92+
invoked with ``-X showrefcount`` on the command line.
93+
If you are not keeping references to objects and the
94+
count is increasing there is probably a leak.
95+
Also adds ``sys.gettotalrefcount()`` to the ``sys``
96+
module and this returns the total number of references.
97+
- No
98+
* - ``Py_TRACE_REFS``
99+
- Turns on reference tracing. Sets ``Py_REF_DEBUG``.
100+
- Yes
101+
* - ``WITH_PYMALLOC``
102+
- Enables Pythons small memory allocator. For Valgrind
103+
this must be disabled, if using Pythons malloc
104+
debugger (using ``PYMALLOC_DEBUG``) this must be
105+
enabled.
106+
See: :ref:`debug-version-of-python-memory_alloc-label`
107+
- No
108+
* - ``PYMALLOC_DEBUG``
109+
- Enables Python's malloc debugger that annotates
110+
memory blocks. Requires ``WITH_PYMALLOC``.
111+
See: :ref:`debug-version-of-python-memory_alloc-label`
112+
- No
103113

104114
Here is the description of other debug macros that are set by one of the macros above:
105115

@@ -161,11 +171,17 @@ Or:
161171
162172
This builds Python with the ``WITH_PYMALLOC`` and ``PYMALLOC_DEBUG`` macros defined.
163173

174+
.. index::
175+
pair: Debugging; Access After Free
176+
164177
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
165178
Finding Access after Free With ``PYMALLOC_DEBUG``
166179
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
167180

168-
Python built with ``PYMALLOC_DEBUG`` is the most effective way of detecting access after free. For example if we have this CPython code:
181+
TODO:
182+
183+
Python built with ``PYMALLOC_DEBUG`` is the most effective way of detecting access after free.
184+
For example if we have this CPython code:
169185

170186
.. code-block:: c
171187
@@ -180,13 +196,41 @@ And we call this from the interpreter we get a diagnostic:
180196

181197
.. code-block:: python
182198
183-
Python 3.4.3 (default, Sep 16 2015, 16:56:10)
199+
Python 3.4.3 (default, Sep 16 2015, 16:56:10)
184200
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.51)] on darwin
185201
Type "help", "copyright", "credits" or "license" for more information.
186202
>>> from cPyExtPatt import cPyRefs
187203
>>> cPyRefs.afterFree()
188204
<refcnt -2604246222170760229 at 0x10a474130>
189-
>>>
205+
>>>
206+
207+
.. code-block:: python
208+
209+
# $ python
210+
# Python 3.9.7 (v3.9.7:1016ef3790, Aug 30 2021, 16:39:15)
211+
# [Clang 6.0 (clang-600.0.57)] on darwin
212+
# Type "help", "copyright", "credits" or "license" for more information.
213+
>>> from cPyExtPatt import cPyRefs
214+
>>> cPyRefs.access_after_free()
215+
access_after_free(): Before Py_DECREF(0x0x7fe55f1e2fb0) Ref count: 1
216+
1048576
217+
access_after_free(): After Py_DECREF(0x0x7fe55f1e2fb0) Ref count: 140623120051984
218+
1048576
219+
>>>
220+
221+
.. code-block:: python
222+
223+
# $ python
224+
# Python 3.13.1 (v3.13.1:06714517797, Dec 3 2024, 14:00:22) [Clang 15.0.0 (clang-1500.3.9.4)] on darwin
225+
# Type "help", "copyright", "credits" or "license" for more information.
226+
>>> from cPyExtPatt import cPyRefs
227+
>>> cPyRefs.access_after_free()
228+
access_after_free(): Before Py_DECREF(0x0x102465890) Ref count: 1
229+
1048576
230+
access_after_free(): After Py_DECREF(0x0x102465890) Ref count: 4333131856
231+
0
232+
>>>
233+
190234
191235
.. index::
192236
single: Debugging; PyMalloc Statistics

doc/sphinx/source/debugging/debug_tools.rst

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ First create your toolbox, in this one we have:
1818

1919
* Debug version of Python - great for finding out more detail of your Python code as it executes.
2020
* Valgrind - the goto tool for memory leaks. It is a little tricky to get working but should be in every developers toolbox.
21-
* OS memory monitioring - this is a quick and simple way of identifying whether memory leaks are happening or not. An example is given below: :ref:`simple-memory-monitor-label`
21+
* OS memory monitioring - this is a quick and simple way of identifying whether memory leaks are happening or not.
22+
An example is given below: :ref:`simple-memory-monitor-label`
2223

2324
.. _debug-tools-debug-python-label:
2425

@@ -74,7 +75,10 @@ Here :ref:`leaked-new-references-valgrind-label` is an example of finding a leak
7475
A Simple Memory Monitor
7576
------------------------------------------------
7677

77-
Here is a simple process memory monitor using the ``psutil`` library:
78+
A useful technique is to monitor the memory usage of a Python program.
79+
Here is a simple process memory monitor using the ``psutil`` library.
80+
See the :ref:`memory_leaks-label` chapter for a more comprehensive approach, in particular
81+
:ref:`memory-leaks.pymemtrace`.
7882

7983

8084
.. code-block:: python

src/cpy/cPyRefs.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,25 @@ static PyObject *subtract_two_longs(PyObject *Py_UNUSED(module)) {
7878
* Not pytest tested.
7979
* */
8080
static PyObject *access_after_free(PyObject *Py_UNUSED(module)) {
81-
PyObject *pA = PyLong_FromLong(1024L);
81+
PyObject *pA = PyLong_FromLong(1024L * 1024L);
82+
fprintf(
83+
stdout,
84+
"%s(): Before Py_DECREF(0x%p) Ref count: %zd\n",
85+
__FUNCTION__, (void *)pA, Py_REFCNT(pA)
86+
);
87+
PyObject_Print(pA, stdout, Py_PRINT_RAW);
88+
fprintf(stdout, "\n");
89+
8290
Py_DECREF(pA);
83-
PyObject_Print(pA, stdout, 0);
91+
92+
fprintf(
93+
stdout,
94+
"%s(): After Py_DECREF(0x%p) Ref count: %zd\n",
95+
__FUNCTION__, (void *)pA, Py_REFCNT(pA)
96+
);
97+
PyObject_Print(pA, stdout, Py_PRINT_RAW);
98+
fprintf(stdout, "\n");
99+
84100
Py_RETURN_NONE;
85101
}
86102

0 commit comments

Comments
 (0)