Skip to content

Commit 43fdbd2

Browse files
ZackerySpytztiran
authored andcommitted
bpo-26836: Add os.memfd_create() (#13567)
* bpo-26836: Add os.memfd_create() * Use the glibc wrapper for memfd_create() Co-Authored-By: Christian Heimes <[email protected]> * Fix deletions caused by autoreconf. * Use MFD_CLOEXEC as the default value for *flags*. * Add memset_s to configure.ac. * Revert memset_s changes. * Apply the requested changes. * Tweak the docs.
1 parent 0c2f930 commit 43fdbd2

File tree

10 files changed

+259
-12
lines changed

10 files changed

+259
-12
lines changed

Doc/library/os.rst

+38
Original file line numberDiff line numberDiff line change
@@ -2982,6 +2982,44 @@ features:
29822982
Added support for :class:`bytes` paths.
29832983

29842984

2985+
.. function:: memfd_create(name[, flags=os.MFD_CLOEXEC])
2986+
2987+
Create an anonymous file and return a file descriptor that refers to it.
2988+
*flags* must be one of the ``os.MFD_*`` constants available on the system
2989+
(or a bitwise ORed combination of them). By default, the new file
2990+
descriptor is :ref:`non-inheritable <fd_inheritance>`.
2991+
2992+
.. availability:: Linux 3.17 or newer with glibc 2.27 or newer.
2993+
2994+
.. versionadded:: 3.8
2995+
2996+
2997+
.. data:: MFD_CLOEXEC
2998+
MFD_ALLOW_SEALING
2999+
MFD_HUGETLB
3000+
MFD_HUGE_SHIFT
3001+
MFD_HUGE_MASK
3002+
MFD_HUGE_64KB
3003+
MFD_HUGE_512KB
3004+
MFD_HUGE_1MB
3005+
MFD_HUGE_2MB
3006+
MFD_HUGE_8MB
3007+
MFD_HUGE_16MB
3008+
MFD_HUGE_32MB
3009+
MFD_HUGE_256MB
3010+
MFD_HUGE_512MB
3011+
MFD_HUGE_1GB
3012+
MFD_HUGE_2GB
3013+
MFD_HUGE_16GB
3014+
3015+
These flags can be passed to :func:`memfd_create`.
3016+
3017+
.. availability:: Linux 3.17 or newer with glibc 2.27 or newer. The
3018+
``MFD_HUGE*`` flags are only available since Linux 4.14.
3019+
3020+
.. versionadded:: 3.8
3021+
3022+
29853023
Linux extended attributes
29863024
~~~~~~~~~~~~~~~~~~~~~~~~~
29873025

Doc/whatsnew/3.8.rst

+4
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,10 @@ Added new function :func:`~os.add_dll_directory` on Windows for providing
486486
additional search paths for native dependencies when importing extension
487487
modules or loading DLLs using :mod:`ctypes`.
488488

489+
A new :func:`os.memfd_create` function was added to wrap the
490+
``memfd_create()`` syscall.
491+
(Contributed by Zackery Spytz and Christian Heimes in :issue:`26836`.)
492+
489493

490494
os.path
491495
-------

Lib/test/test_os.py

+16
Original file line numberDiff line numberDiff line change
@@ -3122,6 +3122,22 @@ def test_stty_match(self):
31223122
self.assertEqual(expected, actual)
31233123

31243124

3125+
@unittest.skipUnless(hasattr(os, 'memfd_create'), 'requires os.memfd_create')
3126+
class MemfdCreateTests(unittest.TestCase):
3127+
def test_memfd_create(self):
3128+
fd = os.memfd_create("Hi", os.MFD_CLOEXEC)
3129+
self.assertNotEqual(fd, -1)
3130+
self.addCleanup(os.close, fd)
3131+
self.assertFalse(os.get_inheritable(fd))
3132+
with open(fd, "wb", closefd=False) as f:
3133+
f.write(b'memfd_create')
3134+
self.assertEqual(f.tell(), 12)
3135+
3136+
fd2 = os.memfd_create("Hi")
3137+
self.addCleanup(os.close, fd2)
3138+
self.assertFalse(os.get_inheritable(fd2))
3139+
3140+
31253141
class OSErrorTests(unittest.TestCase):
31263142
def setUp(self):
31273143
class Str(str):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add :func:`os.memfd_create`.

Modules/clinic/posixmodule.c.h

+60-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/posixmodule.c

+64
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,19 @@ extern char *ctermid_r(char *);
389389
#define HAVE_STRUCT_STAT_ST_FSTYPE 1
390390
#endif
391391

392+
/* memfd_create is either defined in sys/mman.h or sys/memfd.h
393+
* linux/memfd.h defines additional flags
394+
*/
395+
#ifdef HAVE_SYS_MMAN_H
396+
#include <sys/mman.h>
397+
#endif
398+
#ifdef HAVE_SYS_MEMFD_H
399+
#include <sys/memfd.h>
400+
#endif
401+
#ifdef HAVE_LINUX_MEMFD_H
402+
#include <linux/memfd.h>
403+
#endif
404+
392405
#ifdef _Py_MEMORY_SANITIZER
393406
# include <sanitizer/msan_interface.h>
394407
#endif
@@ -11897,6 +11910,31 @@ os_urandom_impl(PyObject *module, Py_ssize_t size)
1189711910
return bytes;
1189811911
}
1189911912

11913+
#ifdef HAVE_MEMFD_CREATE
11914+
/*[clinic input]
11915+
os.memfd_create
11916+
11917+
name: FSConverter
11918+
flags: unsigned_int(bitwise=True, c_default="MFD_CLOEXEC") = MFD_CLOEXEC
11919+
11920+
[clinic start generated code]*/
11921+
11922+
static PyObject *
11923+
os_memfd_create_impl(PyObject *module, PyObject *name, unsigned int flags)
11924+
/*[clinic end generated code: output=6681ede983bdb9a6 input=a42cfc199bcd56e9]*/
11925+
{
11926+
int fd;
11927+
const char *bytes = PyBytes_AS_STRING(name);
11928+
Py_BEGIN_ALLOW_THREADS
11929+
fd = memfd_create(bytes, flags);
11930+
Py_END_ALLOW_THREADS
11931+
if (fd == -1) {
11932+
return PyErr_SetFromErrno(PyExc_OSError);
11933+
}
11934+
return PyLong_FromLong(fd);
11935+
}
11936+
#endif
11937+
1190011938
/* Terminal size querying */
1190111939

1190211940
static PyTypeObject* TerminalSizeType;
@@ -13554,6 +13592,7 @@ static PyMethodDef posix_methods[] = {
1355413592
OS_SCANDIR_METHODDEF
1355513593
OS_FSPATH_METHODDEF
1355613594
OS_GETRANDOM_METHODDEF
13595+
OS_MEMFD_CREATE_METHODDEF
1355713596
#ifdef MS_WINDOWS
1355813597
OS__ADD_DLL_DIRECTORY_METHODDEF
1355913598
OS__REMOVE_DLL_DIRECTORY_METHODDEF
@@ -14003,6 +14042,27 @@ all_ins(PyObject *m)
1400314042
if (PyModule_AddIntMacro(m, GRND_RANDOM)) return -1;
1400414043
if (PyModule_AddIntMacro(m, GRND_NONBLOCK)) return -1;
1400514044
#endif
14045+
#ifdef HAVE_MEMFD_CREATE
14046+
if (PyModule_AddIntMacro(m, MFD_CLOEXEC)) return -1;
14047+
if (PyModule_AddIntMacro(m, MFD_ALLOW_SEALING)) return -1;
14048+
#ifdef MFD_HUGETLB
14049+
if (PyModule_AddIntMacro(m, MFD_HUGETLB)) return -1;
14050+
if (PyModule_AddIntMacro(m, MFD_HUGE_SHIFT)) return -1;
14051+
if (PyModule_AddIntMacro(m, MFD_HUGE_MASK)) return -1;
14052+
if (PyModule_AddIntMacro(m, MFD_HUGE_64KB)) return -1;
14053+
if (PyModule_AddIntMacro(m, MFD_HUGE_512KB)) return -1;
14054+
if (PyModule_AddIntMacro(m, MFD_HUGE_1MB)) return -1;
14055+
if (PyModule_AddIntMacro(m, MFD_HUGE_2MB)) return -1;
14056+
if (PyModule_AddIntMacro(m, MFD_HUGE_8MB)) return -1;
14057+
if (PyModule_AddIntMacro(m, MFD_HUGE_16MB)) return -1;
14058+
if (PyModule_AddIntMacro(m, MFD_HUGE_32MB)) return -1;
14059+
if (PyModule_AddIntMacro(m, MFD_HUGE_256MB)) return -1;
14060+
if (PyModule_AddIntMacro(m, MFD_HUGE_512MB)) return -1;
14061+
if (PyModule_AddIntMacro(m, MFD_HUGE_1GB)) return -1;
14062+
if (PyModule_AddIntMacro(m, MFD_HUGE_2GB)) return -1;
14063+
if (PyModule_AddIntMacro(m, MFD_HUGE_16GB)) return -1;
14064+
#endif
14065+
#endif
1400614066

1400714067
#if defined(__APPLE__)
1400814068
if (PyModule_AddIntConstant(m, "_COPYFILE_DATA", COPYFILE_DATA)) return -1;
@@ -14119,6 +14179,10 @@ static const char * const have_functions[] = {
1411914179
"HAVE_LUTIMES",
1412014180
#endif
1412114181

14182+
#ifdef HAVE_MEMFD_CREATE
14183+
"HAVE_MEMFD_CREATE",
14184+
#endif
14185+
1412214186
#ifdef HAVE_MKDIRAT
1412314187
"HAVE_MKDIRAT",
1412414188
#endif

aclocal.m4

+5-5
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ dnl
5555
dnl See the "Since" comment for each macro you use to see what version
5656
dnl of the macros you require.
5757
m4_defun([PKG_PREREQ],
58-
[m4_define([PKG_MACROS_VERSION], [0.29.2])
58+
[m4_define([PKG_MACROS_VERSION], [0.29.1])
5959
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
6060
[m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
6161
])dnl PKG_PREREQ
@@ -156,7 +156,7 @@ AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
156156
AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
157157
158158
pkg_failed=no
159-
AC_MSG_CHECKING([for $2])
159+
AC_MSG_CHECKING([for $1])
160160
161161
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
162162
_PKG_CONFIG([$1][_LIBS], [libs], [$2])
@@ -166,11 +166,11 @@ and $1[]_LIBS to avoid the need to call pkg-config.
166166
See the pkg-config man page for more details.])
167167
168168
if test $pkg_failed = yes; then
169-
AC_MSG_RESULT([no])
169+
AC_MSG_RESULT([no])
170170
_PKG_SHORT_ERRORS_SUPPORTED
171171
if test $_pkg_short_errors_supported = yes; then
172172
$1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
173-
else
173+
else
174174
$1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
175175
fi
176176
# Put the nasty error message in config.log where it belongs
@@ -187,7 +187,7 @@ installed software in a non-standard prefix.
187187
_PKG_TEXT])[]dnl
188188
])
189189
elif test $pkg_failed = untried; then
190-
AC_MSG_RESULT([no])
190+
AC_MSG_RESULT([no])
191191
m4_default([$4], [AC_MSG_FAILURE(
192192
[The pkg-config script could not be found or is too old. Make sure it
193193
is in your PATH or set the PKG_CONFIG environment variable to the full

configure

+47-2
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,7 @@ infodir
785785
docdir
786786
oldincludedir
787787
includedir
788+
runstatedir
788789
localstatedir
789790
sharedstatedir
790791
sysconfdir
@@ -897,6 +898,7 @@ datadir='${datarootdir}'
897898
sysconfdir='${prefix}/etc'
898899
sharedstatedir='${prefix}/com'
899900
localstatedir='${prefix}/var'
901+
runstatedir='${localstatedir}/run'
900902
includedir='${prefix}/include'
901903
oldincludedir='/usr/include'
902904
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -1149,6 +1151,15 @@ do
11491151
| -silent | --silent | --silen | --sile | --sil)
11501152
silent=yes ;;
11511153

1154+
-runstatedir | --runstatedir | --runstatedi | --runstated \
1155+
| --runstate | --runstat | --runsta | --runst | --runs \
1156+
| --run | --ru | --r)
1157+
ac_prev=runstatedir ;;
1158+
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
1159+
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
1160+
| --run=* | --ru=* | --r=*)
1161+
runstatedir=$ac_optarg ;;
1162+
11521163
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
11531164
ac_prev=sbindir ;;
11541165
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1286,7 +1297,7 @@ fi
12861297
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
12871298
datadir sysconfdir sharedstatedir localstatedir includedir \
12881299
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
1289-
libdir localedir mandir
1300+
libdir localedir mandir runstatedir
12901301
do
12911302
eval ac_val=\$$ac_var
12921303
# Remove trailing slashes.
@@ -1439,6 +1450,7 @@ Fine tuning of the installation directories:
14391450
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
14401451
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
14411452
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
1453+
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
14421454
--libdir=DIR object code libraries [EPREFIX/lib]
14431455
--includedir=DIR C header files [PREFIX/include]
14441456
--oldincludedir=DIR C header files for non-gcc [/usr/include]
@@ -7892,7 +7904,7 @@ sys/stat.h sys/syscall.h sys/sys_domain.h sys/termio.h sys/time.h \
78927904
sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \
78937905
libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \
78947906
linux/tipc.h linux/random.h spawn.h util.h alloca.h endian.h \
7895-
sys/endian.h sys/sysmacros.h
7907+
sys/endian.h sys/sysmacros.h linux/memfd.h sys/memfd.h sys/mman.h
78967908
do :
78977909
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
78987910
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
@@ -11785,6 +11797,39 @@ $as_echo "no" >&6; }
1178511797
fi
1178611798
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
1178711799

11800+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for memfd_create" >&5
11801+
$as_echo_n "checking for memfd_create... " >&6; }
11802+
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
11803+
/* end confdefs.h. */
11804+
11805+
#ifdef HAVE_SYS_MMAN_H
11806+
#include <sys/mman.h>
11807+
#endif
11808+
#ifdef HAVE_SYS_MEMFD_H
11809+
#include <sys/memfd.h>
11810+
#endif
11811+
11812+
int
11813+
main ()
11814+
{
11815+
void *x=memfd_create
11816+
;
11817+
return 0;
11818+
}
11819+
_ACEOF
11820+
if ac_fn_c_try_compile "$LINENO"; then :
11821+
11822+
$as_echo "#define HAVE_MEMFD_CREATE 1" >>confdefs.h
11823+
11824+
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
11825+
$as_echo "yes" >&6; }
11826+
else
11827+
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
11828+
$as_echo "no" >&6; }
11829+
11830+
fi
11831+
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
11832+
1178811833
# On some systems (eg. FreeBSD 5), we would find a definition of the
1178911834
# functions ctermid_r, setgroups in the library, but no prototype
1179011835
# (e.g. because we use _XOPEN_SOURCE). See whether we can take their

0 commit comments

Comments
 (0)