Skip to content

Commit c99f647

Browse files
committed
gh-153400: Use glibc functions instead of syscall()
Use glibc functions instead of syscall(): pidfd_open(), pidfd_getfd() and pidfd_send_signal() (glibc 2.36), gettid() and getdents64() (glibc 2.30), and getrandom() (glibc 2.25).
1 parent 219768f commit c99f647

12 files changed

Lines changed: 151 additions & 43 deletions
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
:mod:`os` and :mod:`signal`: Use glibc functions instead of ``syscall()``:
2+
``pidfd_open()``, ``pidfd_getfd()`` and ``pidfd_send_signal()`` (glibc 2.36),
3+
``gettid()`` and ``getdents64()`` (glibc 2.30), and ``getrandom()`` (glibc
4+
2.25). Patch by Victor Stinner.

Modules/_posixsubprocess.c

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -388,20 +388,26 @@ _close_range_except(int start_fd,
388388
return 0;
389389
}
390390

391-
#if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)
391+
#if defined(HAVE_GETDENTS64) \
392+
|| (defined(__linux__) && defined(HAVE_SYS_SYSCALL_H))
393+
394+
#ifdef HAVE_GETDENTS64
395+
# define py_dirent64 dirent64
396+
#else
392397
/* It doesn't matter if d_name has room for NAME_MAX chars; we're using this
393398
* only to read a directory of short file descriptor number names. The kernel
394399
* will return an error if we didn't give it enough space. Highly Unlikely.
395400
* This structure is very old and stable: It will not change unless the kernel
396401
* chooses to break compatibility with all existing binaries. Highly Unlikely.
397402
*/
398-
struct linux_dirent64 {
403+
struct py_dirent64 {
399404
unsigned long long d_ino;
400405
long long d_off;
401406
unsigned short d_reclen; /* Length of this linux_dirent */
402407
unsigned char d_type;
403408
char d_name[256]; /* Filename (null-terminated) */
404409
};
410+
#endif // !HAVE_GETDENTS64
405411

406412
static int
407413
_brute_force_closer(int first, int last)
@@ -441,19 +447,27 @@ _close_open_fds_safe(int start_fd, int *fds_to_keep, Py_ssize_t fds_to_keep_len)
441447
_brute_force_closer);
442448
return;
443449
} else {
444-
char buffer[sizeof(struct linux_dirent64)];
445-
int bytes;
446-
while ((bytes = syscall(SYS_getdents64, fd_dir_fd,
447-
(struct linux_dirent64 *)buffer,
448-
sizeof(buffer))) > 0) {
449-
struct linux_dirent64 *entry;
450+
char buffer[sizeof(struct py_dirent64)];
451+
Py_ssize_t bytes;
452+
while (1) {
453+
#ifdef HAVE_GETDENTS64
454+
bytes = getdents64(fd_dir_fd, buffer, sizeof(buffer));
455+
#else
456+
bytes = syscall(SYS_getdents64, fd_dir_fd,
457+
(struct py_dirent64 *)buffer, sizeof(buffer));
458+
#endif
459+
if (bytes <= 0) {
460+
break;
461+
}
462+
463+
struct py_dirent64 *entry;
450464
int offset;
451465
#ifdef _Py_MEMORY_SANITIZER
452466
__msan_unpoison(buffer, bytes);
453467
#endif
454468
for (offset = 0; offset < bytes; offset += entry->d_reclen) {
455469
int fd;
456-
entry = (struct linux_dirent64 *)(buffer + offset);
470+
entry = (struct py_dirent64 *)(buffer + offset);
457471
if ((fd = _pos_int_from_ascii(entry->d_name)) < 0)
458472
continue; /* Not a number. */
459473
if (fd != fd_dir_fd && fd >= start_fd &&

Modules/clinic/posixmodule.c.h

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/clinic/signalmodule.c.h

Lines changed: 20 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/posixmodule.c

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@
6868
# include "emscripten.h" // emscripten_debugger()
6969
#endif
7070

71+
#ifdef HAVE_SYS_RANDOM_H
72+
# include <sys/random.h>
73+
#endif
74+
7175
#ifdef HAVE_SYS_UIO_H
7276
# include <sys/uio.h>
7377
#endif
@@ -10810,8 +10814,9 @@ os_wait_impl(PyObject *module)
1081010814

1081110815

1081210816
// This system call always crashes on older Android versions.
10813-
#if defined(__linux__) && defined(__NR_pidfd_open) && \
10814-
!(defined(__ANDROID__) && __ANDROID_API__ < 31)
10817+
#if defined(HAVE_PIDFD_OPEN) \
10818+
|| (defined(__linux__) && defined(__NR_pidfd_open) \
10819+
&& !(defined(__ANDROID__) && __ANDROID_API__ < 31))
1081510820
/*[clinic input]
1081610821
os.pidfd_open
1081710822
pid: pid_t
@@ -10827,7 +10832,11 @@ static PyObject *
1082710832
os_pidfd_open_impl(PyObject *module, pid_t pid, unsigned int flags)
1082810833
/*[clinic end generated code: output=5c7252698947dc41 input=03058b32c389f874]*/
1082910834
{
10835+
#ifdef HAVE_PIDFD_OPEN
10836+
int fd = pidfd_open(pid, flags);
10837+
#else
1083010838
int fd = syscall(__NR_pidfd_open, pid, flags);
10839+
#endif
1083110840
if (fd < 0) {
1083210841
return posix_error();
1083310842
}
@@ -10836,8 +10845,9 @@ os_pidfd_open_impl(PyObject *module, pid_t pid, unsigned int flags)
1083610845
#endif
1083710846

1083810847

10839-
#if defined(__linux__) && defined(__NR_pidfd_getfd) && \
10840-
!(defined(__ANDROID__) && __ANDROID_API__ < 31)
10848+
#if defined(HAVE_PIDFD_GETFD) \
10849+
|| (defined(__linux__) && defined(__NR_pidfd_getfd) \
10850+
&& !(defined(__ANDROID__) && __ANDROID_API__ < 31))
1084110851
/*[clinic input]
1084210852
os.pidfd_getfd
1084310853
pidfd: int
@@ -10856,7 +10866,11 @@ os_pidfd_getfd_impl(PyObject *module, int pidfd, int targetfd,
1085610866
unsigned int flags)
1085710867
/*[clinic end generated code: output=e1a1415a13c7137f input=ef6417fb10deb1cc]*/
1085810868
{
10869+
#ifdef HAVE_PIDFD_GETFD
10870+
int fd = pidfd_getfd(pidfd, targetfd, flags);
10871+
#else
1085910872
int fd = syscall(__NR_pidfd_getfd, pidfd, targetfd, flags);
10873+
#endif
1086010874
if (fd < 0) {
1086110875
return posix_error();
1086210876
}
@@ -17369,7 +17383,7 @@ os_fspath_impl(PyObject *module, PyObject *path)
1736917383
return PyOS_FSPath(path);
1737017384
}
1737117385

17372-
#ifdef HAVE_GETRANDOM_SYSCALL
17386+
#if defined(HAVE_GETRANDOM) || defined(HAVE_GETRANDOM_SYSCALL)
1737317387
/*[clinic input]
1737417388
os.getrandom
1737517389

@@ -17396,7 +17410,11 @@ os_getrandom_impl(PyObject *module, Py_ssize_t size, int flags)
1739617410

1739717411
Py_ssize_t n;
1739817412
while (1) {
17413+
#ifdef HAVE_GETRANDOM
17414+
n = getrandom(data, size, flags);
17415+
#else
1739917416
n = syscall(SYS_getrandom, data, size, flags);
17417+
#endif
1740017418
if (n < 0 && errno == EINTR) {
1740117419
if (PyErr_CheckSignals() < 0) {
1740217420
goto error;
@@ -18504,7 +18522,7 @@ all_ins(PyObject *m)
1850418522
if (PyModule_AddIntMacro(m, RTLD_MEMBER)) return -1;
1850518523
#endif
1850618524

18507-
#ifdef HAVE_GETRANDOM_SYSCALL
18525+
#if defined(HAVE_GETRANDOM) || defined(HAVE_GETRANDOM_SYSCALL)
1850818526
if (PyModule_AddIntMacro(m, GRND_RANDOM)) return -1;
1850918527
if (PyModule_AddIntMacro(m, GRND_NONBLOCK)) return -1;
1851018528
#endif

Modules/signalmodule.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@
5353
# include <pthread.h>
5454
#endif
5555

56+
#ifdef HAVE_SYS_PIDFD_H
57+
# include <sys/pidfd.h> // pidfd_send_signal()
58+
#endif
59+
5660
#ifndef SIG_ERR
5761
# define SIG_ERR ((PyOS_sighandler_t)(-1))
5862
#endif
@@ -1300,31 +1304,37 @@ signal_pthread_kill_impl(PyObject *module, unsigned long thread_id,
13001304

13011305

13021306
// This system call always crashes on older Android versions.
1303-
#if defined(__linux__) && defined(__NR_pidfd_send_signal) && \
1304-
!(defined(__ANDROID__) && __ANDROID_API__ < 31)
1307+
#if defined(HAVE_PIDFD_SEND_SIGNAL) \
1308+
|| (defined(__linux__) && defined(__NR_pidfd_send_signal) \
1309+
&& !(defined(__ANDROID__) && __ANDROID_API__ < 31))
13051310
/*[clinic input]
13061311
signal.pidfd_send_signal
13071312
13081313
pidfd: int
13091314
signalnum: int
13101315
siginfo: object = None
1311-
flags: int = 0
1316+
flags: unsigned_int(bitwise=True) = 0
13121317
/
13131318
13141319
Send a signal to a process referred to by a pid file descriptor.
13151320
[clinic start generated code]*/
13161321

13171322
static PyObject *
13181323
signal_pidfd_send_signal_impl(PyObject *module, int pidfd, int signalnum,
1319-
PyObject *siginfo, int flags)
1320-
/*[clinic end generated code: output=2d59f04a75d9cbdf input=2a6543a1f4ac2000]*/
1324+
PyObject *siginfo, unsigned int flags)
1325+
/*[clinic end generated code: output=1804b5a19d269104 input=a6e82a3c264fa19d]*/
13211326

13221327
{
13231328
if (siginfo != Py_None) {
13241329
PyErr_SetString(PyExc_TypeError, "siginfo must be None");
13251330
return NULL;
13261331
}
1327-
if (syscall(__NR_pidfd_send_signal, pidfd, signalnum, NULL, flags) < 0) {
1332+
#ifdef HAVE_PIDFD_SEND_SIGNAL
1333+
int res = pidfd_send_signal(pidfd, signalnum, NULL, flags);
1334+
#else
1335+
int res = syscall(__NR_pidfd_send_signal, pidfd, signalnum, NULL, flags);
1336+
#endif
1337+
if (res < 0) {
13281338
PyErr_SetFromErrno(PyExc_OSError);
13291339
return NULL;
13301340
}

Python/bootstrap_hash.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,6 @@ py_getrandom(void *buffer, Py_ssize_t size, int blocking, int raise)
126126
n = getrandom(dest, n, flags);
127127
}
128128
#else
129-
/* On Linux, use the syscall() function because the GNU libc doesn't
130-
expose the Linux getrandom() syscall yet. See:
131-
https://sourceware.org/bugzilla/show_bug.cgi?id=17252 */
132129
if (raise) {
133130
Py_BEGIN_ALLOW_THREADS
134131
n = syscall(SYS_getrandom, dest, n, flags);

Python/perf_jit_trampoline.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,8 @@ static void perf_map_jit_write_entry_with_name(
672672
uint64_t thread_id = 0;
673673
pthread_threadid_np(NULL, &thread_id);
674674
ev.thread_id = (uint32_t)thread_id;
675+
#elif defined(HAVE_GETTID)
676+
ev.thread_id = gettid();
675677
#else
676678
ev.thread_id = syscall(SYS_gettid); // Get thread ID via system call
677679
#endif

Python/thread_pthread.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
#include <signal.h>
1919
#include <unistd.h> /* pause(), also getthrid() on OpenBSD */
2020

21-
#if defined(__linux__)
21+
#ifdef HAVE_GETTID
22+
# include <unistd.h> // gettid()
23+
#elif defined(__linux__)
2224
# include <sys/syscall.h> /* syscall(SYS_gettid) */
2325
#elif defined(__FreeBSD__)
2426
# include <pthread_np.h> /* pthread_getthreadid_np() */
@@ -380,6 +382,9 @@ PyThread_get_thread_native_id(void)
380382
#ifdef __APPLE__
381383
uint64_t native_id;
382384
(void) pthread_threadid_np(NULL, &native_id);
385+
#elif defined(HAVE_GETTID)
386+
pid_t native_id;
387+
native_id = gettid();
383388
#elif defined(__linux__)
384389
pid_t native_id;
385390
native_id = syscall(SYS_gettid);

0 commit comments

Comments
 (0)