Skip to content

Commit c4ccaf4

Browse files
authored
pythongh-141770: Annotate anonymous mmap usage if "-X dev" is used (pythongh-142079)
1 parent e3539e9 commit c4ccaf4

File tree

15 files changed

+107
-1
lines changed

15 files changed

+107
-1
lines changed

Doc/whatsnew/3.15.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,6 +1236,12 @@ Build changes
12361236
modules that are missing or packaged separately.
12371237
(Contributed by Stan Ulbrych and Petr Viktorin in :gh:`139707`.)
12381238

1239+
* Annotating anonymous mmap usage is now supported if Linux kernel supports
1240+
:manpage:`PR_SET_VMA_ANON_NAME <PR_SET_VMA(2const)>` (Linux 5.17 or newer).
1241+
Annotations are visible in ``/proc/<pid>/maps`` if the kernel supports the feature
1242+
and :option:`-X dev <-X>` is passed to the Python or Python is built in :ref:`debug mode <debug-build>`.
1243+
(Contributed by Donghee Na in :gh:`141770`)
1244+
12391245

12401246
Porting to Python 3.15
12411247
======================

Include/internal/pycore_mmap.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#ifndef Py_INTERNAL_MMAP_H
2+
#define Py_INTERNAL_MMAP_H
3+
4+
#ifdef __cplusplus
5+
extern "C" {
6+
#endif
7+
8+
#ifndef Py_BUILD_CORE
9+
# error "this header requires Py_BUILD_CORE define"
10+
#endif
11+
12+
#include "pycore_pystate.h"
13+
14+
#if defined(HAVE_PR_SET_VMA_ANON_NAME) && defined(__linux__)
15+
# include <linux/prctl.h>
16+
# include <sys/prctl.h>
17+
#endif
18+
19+
#if defined(HAVE_PR_SET_VMA_ANON_NAME) && defined(__linux__)
20+
static inline void
21+
_PyAnnotateMemoryMap(void *addr, size_t size, const char *name)
22+
{
23+
#ifndef Py_DEBUG
24+
if (!_Py_GetConfig()->dev_mode) {
25+
return;
26+
}
27+
#endif
28+
assert(strlen(name) < 80);
29+
int old_errno = errno;
30+
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, (unsigned long)addr, size, name);
31+
/* Ignore errno from prctl */
32+
/* See: https://bugzilla.redhat.com/show_bug.cgi?id=2302746 */
33+
errno = old_errno;
34+
}
35+
#else
36+
static inline void
37+
_PyAnnotateMemoryMap(void *Py_UNUSED(addr), size_t Py_UNUSED(size), const char *Py_UNUSED(name))
38+
{
39+
}
40+
#endif
41+
42+
#ifdef __cplusplus
43+
}
44+
#endif
45+
#endif // !Py_INTERNAL_MMAP_H

Makefile.pre.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,6 +1378,7 @@ PYTHON_HEADERS= \
13781378
$(srcdir)/Include/internal/pycore_long.h \
13791379
$(srcdir)/Include/internal/pycore_memoryobject.h \
13801380
$(srcdir)/Include/internal/pycore_mimalloc.h \
1381+
$(srcdir)/Include/internal/pycore_mmap.h \
13811382
$(srcdir)/Include/internal/pycore_modsupport.h \
13821383
$(srcdir)/Include/internal/pycore_moduleobject.h \
13831384
$(srcdir)/Include/internal/pycore_namespace.h \
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Annotate anonymous mmap usage only when supported by the
2+
Linux kernel and if ``-X dev`` is used or Python is built in debug mode. Patch by Donghee Na.

Modules/_ctypes/malloc_closure.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
# endif
1515
#endif
1616
#include "ctypes.h"
17+
#include "pycore_mmap.h" // _PyAnnotateMemoryMap()
1718

1819
/* BLOCKSIZE can be adjusted. Larger blocksize will take a larger memory
1920
overhead, but allocate less blocks from the system. It may be that some
@@ -74,14 +75,16 @@ static void more_core(void)
7475
if (item == NULL)
7576
return;
7677
#else
78+
size_t mem_size = count * sizeof(ITEM);
7779
item = (ITEM *)mmap(NULL,
78-
count * sizeof(ITEM),
80+
mem_size,
7981
PROT_READ | PROT_WRITE | PROT_EXEC,
8082
MAP_PRIVATE | MAP_ANONYMOUS,
8183
-1,
8284
0);
8385
if (item == (void *)MAP_FAILED)
8486
return;
87+
_PyAnnotateMemoryMap(item, mem_size, "cpython:ctypes");
8588
#endif
8689

8790
#ifdef MALLOC_CLOSURE_DEBUG

Modules/mmapmodule.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "pycore_abstract.h" // _Py_convert_optional_to_ssize_t()
2727
#include "pycore_bytesobject.h" // _PyBytes_Find()
2828
#include "pycore_fileutils.h" // _Py_stat_struct
29+
#include "pycore_mmap.h" // _PyAnnotateMemoryMap()
2930
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
3031

3132
#include <stddef.h> // offsetof()
@@ -1951,6 +1952,7 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
19511952
PyErr_SetFromErrno(PyExc_OSError);
19521953
return NULL;
19531954
}
1955+
_PyAnnotateMemoryMap(m_obj->data, map_size, "cpython:mmap");
19541956
m_obj->access = (access_mode)access;
19551957
return (PyObject *)m_obj;
19561958
}

Objects/obmalloc.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "Python.h"
44
#include "pycore_interp.h" // _PyInterpreterState_HasFeature
5+
#include "pycore_mmap.h" // _PyAnnotateMemoryMap()
56
#include "pycore_object.h" // _PyDebugAllocatorStats() definition
67
#include "pycore_obmalloc.h"
78
#include "pycore_obmalloc_init.h"
@@ -467,6 +468,7 @@ _PyMem_ArenaAlloc(void *Py_UNUSED(ctx), size_t size)
467468
if (ptr == MAP_FAILED)
468469
return NULL;
469470
assert(ptr != NULL);
471+
_PyAnnotateMemoryMap(ptr, size, "cpython:pymalloc");
470472
return ptr;
471473
#else
472474
return malloc(size);

PCbuild/pythoncore.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@
277277
<ClInclude Include="..\Include\internal\pycore_llist.h" />
278278
<ClInclude Include="..\Include\internal\pycore_lock.h" />
279279
<ClInclude Include="..\Include\internal\pycore_long.h" />
280+
<ClInclude Include="..\Include\internal\pycore_mmap.h" />
280281
<ClInclude Include="..\Include\internal\pycore_modsupport.h" />
281282
<ClInclude Include="..\Include\internal\pycore_moduleobject.h" />
282283
<ClInclude Include="..\Include\internal\pycore_namespace.h" />

PCbuild/pythoncore.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,9 @@
735735
<ClInclude Include="..\Include\internal\pycore_long.h">
736736
<Filter>Include\internal</Filter>
737737
</ClInclude>
738+
<ClInclude Include="..\Include\internal\pycore_mmap.h">
739+
<Filter>Include\internal</Filter>
740+
</ClInclude>
738741
<ClInclude Include="..\Include\internal\pycore_modsupport.h">
739742
<Filter>Include\internal</Filter>
740743
</ClInclude>

Python/jit.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "pycore_intrinsics.h"
1717
#include "pycore_list.h"
1818
#include "pycore_long.h"
19+
#include "pycore_mmap.h"
1920
#include "pycore_opcode_metadata.h"
2021
#include "pycore_opcode_utils.h"
2122
#include "pycore_optimizer.h"
@@ -75,6 +76,9 @@ jit_alloc(size_t size)
7576
int prot = PROT_READ | PROT_WRITE;
7677
unsigned char *memory = mmap(NULL, size, prot, flags, -1, 0);
7778
int failed = memory == MAP_FAILED;
79+
if (!failed) {
80+
_PyAnnotateMemoryMap(memory, size, "cpython:jit");
81+
}
7882
#endif
7983
if (failed) {
8084
jit_error("unable to allocate memory");

0 commit comments

Comments
 (0)