Make improvements

- Invent openatemp() API
- Invent O_UNLINK open flag
- Introduce getenv_secure() API
- Remove `git pull` from cosmocc
- Fix utimes() when path is NULL
- Fix mktemp() to never return NULL
- Fix utimensat() UTIME_OMIT on XNU
- Improve utimensat() code for RHEL5
- Turn `argv[0]` C:/ to /C/ on Windows
- Introduce tmpnam() and tmpnam_r() APIs
- Fix more const issues with internal APIs
- Permit utimes() on WIN32 in O_RDONLY mode
- Fix fdopendir() to check fd is a directory
- Fix recent crash regression in landlock make
- Fix futimens(AT_FDCWD, NULL) to return EBADF
- Use workaround so `make -j` doesn't fork bomb
- Rename dontdiscard to __wur (just like glibc)
- Fix st_size for WIN32 symlinks containing UTF-8
- Introduce stdio ext APIs needed by GNU coreutils
- Fix lstat() on WIN32 for symlinks to directories
- Move some constants from normalize.inc to limits.h
- Fix segv with memchr() and memcmp() overlapping page
- Implement POSIX fflush() behavior for reader streams
- Implement AT_SYMLINK_NOFOLLOW for utimensat() on WIN32
- Don't change read-only status of existing files on WIN32
- Correctly handle `0x[^[:xdigit:]]` case in strtol() functions
This commit is contained in:
Justine Tunney 2023-09-06 03:54:42 -07:00
parent 8596e83cce
commit f531acc8f9
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
297 changed files with 1920 additions and 1681 deletions

View file

@ -44,7 +44,7 @@ TEST(clock_gettime, test) {
#ifndef __aarch64__
bool isfast;
// we support vdso on aarch64 but qemu-aarch64 won't let us test it
if (__is_linux_2_6_23()) {
if (IsLinux() && __is_linux_2_6_23()) {
ASSERT_GT((intptr_t)__clock_gettime_get(&isfast),
getauxval(AT_SYSINFO_EHDR));
ASSERT_TRUE(isfast);

View file

@ -23,6 +23,7 @@
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/limits.h"
#include "libc/log/check.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/mem.h"

View file

@ -25,8 +25,8 @@
#include "libc/fmt/itoa.h"
#include "libc/intrin/kprintf.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/temp.h"
#include "libc/str/str.h"
#include "libc/temp.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/subprocess.h"
#include "libc/testlib/testlib.h"
@ -69,8 +69,8 @@ TEST(execve, testArgPassing) {
}
TEST(execve, ziposELF) {
if (IsFreebsd()) return; // TODO: fixme on freebsd
if (!__is_linux_2_6_23()) return; // TODO: fixme on old linux
if (IsFreebsd()) return; // TODO: fixme on freebsd
if (IsLinux() && !__is_linux_2_6_23()) return; // TODO: fixme on old linux
if (!IsLinux() && !IsFreebsd()) {
EXPECT_SYS(ENOSYS, -1,
execve("/zip/life.elf", (char *const[]){0}, (char *const[]){0}));
@ -83,8 +83,8 @@ TEST(execve, ziposELF) {
}
TEST(execve, ziposAPE) {
if (IsFreebsd()) return; // TODO: fixme on freebsd
if (!__is_linux_2_6_23()) return; // TODO: fixme on old linux
if (IsFreebsd()) return; // TODO: fixme on freebsd
if (IsLinux() && !__is_linux_2_6_23()) return; // TODO: fixme on old linux
if (!IsLinux() && !IsFreebsd()) {
EXPECT_EQ(-1, execve("/zip/life-nomod.com", (char *const[]){0},
(char *const[]){0}));

View file

@ -37,7 +37,7 @@ char testlib_enable_tmp_setup_teardown;
void SetUp(void) {
if (IsFreebsd()) exit(0); // TODO: fixme on freebsd
if (!__is_linux_2_6_23()) exit(0); // TODO: fixme on old linux
if (IsLinux() && !__is_linux_2_6_23()) exit(0); // TODO: fixme on old linux
}
TEST(execve, elfIsUnreadable_mayBeExecuted) {

View file

@ -19,6 +19,7 @@
#include "libc/calls/calls.h"
#include "libc/fmt/fmt.h"
#include "libc/fmt/libgen.h"
#include "libc/limits.h"
#include "libc/log/check.h"
#include "libc/macros.internal.h"
#include "libc/mem/gc.internal.h"

View file

@ -19,6 +19,8 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/macros.internal.h"
@ -26,7 +28,12 @@
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/fd.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/s.h"
#include "libc/testlib/subprocess.h"
#include "libc/testlib/testlib.h"
#include "libc/x/x.h"
#include "libc/x/xasprintf.h"
@ -36,7 +43,7 @@
char testlib_enable_tmp_setup_teardown;
void SetUpOnce(void) {
ASSERT_SYS(0, 0, pledge("stdio rpath wpath cpath fattr", 0));
ASSERT_SYS(0, 0, pledge("stdio rpath wpath cpath fattr proc id", 0));
}
TEST(open, efault) {
@ -72,6 +79,18 @@ TEST(open, doubleSlash_worksAndGetsNormalizedOnWindows) {
ASSERT_SYS(0, 0, close(3));
}
TEST(open, fdWillBeInheritedByExecutedPrograms) {
ASSERT_SYS(0, 3, open("x", O_RDWR | O_CREAT | O_TRUNC, 0666));
ASSERT_SYS(0, 0, fcntl(3, F_GETFD));
ASSERT_SYS(0, 0, close(3));
}
TEST(open, fdWillBeClosedByExecveAutomatically) {
ASSERT_SYS(0, 3, open("x", O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0666));
ASSERT_SYS(0, FD_CLOEXEC, fcntl(3, F_GETFD));
ASSERT_SYS(0, 0, close(3));
}
TEST(open, enametoolong) {
size_t n = 260;
char *s = gc(xcalloc(1, n + 1));
@ -320,3 +339,159 @@ TEST(open, drive) {
ASSERT_SYS(0, 3, open("/", O_RDONLY));
ASSERT_SYS(0, 0, close(3));
}
TEST(open, readOnlyCreatMode) {
char buf[8];
struct stat st;
ASSERT_SYS(0, 3, open("x", O_RDWR | O_CREAT | O_TRUNC, 0500));
ASSERT_SYS(0, 2, pwrite(3, "hi", 2, 0));
ASSERT_SYS(0, 2, pread(3, buf, 8, 0));
ASSERT_SYS(0, 0, close(3));
ASSERT_SYS(0, 0, stat("x", &st));
ASSERT_EQ(0100500, st.st_mode);
if (getuid()) {
ASSERT_SYS(EACCES, -1, open("x", O_RDWR));
ASSERT_SYS(EACCES, -1, open("x", O_RDWR | O_CREAT));
} else {
// root is invulnerable to eacces
ASSERT_SYS(0, 3, open("x", O_RDWR));
ASSERT_SYS(0, 0, close(3));
ASSERT_SYS(0, 3, open("x", O_RDWR | O_CREAT));
ASSERT_SYS(0, 0, close(3));
SPAWN(fork);
setuid(1000);
setgid(1000);
ASSERT_SYS(EACCES, -1, open("x", O_RDWR));
ASSERT_SYS(EACCES, -1, open("x", O_RDWR | O_CREAT));
EXITS(0);
}
}
TEST(open, parentSymlink) {
struct stat st;
ASSERT_SYS(0, 0, mkdir("parent", 0755));
// create directory symlink
ASSERT_SYS(0, 0, symlink("parent", "parent-link"));
// test the symlink we just made is a symlink
ASSERT_SYS(0, 0, lstat("parent-link", &st));
ASSERT_TRUE(S_ISLNK(st.st_mode));
// create regular file when parent component is symlink dir
ASSERT_SYS(0, 0, touch("parent-link/regular", 0644));
// test stat works
ASSERT_SYS(0, 0, stat("parent-link/regular", &st));
ASSERT_TRUE(S_ISREG(st.st_mode));
// test open works
ASSERT_SYS(0, 3, open("parent-link/regular", O_RDONLY));
ASSERT_SYS(0, 0, fstat(3, &st));
ASSERT_TRUE(S_ISREG(st.st_mode));
ASSERT_SYS(0, 0, close(3));
// test O_NOFOLLOW doesn't apply to parent components
ASSERT_SYS(0, 3, open("parent-link/regular", O_RDONLY | O_NOFOLLOW));
ASSERT_SYS(0, 0, fstat(3, &st));
ASSERT_TRUE(S_ISREG(st.st_mode));
ASSERT_SYS(0, 0, close(3));
// create regular symlink
ASSERT_SYS(0, 0, symlink("regular", "parent-link/regular-link"));
// test stat works
ASSERT_SYS(0, 0, stat("parent-link/regular-link", &st));
ASSERT_TRUE(S_ISREG(st.st_mode));
ASSERT_SYS(0, 0, lstat("parent-link/regular-link", &st));
ASSERT_TRUE(S_ISLNK(st.st_mode));
// test open works
ASSERT_SYS(0, 3, open("parent-link/regular-link", O_RDONLY));
ASSERT_SYS(0, 0, fstat(3, &st));
ASSERT_TRUE(S_ISREG(st.st_mode));
ASSERT_SYS(0, 0, close(3));
// test O_NOFOLLOW applies to last component
ASSERT_SYS(ELOOP, -1,
open("parent-link/regular-link", O_RDONLY | O_NOFOLLOW));
}
TEST(open, readonlyCreateMode_dontChangeStatusIfExists) {
char buf[8];
struct stat st;
ASSERT_SYS(0, 3, creat("wut", 0700));
ASSERT_SYS(0, 2, pwrite(3, "hi", 2, 0));
ASSERT_SYS(0, 0, close(3));
// since the file already exists, unix doesn't change read-only
ASSERT_SYS(0, 3, open("wut", O_CREAT | O_TRUNC | O_RDWR, 0500));
ASSERT_SYS(0, 0, pread(3, buf, 8, 0));
ASSERT_SYS(0, 0, fstat(3, &st));
ASSERT_EQ(0100700, st.st_mode);
ASSERT_SYS(0, 0, close(3));
}
TEST(open, creatRdonly) {
char buf[8];
ASSERT_SYS(EINVAL, -1, open("foo", O_CREAT | O_TRUNC | O_RDONLY, 0700));
ASSERT_SYS(0, 3, open("foo", O_CREAT | O_RDONLY, 0700));
ASSERT_SYS(EBADF, -1, pwrite(3, "hi", 2, 0));
ASSERT_SYS(0, 0, pread(3, buf, 8, 0));
ASSERT_SYS(0, 0, close(3));
}
TEST(open, sequentialRandom_EINVAL) {
if (!IsWindows()) return;
ASSERT_SYS(
EINVAL, -1,
open("foo", O_CREAT | O_TRUNC | O_RDWR | O_SEQUENTIAL | O_RANDOM, 0700));
}
// "If O_CREAT is set and the file did not previously exist, upon
// successful completion, open() shall mark for update the last data
// access, last data modification, and last file status change
// timestamps of the file and the last data modification and last
// file status change timestamps of the parent directory." -POSIX
TEST(open, creatFile_touchesDirectory) {
struct stat st;
struct timespec birth;
ASSERT_SYS(0, 0, mkdir("dir", 0755));
ASSERT_SYS(0, 0, stat("dir", &st));
birth = st.st_ctim;
// check we can read time without changing it
sleep(1);
ASSERT_SYS(0, 0, stat("dir", &st));
EXPECT_EQ(0, timespec_cmp(st.st_ctim, birth));
EXPECT_EQ(0, timespec_cmp(st.st_mtim, birth));
EXPECT_EQ(0, timespec_cmp(st.st_atim, birth));
// check that the directory time changes when file is made
sleep(1);
ASSERT_SYS(0, 0, touch("dir/file", 0644));
ASSERT_SYS(0, 0, stat("dir", &st));
EXPECT_EQ(1, timespec_cmp(st.st_ctim, birth));
EXPECT_EQ(1, timespec_cmp(st.st_mtim, birth));
// TODO: Maybe statfs() for noatime / relative?
// EXPECT_EQ(1, timespec_cmp(st.st_atim, birth));
}
// "If O_TRUNC is set and the file did previously exist, upon successful
// completion, open() shall mark for update the last data modification
// and last file status change timestamps of the file." -POSIX
TEST(open, trunc_touchesMtimCtim) {
struct stat st;
struct timespec birth;
ASSERT_SYS(0, 0, touch("regular", 0755));
ASSERT_SYS(0, 0, stat("regular", &st));
birth = st.st_ctim;
sleep(1);
ASSERT_SYS(0, 3, open("regular", O_RDWR | O_TRUNC));
ASSERT_SYS(0, 0, fstat(3, &st));
EXPECT_EQ(1, timespec_cmp(st.st_ctim, birth));
EXPECT_EQ(1, timespec_cmp(st.st_mtim, birth));
ASSERT_SYS(0, 0, close(3));
}
TEST(open, mereOpen_doesntTouch) {
struct stat st;
struct timespec birth;
ASSERT_SYS(0, 0, touch("regular", 0755));
ASSERT_SYS(0, 0, stat("regular", &st));
birth = st.st_ctim;
sleep(1);
ASSERT_SYS(0, 3, open("regular", O_RDWR));
ASSERT_SYS(0, 0, close(3));
ASSERT_SYS(0, 0, stat("regular", &st));
EXPECT_EQ(0, timespec_cmp(st.st_ctim, birth));
EXPECT_EQ(0, timespec_cmp(st.st_mtim, birth));
EXPECT_EQ(0, timespec_cmp(st.st_atim, birth));
}

View file

@ -0,0 +1,115 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2023 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/limits.h"
#include "libc/mem/gc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/o.h"
#include "libc/temp.h"
#include "libc/testlib/testlib.h"
#include "libc/x/x.h"
char testlib_enable_tmp_setup_teardown;
TEST(openatemp, test) {
char path[] = "foo.XXXXXX";
ASSERT_SYS(0, 3, openatemp(AT_FDCWD, path, 0, O_CLOEXEC, 0));
ASSERT_NE(0, strcmp(path, "foo.XXXXXX"));
EXPECT_TRUE(fileexists(path));
EXPECT_SYS(0, 0, close(3));
}
TEST(openatemp, dirfd) {
ASSERT_SYS(0, 3, open(kTmpPath, O_RDONLY | O_DIRECTORY));
char path[] = "foo.XXXXXX.txt";
ASSERT_SYS(0, 4, openatemp(3, path, 4, 0, 0));
EXPECT_TRUE(fileexists(gc(xjoinpaths(kTmpPath, path))));
EXPECT_SYS(0, 0, close(4));
EXPECT_SYS(0, 0, close(3));
}
TEST(openatemp, unlink) {
char path[] = "foo.XXXXXX";
ASSERT_SYS(0, 3, openatemp(AT_FDCWD, path, 0, O_UNLINK, 0));
EXPECT_SYS(0, 0, close(3));
EXPECT_FALSE(fileexists(path));
}
TEST(openatemp, mode) {
if (IsWindows()) return;
unsigned omask = umask(0);
char path[] = "foo.XXXXXX";
ASSERT_SYS(0, 3, openatemp(AT_FDCWD, path, 0, 0, 0764));
struct stat st;
ASSERT_SYS(0, 0, stat(path, &st));
ASSERT_SYS(0, 0, fstat(3, &st));
EXPECT_EQ(0100764, st.st_mode);
EXPECT_SYS(0, 0, close(3));
umask(omask);
}
TEST(openatemp, tooFewX_EINVAL) {
char path[] = "foo.XXXXX";
ASSERT_SYS(EINVAL, -1, openatemp(AT_FDCWD, path, 0, O_CLOEXEC, 0));
}
TEST(openatemp, suffixTooFewX_EINVAL) {
char path[] = "foo.XXXXX.txt";
ASSERT_SYS(EINVAL, -1, openatemp(AT_FDCWD, path, 4, O_CLOEXEC, 0));
}
TEST(openatemp, badSuffixLen_EINVAL) {
char path[] = "foo.XXXXXX";
ASSERT_SYS(EINVAL, -1, openatemp(AT_FDCWD, path, -1, O_CLOEXEC, 0));
ASSERT_SYS(EINVAL, -1, openatemp(AT_FDCWD, path, -6, O_CLOEXEC, 0));
ASSERT_SYS(EINVAL, -1, openatemp(AT_FDCWD, path, 11, O_CLOEXEC, 0));
ASSERT_SYS(EINVAL, -1, openatemp(AT_FDCWD, path, 99, O_CLOEXEC, 0));
}
TEST(openatemp, missingDir_ENOENT) {
char path[] = "missing/foo.XXXXXX";
ASSERT_SYS(ENOENT, -1, openatemp(AT_FDCWD, path, 0, O_CLOEXEC, 0));
}
TEST(openatemp, notDir_ENOTDIR) {
char path[] = "regular/foo.XXXXXX";
ASSERT_SYS(0, 0, touch("regular", 0644));
ASSERT_SYS(ENOTDIR, -1, openatemp(AT_FDCWD, path, 0, O_CLOEXEC, 0));
}
TEST(mktemp, fails_returnsEmptyString) {
char path[] = "regular/foo.XXXXXX";
ASSERT_SYS(0, 0, touch("regular", 0644));
ASSERT_STREQ("", mktemp(path));
ASSERT_STREQ("", path);
ASSERT_EQ(ENOTDIR, errno);
errno = 0;
}
TEST(mkstemp, fails_returnsNull) {
char path[] = "regular/foo.XXXXXX";
ASSERT_SYS(0, 0, touch("regular", 0644));
ASSERT_SYS(ENOTDIR, -1, mkstemp(path));
ASSERT_STREQ("regular/foo.XXXXXX", path);
}

View file

@ -28,8 +28,8 @@
char testlib_enable_tmp_setup_teardown;
void CheckPlatform(void) {
if (IsOpenbsd()) return;
if (__is_linux_2_6_23()) return;
if (IsOpenbsd()) return; // openbsd is ok
if (IsLinux() && __is_linux_2_6_23()) return; // non-ancient linux is ok
kprintf("skipping openbsd_test\n");
exit(0);
}

View file

@ -55,7 +55,7 @@ void OnSig(int sig) {
gotsig = true;
}
dontdiscard char *FormatPollFd(struct pollfd p[2]) {
__wur char *FormatPollFd(struct pollfd p[2]) {
return xasprintf("fd:%d revents:%s\n"
"fd:%d revents:%s\n",
p[0].fd, "<TODO:kPollNames>", p[1].fd, "<TODO:kPollNames>");

View file

@ -20,6 +20,7 @@
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/limits.h"
#include "libc/log/log.h"
#include "libc/mem/gc.h"
#include "libc/mem/gc.internal.h"
@ -96,10 +97,10 @@ TEST(readlinkat, frootloop) {
TEST(readlinkat, statReadsNameLength) {
struct stat st;
ASSERT_SYS(0, 0, symlink("froot", "froot"));
ASSERT_SYS(0, 0, fstatat(AT_FDCWD, "froot", &st, AT_SYMLINK_NOFOLLOW));
ASSERT_SYS(0, 0, symlink("froÒt", "froÒt"));
ASSERT_SYS(0, 0, fstatat(AT_FDCWD, "froÒt", &st, AT_SYMLINK_NOFOLLOW));
EXPECT_TRUE(S_ISLNK(st.st_mode));
EXPECT_EQ(5, st.st_size);
EXPECT_EQ(6, st.st_size);
}
TEST(readlinkat, realpathReturnsLongPath) {

View file

@ -75,7 +75,7 @@ TEST(reservefd, testGrowthOfFdsDataStructure) {
for (i = 0; i < n; ++i) {
ASSERT_SYS(0, i + 3, open("/zip/usr/share/zoneinfo/UTC", O_RDONLY));
}
ASSERT_GT(g_fds.n, OPEN_MAX);
ASSERT_GT(g_fds.n, 16);
for (i = 0; i < n; ++i) {
ASSERT_SYS(0, 0, close(i + 3));
}

View file

@ -53,7 +53,7 @@ bool CanUseSeccomp(void) {
}
void SetUp(void) {
if (!__is_linux_2_6_23() || !CanUseSeccomp()) {
if (!IsLinux() || !__is_linux_2_6_23() || !CanUseSeccomp()) {
exit(0);
}
}

View file

@ -24,6 +24,7 @@
#include "libc/fmt/fmt.h"
#include "libc/intrin/directmap.internal.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/limits.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/rand.h"
#include "libc/sysv/consts/auxv.h"

View file

@ -21,6 +21,7 @@
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h"
#include "libc/limits.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/rand.h"
#include "libc/sysv/consts/at.h"

View file

@ -18,11 +18,13 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/stat.macros.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/utime.h"
@ -70,15 +72,6 @@ TEST(futimes, test) {
EXPECT_SYS(0, 0, close(3));
}
TEST(futimes, rhel5_enosys) {
if (IsLinux() && !__is_linux_2_6_23()) {
struct timeval tv[2] = {{1655455857}, {827727928}};
EXPECT_SYS(0, 3, creat("boop", 0644));
EXPECT_SYS(ENOSYS, -1, futimes(3, tv));
EXPECT_SYS(0, 0, close(3));
}
}
TEST(utimensat, test) {
struct stat st;
struct timespec ts[2] = {
@ -127,3 +120,39 @@ TEST(utimensat, testOmit) {
EXPECT_NE(123, st.st_atim.tv_sec);
EXPECT_NE(123, st.st_mtim.tv_sec);
}
TEST(futimens, test2) {
struct timespec ts[2];
int fd = creat("foo", 0600);
if (fd < 0) exit(1);
struct stat st;
int64_t birth;
ASSERT_SYS(0, 0, fstat(fd, &st));
ASSERT_EQ(st.st_ctime, st.st_atime);
ASSERT_EQ(st.st_ctime, st.st_mtime);
birth = st.st_ctime;
ts[0].tv_sec = 1;
ts[0].tv_nsec = UTIME_OMIT;
ts[1].tv_sec = 1;
ts[1].tv_nsec = UTIME_NOW;
errno = 0;
ASSERT_SYS(EBADF, -1, futimens(AT_FDCWD, NULL));
ASSERT_SYS(0, 0, futimens(fd, ts));
sleep(1);
ts[0].tv_nsec = UTIME_NOW; // change access time
ts[1].tv_nsec = UTIME_OMIT; // don't change modified time
close(fd);
fd = open("foo", O_RDONLY);
ASSERT_SYS(0, 0, futimens(fd, ts));
ASSERT_SYS(0, 0, fstat(fd, &st));
// check time of last status change equals access time
ASSERT_GT(st.st_atime, birth);
ASSERT_EQ(st.st_mtime, birth);
// NetBSD doesn't appear to change ctime even though it says it does
if (!IsNetbsd()) {
ASSERT_GT(st.st_ctime, birth);
ASSERT_EQ(st.st_ctime, st.st_atime);
ASSERT_GT(st.st_ctime, st.st_mtime);
}
close(fd);
}

View file

@ -512,6 +512,18 @@ TEST(wcstoumax, testIBM) {
ASSERT_STREQ(L"f", e);
}
TEST(strtol, term) {
static char const input[2][3] = {"0x", "0b"};
static int const base[] = {0, 2, 10};
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
char *term;
strtoll(input[i], &term, base[j]);
ASSERT_EQ(input[i] + 1, term);
}
}
}
TEST(strtoul, testoverflow) {
errno = 0;
char *e = 0;
@ -521,20 +533,41 @@ TEST(strtoul, testoverflow) {
ASSERT_STREQ("", e);
}
TEST(strtol, invalidHex_consistentWithBsd) {
TEST(strtol, invalidHex1) {
char *c = 0;
long x = strtol("0xz", &c, 16);
ASSERT_EQ(0, x);
ASSERT_STREQ("z", c);
ASSERT_STREQ("xz", c);
}
TEST(strtol, invalidHex_consistentWithBsd2) {
TEST(strtol, invalidHex2) {
char *c = 0;
long x = strtol("0xez", &c, 16);
ASSERT_EQ(0xe, x);
ASSERT_STREQ("z", c);
}
TEST(strtol, invalidHex3) {
char *c = 0;
long x = strtol("0xez", &c, 0);
ASSERT_EQ(0xe, x);
ASSERT_STREQ("z", c);
}
TEST(strtol, invalidBin1) {
char *c = 0;
long x = strtol("0b2", &c, 2);
ASSERT_EQ(0, x);
ASSERT_STREQ("b2", c);
}
TEST(strtol, invalidBin2) {
char *c = 0;
long x = strtol("0b2", &c, 0);
ASSERT_EQ(0, x);
ASSERT_STREQ("b2", c);
}
BENCH(atoi, bench) {
EZBENCH2("atoi 10⁸", donothing,
__expropriate(atoi(__veil("r", "100000000"))));

View file

@ -16,11 +16,12 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/popcnt.h"
#include "libc/calls/calls.h"
#include "libc/mem/mem.h"
#include "libc/limits.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/hyperion.h"

View file

@ -0,0 +1,39 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2023 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/runtime/runtime.h"
#include "libc/runtime/sysconf.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
#include "libc/testlib/testlib.h"
TEST(memchr, test) {
const char *s = "hello";
ASSERT_EQ(s + 1, memchr(s, 'e', 5));
}
TEST(memchr, pageOverlapTorture) {
long pagesz = sysconf(_SC_PAGESIZE);
char *map = mmap(0, pagesz * 2, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
ASSERT_SYS(0, 0, mprotect(map + pagesz, pagesz, PROT_NONE));
strcpy(map + pagesz - 9, "12345678");
EXPECT_EQ(map + pagesz - 1, memchr(map + pagesz - 9, 0, 79));
EXPECT_SYS(0, 0, munmap(map, pagesz * 2));
}

View file

@ -18,9 +18,13 @@
*/
#include "libc/mem/gc.internal.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/sysconf.h"
#include "libc/stdio/rand.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/fastrandomstring.h"
#include "libc/testlib/hyperion.h"
@ -109,100 +113,67 @@ TEST(memcmp, fuzz) {
}
}
TEST(memcmp, pageOverlapTorture) {
long pagesz = sysconf(_SC_PAGESIZE);
char *map = mmap(0, pagesz * 2, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
char *map2 = mmap(0, pagesz * 2, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
ASSERT_SYS(0, 0, mprotect(map + pagesz, pagesz, PROT_NONE));
ASSERT_SYS(0, 0, mprotect(map2 + pagesz, pagesz, PROT_NONE));
strcpy(map + pagesz - 9, "12345678");
strcpy(map2 + pagesz - 9, "12345679");
EXPECT_LT(memcmp(map + pagesz - 9, map2 + pagesz - 9, 79), 0);
EXPECT_SYS(0, 0, munmap(map2, pagesz * 2));
EXPECT_SYS(0, 0, munmap(map, pagesz * 2));
}
int buncmp(const void *, const void *, size_t) asm("bcmp");
int funcmp(const void *, const void *, size_t) asm("memcmp");
#if 0
BENCH(bcmp, bench) {
volatile int v;
const char *volatile a;
const char *volatile b;
b = a = "123456789123456789123456789123456789123456789123456789";
b = gc(strdup(b));
EZBENCH_N("bcmp", 0, v = buncmp(a, b, 0));
EZBENCH_N("bcmp", 1, v = buncmp(a, b, 1));
EZBENCH_N("bcmp", 2, v = buncmp(a, b, 2));
EZBENCH_N("bcmp", 3, v = buncmp(a, b, 3));
EZBENCH_N("𝗯𝗰𝗺𝗽", 4, v = buncmp(a, b, 4));
EZBENCH_N("bcmp", 5, v = buncmp(a, b, 5));
EZBENCH_N("bcmp", 6, v = buncmp(a, b, 6));
EZBENCH_N("bcmp", 7, v = buncmp(a, b, 7));
EZBENCH_N("𝗯𝗰𝗺𝗽", 8, v = buncmp(a, b, 8));
EZBENCH_N("bcmp", 9, v = buncmp(a, b, 9));
EZBENCH_N("bcmp", 15, v = buncmp(a, b, 15));
EZBENCH_N("𝗯𝗰𝗺𝗽", 16, v = buncmp(a, b, 16));
EZBENCH_N("bcmp", 17, v = buncmp(a, b, 17));
EZBENCH_N("bcmp", 31, v = buncmp(a, b, 31));
EZBENCH_N("bcmp", 32, v = buncmp(a, b, 32));
a = kHyperion;
b = gc(strdup(kHyperion));
EZBENCH_N("bcmp", 33, v = buncmp(a, b, 33));
EZBENCH_N("bcmp", 79, v = buncmp(a, b, 79));
EZBENCH_N("𝗯𝗰𝗺𝗽", 80, v = buncmp(a, b, 80));
EZBENCH_N("bcmp", 128, v = buncmp(a, b, 128));
EZBENCH_N("bcmp", 256, v = buncmp(a, b, 256));
a = gc(malloc(16 * 1024));
b = gc(malloc(16 * 1024));
rngset(a, 16 * 1024, lemur64, -1);
memcpy(b, a, 16 * 1024);
EZBENCH_N("bcmp", 16384, v = buncmp(a, b, 16384));
a = gc(malloc(32 * 1024));
b = gc(malloc(32 * 1024));
rngset(a, 32 * 1024, lemur64, -1);
memcpy(b, a, 32 * 1024);
EZBENCH_N("bcmp", 32768, v = buncmp(a, b, 32768));
a = gc(malloc(128 * 1024));
b = gc(malloc(128 * 1024));
rngset(a, 128 * 1024, lemur64, -1);
memcpy(b, a, 128 * 1024);
EZBENCH_N("bcmp", 131072, v = buncmp(a, b, 131072));
}
#endif
#if 0
#if 1
BENCH(memcmp, bench) {
volatile int v;
const char *volatile a;
const char *volatile b;
char *volatile a;
char *volatile b;
b = a = "123456789123456789123456789123456789123456789123456789";
b = gc(strdup(b));
EZBENCH_N("memcmp", 0, v = funcmp(a, b, 0));
EZBENCH_N("memcmp", 1, v = funcmp(a, b, 1));
EZBENCH_N("memcmp", 2, v = funcmp(a, b, 2));
EZBENCH_N("memcmp", 3, v = funcmp(a, b, 3));
EZBENCH_N("𝗺𝗲𝗺𝗰𝗺𝗽", 4, v = funcmp(a, b, 4));
EZBENCH_N("memcmp", 5, v = funcmp(a, b, 5));
EZBENCH_N("memcmp", 6, v = funcmp(a, b, 6));
EZBENCH_N("memcmp", 7, v = funcmp(a, b, 7));
EZBENCH_N("𝗺𝗲𝗺𝗰𝗺𝗽", 8, v = funcmp(a, b, 8));
EZBENCH_N("memcmp", 9, v = funcmp(a, b, 9));
EZBENCH_N("memcmp", 15, v = funcmp(a, b, 15));
EZBENCH_N("𝗺𝗲𝗺𝗰𝗺𝗽", 16, v = funcmp(a, b, 16));
EZBENCH_N("memcmp", 17, v = funcmp(a, b, 17));
EZBENCH_N("memcmp", 31, v = funcmp(a, b, 31));
EZBENCH_N("memcmp", 32, v = funcmp(a, b, 32));
EZBENCH_N("memcmp", 0, __expropriate(funcmp(a, b, 0)));
EZBENCH_N("memcmp", 1, __expropriate(funcmp(a, b, 1)));
EZBENCH_N("memcmp", 2, __expropriate(funcmp(a, b, 2)));
EZBENCH_N("memcmp", 3, __expropriate(funcmp(a, b, 3)));
EZBENCH_N("𝗺𝗲𝗺𝗰𝗺𝗽", 4, __expropriate(funcmp(a, b, 4)));
EZBENCH_N("memcmp", 5, __expropriate(funcmp(a, b, 5)));
EZBENCH_N("memcmp", 6, __expropriate(funcmp(a, b, 6)));
EZBENCH_N("memcmp", 7, __expropriate(funcmp(a, b, 7)));
EZBENCH_N("𝗺𝗲𝗺𝗰𝗺𝗽", 8, __expropriate(funcmp(a, b, 8)));
EZBENCH_N("memcmp", 9, __expropriate(funcmp(a, b, 9)));
EZBENCH_N("memcmp", 15, __expropriate(funcmp(a, b, 15)));
EZBENCH_N("𝗺𝗲𝗺𝗰𝗺𝗽", 16, __expropriate(funcmp(a, b, 16)));
EZBENCH_N("memcmp", 17, __expropriate(funcmp(a, b, 17)));
EZBENCH_N("memcmp", 31, __expropriate(funcmp(a, b, 31)));
EZBENCH_N("memcmp", 32, __expropriate(funcmp(a, b, 32)));
a = kHyperion;
b = gc(strdup(kHyperion));
EZBENCH_N("memcmp", 33, v = funcmp(a, b, 33));
EZBENCH_N("memcmp", 79, v = funcmp(a, b, 79));
EZBENCH_N("𝗺𝗲𝗺𝗰𝗺𝗽", 80, v = funcmp(a, b, 80));
EZBENCH_N("memcmp", 128, v = funcmp(a, b, 128));
EZBENCH_N("memcmp", 256, v = funcmp(a, b, 256));
EZBENCH_N("memcmp", 33, __expropriate(funcmp(a, b, 33)));
EZBENCH_N("memcmp", 79, __expropriate(funcmp(a, b, 79)));
EZBENCH_N("𝗺𝗲𝗺𝗰𝗺𝗽", 80, __expropriate(funcmp(a, b, 80)));
EZBENCH_N("memcmp", 128, __expropriate(funcmp(a, b, 128)));
EZBENCH_N("memcmp", 256, __expropriate(funcmp(a, b, 256)));
a = gc(malloc(16 * 1024));
b = gc(malloc(16 * 1024));
rngset(a, 16 * 1024, lemur64, -1);
memcpy(b, a, 16 * 1024);
EZBENCH_N("memcmp", 16384, v = funcmp(a, b, 16384));
EZBENCH_N("memcmp", 16384, __expropriate(funcmp(a, b, 16384)));
a = gc(malloc(32 * 1024));
b = gc(malloc(32 * 1024));
rngset(a, 32 * 1024, lemur64, -1);
memcpy(b, a, 32 * 1024);
EZBENCH_N("memcmp", 32768, v = funcmp(a, b, 32768));
EZBENCH_N("memcmp", 32768, __expropriate(funcmp(a, b, 32768)));
a = gc(malloc(128 * 1024));
b = gc(malloc(128 * 1024));
rngset(a, 128 * 1024, lemur64, -1);
memcpy(b, a, 128 * 1024);
EZBENCH_N("memcmp", 131072, v = funcmp(a, b, 131072));
EZBENCH_N("memcmp", 131072, __expropriate(funcmp(a, b, 131072)));
}
#endif
@ -253,53 +224,6 @@ BENCH(timingsafe_memcmp, bench) {
}
#endif
#if 0
BENCH(timingsafe_bcmp, bench) {
volatile int v;
const char *volatile a;
const char *volatile b;
b = a = "123456789123456789123456789123456789123456789123456789";
b = gc(strdup(b));
EZBENCH_N("timingsafe_bcmp", 0, v = timingsafe_bcmp(a, b, 0));
EZBENCH_N("timingsafe_bcmp", 1, v = timingsafe_bcmp(a, b, 1));
EZBENCH_N("timingsafe_bcmp", 2, v = timingsafe_bcmp(a, b, 2));
EZBENCH_N("timingsafe_bcmp", 3, v = timingsafe_bcmp(a, b, 3));
EZBENCH_N("𝘁𝗶𝗺𝗶𝗻𝗴𝘀𝗮𝗳𝗲_𝗯𝗰𝗺𝗽", 4, v = timingsafe_bcmp(a, b, 4));
EZBENCH_N("timingsafe_bcmp", 5, v = timingsafe_bcmp(a, b, 5));
EZBENCH_N("timingsafe_bcmp", 6, v = timingsafe_bcmp(a, b, 6));
EZBENCH_N("timingsafe_bcmp", 7, v = timingsafe_bcmp(a, b, 7));
EZBENCH_N("𝘁𝗶𝗺𝗶𝗻𝗴𝘀𝗮𝗳𝗲_𝗯𝗰𝗺𝗽", 8, v = timingsafe_bcmp(a, b, 8));
EZBENCH_N("timingsafe_bcmp", 9, v = timingsafe_bcmp(a, b, 9));
EZBENCH_N("timingsafe_bcmp", 15, v = timingsafe_bcmp(a, b, 15));
EZBENCH_N("𝘁𝗶𝗺𝗶𝗻𝗴𝘀𝗮𝗳𝗲_𝗯𝗰𝗺𝗽", 16, v = timingsafe_bcmp(a, b, 16));
EZBENCH_N("timingsafe_bcmp", 17, v = timingsafe_bcmp(a, b, 17));
EZBENCH_N("timingsafe_bcmp", 31, v = timingsafe_bcmp(a, b, 31));
EZBENCH_N("timingsafe_bcmp", 32, v = timingsafe_bcmp(a, b, 32));
a = kHyperion;
b = gc(strdup(kHyperion));
EZBENCH_N("timingsafe_bcmp", 33, v = timingsafe_bcmp(a, b, 33));
EZBENCH_N("timingsafe_bcmp", 79, v = timingsafe_bcmp(a, b, 79));
EZBENCH_N("𝘁𝗶𝗺𝗶𝗻𝗴𝘀𝗮𝗳𝗲_𝗯𝗰𝗺𝗽", 80, v = timingsafe_bcmp(a, b, 80));
EZBENCH_N("timingsafe_bcmp", 128, v = timingsafe_bcmp(a, b, 128));
EZBENCH_N("timingsafe_bcmp", 256, v = timingsafe_bcmp(a, b, 256));
a = gc(malloc(16 * 1024));
b = gc(malloc(16 * 1024));
rngset(a, 16 * 1024, lemur64, -1);
memcpy(b, a, 16 * 1024);
EZBENCH_N("timingsafe_bcmp", 16384, v = timingsafe_bcmp(a, b, 16384));
a = gc(malloc(32 * 1024));
b = gc(malloc(32 * 1024));
rngset(a, 32 * 1024, lemur64, -1);
memcpy(b, a, 32 * 1024);
EZBENCH_N("timingsafe_bcmp", 32768, v = timingsafe_bcmp(a, b, 32768));
a = gc(malloc(128 * 1024));
b = gc(malloc(128 * 1024));
rngset(a, 128 * 1024, lemur64, -1);
memcpy(b, a, 128 * 1024);
EZBENCH_N("timingsafe_bcmp", 131072, v = timingsafe_bcmp(a, b, 131072));
}
#endif
#if 0
BENCH(memcasecmp, bench) {
volatile int v;

View file

@ -33,7 +33,7 @@ struct Bog {
const char *p[];
};
static dontdiscard struct Bog *NewBog(unsigned n) {
static __wur struct Bog *NewBog(unsigned n) {
struct Bog *res = malloc(sizeof(struct Bog) + sizeof(const char *) * n);
res->i = 0;
res->n = n;

View file

@ -18,6 +18,7 @@
*/
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/limits.h"
#include "libc/mem/mem.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"

View file

@ -28,6 +28,8 @@
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"
#define OPEN_MAX 16
#define I(x, y) \
{ x, y, 0, (y - x) * FRAMESIZE + FRAMESIZE }

View file

@ -27,6 +27,7 @@
#include "libc/intrin/bits.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/intrin/xchg.internal.h"
#include "libc/limits.h"
#include "libc/log/log.h"
#include "libc/mem/gc.h"
#include "libc/mem/mem.h"

View file

@ -25,6 +25,7 @@
#include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/kprintf.h"
#include "libc/limits.h"
#include "libc/mem/critbit0.h"
#include "libc/mem/gc.h"
#include "libc/mem/gc.internal.h"
@ -95,6 +96,13 @@ TEST(opendir, openRealDirEntry) {
EXPECT_EQ(0, closedir(dir));
}
TEST(fdopendir, test) {
ASSERT_SYS(0, 0, touch("foo", 0644));
ASSERT_SYS(0, 3, open("foo", O_RDONLY));
ASSERT_SYS(ENOTDIR, 0, fdopendir(3));
ASSERT_SYS(0, 0, close(3));
}
TEST(dirstream, testDots) {
int hasdot = 0;
int hasdotdot = 0;

View file

@ -21,7 +21,7 @@
#include "libc/mem/gc.internal.h"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/stdio/temp.h"
#include "libc/temp.h"
#include "libc/testlib/testlib.h"
TEST(fmemopen, testWriteRewindRead) {

View file

@ -21,12 +21,13 @@
#include "libc/calls/struct/stat.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/dce.h"
#include "libc/limits.h"
#include "libc/mem/gc.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/stdio/temp.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/temp.h"
#include "libc/testlib/testlib.h"
#include "libc/x/xasprintf.h"
@ -79,7 +80,7 @@ TEST(tmpfile, test) {
#ifndef __aarch64__
// TODO(jart): Find way to detect qemu-aarch64
TEST(tmpfile, renameToRealFile) {
if (!IsLinux() || !__is_linux_2_6_23()) return;
if (!(IsLinux() && __is_linux_2_6_23())) return; // need non-ancient linux
FILE *f;
f = tmpfile();
ASSERT_EQ(2, fputs("hi", f));

View file

@ -16,6 +16,9 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/nexgen32e/crc32.h"
#include "libc/stdio/rand.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/testlib/hyperion.h"
@ -68,3 +71,28 @@ TEST(ungetwc, testGetWideChar_canBeUndoneWithinReason) {
EXPECT_STREQ("𐌰𐌱\n", buf);
EXPECT_EQ(0, fclose(f));
}
TEST(ungetc, io) {
static char b1[BUFSIZ * 2];
static char b2[BUFSIZ * 2];
for (int i = 0; i < sizeof(b1); ++i) {
b1[i] = rand();
}
FILE *f = tmpfile();
fwrite(b1, 1, sizeof(b1), f);
rewind(f);
for (int i = 0; i < sizeof(b1); ++i) {
int c;
ASSERT_NE(EOF, (c = fgetc(f)));
ASSERT_EQ(c, ungetc(c, f));
ASSERT_EQ(c, fgetc(f));
b2[i] = c;
if (rand() % 10 == 0) {
ASSERT_NE(EOF, fflush(f));
ASSERT_NE(i, lseek(fileno(f), 0, SEEK_CUR));
}
}
ASSERT_EQ(EOF, fgetc(f));
fclose(f);
ASSERT_EQ(crc32c(0, b1, sizeof(b1)), crc32c(0, b2, sizeof(b2)));
}

View file

@ -21,7 +21,7 @@
#include "libc/mem/gc.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/temp.h"
#include "libc/temp.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/consts/o.h"

View file

@ -6,7 +6,7 @@ COSMOPOLITAN_C_START_
int ild(const char16_t *codez);
int ildreal(const char16_t *codez);
int ildlegacy(const char16_t *codez);
uint8_t *unbingx86op(const char16_t *codez) dontdiscard;
uint8_t *unbingx86op(const char16_t *codez) __wur;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -25,7 +25,7 @@
#include "test/libc/xed/lib.h"
#include "third_party/xed/x86.h"
dontdiscard uint8_t *unbingx86op(const char16_t *codez) {
__wur uint8_t *unbingx86op(const char16_t *codez) {
size_t len;
len = strlen16(codez);
return unbingbuf(xmalloc(ROUNDUP(len, 16)), len, codez, 0x90);