From 7fcc4f29df3c04c202616a9f7aa552f404807728 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 4 Nov 2019 14:56:35 -0800 Subject: [PATCH] Revamp and simplify the libpreopen code. (#110) wasi-libc's copy of libpreopen has evolved so many local changes that it's no longer worth keeping the upstream code structure and marking changes with __wasilibc_unmodified_upstream. This PR merges the source files into a single file, removes all __wasilibc_unmodified_upstream code, eliminates the ability to allocate multiple preopen lists, eliminates the need for __wasilibc_init_preopen, eliminates the non-standard eaccess, and makes several other cleanups. It also enables NDEBUG so that internal assertions are disabled in release builds. --- Makefile | 10 +- expected/wasm32-wasi/defined-symbols.txt | 2 - expected/wasm32-wasi/predefined-macros.txt | 3 +- libc-bottom-half/crt/crt1.c | 2 - .../libpreopen/include/libpreopen.h | 215 ------ libc-bottom-half/libpreopen/lib/internal.h | 166 ---- libc-bottom-half/libpreopen/lib/libpreopen.c | 261 ------- libc-bottom-half/libpreopen/lib/po_err.c | 105 --- .../libpreopen/lib/po_libc_wrappers.c | 717 ------------------ libc-bottom-half/libpreopen/lib/po_map.c | 131 ---- libc-bottom-half/libpreopen/libpreopen.c | 551 ++++++++++++++ libc-top-half/musl/src/regex/tre.h | 2 + 12 files changed, 558 insertions(+), 1607 deletions(-) delete mode 100644 libc-bottom-half/libpreopen/include/libpreopen.h delete mode 100644 libc-bottom-half/libpreopen/lib/internal.h delete mode 100644 libc-bottom-half/libpreopen/lib/libpreopen.c delete mode 100644 libc-bottom-half/libpreopen/lib/po_err.c delete mode 100644 libc-bottom-half/libpreopen/lib/po_libc_wrappers.c delete mode 100644 libc-bottom-half/libpreopen/lib/po_map.c create mode 100644 libc-bottom-half/libpreopen/libpreopen.c diff --git a/Makefile b/Makefile index 1670153..204f25f 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ WASM_CC ?= clang WASM_NM ?= $(patsubst %clang,%llvm-nm,$(WASM_CC)) WASM_AR ?= $(patsubst %clang,%llvm-ar,$(WASM_CC)) -WASM_CFLAGS ?= -O2 +WASM_CFLAGS ?= -O2 -DNDEBUG # The directory where we build the sysroot. SYSROOT ?= $(CURDIR)/sysroot # A directory to install to for "make install". @@ -45,12 +45,10 @@ LIBC_BOTTOM_HALF_CLOUDLIBC_SRC_INC = $(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC)/include LIBC_BOTTOM_HALF_HEADERS_PUBLIC = $(LIBC_BOTTOM_HALF_DIR)/headers/public LIBC_BOTTOM_HALF_HEADERS_PRIVATE = $(LIBC_BOTTOM_HALF_DIR)/headers/private LIBC_BOTTOM_HALF_LIBPREOPEN_DIR = $(LIBC_BOTTOM_HALF_DIR)/libpreopen -LIBC_BOTTOM_HALF_LIBPREOPEN_LIB = $(LIBC_BOTTOM_HALF_LIBPREOPEN_DIR)/lib -LIBC_BOTTOM_HALF_LIBPREOPEN_INC = $(LIBC_BOTTOM_HALF_LIBPREOPEN_DIR)/include LIBC_BOTTOM_HALF_SOURCES = $(LIBC_BOTTOM_HALF_DIR)/sources LIBC_BOTTOM_HALF_ALL_SOURCES = \ $(shell find $(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC) -name \*.c) \ - $(LIBC_BOTTOM_HALF_LIBPREOPEN_LIB)/po_libc_wrappers.c \ + $(LIBC_BOTTOM_HALF_LIBPREOPEN_DIR)/libpreopen.c \ $(shell find $(LIBC_BOTTOM_HALF_SOURCES) -name \*.c) LIBWASI_EMULATED_MMAN_SOURCES = \ $(shell find $(LIBC_BOTTOM_HALF_DIR)/mman -name \*.c) @@ -364,9 +362,7 @@ $(DLMALLOC_OBJS): override WASM_CFLAGS += \ startup_files $(LIBC_BOTTOM_HALF_ALL_OBJS): override WASM_CFLAGS += \ -I$(LIBC_BOTTOM_HALF_HEADERS_PRIVATE) \ -I$(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC_INC) \ - -I$(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC) \ - -I$(LIBC_BOTTOM_HALF_LIBPREOPEN_LIB) \ - -I$(LIBC_BOTTOM_HALF_LIBPREOPEN_INC) + -I$(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC) $(LIBC_TOP_HALF_ALL_OBJS) $(MUSL_PRINTSCAN_LONG_DOUBLE_OBJS) $(MUSL_PRINTSCAN_NO_FLOATING_POINT_OBJS): override WASM_CFLAGS += \ -I$(LIBC_TOP_HALF_MUSL_SRC_DIR)/include \ diff --git a/expected/wasm32-wasi/defined-symbols.txt b/expected/wasm32-wasi/defined-symbols.txt index e80a453..2b6a0af 100644 --- a/expected/wasm32-wasi/defined-symbols.txt +++ b/expected/wasm32-wasi/defined-symbols.txt @@ -251,7 +251,6 @@ __uselocale __utc __wasilibc_fd_renumber __wasilibc_find_relpath -__wasilibc_init_preopen __wasilibc_populate_environ __wasilibc_register_preopened_fd __wasilibc_rmdirat @@ -428,7 +427,6 @@ drand48 drem dremf duplocale -eaccess ecvt encrypt environ diff --git a/expected/wasm32-wasi/predefined-macros.txt b/expected/wasm32-wasi/predefined-macros.txt index 52ce3ce..ef86093 100644 --- a/expected/wasm32-wasi/predefined-macros.txt +++ b/expected/wasm32-wasi/predefined-macros.txt @@ -1143,6 +1143,7 @@ #define NAN (0.0f/0.0f) #define NBBY 8 #define NCARGS 131072 +#define NDEBUG 1 #define ND_NA_FLAG_OVERRIDE 0x00000020 #define ND_NA_FLAG_ROUTER 0x00000080 #define ND_NA_FLAG_SOLICITED 0x00000040 @@ -3171,7 +3172,7 @@ #define and_eq &= #define asin(x) __tg_real_complex(asin, (x)) #define asinh(x) __tg_real_complex(asinh, (x)) -#define assert(x) ((void)((x) || (__assert_fail(#x, __FILE__, __LINE__, __func__),0))) +#define assert(x) (void)0 #define atan(x) __tg_real_complex(atan, (x)) #define atan2(x,y) __tg_real_2(atan2, (x), (y)) #define atanh(x) __tg_real_complex(atanh, (x)) diff --git a/libc-bottom-half/crt/crt1.c b/libc-bottom-half/crt/crt1.c index 247604a..ddf352f 100644 --- a/libc-bottom-half/crt/crt1.c +++ b/libc-bottom-half/crt/crt1.c @@ -11,8 +11,6 @@ extern void __prepare_for_exit(void); void _Exit(int) __attribute__((noreturn)); static __wasi_errno_t populate_libpreopen(void) { - __wasilibc_init_preopen(); - // Skip stdin, stdout, and stderr, and count up until we reach an invalid // file descriptor. for (__wasi_fd_t fd = 3; fd != 0; ++fd) { diff --git a/libc-bottom-half/libpreopen/include/libpreopen.h b/libc-bottom-half/libpreopen/include/libpreopen.h deleted file mode 100644 index 163bce3..0000000 --- a/libc-bottom-half/libpreopen/include/libpreopen.h +++ /dev/null @@ -1,215 +0,0 @@ -/** - * @file libpreopen.h - * @brief Public header for libpreopen - * - * Copyright (c) 2016 Stanley Uche Godfrey - * Copyright (c) 2016, 2018 Jonathan Anderson - * All rights reserved. - * - * This software was developed at Memorial University under the - * NSERC Discovery program (RGPIN-2015-06048). - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef LIBPO_H -#define LIBPO_H - -#ifdef __wasilibc_unmodified_upstream -#include -#include -#endif - -#include - - -__BEGIN_DECLS - -/** - * @struct po_map - * @brief A mapping from paths to pre-opened directories. - * - * This type is opaque to clients, but it is reference-counted and can be - * thought of as containing a set (with no particular ordering guarantees) - * of path->dirfd mappings. - */ -struct po_map; - -#ifdef __wasilibc_unmodified_upstream -/** - * A callback that can be used to inpect the contents of a @ref po_map. - * - * This callback can be invoked by iteration code to expose elements of a - * @ref po_map (in no particular order). - * - * @returns whether or not to continue iterating over the @ref po_map - */ -typedef bool (po_map_iter_cb)(const char *dirname, int dirfd, cap_rights_t); - -/** - * A simple @ref po_map_iter_cb that will print a @ref po_map's entries, - * one per line. - */ -po_map_iter_cb po_print_entry; -#endif - -/** - * A filesystem path, relative to a directory descriptor. - */ -struct po_relpath { - /** The directory the path is relative to */ - int dirfd; - - /** The path, relative to the directory represented by @ref dirfd */ - const char *relative_path; -}; -#ifdef __wasilibc_unmodified_upstream -#else -// This functionality is exposed in a libc header, so include that header -// and use its declarations. -#include -#endif - -/** - * Create a @ref po_map of at least the specified capacity. - * - * The returned @ref po_map will have a reference count of 1. - */ -#ifdef __wasilibc_unmodified_upstream -#else -static -#endif -struct po_map* po_map_create(int capacity); - -/** - * Release a reference to a @ref po_map. - * - * This may cause memory to be freed. - */ -#ifdef __wasilibc_unmodified_upstream -#else -static -#endif -void po_map_release(struct po_map *); - -#ifdef __wasilibc_unmodified_upstream -/** - * Iterate over a @ref po_map, invoking a callback for each element in the map. - * - * This function will cause @b callback to be invoked repeatedly, in no - * particular order, until the entire map has been iterated over or until the - * callback returns `false`. - * - * @return number of elements iterated over - */ -size_t po_map_foreach(const struct po_map*, po_map_iter_cb); -#endif - -/** - * Add an already-opened directory to a @ref po_map. - * - * @param map the map to add the path->fd mapping to - * @param path the path that will map to this directory - * (which may or may not be the path used to open it) - * @param fd the directory descriptor (must be a directory!) - */ -#ifdef __wasilibc_unmodified_upstream -#else -static -#endif -struct po_map* po_add(struct po_map *map, const char *path, int fd); - -#ifdef __wasilibc_unmodified_upstream -/** - * Pre-open a path and store it in a @ref po_map for later use. - * - * @param map the map to add the path->fd mapping to - * @param path the path to pre-open (which may be a directory if - * `O_DIRECTORY` is passed via @b flags) - * @param flags flags to pass to `open(2)` / `openat(2)` - * @param ... optional file mode, as accepted by `open(2)` - * - * @returns the file descriptor of the opened directory or -1 if - * @b path is not a directory or cannot be opened or if - * the @ref po_map cannot store the directory (e.g., resizing fails) - */ -int po_preopen(struct po_map *map, const char *path, int flags, ...); -#endif - -/** - * Find a directory whose path is a prefix of @b path and (on platforms that - * support Capsicum) that has the rights required by @b rights. - * - * @param map the map to look for a directory in - * @param path the path we want to find a pre-opened prefix for - * @param rights if non-NULL on a platform with Capsicum support, - * the rights any directory descriptor must have to - * qualify as a match - * @returns a @ref po_relpath containing the descriptor of the best-match - * directory in the map (or -1 if none was found) and the remaining - * path, relative to the file (or undefined if no match found) - */ -#ifdef __wasilibc_unmodified_upstream -struct po_relpath po_find(struct po_map *map, const char *path, - cap_rights_t *rights); -#else -static struct po_relpath po_find(struct po_map *map, const char *path, - __wasi_rights_t rights_base, __wasi_rights_t rights_inheriting); -#endif - -#ifdef __wasilibc_unmodified_upstream -/** - * Retrieve a message from with the last libpreopen error. - * - * @returns NULL if there are no errors, null-terminated string otherwise - */ -const char* po_last_error(void); - -/** - * Pack a `struct po_map` into a shared memory segment. - * - * To inherit a `po_map` across the process execution boundary, it needs to be - * packed into an inheritable form such as a shared memory segment. This can - * then be unpacked in the child process for direct access. - * - * @param map the map to pack into shared memory - * - * @returns a file descriptor of a shared memory segment - * (or -1 on error) - */ -int po_pack(struct po_map *map); - -/** - * Unpack a `struct po_map` from a file. - * - * Using the representation generated by `po_pack`, unpack a `po_map` - * and make it available for normal usage. - * - * @param fd a file containing a packed `po_map` representation - */ -struct po_map* po_unpack(int fd); -#endif - -__END_DECLS - -#endif /* !LIBPO_H */ - diff --git a/libc-bottom-half/libpreopen/lib/internal.h b/libc-bottom-half/libpreopen/lib/internal.h deleted file mode 100644 index 93d908b..0000000 --- a/libc-bottom-half/libpreopen/lib/internal.h +++ /dev/null @@ -1,166 +0,0 @@ -/** - * @file internal.h - * @brief Declarations of internal data structures and functions - * - * @cond internal - */ - -/*- - * Copyright (c) 2016-2017 Stanley Uche Godfrey - * Copyright (c) 2016-2018 Jonathan Anderson - * All rights reserved. - * - * This software was developed at Memorial University under the - * NSERC Discovery program (RGPIN-2015-06048). - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef LIBPO_INTERNAL_H -#define LIBPO_INTERNAL_H - -#ifdef __wasilibc_unmodified_upstream -#include -#endif - -#ifdef __wasilibc_unmodified_upstream -#ifdef WITH_CAPSICUM -#include -#endif -#else -// We do Capsicum-style rights-checking, though we use the WASI API directly -// rather than the Capsicum API. -#define WITH_CAPSICUM -#endif - -#include -#include - -#include "libpreopen.h" - -/** - * An entry in a po_map. - * - * @internal - */ -struct po_map_entry { - /** - * The name this file or directory is mapped to. - * - * This name should look like a path, but it does not necessarily need - * match to match the path it was originally obtained from. - */ - const char *name; - - /** File descriptor (which may be a directory) */ - int fd; - -#ifdef WITH_CAPSICUM - /** Capability rights associated with the file descriptor */ -#ifdef __wasilibc_unmodified_upstream - cap_rights_t rights; -#else - __wasi_rights_t rights_base; - __wasi_rights_t rights_inheriting; -#endif -#endif -}; - -// Documented in external header file -struct po_map { - //! @internal - int refcount; - struct po_map_entry *entries; - size_t capacity; - size_t length; -}; - - -/** - * Is a directory a prefix of a given path? - * - * @param dir a directory path, e.g., `/foo/bar` - * @param dirlen the length of @b dir - * @param path a path that may have @b dir as a prefix, - * e.g., `/foo/bar/baz` - * - * @internal - */ -#ifdef __wasilibc_unmodified_upstream -#else -static -#endif -bool po_isprefix(const char *dir, size_t dirlen, const char *path); - - -/** - * Check that a @ref po_map is valid (assert out if it's not). - * - * @internal - */ -#ifdef NDEBUG -#define po_map_assertvalid(...) -#else -#ifdef __wasilibc_unmodified_upstream -#else -static -#endif -void po_map_assertvalid(const struct po_map *); -#endif - -/** - * Enlarge a @ref po_map's capacity. - * - * This results in new memory being allocated and existing entries being copied. - * If the allocation fails, the function will return NULL but the original - * map will remain valid. - * - * @internal - */ -#ifdef __wasilibc_unmodified_upstream -#else -static -#endif -struct po_map* po_map_enlarge(struct po_map *map); - -#ifdef __wasilibc_unmodified_upstream -/** - * Store an error message in the global "last error message" buffer. - * - * @internal - */ -void po_errormessage(const char *msg); -#endif - -/** - * Set the default map used by the libpreopen libc wrappers. - * - * If there is an existing default map, it will be freed before it is replaced. - * Passing NULL to this function will thus clear the default map. - */ -#ifdef __wasilibc_unmodified_upstream -void po_set_libc_map(struct po_map *); -#endif - -#endif /* LIBPO_INTERNAL_H */ - -/** @endcond */ diff --git a/libc-bottom-half/libpreopen/lib/libpreopen.c b/libc-bottom-half/libpreopen/lib/libpreopen.c deleted file mode 100644 index c1190c8..0000000 --- a/libc-bottom-half/libpreopen/lib/libpreopen.c +++ /dev/null @@ -1,261 +0,0 @@ -/*- - * Copyright (c) 2016 Stanley Uche Godfrey - * Copyright (c) 2016, 2018 Jonathan Anderson - * All rights reserved. - * - * This software was developed at Memorial University under the - * NSERC Discovery program (RGPIN-2015-06048). - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/** - * @file libpreopen.c - * Implementation of high-level libpreopen functions. - * - * The functions defined in this source file are the highest-level API calls - * that client code will mostly use (plus po_map_create and po_map_release). - * po_isprefix is also defined here because it doesn't fit anywhere else. - */ - -#include -#include -#include -#include -#ifdef __wasilibc_unmodified_upstream -#else -#include -#endif - -#include "internal.h" - - -#ifdef __wasilibc_unmodified_upstream -#else -static -#endif -struct po_map* -po_add(struct po_map *map, const char *path, int fd) -{ - struct po_map_entry *entry; - - po_map_assertvalid(map); - - if (path == NULL || fd < 0) { - return (NULL); - } - - if (map->length == map->capacity) { - map = po_map_enlarge(map); - if (map == NULL) { - return (NULL); - } - } - - entry = map->entries + map->length; - map->length++; - - entry->name = strdup(path); - entry->fd = fd; - -#ifdef WITH_CAPSICUM -#ifdef __wasilibc_unmodified_upstream - if (cap_rights_get(fd, &entry->rights) != 0) { - return (NULL); - } -#else - __wasi_fdstat_t statbuf; - int r = __wasi_fd_fdstat_get(fd, &statbuf); - if (r != 0) { - errno = r; - return NULL; // TODO: Add an infallible way to get the rights? - } - - entry->rights_base = statbuf.fs_rights_base; - entry->rights_inheriting = statbuf.fs_rights_inheriting; -#endif -#endif - - - po_map_assertvalid(map); - - return (map); -} - -#ifdef __wasilibc_unmodified_upstream -struct po_relpath -po_find(struct po_map* map, const char *path, cap_rights_t *rights) -#else -static struct po_relpath -po_find(struct po_map* map, const char *path, - __wasi_rights_t rights_base, __wasi_rights_t rights_inheriting) -#endif -{ - const char *relpath ; - struct po_relpath match = { .relative_path = NULL, .dirfd = -1 }; - size_t bestlen = 0; - int best = -1; - - po_map_assertvalid(map); - - if (path == NULL) { - return (match); - } - - for(size_t i = 0; i < map->length; i++) { - const struct po_map_entry *entry = map->entries + i; - const char *name = entry->name; -#ifdef __wasilibc_unmodified_upstream - size_t len = strnlen(name, MAXPATHLEN); -#else - size_t len = strlen(name); - bool any_matches = false; - - if (path[0] != '/' && (path[0] != '.' || (path[1] != '/' && path[1] != '\0'))) { - // We're matching a relative path that doesn't start with "./" and isn't ".". - if (len >= 2 && name[0] == '.' && name[1] == '/') { - // The entry starts with "./", so skip that prefix. - name += 2; - len -= 2; - } else if (len == 1 && name[0] == '.') { - // The entry is ".", so match it as an empty string. - name += 1; - len -= 1; - } - } -#endif - -#ifdef __wasilibc_unmodified_upstream - if ((len <= bestlen) || !po_isprefix(name, len, path)) { -#else - if ((any_matches && len <= bestlen) || !po_isprefix(name, len, path)) { -#endif - continue; - } - -#ifdef WITH_CAPSICUM -#ifdef __wasilibc_unmodified_upstream - if (rights && !cap_rights_contains(&entry->rights, rights)) { -#else - if ((rights_base & ~entry->rights_base) != 0 || - (rights_inheriting & ~entry->rights_inheriting) != 0) { -#endif - continue; - } -#endif - - best = entry->fd; - bestlen = len; -#ifdef __wasilibc_unmodified_upstream -#else - any_matches = true; -#endif - } - - relpath = path + bestlen; - - while (*relpath == '/') { - relpath++; - } - - if (*relpath == '\0') { - relpath = "."; - } - - match.relative_path = relpath; - match.dirfd = best; - - return match; -} - -#ifdef __wasilibc_unmodified_upstream -#else -static -#endif -bool -po_isprefix(const char *dir, size_t dirlen, const char *path) -{ - size_t i; - assert(dir != NULL); - assert(path != NULL); -#ifdef __wasilibc_unmodified_upstream -#else - // Allow an empty string as a prefix of any relative path. - if (path[0] != '/' && dirlen == 0) - return true; -#endif - for (i = 0; i < dirlen; i++) - { - if (path[i] != dir[i]) - return false; - } -#ifdef __wasilibc_unmodified_upstream -#else - // Ignore trailing slashes in directory names. - while (i > 0 && dir[i - 1] == '/') { - --i; - } -#endif - return path[i] == '/' || path[i] == '\0'; -} - -#ifdef __wasilibc_unmodified_upstream -int -po_preopen(struct po_map *map, const char *path, int flags, ...) -{ - va_list args; - int fd, mode; - - va_start(args, flags); - mode = va_arg(args, int); - - po_map_assertvalid(map); - - if (path == NULL) { - return (-1); - } - - fd = openat(AT_FDCWD, path, flags, mode); - if (fd == -1) { - return (-1); - } - - if (po_add(map, path, fd) == NULL) { - return (-1); - } - - po_map_assertvalid(map); - - return (fd); -} -#endif - -#ifdef __wasilibc_unmodified_upstream -bool -po_print_entry(const char *name, int fd, cap_rights_t rights) -{ - printf(" - name: '%s', fd: %d, rights: \n", - name, fd); - return (true); -} -#endif diff --git a/libc-bottom-half/libpreopen/lib/po_err.c b/libc-bottom-half/libpreopen/lib/po_err.c deleted file mode 100644 index db3b90b..0000000 --- a/libc-bottom-half/libpreopen/lib/po_err.c +++ /dev/null @@ -1,105 +0,0 @@ -/*- - * Copyright (c) 2016 Stanley Uche Godfrey - * Copyright (c) 2018 Jonathan Anderson - * All rights reserved. - * - * This software was developed at Memorial University under the - * NSERC Discovery program (RGPIN-2015-06048). - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/** - * @file po_err.c - * @brief Error handling for libpreopen - */ - -#ifdef __wasilibc_unmodified_upstream -#include -#include -#include -#endif -#include -#include -#ifdef __wasilibc_unmodified_upstream -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internal.h" -#include "libpreopen.h" - -#ifdef __wasilibc_unmodified_upstream -/* Disable all this error reporting code. */ -static char error_buffer[1024]; -#endif - -#if !defined(NDEBUG) -#ifdef __wasilibc_unmodified_upstream -#else -static -#endif -void -po_map_assertvalid(const struct po_map *map) -{ - const struct po_map_entry *entry; - size_t i; - - assert(map->refcount > 0); - assert(map->length <= map->capacity); - assert(map->entries != NULL || map->capacity == 0); - - for (i = 0; i < map->length; i++) { - entry = map->entries + i; - - assert(entry->name != NULL); - assert(entry->fd >= 0); - } -} -#endif /* !defined(NDEBUG) */ - -#ifdef __wasilibc_unmodified_upstream -void -po_errormessage(const char *msg) -{ - - snprintf(error_buffer, sizeof(error_buffer), "%s: error %d", - msg, errno); -} - -const char* -po_last_error() -{ - - return (error_buffer); -} -#endif diff --git a/libc-bottom-half/libpreopen/lib/po_libc_wrappers.c b/libc-bottom-half/libpreopen/lib/po_libc_wrappers.c deleted file mode 100644 index 680699b..0000000 --- a/libc-bottom-half/libpreopen/lib/po_libc_wrappers.c +++ /dev/null @@ -1,717 +0,0 @@ -/*- - * Copyright (c) 2016 Stanley Uche Godfrey - * Copyright (c) 2018 Jonathan Anderson - * All rights reserved. - * - * This software was developed at Memorial University under the - * NSERC Discovery program (RGPIN-2015-06048). - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/** - * @file po_libc_wrappers.c - * @brief Wrappers of libc functions that access global variables. - */ - -#include -#include -#include -#include - -#include -#ifdef __wasilibc_unmodified_upstream // dlfcn -#include -#endif -#include -#include -#include -#include -#include -#ifdef __wasilibc_unmodified_upstream -#else -#include -#include -#endif - -#include "internal.h" -#ifdef __wasilibc_unmodified_upstream -#else -// Make all of the po_* implementation details private. -#include "libpreopen.c" -#include "po_map.c" -#include "po_err.c" -#endif - -/** - * A default po_map that can be used implicitly by libc wrappers. - * - * @internal - */ -static struct po_map *global_map; - -/** - * Find a relative path within the po_map given by SHARED_MEMORYFD (if it - * exists). - * - * @returns a struct po_relpath with dirfd and relative_path as set by po_find - * if there is an available po_map, or AT_FDCWD/path otherwise - */ -#ifdef __wasilibc_unmodified_upstream -static struct po_relpath find_relative(const char *path, cap_rights_t *); -#else -static struct po_relpath find_relative(const char *path, - __wasi_rights_t rights_base, - __wasi_rights_t rights_inheriting); -#endif - -/** - * Get the map that was handed into the process via `SHARED_MEMORYFD` - * (if it exists). - */ -static struct po_map* get_shared_map(void); - - -/* - * Wrappers around system calls: - */ - -/** - * Capability-safe wrapper around the `_open(2)` system call. - * - * `_open(2)` accepts a path argument that can reference the global filesystem - * namespace. This is not a capability-safe operation, so this wrapper function - * attempts to look up the path (or a prefix of it) within the current global - * po_map and converts the call into the capability-safe `openat(2)` if - * possible. If the current po_map does not contain the sought-after path, - * this wrapper will call `openat(AT_FDCWD, original_path, ...)`, which is - * the same as the unwrapped `open(2)` call (i.e., will fail with `ECAPMODE`). - */ -int -#ifdef __wasilibc_unmodified_upstream -_open(const char *path, int flags, ...) -#else -/* We just need a plain open definition. */ -open(const char *path, int flags, ...) -#endif -{ - struct po_relpath rel; - va_list args; - int mode; - -#ifdef __wasilibc_unmodified_upstream - va_start(args, flags); - mode = va_arg(args, int); - rel = find_relative(path, NULL); -#else - if (flags & O_CREAT) { - va_start(args, flags); - mode = va_arg(args, int); - va_end(args); - } else { - mode = 0; - } - rel = find_relative(path, __WASI_RIGHT_PATH_OPEN, 0); - - // If we can't find a preopened directory handle to open this file with, - // indicate that the program lacks the capabilities. - if (rel.dirfd == -1) { - errno = ENOTCAPABLE; - return -1; - } -#endif - -#ifdef __wasilibc_unmodified_upstream - // If the file is already opened, no need of relative opening! - if( strcmp(rel.relative_path,".") == 0 ) - return dup(rel.dirfd); - else - return openat(rel.dirfd, rel.relative_path, flags, mode); -#else - return openat(rel.dirfd, rel.relative_path, flags, mode); -#endif -} - -/** - * Capability-safe wrapper around the `access(2)` system call. - * - * `access(2)` accepts a path argument that can reference the global filesystem - * namespace. This is not a capability-safe operation, so this wrapper function - * attempts to look up the path (or a prefix of it) within the current global - * po_map and converts the call into the capability-safe `faccessat(2)` if - * possible. If the current po_map does not contain the sought-after path, - * this wrapper will call `faccessat(AT_FDCWD, original_path, ...)`, which is - * the same as the unwrapped `access(2)` call (i.e., will fail with `ECAPMODE`). - */ -int -access(const char *path, int mode) -{ -#ifdef __wasilibc_unmodified_upstream - struct po_relpath rel = find_relative(path, NULL); -#else - struct po_relpath rel = find_relative(path, __WASI_RIGHT_PATH_FILESTAT_GET, 0); - - // If we can't find a preopened directory handle to open this file with, - // indicate that the program lacks the capabilities. - if (rel.dirfd == -1) { - errno = ENOTCAPABLE; - return -1; - } -#endif - - return faccessat(rel.dirfd, rel.relative_path, mode,0); -} - -#ifdef __wasilibc_unmodified_upstream -/** - * Capability-safe wrapper around the `connect(2)` system call. - * - * `connect(2)` accepts a path argument that can reference the global filesystem - * namespace. This is not a capability-safe operation, so this wrapper function - * attempts to look up the path (or a prefix of it) within the current global - * po_map and converts the call into the capability-safe `connectat(2)` if - * possible. If the current po_map does not contain the sought-after path, this - * wrapper will call `connectat(AT_FDCWD, original_path, ...)`, which is the - * same as the unwrapped `connect(2)` call (i.e., will fail with `ECAPMODE`). - */ -int -connect(int s, const struct sockaddr *name, socklen_t namelen) -{ - struct po_relpath rel; - - if (name->sa_family == AF_UNIX) { - struct sockaddr_un *usock = (struct sockaddr_un *)name; -#ifdef __wasilibc_unmodified_upstream - rel = find_relative(usock->sun_path, NULL); - strlcpy(usock->sun_path, rel.relative_path, sizeof(usock->sun_path)); -#else - rel = find_relative(usock->sun_path, __WASI_RIGHT_CONNECT, 0); - if (strlen(rel.relative_path) + 1 > sizeof(usock->sun_path)) { - errno = ENOMEM; - return -1; - } - - // If we can't find a preopened directory handle to open this file with, - // indicate that the program lacks the capabilities. - if (rel.dirfd == -1) { - errno = ENOTCAPABLE; - return -1; - } - - strcpy(usock->sun_path, rel.relative_path); -#endif - return connectat(rel.dirfd, s, name, namelen); - } - - return connectat(AT_FDCWD, s, name, namelen); -} -#endif - -/** - * Capability-safe wrapper around the `eaccess(2)` system call. - * - * `eaccess(2)` accepts a path argument that can reference the global filesystem - * namespace. This is not a capability-safe operation, so this wrapper function - * attempts to look up the path (or a prefix of it) within the current global - * po_map and converts the call into the capability-safe `faccessat(2)` if - * possible. If the current po_map does not contain the sought-after path, this - * wrapper will call `faccessat(AT_FDCWD, original_path, ...)`, which is the - * same as the unwrapped `eaccess(2)` call (i.e., will fail with `ECAPMODE`). - */ -int -eaccess(const char *path, int mode) -{ -#ifdef __wasilibc_unmodified_upstream - struct po_relpath rel = find_relative(path, NULL); -#else - struct po_relpath rel = find_relative(path, __WASI_RIGHT_PATH_FILESTAT_GET, 0); - - // If we can't find a preopened directory handle to open this file with, - // indicate that the program lacks the capabilities. - if (rel.dirfd == -1) { - errno = ENOTCAPABLE; - return -1; - } -#endif - - return faccessat(rel.dirfd, rel.relative_path, mode, 0); -} - -/** - * Capability-safe wrapper around the `lstat(2)` system call. - * - * `lstat(2)` accepts a path argument that can reference the global filesystem - * namespace. This is not a capability-safe operation, so this wrapper function - * attempts to look up the path (or a prefix of it) within the current global - * po_map and converts the call into the capability-safe `fstatat(2)` if - * possible. If the current po_map does not contain the sought-after path, - * this wrapper will call `fstatat(AT_FDCWD, original_path, ...)`, which is - * the same as the unwrapped `lstat(2)` call (i.e., will fail with `ECAPMODE`). - */ -int -lstat(const char *path, struct stat *st) -{ -#ifdef __wasilibc_unmodified_upstream - struct po_relpath rel = find_relative(path, NULL); -#else - struct po_relpath rel = find_relative(path, __WASI_RIGHT_PATH_FILESTAT_GET, 0); - - // If we can't find a preopened directory handle to open this file with, - // indicate that the program lacks the capabilities. - if (rel.dirfd == -1) { - errno = ENOTCAPABLE; - return -1; - } -#endif - - return fstatat(rel.dirfd, rel.relative_path,st,AT_SYMLINK_NOFOLLOW); -} - -#ifdef __wasilibc_unmodified_upstream -/** - * Capability-safe wrapper around the `open(2)` system call. - * - * `open(2)` will behave just like `_open(2)` if the varargs are unpacked and - * passed. - */ -int -open(const char *path, int flags, ...) -{ - va_list args; - int mode; - - va_start(args, flags); - mode = va_arg(args, int); - return _open(path, flags, mode); -} -#endif - -/** - * Capability-safe wrapper around the `rename(2)` system call. - * - * `rename(2)` accepts a path argument that can reference the global filesystem - * namespace. This is not a capability-safe operation, so this wrapper function - * attempts to look up the path (or a prefix of it) within the current global - * po_map and converts the call into the capability-safe `renameat(2)` if - * possible. If the current po_map does not contain the sought-after path, - * this wrapper will call `renameat(AT_FDCWD, original_path, ...)`, which is - * the same as the unwrapped `rename(2)` call (i.e., will fail with `ECAPMODE`). - */ -int -rename(const char *from, const char *to) -{ -#ifdef __wasilibc_unmodified_upstream - struct po_relpath rel_from = find_relative(from, NULL); - struct po_relpath rel_to = find_relative(to, NULL); -#else - struct po_relpath rel_from = find_relative(from, __WASI_RIGHT_PATH_RENAME_SOURCE, 0); - struct po_relpath rel_to = find_relative(to, __WASI_RIGHT_PATH_RENAME_TARGET, 0); - - // If we can't find a preopened directory handle to open this file with, - // indicate that the program lacks the capabilities. - if (rel_from.dirfd == -1 || rel_to.dirfd == -1) { - errno = ENOTCAPABLE; - return -1; - } -#endif - - return renameat(rel_from.dirfd, rel_from.relative_path, rel_to.dirfd, - rel_to.relative_path); -} - -/** - * Capability-safe wrapper around the `stat(2)` system call. - * - * `stat(2)` accepts a path argument that can reference the global filesystem - * namespace. This is not a capability-safe operation, so this wrapper function - * attempts to look up the path (or a prefix of it) within the current global - * po_map and converts the call into the capability-safe `fstatat(2)` if - * possible. If the current po_map does not contain the sought-after path, - * this wrapper will call `fstatat(AT_FDCWD, original_path, ...)`, which is - * the same as the unwrapped `stat(2)` call (i.e., will fail with `ECAPMODE`). - */ -int -stat(const char *path, struct stat *st) -{ -#ifdef __wasilibc_unmodified_upstream - struct po_relpath rel = find_relative(path, NULL); -#else - struct po_relpath rel = find_relative(path, __WASI_RIGHT_PATH_FILESTAT_GET, 0); - - // If we can't find a preopened directory handle to open this file with, - // indicate that the program lacks the capabilities. - if (rel.dirfd == -1) { - errno = ENOTCAPABLE; - return -1; - } -#endif - - return fstatat(rel.dirfd, rel.relative_path,st, AT_SYMLINK_NOFOLLOW); -} - -/** - * Capability-safe wrapper around the `unlink(2)` system call. - * - * `unlink(2)` accepts a path argument that can reference the global filesystem - * namespace. This is not a capability-safe operation, so this wrapper function - * attempts to look up the path (or a prefix of it) within the current global - * po_map and converts the call into the capability-safe `unlinkat(2)` if - * possible. If the current po_map does not contain the sought-after path, - * this wrapper will call `unlinkat(AT_FDCWD, original_path, 0) which is - * the same as the unwrapped `unlink(2)` call (i.e., will fail with `ECAPMODE`). - */ -int -unlink(const char *path) -{ -#ifdef __wasilibc_unmodified_upstream - struct po_relpath rel = find_relative(path, NULL); -#else - struct po_relpath rel_pathname = find_relative(path, __WASI_RIGHT_PATH_UNLINK_FILE, 0); - - // If we can't find a preopened directory handle to open this file with, - // indicate that the program lacks the capabilities. - if (rel_pathname.dirfd == -1) { - errno = ENOTCAPABLE; - return -1; - } -#endif - -#ifdef __wasilibc_unmodified_upstream - return unlinkat(rel.dirfd, rel.relative_path, 0); -#else - // `unlinkat` ends up importing `__wasi_path_remove_directory` even - // though we're not passing `AT_REMOVEDIR` here. So instead, use a - // specialized function which just imports `__wasi_path_unlink_file`. - return __wasilibc_unlinkat(rel_pathname.dirfd, rel_pathname.relative_path); -#endif -} - -/* - * Wrappers around other libc calls: - */ - -#ifdef __wasilibc_unmodified_upstream -/** - * Capability-safe wrapper around the `dlopen(3)` libc function. - * - * `dlopen(3)` accepts a path argument that can reference the global filesystem - * namespace. This is not a capability-safe operation, so this wrapper function - * attempts to look up the path (or a prefix of it) within the current global - * po_map and converts the call into the capability-safe `fdlopen(3)` if - * possible. If the current po_map does not contain the sought-after path, this - * wrapper will call `fdlopen(openat(AT_FDCWD, original_path), ...)`, which is - * the same as the unwrapped `dlopen(3)` call (i.e., will fail with `ECAPMODE`). - */ -void * -dlopen(const char *path, int mode) -{ - struct po_relpath rel = find_relative(path, NULL); - - return fdlopen(openat(rel.dirfd, rel.relative_path, 0, mode), mode); -} -#endif -#ifdef __wasilibc_unmodified_upstream -#else -#include - -int -rmdir(const char *pathname) -{ - struct po_relpath rel_pathname = find_relative(pathname, __WASI_RIGHT_PATH_REMOVE_DIRECTORY, 0); - - // If we can't find a preopened directory handle to open this file with, - // indicate that the program lacks the capabilities. - if (rel_pathname.dirfd == -1) { - errno = ENOTCAPABLE; - return -1; - } - - return __wasilibc_rmdirat(rel_pathname.dirfd, rel_pathname.relative_path); -} - -int -remove(const char *pathname) -{ - struct po_relpath rel_pathname = find_relative(pathname, - __WASI_RIGHT_PATH_UNLINK_FILE | - __WASI_RIGHT_PATH_REMOVE_DIRECTORY, - 0); - - // If searching for both file and directory rights failed, try searching - // for either individually. - if (rel_pathname.dirfd == -1) { - rel_pathname = find_relative(pathname, __WASI_RIGHT_PATH_UNLINK_FILE, 0); - if (rel_pathname.dirfd == -1) { - rel_pathname = find_relative(pathname, __WASI_RIGHT_PATH_REMOVE_DIRECTORY, 0); - } - } - - // If we can't find a preopened directory handle to open this file with, - // indicate that the program lacks the capabilities. - if (rel_pathname.dirfd == -1) { - errno = ENOTCAPABLE; - return -1; - } - - int r = __wasilibc_unlinkat(rel_pathname.dirfd, rel_pathname.relative_path); - if (r != 0 && (errno == EISDIR || errno == ENOTCAPABLE)) - r = __wasilibc_rmdirat(rel_pathname.dirfd, rel_pathname.relative_path); - return r; -} - -int -link(const char *oldpath, const char *newpath) -{ - struct po_relpath rel_oldpath = find_relative(oldpath, __WASI_RIGHT_PATH_LINK_SOURCE, 0); - struct po_relpath rel_newpath = find_relative(newpath, __WASI_RIGHT_PATH_LINK_TARGET, 0); - - // If we can't find a preopened directory handle to open this file with, - // indicate that the program lacks the capabilities. - if (rel_oldpath.dirfd == -1 || rel_newpath.dirfd == -1) { - errno = ENOTCAPABLE; - return -1; - } - - return linkat(rel_oldpath.dirfd, rel_oldpath.relative_path, - rel_newpath.dirfd, rel_newpath.relative_path, - 0); -} - -int -mkdir(const char *pathname, mode_t mode) -{ - struct po_relpath rel_pathname = find_relative(pathname, __WASI_RIGHT_PATH_CREATE_DIRECTORY, 0); - - // If we can't find a preopened directory handle to open this file with, - // indicate that the program lacks the capabilities. - if (rel_pathname.dirfd == -1) { - errno = ENOTCAPABLE; - return -1; - } - - return mkdirat(rel_pathname.dirfd, rel_pathname.relative_path, mode); -} - -DIR * -opendir(const char *name) -{ - struct po_relpath rel_name = find_relative(name, __WASI_RIGHT_PATH_OPEN, 0); - - // If we can't find a preopened directory handle to open this file with, - // indicate that the program lacks the capabilities. - if (rel_name.dirfd == -1) { - errno = ENOTCAPABLE; - return NULL; - } - - return opendirat(rel_name.dirfd, rel_name.relative_path); -} - -ssize_t -readlink(const char *pathname, char *buf, size_t bufsiz) -{ - struct po_relpath rel_pathname = find_relative(pathname, __WASI_RIGHT_PATH_READLINK, 0); - - // If we can't find a preopened directory handle to open this file with, - // indicate that the program lacks the capabilities. - if (rel_pathname.dirfd == -1) { - errno = ENOTCAPABLE; - return -1; - } - - return readlinkat(rel_pathname.dirfd, rel_pathname.relative_path, - buf, bufsiz); -} - -int -scandir(const char *dirp, struct dirent ***namelist, - int (*filter)(const struct dirent *), - int (*compar)(const struct dirent **, const struct dirent **)) -{ - struct po_relpath rel_dirp = find_relative(dirp, - __WASI_RIGHT_PATH_OPEN, - __WASI_RIGHT_FD_READDIR); - - // If we can't find a preopened directory handle to open this file with, - // indicate that the program lacks the capabilities. - if (rel_dirp.dirfd == -1) { - errno = ENOTCAPABLE; - return -1; - } - - return scandirat(rel_dirp.dirfd, rel_dirp.relative_path, - namelist, filter, compar); -} - -int -symlink(const char *target, const char *linkpath) -{ - struct po_relpath rel_linkpath = find_relative(linkpath, __WASI_RIGHT_PATH_SYMLINK, 0); - - // If we can't find a preopened directory handle to open this file with, - // indicate that the program lacks the capabilities. - if (rel_linkpath.dirfd == -1) { - errno = ENOTCAPABLE; - return -1; - } - - return symlinkat(target, rel_linkpath.dirfd, rel_linkpath.relative_path); -} -#endif - -#ifdef __wasilibc_unmodified_upstream -#else -static -#endif -/* Provide tests with mechanism to set our static po_map */ -void -po_set_libc_map(struct po_map *map) -{ - po_map_assertvalid(map); - - map->refcount += 1; - - if (global_map != NULL) { - po_map_release(global_map); - } - - global_map = map; -} - -static struct po_relpath -#ifdef __wasilibc_unmodified_upstream -find_relative(const char *path, cap_rights_t *rights) -#else -find_relative(const char *path, - __wasi_rights_t rights_base, - __wasi_rights_t rights_inheriting) -#endif -{ - struct po_relpath rel; - struct po_map *map; - - map = get_shared_map(); -#ifdef __wasilibc_unmodified_upstream - if (map == NULL) { - rel.dirfd = AT_FDCWD; - rel.relative_path = path; - } else { - rel = po_find(map, path, NULL); - } -#else - rel = po_find(map, path, rights_base, rights_inheriting); -#endif - - return (rel); -} - -static struct po_map* -get_shared_map() -{ -#ifdef __wasilibc_unmodified_upstream - struct po_map *map; - char *end, *env; - long fd; - - // Do we already have a default map? - if (global_map) { - po_map_assertvalid(global_map); - return (global_map); - } - - // Attempt to unwrap po_map from a shared memory segment specified by - // SHARED_MEMORYFD - env = getenv("SHARED_MEMORYFD"); - if (env == NULL || *env == '\0') { - return (NULL); - } - - // We expect this environment variable to be an integer and nothing but - // an integer. - fd = strtol(env, &end, 10); - if (*end != '\0') { - return (NULL); - } - - map = po_unpack(fd); - if (map == NULL) { - return (NULL); - } - - global_map = map; - - return (map); -#else - assert(global_map); - po_map_assertvalid(global_map); - return global_map; -#endif -} -#ifdef __wasilibc_unmodified_upstream -#else -void -__wasilibc_init_preopen(void) -{ - global_map = po_map_create(4); - if (global_map == NULL) - __builtin_trap(); - po_map_assertvalid(global_map); -} - -/* - * Register the given pre-opened file descriptor under the given path. - */ -int -__wasilibc_register_preopened_fd(int fd, const char *path) -{ - po_map_assertvalid(global_map); - - if (path == NULL) { - return -1; - } - -#ifdef _REENTRANT -#error "__wasilibc_register_preopened_fd doesn't yet support multiple threads" -#endif - - struct po_map *map = po_add(global_map, path, fd); - if (map == NULL) { - return -1; - } - - po_map_assertvalid(map); - global_map = map; - - return 0; -} - -int __wasilibc_find_relpath(const char *path, - __wasi_rights_t rights_base, - __wasi_rights_t rights_inheriting, - const char **relpath) -{ - struct po_relpath rel = find_relative(path, rights_base, rights_inheriting); - *relpath = rel.relative_path; - return rel.dirfd; -} -#endif diff --git a/libc-bottom-half/libpreopen/lib/po_map.c b/libc-bottom-half/libpreopen/lib/po_map.c deleted file mode 100644 index 6d5dfbc..0000000 --- a/libc-bottom-half/libpreopen/lib/po_map.c +++ /dev/null @@ -1,131 +0,0 @@ -/*- - * Copyright (c) 2016 Stanley Uche Godfrey - * Copyright (c) 2016, 2018 Jonathan Anderson - * All rights reserved. - * - * This software was developed at Memorial University under the - * NSERC Discovery program (RGPIN-2015-06048). - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/** - * @file po_map.c - * @brief Implementation of po_map management functions - */ - -#include -#include -#include - -#include "internal.h" - -#ifdef __wasilibc_unmodified_upstream -#else -static -#endif -struct po_map* -po_map_create(int capacity) -{ - struct po_map *map; - - map = malloc(sizeof(struct po_map)); - if (map == NULL) { - return (NULL); - } - - map->entries = calloc(sizeof(struct po_map_entry), capacity); - if (map->entries == NULL) { - free(map); - return (NULL); - } - - map->refcount = 1; - map->capacity = capacity; - map->length = 0; - - po_map_assertvalid(map); - - return (map); -} - -#ifdef __wasilibc_unmodified_upstream -#else -static -#endif -struct po_map* -po_map_enlarge(struct po_map *map) -{ - struct po_map_entry *enlarged; - enlarged = calloc(sizeof(struct po_map_entry), 2 * map->capacity); - if (enlarged == NULL) { - return (NULL); - } - memcpy(enlarged, map->entries, map->length * sizeof(*enlarged)); - free(map->entries); - map->entries = enlarged; - map->capacity = 2 * map->capacity; - return map; -} - -#ifdef __wasilibc_unmodified_upstream -size_t -po_map_foreach(const struct po_map *map, po_map_iter_cb cb) -{ - struct po_map_entry *entry; - size_t n; - - po_map_assertvalid(map); - - for (n = 0; n < map->length; n++) { - entry = map->entries + n; - - if (!cb(entry->name, entry->fd, entry->rights)) { - break; - } - } - - return (n); -} -#endif - -#ifdef __wasilibc_unmodified_upstream -#else -static -#endif -void -po_map_release(struct po_map *map) -{ - if (map == NULL) { - return; - } - - po_map_assertvalid(map); - - map->refcount -= 1; - - if (map->refcount == 0) { - free(map->entries); - free(map); - } -} diff --git a/libc-bottom-half/libpreopen/libpreopen.c b/libc-bottom-half/libpreopen/libpreopen.c new file mode 100644 index 0000000..2579110 --- /dev/null +++ b/libc-bottom-half/libpreopen/libpreopen.c @@ -0,0 +1,551 @@ +//! Preopen functionality for WASI libc, for emulating support for absolute +//! path names on top of WASI's OCap-style API. +//! +//! This file is derived from code in libpreopen, the upstream for which is: +//! +//! https://github.com/musec/libpreopen +//! +//! and which bears the following copyrights and license: + +/*- + * Copyright (c) 2016-2017 Stanley Uche Godfrey + * Copyright (c) 2016-2018 Jonathan Anderson + * All rights reserved. + * + * This software was developed at Memorial University under the + * NSERC Discovery program (RGPIN-2015-06048). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef _REENTRANT +#error "__wasilibc_register_preopened_fd doesn't yet support multiple threads" +#endif + +#define _ALL_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//////////////////////////////////////////////////////////////////////////////// +// +// POSIX API compatibility wrappers +// +//////////////////////////////////////////////////////////////////////////////// + +int +open(const char *path, int flags, ...) +{ + const char *relative_path; + int dirfd = __wasilibc_find_relpath(path, __WASI_RIGHT_PATH_OPEN, 0, + &relative_path); + + // If we can't find a preopened directory handle to open this file with, + // indicate that the program lacks the capabilities. + if (dirfd == -1) { + errno = ENOTCAPABLE; + return -1; + } + + // WASI libc's openat ignores the mode argument, so don't bother passing + // the actual mode value through. + return openat(dirfd, relative_path, flags); +} + +int +access(const char *path, int mode) +{ + const char *relative_path; + int dirfd = __wasilibc_find_relpath(path, __WASI_RIGHT_PATH_FILESTAT_GET, 0, + &relative_path); + + // If we can't find a preopened directory handle to open this file with, + // indicate that the program lacks the capabilities. + if (dirfd == -1) { + errno = ENOTCAPABLE; + return -1; + } + + return faccessat(dirfd, relative_path, mode, 0); +} + +int +lstat(const char *path, struct stat *st) +{ + const char *relative_path; + int dirfd = __wasilibc_find_relpath(path, __WASI_RIGHT_PATH_FILESTAT_GET, 0, + &relative_path); + + // If we can't find a preopened directory handle to open this file with, + // indicate that the program lacks the capabilities. + if (dirfd == -1) { + errno = ENOTCAPABLE; + return -1; + } + + return fstatat(dirfd, relative_path, st, AT_SYMLINK_NOFOLLOW); +} + +int +rename(const char *from, const char *to) +{ + const char *from_relative_path; + int from_dirfd = __wasilibc_find_relpath(from, __WASI_RIGHT_PATH_RENAME_SOURCE, 0, + &from_relative_path); + + const char *to_relative_path; + int to_dirfd = __wasilibc_find_relpath(to, __WASI_RIGHT_PATH_RENAME_TARGET, 0, + &to_relative_path); + + // If we can't find a preopened directory handle to open this file with, + // indicate that the program lacks the capabilities. + if (from_dirfd == -1 || to_dirfd == -1) { + errno = ENOTCAPABLE; + return -1; + } + + return renameat(from_dirfd, from_relative_path, to_dirfd, to_relative_path); +} + +int +stat(const char *path, struct stat *st) +{ + const char *relative_path; + int dirfd = __wasilibc_find_relpath(path, __WASI_RIGHT_PATH_FILESTAT_GET, 0, + &relative_path); + + // If we can't find a preopened directory handle to open this file with, + // indicate that the program lacks the capabilities. + if (dirfd == -1) { + errno = ENOTCAPABLE; + return -1; + } + + return fstatat(dirfd, relative_path, st, AT_SYMLINK_NOFOLLOW); +} + +int +unlink(const char *path) +{ + const char *relative_path; + int dirfd = __wasilibc_find_relpath(path, __WASI_RIGHT_PATH_UNLINK_FILE, 0, + &relative_path); + + // If we can't find a preopened directory handle to open this file with, + // indicate that the program lacks the capabilities. + if (dirfd == -1) { + errno = ENOTCAPABLE; + return -1; + } + + // `unlinkat` ends up importing `__wasi_path_remove_directory` even + // though we're not passing `AT_REMOVEDIR` here. So instead, use a + // specialized function which just imports `__wasi_path_unlink_file`. + return __wasilibc_unlinkat(dirfd, relative_path); +} + +int +rmdir(const char *pathname) +{ + const char *relative_path; + int dirfd = __wasilibc_find_relpath(pathname, __WASI_RIGHT_PATH_REMOVE_DIRECTORY, 0, + &relative_path); + + // If we can't find a preopened directory handle to open this file with, + // indicate that the program lacks the capabilities. + if (dirfd == -1) { + errno = ENOTCAPABLE; + return -1; + } + + return __wasilibc_rmdirat(dirfd, relative_path); +} + +int +remove(const char *pathname) +{ + const char *relative_path; + int dirfd = __wasilibc_find_relpath(pathname, + __WASI_RIGHT_PATH_UNLINK_FILE | + __WASI_RIGHT_PATH_REMOVE_DIRECTORY, + 0, + &relative_path); + + // If searching for both file and directory rights failed, try searching + // for either individually. + if (dirfd == -1) { + dirfd = __wasilibc_find_relpath(pathname, __WASI_RIGHT_PATH_UNLINK_FILE, 0, + &relative_path); + if (dirfd == -1) { + dirfd = __wasilibc_find_relpath(pathname, __WASI_RIGHT_PATH_REMOVE_DIRECTORY, 0, + &relative_path); + } + } + + // If we can't find a preopened directory handle to open this file with, + // indicate that the program lacks the capabilities. + if (dirfd == -1) { + errno = ENOTCAPABLE; + return -1; + } + + int r = __wasilibc_unlinkat(dirfd, relative_path); + if (r != 0 && (errno == EISDIR || errno == ENOTCAPABLE)) + r = __wasilibc_rmdirat(dirfd, relative_path); + return r; +} + +int +link(const char *oldpath, const char *newpath) +{ + const char *old_relative_path; + int old_dirfd = __wasilibc_find_relpath(oldpath, __WASI_RIGHT_PATH_LINK_SOURCE, 0, + &old_relative_path); + + const char *new_relative_path; + int new_dirfd = __wasilibc_find_relpath(newpath, __WASI_RIGHT_PATH_LINK_TARGET, 0, + &new_relative_path); + + // If we can't find a preopened directory handle to open this file with, + // indicate that the program lacks the capabilities. + if (old_dirfd == -1 || new_dirfd == -1) { + errno = ENOTCAPABLE; + return -1; + } + + return linkat(old_dirfd, old_relative_path, new_dirfd, new_relative_path, 0); +} + +int +mkdir(const char *pathname, mode_t mode) +{ + const char *relative_path; + int dirfd = __wasilibc_find_relpath(pathname, __WASI_RIGHT_PATH_CREATE_DIRECTORY, 0, + &relative_path); + + // If we can't find a preopened directory handle to open this file with, + // indicate that the program lacks the capabilities. + if (dirfd == -1) { + errno = ENOTCAPABLE; + return -1; + } + + return mkdirat(dirfd, relative_path, mode); +} + +DIR * +opendir(const char *name) +{ + const char *relative_path; + int dirfd = __wasilibc_find_relpath(name, __WASI_RIGHT_PATH_OPEN, 0, + &relative_path); + + // If we can't find a preopened directory handle to open this file with, + // indicate that the program lacks the capabilities. + if (dirfd == -1) { + errno = ENOTCAPABLE; + return NULL; + } + + return opendirat(dirfd, relative_path); +} + +ssize_t +readlink(const char *pathname, char *buf, size_t bufsiz) +{ + const char *relative_path; + int dirfd = __wasilibc_find_relpath(pathname, __WASI_RIGHT_PATH_READLINK, 0, + &relative_path); + + // If we can't find a preopened directory handle to open this file with, + // indicate that the program lacks the capabilities. + if (dirfd == -1) { + errno = ENOTCAPABLE; + return -1; + } + + return readlinkat(dirfd, relative_path, buf, bufsiz); +} + +int +scandir( + const char *dirp, + struct dirent ***namelist, + int (*filter)(const struct dirent *), + int (*compar)(const struct dirent **, const struct dirent **)) +{ + const char *relative_path; + int dirfd = __wasilibc_find_relpath(dirp, + __WASI_RIGHT_PATH_OPEN, + __WASI_RIGHT_FD_READDIR, + &relative_path); + + // If we can't find a preopened directory handle to open this file with, + // indicate that the program lacks the capabilities. + if (dirfd == -1) { + errno = ENOTCAPABLE; + return -1; + } + + return scandirat(dirfd, relative_path, namelist, filter, compar); +} + +int +symlink(const char *target, const char *linkpath) +{ + const char *relative_path; + int dirfd = __wasilibc_find_relpath(linkpath, __WASI_RIGHT_PATH_SYMLINK, 0, + &relative_path); + + // If we can't find a preopened directory handle to open this file with, + // indicate that the program lacks the capabilities. + if (dirfd == -1) { + errno = ENOTCAPABLE; + return -1; + } + + return symlinkat(target, dirfd, relative_path); +} + +//////////////////////////////////////////////////////////////////////////////// +// +// Support library +// +//////////////////////////////////////////////////////////////////////////////// + +/// An entry in a po_map. +struct po_map_entry { + /// The name this file or directory is mapped to. + /// + /// This name should look like a path, but it does not necessarily need + /// match to match the path it was originally obtained from. + const char *name; + + /// File descriptor (which may be a directory) + int fd; + + /// Capability rights associated with the file descriptor + __wasi_rights_t rights_base; + __wasi_rights_t rights_inheriting; +}; + +/// A vector of po_map_entry. +struct po_map { + struct po_map_entry *entries; + size_t capacity; + size_t length; +}; + +static struct po_map global_map; + +/// Is a directory a prefix of a given path? +/// +/// @param dir a directory path, e.g., `/foo/bar` +/// @param dirlen the length of @b dir +/// @param path a path that may have @b dir as a prefix, +/// e.g., `/foo/bar/baz` +static bool +po_isprefix(const char *dir, size_t dirlen, const char *path) +{ + assert(dir != NULL); + assert(path != NULL); + + // Allow an empty string as a prefix of any relative path. + if (path[0] != '/' && dirlen == 0) + return true; + + size_t i; + for (i = 0; i < dirlen; i++) + { + if (path[i] != dir[i]) + return false; + } + + // Ignore trailing slashes in directory names. + while (i > 0 && dir[i - 1] == '/') { + --i; + } + + return path[i] == '/' || path[i] == '\0'; +} + +/// Enlarge a @ref po_map's capacity. +/// +/// This results in new memory being allocated and existing entries being copied. +/// If the allocation fails, the function will return -1. +static int +po_map_enlarge(void) +{ + size_t start_capacity = 4; + size_t new_capacity = global_map.capacity == 0 ? + start_capacity : + global_map.capacity * 2; + + struct po_map_entry *enlarged = + calloc(sizeof(struct po_map_entry), new_capacity); + if (enlarged == NULL) { + return -1; + } + memcpy(enlarged, global_map.entries, global_map.length * sizeof(*enlarged)); + free(global_map.entries); + global_map.entries = enlarged; + global_map.capacity = new_capacity; + return 0; +} + +/// Assert that the global_map is valid. +#ifdef NDEBUG +#define po_map_assertvalid() +#else +static void +po_map_assertvalid(void) +{ + const struct po_map_entry *entry; + size_t i; + + assert(global_map.length <= global_map.capacity); + assert(global_map.entries != NULL || global_map.capacity == 0); + + for (i = 0; i < global_map.length; i++) { + entry = &global_map.entries[i]; + + assert(entry->name != NULL); + assert(entry->fd >= 0); + } +} +#endif + +/// Register the given pre-opened file descriptor under the given path. +int +__wasilibc_register_preopened_fd(int fd, const char *path) +{ + po_map_assertvalid(); + + assert(fd >= 0); + assert(path != NULL); + + if (global_map.length == global_map.capacity) { + int n = po_map_enlarge(); + + po_map_assertvalid(); + + if (n != 0) { + return n; + } + } + + __wasi_fdstat_t statbuf; + int r = __wasi_fd_fdstat_get((__wasi_fd_t)fd, &statbuf); + if (r != 0) { + errno = r; + return -1; // TODO: Add an infallible way to get the rights? + } + + const char *name = strdup(path); + if (name == NULL) { + return -1; + } + + struct po_map_entry *entry = &global_map.entries[global_map.length++]; + + entry->name = name; + entry->fd = fd; + entry->rights_base = statbuf.fs_rights_base; + entry->rights_inheriting = statbuf.fs_rights_inheriting; + + po_map_assertvalid(); + + return 0; +} + +int +__wasilibc_find_relpath( + const char *path, + __wasi_rights_t rights_base, + __wasi_rights_t rights_inheriting, + const char **relative_path) +{ + size_t bestlen = 0; + int best = -1; + + po_map_assertvalid(); + + assert(path != NULL); + assert(relative_path != NULL); + + bool any_matches = false; + for (size_t i = 0; i < global_map.length; i++) { + const struct po_map_entry *entry = &global_map.entries[i]; + const char *name = entry->name; + size_t len = strlen(name); + + if (path[0] != '/' && (path[0] != '.' || (path[1] != '/' && path[1] != '\0'))) { + // We're matching a relative path that doesn't start with "./" and isn't ".". + if (len >= 2 && name[0] == '.' && name[1] == '/') { + // The entry starts with "./", so skip that prefix. + name += 2; + len -= 2; + } else if (len == 1 && name[0] == '.') { + // The entry is ".", so match it as an empty string. + name += 1; + len -= 1; + } + } + + if ((any_matches && len <= bestlen) || !po_isprefix(name, len, path)) { + continue; + } + + if ((rights_base & ~entry->rights_base) != 0 || + (rights_inheriting & ~entry->rights_inheriting) != 0) { + continue; + } + + best = entry->fd; + bestlen = len; + any_matches = true; + } + + const char *relpath = path + bestlen; + + while (*relpath == '/') { + relpath++; + } + + if (*relpath == '\0') { + relpath = "."; + } + + *relative_path = relpath; + return best; +} diff --git a/libc-top-half/musl/src/regex/tre.h b/libc-top-half/musl/src/regex/tre.h index 9aae851..aed64f3 100644 --- a/libc-top-half/musl/src/regex/tre.h +++ b/libc-top-half/musl/src/regex/tre.h @@ -35,7 +35,9 @@ #undef TRE_MBSTATE +#ifdef __wasilibc_unmodified_upstream // Allow NDEBUG to be predefined. #define NDEBUG +#endif #define TRE_REGEX_T_FIELD __opaque typedef int reg_errcode_t;