Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions Include/internal/pycore_mmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,27 @@ extern "C" {
#endif

#if defined(HAVE_PR_SET_VMA_ANON_NAME) && defined(__linux__)
static inline void
static inline int
_PyAnnotateMemoryMap(void *addr, size_t size, const char *name)
{
#ifndef Py_DEBUG
if (!_Py_GetConfig()->dev_mode) {
return;
return 0;
}
#endif
// The name length cannot exceed 80 (including the '\0').
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;
int res = prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, (unsigned long)addr, size, name);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that we still need to restore errno because it will be called just after mmap is created for builin case

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_PyAnnotateMemoryMap() is only called when a memory allocation succeed. Would you mind to elaborate in which case it matters to preserve the previous errno?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mmap called -> errno 0 -> _PyAnnotateMemoryMap called -> errno non 0 -> propagate errno?

Since _PyAnnotateMemoryMap is optional, I would like to avoid this errno is exposed to caller.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Modules/mmapmodule.c, errno is only used if mmap() fails:

    Py_BEGIN_ALLOW_THREADS
    m_obj->data = mmap(NULL, map_size, prot, flags, fd, offset);
    Py_END_ALLOW_THREADS

    int saved_errno = errno;
    if (devzero != -1) {
        close(devzero);
    }

    if (m_obj->data == (char *)-1) {
        m_obj->data = NULL;
        Py_DECREF(m_obj);
        errno = saved_errno;
        PyErr_SetFromErrno(PyExc_OSError);
        return NULL;
    }
#ifdef MAP_ANONYMOUS
    if (m_obj->flags & MAP_ANONYMOUS) {
        (void)_PyAnnotateMemoryMap(m_obj->data, map_size, "cpython:mmap");
    }
#endif
    m_obj->access = (access_mode)access;
    return (PyObject *)m_obj;

I don't see what you mean by propagate errno, since errno is not used when _PyAnnotateMemoryMap() is called.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Get it!

if (res < 0) {
return -1;
}
return 0;
}
#else
static inline void
static inline int
_PyAnnotateMemoryMap(void *Py_UNUSED(addr), size_t Py_UNUSED(size), const char *Py_UNUSED(name))
{
return 0;
}
#endif

Expand Down
13 changes: 12 additions & 1 deletion Lib/test/test_mmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from test.support.import_helper import import_module
from test.support.os_helper import TESTFN, unlink
from test.support.script_helper import assert_python_ok
import errno
import unittest
import os
import re
Expand Down Expand Up @@ -1171,7 +1172,17 @@ def test_set_name(self):
# Test setting name on anonymous mmap
m = mmap.mmap(-1, PAGESIZE)
self.addCleanup(m.close)
result = m.set_name('test_mapping')
try:
result = m.set_name('test_mapping')
except OSError as exc:
if exc.errno == errno.EINVAL:
# gh-142419: On Fedora, prctl(PR_SET_VMA_ANON_NAME) fails with
# EINVAL because the kernel option CONFIG_ANON_VMA_NAME is
# disabled.
# See: https://bugzilla.redhat.com/show_bug.cgi?id=2302746
self.skipTest("prctl() failed with EINVAL")
else:
raise
self.assertIsNone(result)

# Test name length limit (80 chars including prefix "cpython:mmap:" and '\0')
Expand Down
7 changes: 5 additions & 2 deletions Modules/mmapmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1138,7 +1138,10 @@ mmap_mmap_set_name_impl(mmap_object *self, const char *name)
if (self->flags & MAP_ANONYMOUS) {
char buf[80];
sprintf(buf, "%s%s", prefix, name);
_PyAnnotateMemoryMap(self->data, self->size, buf);
if (_PyAnnotateMemoryMap(self->data, self->size, buf) < 0) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
Py_RETURN_NONE;
}
else {
Expand Down Expand Up @@ -1993,7 +1996,7 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
}
#ifdef MAP_ANONYMOUS
if (m_obj->flags & MAP_ANONYMOUS) {
_PyAnnotateMemoryMap(m_obj->data, map_size, "cpython:mmap");
(void)_PyAnnotateMemoryMap(m_obj->data, map_size, "cpython:mmap");
}
#endif
m_obj->access = (access_mode)access;
Expand Down
2 changes: 1 addition & 1 deletion Objects/obmalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +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");
(void)_PyAnnotateMemoryMap(ptr, size, "cpython:pymalloc");
return ptr;
#else
return malloc(size);
Expand Down
2 changes: 1 addition & 1 deletion Python/jit.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ jit_alloc(size_t size)
unsigned char *memory = mmap(NULL, size, prot, flags, -1, 0);
int failed = memory == MAP_FAILED;
if (!failed) {
_PyAnnotateMemoryMap(memory, size, "cpython:jit");
(void)_PyAnnotateMemoryMap(memory, size, "cpython:jit");
}
#endif
if (failed) {
Expand Down
3 changes: 2 additions & 1 deletion Python/perf_jit_trampoline.c
Original file line number Diff line number Diff line change
Expand Up @@ -1086,7 +1086,8 @@ 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");
(void)_PyAnnotateMemoryMap(perf_jit_map_state.mapped_buffer, page_size,
"cpython:perf_jit_trampoline");
#endif

perf_jit_map_state.mapped_size = page_size;
Expand Down
2 changes: 1 addition & 1 deletion Python/perf_trampoline.c
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ new_code_arena(void)
perf_status = PERF_STATUS_FAILED;
return -1;
}
_PyAnnotateMemoryMap(memory, mem_size, "cpython:perf_trampoline");
(void)_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;
Expand Down