https://github.com/python/cpython/commit/c4ccaf4b1051b3c1ae0138a9c92657606f578fbd
commit: c4ccaf4b1051b3c1ae0138a9c92657606f578fbd
branch: main
author: Donghee Na <[email protected]>
committer: corona10 <[email protected]>
date: 2025-12-08T14:47:19Z
summary:
gh-141770: Annotate anonymous mmap usage if "-X dev" is used (gh-142079)
files:
A Include/internal/pycore_mmap.h
A
Misc/NEWS.d/next/Core_and_Builtins/2025-11-29-18-14-28.gh-issue-141770.JURnvg.rst
M Doc/whatsnew/3.15.rst
M Makefile.pre.in
M Modules/_ctypes/malloc_closure.c
M Modules/mmapmodule.c
M Objects/obmalloc.c
M PCbuild/pythoncore.vcxproj
M PCbuild/pythoncore.vcxproj.filters
M Python/jit.c
M Python/perf_jit_trampoline.c
M Python/perf_trampoline.c
M configure
M configure.ac
M pyconfig.h.in
diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst
index 1bd82545e588fa..0c892e63393ad1 100644
--- a/Doc/whatsnew/3.15.rst
+++ b/Doc/whatsnew/3.15.rst
@@ -1236,6 +1236,12 @@ Build changes
modules that are missing or packaged separately.
(Contributed by Stan Ulbrych and Petr Viktorin in :gh:`139707`.)
+* Annotating anonymous mmap usage is now supported if Linux kernel supports
+ :manpage:`PR_SET_VMA_ANON_NAME <PR_SET_VMA(2const)>` (Linux 5.17 or newer).
+ Annotations are visible in ``/proc/<pid>/maps`` if the kernel supports the
feature
+ and :option:`-X dev <-X>` is passed to the Python or Python is built in
:ref:`debug mode <debug-build>`.
+ (Contributed by Donghee Na in :gh:`141770`)
+
Porting to Python 3.15
======================
diff --git a/Include/internal/pycore_mmap.h b/Include/internal/pycore_mmap.h
new file mode 100644
index 00000000000000..214fd4362a55fe
--- /dev/null
+++ b/Include/internal/pycore_mmap.h
@@ -0,0 +1,45 @@
+#ifndef Py_INTERNAL_MMAP_H
+#define Py_INTERNAL_MMAP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef Py_BUILD_CORE
+# error "this header requires Py_BUILD_CORE define"
+#endif
+
+#include "pycore_pystate.h"
+
+#if defined(HAVE_PR_SET_VMA_ANON_NAME) && defined(__linux__)
+# include <linux/prctl.h>
+# include <sys/prctl.h>
+#endif
+
+#if defined(HAVE_PR_SET_VMA_ANON_NAME) && defined(__linux__)
+static inline void
+_PyAnnotateMemoryMap(void *addr, size_t size, const char *name)
+{
+#ifndef Py_DEBUG
+ if (!_Py_GetConfig()->dev_mode) {
+ return;
+ }
+#endif
+ assert(strlen(name) < 80);
+ int old_errno = errno;
+ prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, (unsigned long)addr, size, name);
+ /* Ignore errno from prctl */
+ /* See: https://bugzilla.redhat.com/show_bug.cgi?id=2302746 */
+ errno = old_errno;
+}
+#else
+static inline void
+_PyAnnotateMemoryMap(void *Py_UNUSED(addr), size_t Py_UNUSED(size), const char
*Py_UNUSED(name))
+{
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif // !Py_INTERNAL_MMAP_H
diff --git a/Makefile.pre.in b/Makefile.pre.in
index f3086ec1462b6b..2554114fff6d6c 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -1378,6 +1378,7 @@ PYTHON_HEADERS= \
$(srcdir)/Include/internal/pycore_long.h \
$(srcdir)/Include/internal/pycore_memoryobject.h \
$(srcdir)/Include/internal/pycore_mimalloc.h \
+ $(srcdir)/Include/internal/pycore_mmap.h \
$(srcdir)/Include/internal/pycore_modsupport.h \
$(srcdir)/Include/internal/pycore_moduleobject.h \
$(srcdir)/Include/internal/pycore_namespace.h \
diff --git
a/Misc/NEWS.d/next/Core_and_Builtins/2025-11-29-18-14-28.gh-issue-141770.JURnvg.rst
b/Misc/NEWS.d/next/Core_and_Builtins/2025-11-29-18-14-28.gh-issue-141770.JURnvg.rst
new file mode 100644
index 00000000000000..3a5c0fd70edb1e
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2025-11-29-18-14-28.gh-issue-141770.JURnvg.rst
@@ -0,0 +1,2 @@
+Annotate anonymous mmap usage only when supported by the
+Linux kernel and if ``-X dev`` is used or Python is built in debug mode. Patch
by Donghee Na.
diff --git a/Modules/_ctypes/malloc_closure.c b/Modules/_ctypes/malloc_closure.c
index db405acf8727b5..62c7aa5d6affbf 100644
--- a/Modules/_ctypes/malloc_closure.c
+++ b/Modules/_ctypes/malloc_closure.c
@@ -14,6 +14,7 @@
# endif
#endif
#include "ctypes.h"
+#include "pycore_mmap.h" // _PyAnnotateMemoryMap()
/* BLOCKSIZE can be adjusted. Larger blocksize will take a larger memory
overhead, but allocate less blocks from the system. It may be that some
@@ -74,14 +75,16 @@ static void more_core(void)
if (item == NULL)
return;
#else
+ size_t mem_size = count * sizeof(ITEM);
item = (ITEM *)mmap(NULL,
- count * sizeof(ITEM),
+ mem_size,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS,
-1,
0);
if (item == (void *)MAP_FAILED)
return;
+ _PyAnnotateMemoryMap(item, mem_size, "cpython:ctypes");
#endif
#ifdef MALLOC_CLOSURE_DEBUG
diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c
index ac8521f8aa9b6e..37003020de2688 100644
--- a/Modules/mmapmodule.c
+++ b/Modules/mmapmodule.c
@@ -26,6 +26,7 @@
#include "pycore_abstract.h" // _Py_convert_optional_to_ssize_t()
#include "pycore_bytesobject.h" // _PyBytes_Find()
#include "pycore_fileutils.h" // _Py_stat_struct
+#include "pycore_mmap.h" // _PyAnnotateMemoryMap()
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include <stddef.h> // offsetof()
@@ -1951,6 +1952,7 @@ new_mmap_object(PyTypeObject *type, PyObject *args,
PyObject *kwdict)
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
+ _PyAnnotateMemoryMap(m_obj->data, map_size, "cpython:mmap");
m_obj->access = (access_mode)access;
return (PyObject *)m_obj;
}
diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c
index 2b95ebbf8e5ac0..b1f9fa2e692265 100644
--- a/Objects/obmalloc.c
+++ b/Objects/obmalloc.c
@@ -2,6 +2,7 @@
#include "Python.h"
#include "pycore_interp.h" // _PyInterpreterState_HasFeature
+#include "pycore_mmap.h" // _PyAnnotateMemoryMap()
#include "pycore_object.h" // _PyDebugAllocatorStats() definition
#include "pycore_obmalloc.h"
#include "pycore_obmalloc_init.h"
@@ -467,6 +468,7 @@ _PyMem_ArenaAlloc(void *Py_UNUSED(ctx), size_t size)
if (ptr == MAP_FAILED)
return NULL;
assert(ptr != NULL);
+ _PyAnnotateMemoryMap(ptr, size, "cpython:pymalloc");
return ptr;
#else
return malloc(size);
diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj
index 85363949c2344f..dcfb75ce162b2f 100644
--- a/PCbuild/pythoncore.vcxproj
+++ b/PCbuild/pythoncore.vcxproj
@@ -277,6 +277,7 @@
<ClInclude Include="..\Include\internal\pycore_llist.h" />
<ClInclude Include="..\Include\internal\pycore_lock.h" />
<ClInclude Include="..\Include\internal\pycore_long.h" />
+ <ClInclude Include="..\Include\internal\pycore_mmap.h" />
<ClInclude Include="..\Include\internal\pycore_modsupport.h" />
<ClInclude Include="..\Include\internal\pycore_moduleobject.h" />
<ClInclude Include="..\Include\internal\pycore_namespace.h" />
diff --git a/PCbuild/pythoncore.vcxproj.filters
b/PCbuild/pythoncore.vcxproj.filters
index 17999690990fb9..247f4b5a784f9c 100644
--- a/PCbuild/pythoncore.vcxproj.filters
+++ b/PCbuild/pythoncore.vcxproj.filters
@@ -735,6 +735,9 @@
<ClInclude Include="..\Include\internal\pycore_long.h">
<Filter>Include\internal</Filter>
</ClInclude>
+ <ClInclude Include="..\Include\internal\pycore_mmap.h">
+ <Filter>Include\internal</Filter>
+ </ClInclude>
<ClInclude Include="..\Include\internal\pycore_modsupport.h">
<Filter>Include\internal</Filter>
</ClInclude>
diff --git a/Python/jit.c b/Python/jit.c
index 47d3d7a5d27180..7106db8a99a77a 100644
--- a/Python/jit.c
+++ b/Python/jit.c
@@ -16,6 +16,7 @@
#include "pycore_intrinsics.h"
#include "pycore_list.h"
#include "pycore_long.h"
+#include "pycore_mmap.h"
#include "pycore_opcode_metadata.h"
#include "pycore_opcode_utils.h"
#include "pycore_optimizer.h"
@@ -75,6 +76,9 @@ jit_alloc(size_t size)
int prot = PROT_READ | PROT_WRITE;
unsigned char *memory = mmap(NULL, size, prot, flags, -1, 0);
int failed = memory == MAP_FAILED;
+ if (!failed) {
+ _PyAnnotateMemoryMap(memory, size, "cpython:jit");
+ }
#endif
if (failed) {
jit_error("unable to allocate memory");
diff --git a/Python/perf_jit_trampoline.c b/Python/perf_jit_trampoline.c
index 8732be973616d4..af7d8f9f1ec0ae 100644
--- a/Python/perf_jit_trampoline.c
+++ b/Python/perf_jit_trampoline.c
@@ -61,6 +61,7 @@
#include "pycore_ceval.h" // _PyPerf_Callbacks
#include "pycore_frame.h"
#include "pycore_interp.h"
+#include "pycore_mmap.h" // _PyAnnotateMemoryMap()
#include "pycore_runtime.h" // _PyRuntime
#ifdef PY_HAVE_PERF_TRAMPOLINE
@@ -1085,6 +1086,7 @@ static void* perf_map_jit_init(void) {
close(fd);
return NULL; // Memory mapping failed
}
+ _PyAnnotateMemoryMap(perf_jit_map_state.mapped_buffer, page_size,
"cpython:perf_jit_trampoline");
#endif
perf_jit_map_state.mapped_size = page_size;
diff --git a/Python/perf_trampoline.c b/Python/perf_trampoline.c
index 987e8d2a11a659..669a47ae17377a 100644
--- a/Python/perf_trampoline.c
+++ b/Python/perf_trampoline.c
@@ -132,6 +132,7 @@ any DWARF information available for them).
#include "Python.h"
#include "pycore_ceval.h" // _PyPerf_Callbacks
#include "pycore_interpframe.h" // _PyFrame_GetCode()
+#include "pycore_mmap.h" // _PyAnnotateMemoryMap()
#include "pycore_runtime.h" // _PyRuntime
@@ -290,6 +291,7 @@ new_code_arena(void)
perf_status = PERF_STATUS_FAILED;
return -1;
}
+ _PyAnnotateMemoryMap(memory, mem_size, "cpython:perf_trampoline");
void *start = &_Py_trampoline_func_start;
void *end = &_Py_trampoline_func_end;
size_t code_size = end - start;
diff --git a/configure b/configure
index 7561fb9c7ad90e..4f9b9b21ca395e 100755
--- a/configure
+++ b/configure
@@ -23947,6 +23947,25 @@ printf "%s\n" "#define HAVE_UT_NAMESIZE 1" >>confdefs.h
fi
+ac_fn_check_decl "$LINENO" "PR_SET_VMA_ANON_NAME"
"ac_cv_have_decl_PR_SET_VMA_ANON_NAME" "#include <linux/prctl.h>
+ #include <sys/prctl.h>
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_PR_SET_VMA_ANON_NAME" = xyes
+then :
+ ac_have_decl=1
+else case e in #(
+ e) ac_have_decl=0 ;;
+esac
+fi
+printf "%s\n" "#define HAVE_DECL_PR_SET_VMA_ANON_NAME $ac_have_decl"
>>confdefs.h
+if test $ac_have_decl = 1
+then :
+
+printf "%s\n" "#define HAVE_PR_SET_VMA_ANON_NAME 1" >>confdefs.h
+
+fi
+
+
# check for openpty, login_tty, and forkpty
diff --git a/configure.ac b/configure.ac
index fa24bc78a2645a..046c046ffb5d10 100644
--- a/configure.ac
+++ b/configure.ac
@@ -5583,6 +5583,13 @@ AC_CHECK_DECLS([UT_NAMESIZE],
[],
[@%:@include <utmp.h>])
+AC_CHECK_DECLS([PR_SET_VMA_ANON_NAME],
+ [AC_DEFINE([HAVE_PR_SET_VMA_ANON_NAME], [1],
+ [Define if you have the 'PR_SET_VMA_ANON_NAME'
constant.])],
+ [],
+ [@%:@include <linux/prctl.h>
+ @%:@include <sys/prctl.h>])
+
# check for openpty, login_tty, and forkpty
AC_CHECK_FUNCS([openpty], [],
diff --git a/pyconfig.h.in b/pyconfig.h.in
index 8a9f5ca8ec826d..aabf9f0be8da55 100644
--- a/pyconfig.h.in
+++ b/pyconfig.h.in
@@ -228,6 +228,10 @@
/* Define to 1 if you have the <db.h> header file. */
#undef HAVE_DB_H
+/* Define to 1 if you have the declaration of 'PR_SET_VMA_ANON_NAME', and to 0
+ if you don't. */
+#undef HAVE_DECL_PR_SET_VMA_ANON_NAME
+
/* Define to 1 if you have the declaration of 'RTLD_DEEPBIND', and to 0 if you
don't. */
#undef HAVE_DECL_RTLD_DEEPBIND
@@ -996,6 +1000,9 @@
/* Define if your compiler supports function prototype */
#undef HAVE_PROTOTYPES
+/* Define if you have the 'PR_SET_VMA_ANON_NAME' constant. */
+#undef HAVE_PR_SET_VMA_ANON_NAME
+
/* Define to 1 if you have the 'pthread_condattr_setclock' function. */
#undef HAVE_PTHREAD_CONDATTR_SETCLOCK
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]