From 8925fa0622e2acaf6077e284b5dfc5cd54d445aa Mon Sep 17 00:00:00 2001 From: Zebreus Date: Fri, 13 Feb 2026 09:30:05 +0100 Subject: [PATCH 01/10] Implement memfs_create --- Makefile | 1 + Makefile-eh | 1 + libc-top-half/musl/src/mman/memfd_create.c | 57 ++++++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 libc-top-half/musl/src/mman/memfd_create.c diff --git a/Makefile b/Makefile index 90b3dd954..f563bac7e 100644 --- a/Makefile +++ b/Makefile @@ -109,6 +109,7 @@ LIBC_TOP_HALF_MUSL_SOURCES = \ misc/realpath.c \ misc/syslog.c \ mman/shm_open.c \ + mman/memfd_create.c \ errno/strerror.c \ \ network/services.c \ diff --git a/Makefile-eh b/Makefile-eh index a782c86bf..db48f36b2 100644 --- a/Makefile-eh +++ b/Makefile-eh @@ -117,6 +117,7 @@ LIBC_TOP_HALF_MUSL_SOURCES = \ misc/realpath.c \ misc/syslog.c \ mman/shm_open.c \ + mman/memfd_create.c \ errno/strerror.c \ \ network/services.c \ diff --git a/libc-top-half/musl/src/mman/memfd_create.c b/libc-top-half/musl/src/mman/memfd_create.c new file mode 100644 index 000000000..99dc90dd4 --- /dev/null +++ b/libc-top-half/musl/src/mman/memfd_create.c @@ -0,0 +1,57 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +static int create_unlinked_temp(char *template_path, unsigned int flags) +{ + int fd; + if (flags & MFD_CLOEXEC) { + fd = mkostemp(template_path, O_CLOEXEC); + } else { + fd = mkstemp(template_path); + } + if (fd < 0) return -1; + + if (unlink(template_path) != 0) { + int saved_errno = errno; + close(fd); + errno = saved_errno; + return -1; + } + + if ((flags & MFD_CLOEXEC) && fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) { + int saved_errno = errno; + close(fd); + errno = saved_errno; + return -1; + } + + return fd; +} + +int memfd_create(const char *name, unsigned int flags) +{ + (void)name; + + if (flags & ~(MFD_CLOEXEC | MFD_ALLOW_SEALING)) { + errno = EINVAL; + return -1; + } + + /* Seals are not currently supported by the WASIX fcntl subset. */ + if (flags & MFD_ALLOW_SEALING) { + errno = ENOTSUP; + return -1; + } + + char tmp_template[] = "/tmp/.memfd-XXXXXX"; + int fd = create_unlinked_temp(tmp_template, flags); + if (fd >= 0) return fd; + + char cwd_template[] = "./.memfd-XXXXXX"; + return create_unlinked_temp(cwd_template, flags); +} From e9b523b91ff8bc42848254fdccebdb4a3b2132d3 Mon Sep 17 00:00:00 2001 From: Zebreus Date: Fri, 13 Feb 2026 09:37:16 +0100 Subject: [PATCH 02/10] Add memfd_create to expected symbols --- expected/wasm32-wasi-eh/defined-symbols.txt | 1 + expected/wasm32-wasi-ehpic/defined-symbols.txt | 1 + expected/wasm32-wasi-threads/defined-symbols.txt | 1 + expected/wasm32-wasi/defined-symbols.txt | 1 + expected/wasm64-wasi/defined-symbols.txt | 1 + 5 files changed, 5 insertions(+) diff --git a/expected/wasm32-wasi-eh/defined-symbols.txt b/expected/wasm32-wasi-eh/defined-symbols.txt index 51b29a402..885ca8eb6 100644 --- a/expected/wasm32-wasi-eh/defined-symbols.txt +++ b/expected/wasm32-wasi-eh/defined-symbols.txt @@ -1203,6 +1203,7 @@ memccpy memchr memcmp memcpy +memfd_create memmem memmove mempcpy diff --git a/expected/wasm32-wasi-ehpic/defined-symbols.txt b/expected/wasm32-wasi-ehpic/defined-symbols.txt index 3885a6652..0ecadc1cd 100644 --- a/expected/wasm32-wasi-ehpic/defined-symbols.txt +++ b/expected/wasm32-wasi-ehpic/defined-symbols.txt @@ -1211,6 +1211,7 @@ memccpy memchr memcmp memcpy +memfd_create memmem memmove mempcpy diff --git a/expected/wasm32-wasi-threads/defined-symbols.txt b/expected/wasm32-wasi-threads/defined-symbols.txt index c8996ef3b..e42ac12b7 100644 --- a/expected/wasm32-wasi-threads/defined-symbols.txt +++ b/expected/wasm32-wasi-threads/defined-symbols.txt @@ -1133,6 +1133,7 @@ memccpy memchr memcmp memcpy +memfd_create memmem memmove mempcpy diff --git a/expected/wasm32-wasi/defined-symbols.txt b/expected/wasm32-wasi/defined-symbols.txt index 6d33bff74..f34d6fb8a 100644 --- a/expected/wasm32-wasi/defined-symbols.txt +++ b/expected/wasm32-wasi/defined-symbols.txt @@ -1209,6 +1209,7 @@ memccpy memchr memcmp memcpy +memfd_create memmem memmove mempcpy diff --git a/expected/wasm64-wasi/defined-symbols.txt b/expected/wasm64-wasi/defined-symbols.txt index cd3d45b83..9fa4c60cb 100644 --- a/expected/wasm64-wasi/defined-symbols.txt +++ b/expected/wasm64-wasi/defined-symbols.txt @@ -1167,6 +1167,7 @@ memccpy memchr memcmp memcpy +memfd_create memmem memmove mempcpy From 5fc3ef6346b2f34ad01014e06adc698b79149354 Mon Sep 17 00:00:00 2001 From: Zebreus Date: Fri, 13 Feb 2026 10:16:11 +0100 Subject: [PATCH 03/10] Apply review comments --- libc-top-half/musl/src/mman/memfd_create.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/libc-top-half/musl/src/mman/memfd_create.c b/libc-top-half/musl/src/mman/memfd_create.c index 99dc90dd4..e131541cb 100644 --- a/libc-top-half/musl/src/mman/memfd_create.c +++ b/libc-top-half/musl/src/mman/memfd_create.c @@ -23,13 +23,6 @@ static int create_unlinked_temp(char *template_path, unsigned int flags) return -1; } - if ((flags & MFD_CLOEXEC) && fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) { - int saved_errno = errno; - close(fd); - errno = saved_errno; - return -1; - } - return fd; } @@ -37,7 +30,12 @@ int memfd_create(const char *name, unsigned int flags) { (void)name; - if (flags & ~(MFD_CLOEXEC | MFD_ALLOW_SEALING)) { + if (flags & MFD_HUGETLB) { + errno = ENOTSUP; + return -1; + } + + if (flags & ~(MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_HUGETLB)) { errno = EINVAL; return -1; } From 2fbcffebabb02ce389d2f0d95bbcd5496fae2a3f Mon Sep 17 00:00:00 2001 From: Zebreus Date: Fri, 13 Feb 2026 10:57:21 +0100 Subject: [PATCH 04/10] Fix flag check --- libc-top-half/musl/src/mman/memfd_create.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/libc-top-half/musl/src/mman/memfd_create.c b/libc-top-half/musl/src/mman/memfd_create.c index e131541cb..2fbb99940 100644 --- a/libc-top-half/musl/src/mman/memfd_create.c +++ b/libc-top-half/musl/src/mman/memfd_create.c @@ -30,18 +30,14 @@ int memfd_create(const char *name, unsigned int flags) { (void)name; - if (flags & MFD_HUGETLB) { - errno = ENOTSUP; - return -1; - } - if (flags & ~(MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_HUGETLB)) { errno = EINVAL; return -1; } - /* Seals are not currently supported by the WASIX fcntl subset. */ - if (flags & MFD_ALLOW_SEALING) { + if (flags & (MFD_HUGETLB | MFD_ALLOW_SEALING)) { + /* Seals are not currently supported by the WASIX fcntl subset. */ + /* hugetlbfs is not currently supported by the WASIX filesystem subset. */ errno = ENOTSUP; return -1; } From 5e49e07d7dd672f8763c4393b4c0128e17deeba0 Mon Sep 17 00:00:00 2001 From: Zebreus Date: Fri, 13 Feb 2026 11:47:13 +0100 Subject: [PATCH 05/10] Add name to memfd_create --- libc-top-half/musl/src/mman/memfd_create.c | 53 ++++++++++++++++++++-- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/libc-top-half/musl/src/mman/memfd_create.c b/libc-top-half/musl/src/mman/memfd_create.c index 2fbb99940..a88b99963 100644 --- a/libc-top-half/musl/src/mman/memfd_create.c +++ b/libc-top-half/musl/src/mman/memfd_create.c @@ -1,11 +1,16 @@ #define _GNU_SOURCE +#include #include #include +#include #include +#include #include #include +#define MEMFD_NAME_MAX 249 + static int create_unlinked_temp(char *template_path, unsigned int flags) { int fd; @@ -26,10 +31,33 @@ static int create_unlinked_temp(char *template_path, unsigned int flags) return fd; } -int memfd_create(const char *name, unsigned int flags) +// Returns the length of the name without the null character. +// If the returned length == dst_len, the src was too long. dst is not null terminated in this case. +static int sanitize_name(char *dst, size_t dst_len, const char *src) { - (void)name; + size_t i = 0; + + while (i < dst_len && src[i] != '\0') { + unsigned char c = (unsigned char)src[i]; + if (isalnum(c) || c == '_' || c == '-' || c == '.') { + dst[i] = (char)c; + } else { + dst[i] = '_'; + } + i++; + } + + if (i == 0 && dst_len > 1) { + strcpy(dst, "anon"); + return 4; + } + + return i; +} + +int memfd_create(const char *name, unsigned int flags) +{ if (flags & ~(MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_HUGETLB)) { errno = EINVAL; return -1; @@ -42,10 +70,25 @@ int memfd_create(const char *name, unsigned int flags) return -1; } - char tmp_template[] = "/tmp/.memfd-XXXXXX"; + if (name == NULL) { + errno = EFAULT; + return -1; + } + + // Construct a string like "/tmp/.memfd--XXXXXX" + char tmp_template[sizeof("/tmp/.memfd-")-1 + MEMFD_NAME_MAX + sizeof("-XXXXXX")-1 + 1]; + memcpy(tmp_template, "/tmp/.memfd-", sizeof("/tmp/.memfd-")); + int name_len = sanitize_name(tmp_template + sizeof("/tmp/.memfd-") - 1, MEMFD_NAME_MAX + 1, name); + if (name_len > MEMFD_NAME_MAX) { + errno = EINVAL; + return -1; + } + memcpy(tmp_template + sizeof("/tmp/.memfd-") - 1 + name_len, "-XXXXXX", sizeof("-XXXXXX")); + int fd = create_unlinked_temp(tmp_template, flags); if (fd >= 0) return fd; - char cwd_template[] = "./.memfd-XXXXXX"; - return create_unlinked_temp(cwd_template, flags); + // Use ".memfd--XXXXXX" to create a temporary file in the current working directory. + char* cwd_name = tmp_template + sizeof("/tmp/") - 1; + return create_unlinked_temp(cwd_name, flags); } From 4f9cf69ab412712fa6cb739c5764a29da8d6f8d6 Mon Sep 17 00:00:00 2001 From: Zebreus Date: Fri, 13 Feb 2026 12:00:17 +0100 Subject: [PATCH 06/10] Allow empty names in memfd_create --- libc-top-half/musl/src/mman/memfd_create.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libc-top-half/musl/src/mman/memfd_create.c b/libc-top-half/musl/src/mman/memfd_create.c index a88b99963..0ef00d0dc 100644 --- a/libc-top-half/musl/src/mman/memfd_create.c +++ b/libc-top-half/musl/src/mman/memfd_create.c @@ -47,11 +47,6 @@ static int sanitize_name(char *dst, size_t dst_len, const char *src) i++; } - if (i == 0 && dst_len > 1) { - strcpy(dst, "anon"); - return 4; - } - return i; } From d1495fa00ef41f6ea514b0e0fae9c010988b79ca Mon Sep 17 00:00:00 2001 From: Zebreus Date: Fri, 13 Feb 2026 12:56:10 +0100 Subject: [PATCH 07/10] Apply minor review comments --- libc-top-half/musl/src/mman/memfd_create.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libc-top-half/musl/src/mman/memfd_create.c b/libc-top-half/musl/src/mman/memfd_create.c index 0ef00d0dc..d070769cd 100644 --- a/libc-top-half/musl/src/mman/memfd_create.c +++ b/libc-top-half/musl/src/mman/memfd_create.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -72,7 +71,7 @@ int memfd_create(const char *name, unsigned int flags) // Construct a string like "/tmp/.memfd--XXXXXX" char tmp_template[sizeof("/tmp/.memfd-")-1 + MEMFD_NAME_MAX + sizeof("-XXXXXX")-1 + 1]; - memcpy(tmp_template, "/tmp/.memfd-", sizeof("/tmp/.memfd-")); + memcpy(tmp_template, "/tmp/.memfd-", sizeof("/tmp/.memfd-") -1); int name_len = sanitize_name(tmp_template + sizeof("/tmp/.memfd-") - 1, MEMFD_NAME_MAX + 1, name); if (name_len > MEMFD_NAME_MAX) { errno = EINVAL; From bf4c18865cf90183876a439ebc1fc4be32760a9a Mon Sep 17 00:00:00 2001 From: Zebreus Date: Fri, 13 Feb 2026 12:56:47 +0100 Subject: [PATCH 08/10] Restore the placeholder after the first failed mkstemp --- libc-top-half/musl/src/mman/memfd_create.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libc-top-half/musl/src/mman/memfd_create.c b/libc-top-half/musl/src/mman/memfd_create.c index d070769cd..1f14f494a 100644 --- a/libc-top-half/musl/src/mman/memfd_create.c +++ b/libc-top-half/musl/src/mman/memfd_create.c @@ -82,7 +82,8 @@ int memfd_create(const char *name, unsigned int flags) int fd = create_unlinked_temp(tmp_template, flags); if (fd >= 0) return fd; - // Use ".memfd--XXXXXX" to create a temporary file in the current working directory. - char* cwd_name = tmp_template + sizeof("/tmp/") - 1; - return create_unlinked_temp(cwd_name, flags); + // If that failed, try ".memfd--XXXXXX" in the current working directory. + // Restore the -XXXXXX placeholder because it got overwritten by the previous call to mkstemp. + memcpy(tmp_template + sizeof("/tmp/.memfd-") - 1 + name_len, "-XXXXXX", sizeof("-XXXXXX")); + return create_unlinked_temp(tmp_template + sizeof("/tmp/") - 1, flags); } From 191c385cf0027db9664148a4bbd57974aa9705bc Mon Sep 17 00:00:00 2001 From: Zebreus Date: Fri, 13 Feb 2026 13:12:09 +0100 Subject: [PATCH 09/10] Format with clang_format --- libc-top-half/musl/src/mman/memfd_create.c | 128 +++++++++++---------- 1 file changed, 66 insertions(+), 62 deletions(-) diff --git a/libc-top-half/musl/src/mman/memfd_create.c b/libc-top-half/musl/src/mman/memfd_create.c index 1f14f494a..76765ab22 100644 --- a/libc-top-half/musl/src/mman/memfd_create.c +++ b/libc-top-half/musl/src/mman/memfd_create.c @@ -10,80 +10,84 @@ #define MEMFD_NAME_MAX 249 -static int create_unlinked_temp(char *template_path, unsigned int flags) -{ - int fd; - if (flags & MFD_CLOEXEC) { - fd = mkostemp(template_path, O_CLOEXEC); - } else { - fd = mkstemp(template_path); - } - if (fd < 0) return -1; +static int create_unlinked_temp(char *template_path, unsigned int flags) { + int fd; + if (flags & MFD_CLOEXEC) { + fd = mkostemp(template_path, O_CLOEXEC); + } else { + fd = mkstemp(template_path); + } + if (fd < 0) + return -1; - if (unlink(template_path) != 0) { - int saved_errno = errno; - close(fd); - errno = saved_errno; - return -1; - } + if (unlink(template_path) != 0) { + int saved_errno = errno; + close(fd); + errno = saved_errno; + return -1; + } - return fd; + return fd; } // Returns the length of the name without the null character. -// If the returned length == dst_len, the src was too long. dst is not null terminated in this case. -static int sanitize_name(char *dst, size_t dst_len, const char *src) -{ - size_t i = 0; +// If the returned length == dst_len, the src was too long. dst is not null +// terminated in this case. +static int sanitize_name(char *dst, size_t dst_len, const char *src) { + size_t i = 0; - while (i < dst_len && src[i] != '\0') { - unsigned char c = (unsigned char)src[i]; - if (isalnum(c) || c == '_' || c == '-' || c == '.') { - dst[i] = (char)c; - } else { - dst[i] = '_'; - } - i++; - } + while (i < dst_len && src[i] != '\0') { + unsigned char c = (unsigned char)src[i]; + if (isalnum(c) || c == '_' || c == '-' || c == '.') { + dst[i] = (char)c; + } else { + dst[i] = '_'; + } + i++; + } - return i; + return i; } +int memfd_create(const char *name, unsigned int flags) { + if (flags & ~(MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_HUGETLB)) { + errno = EINVAL; + return -1; + } -int memfd_create(const char *name, unsigned int flags) -{ - if (flags & ~(MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_HUGETLB)) { - errno = EINVAL; - return -1; - } + if (flags & (MFD_HUGETLB | MFD_ALLOW_SEALING)) { + /* Seals are not currently supported by the WASIX fcntl subset. */ + /* hugetlbfs is not currently supported by the WASIX filesystem subset. */ + errno = ENOTSUP; + return -1; + } - if (flags & (MFD_HUGETLB | MFD_ALLOW_SEALING)) { - /* Seals are not currently supported by the WASIX fcntl subset. */ - /* hugetlbfs is not currently supported by the WASIX filesystem subset. */ - errno = ENOTSUP; - return -1; - } + if (name == NULL) { + errno = EFAULT; + return -1; + } - if (name == NULL) { - errno = EFAULT; - return -1; - } + // Construct a string like "/tmp/.memfd--XXXXXX" + char tmp_template[sizeof("/tmp/.memfd-") - 1 + MEMFD_NAME_MAX + + sizeof("-XXXXXX") - 1 + 1]; + memcpy(tmp_template, "/tmp/.memfd-", sizeof("/tmp/.memfd-") - 1); + int name_len = sanitize_name(tmp_template + sizeof("/tmp/.memfd-") - 1, + MEMFD_NAME_MAX + 1, name); + if (name_len > MEMFD_NAME_MAX) { + errno = EINVAL; + return -1; + } + memcpy(tmp_template + sizeof("/tmp/.memfd-") - 1 + name_len, "-XXXXXX", + sizeof("-XXXXXX")); - // Construct a string like "/tmp/.memfd--XXXXXX" - char tmp_template[sizeof("/tmp/.memfd-")-1 + MEMFD_NAME_MAX + sizeof("-XXXXXX")-1 + 1]; - memcpy(tmp_template, "/tmp/.memfd-", sizeof("/tmp/.memfd-") -1); - int name_len = sanitize_name(tmp_template + sizeof("/tmp/.memfd-") - 1, MEMFD_NAME_MAX + 1, name); - if (name_len > MEMFD_NAME_MAX) { - errno = EINVAL; - return -1; - } - memcpy(tmp_template + sizeof("/tmp/.memfd-") - 1 + name_len, "-XXXXXX", sizeof("-XXXXXX")); + int fd = create_unlinked_temp(tmp_template, flags); + if (fd >= 0) + return fd; - int fd = create_unlinked_temp(tmp_template, flags); - if (fd >= 0) return fd; - - // If that failed, try ".memfd--XXXXXX" in the current working directory. - // Restore the -XXXXXX placeholder because it got overwritten by the previous call to mkstemp. - memcpy(tmp_template + sizeof("/tmp/.memfd-") - 1 + name_len, "-XXXXXX", sizeof("-XXXXXX")); - return create_unlinked_temp(tmp_template + sizeof("/tmp/") - 1, flags); + // If that failed, try ".memfd--XXXXXX" in the current working + // directory. Restore the -XXXXXX placeholder because it got overwritten by + // the previous call to mkstemp. + memcpy(tmp_template + sizeof("/tmp/.memfd-") - 1 + name_len, "-XXXXXX", + sizeof("-XXXXXX")); + return create_unlinked_temp(tmp_template + sizeof("/tmp/") - 1, flags); } From 3860d9c057f71116112309615dac8ff346c6efc6 Mon Sep 17 00:00:00 2001 From: Zebreus Date: Fri, 13 Feb 2026 13:26:13 +0100 Subject: [PATCH 10/10] Rephrase comment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- libc-top-half/musl/src/mman/memfd_create.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libc-top-half/musl/src/mman/memfd_create.c b/libc-top-half/musl/src/mman/memfd_create.c index 76765ab22..98c2a8ab3 100644 --- a/libc-top-half/musl/src/mman/memfd_create.c +++ b/libc-top-half/musl/src/mman/memfd_create.c @@ -30,9 +30,9 @@ static int create_unlinked_temp(char *template_path, unsigned int flags) { return fd; } -// Returns the length of the name without the null character. -// If the returned length == dst_len, the src was too long. dst is not null -// terminated in this case. +// Returns the number of characters copied, excluding any null terminator. +// If the returned length == dst_len, src contained at least dst_len +// non-null characters and dst is not null-terminated (no room for a terminator). static int sanitize_name(char *dst, size_t dst_len, const char *src) { size_t i = 0;