Make improvements

- Make rand64() thread safe
- Introduce lemur64 lcg prng
- Improve strace on New Technology
- Improve msync() on New Technology
This commit is contained in:
Justine Tunney 2022-04-07 00:15:35 -07:00
parent 43ba3009b2
commit 29bf8b1a30
73 changed files with 888 additions and 269 deletions

View file

@ -209,6 +209,7 @@ const struct Function {
{"getrandom", GetRandom}, // {"getrandom", GetRandom}, //
{"inc", inc}, // {"inc", inc}, //
{"knuth", knuth}, // {"knuth", knuth}, //
{"lemur64", lemur64}, //
{"libc", libc}, // {"libc", libc}, //
{"moby", moby}, // {"moby", moby}, //
{"mt19937", _mt19937}, // {"mt19937", _mt19937}, //

View file

@ -0,0 +1,46 @@
#ifndef COSMOPOLITAN_LIBC_BITS_CMPXCHG16B_INTERNAL_H_
#define COSMOPOLITAN_LIBC_BITS_CMPXCHG16B_INTERNAL_H_
#include "libc/bits/bits.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* Compares and exchanges 128-bit value, i.e.
*
* if (*IfThing == *IsEqualToMe) {
* *IfThing = ReplaceItWithMe;
* return true;
* } else {
* *IsEqualToMe = *IfThing;
* return false;
* }
*
* Please note that Intel Architecture doesn't guarantee 16-byte memory
* accesses to be atomic on their own. Therefore _lockcmpxchg16b should
* be considered instead for both thread and asynchronous signal safety
*
* @param IfThing should point to aligned memory
* @param IsEqualToMe should point to in/out local variable
* @param ReplaceItWithMe might become the new memory value
* @return true if *IfThing was changed
*/
static inline bool _cmpxchg16b(uint128_t *IfThing, uint128_t *IsEqualToMe,
uint128_t ReplaceItWithMe) {
bool DidIt;
uint64_t ax, bx, cx, dx;
ax = *IsEqualToMe;
dx = *IsEqualToMe >> 64;
bx = ReplaceItWithMe;
cx = ReplaceItWithMe >> 64;
asm volatile(ZFLAG_ASM("cmpxchg16b\t%1")
: ZFLAG_CONSTRAINT(DidIt), "+m"(*IfThing), "+a"(ax), "+d"(dx)
: "b"(bx), "c"(cx));
if (!DidIt) {
*IsEqualToMe = ax | (uint128_t)dx << 64;
}
return DidIt;
}
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_CMPXCHG16B_INTERNAL_H_ */

View file

@ -0,0 +1,44 @@
#ifndef COSMOPOLITAN_LIBC_BITS_LOCKCMPXCHG16B_INTERNAL_H_
#define COSMOPOLITAN_LIBC_BITS_LOCKCMPXCHG16B_INTERNAL_H_
#include "libc/bits/bits.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* Compares and exchanges 128-bit value, i.e.
*
* if (*IfThing == *IsEqualToMe) {
* *IfThing = ReplaceItWithMe;
* return true;
* } else {
* *IsEqualToMe = *IfThing;
* return false;
* }
*
* @param IfThing should point to aligned memory
* @param IsEqualToMe should point to in/out local variable
* @param ReplaceItWithMe might become the new memory value
* @return true if *IfThing was changed
* @asyncsignalsafe
* @threadsafe
*/
static inline bool _lockcmpxchg16b(uint128_t *IfThing, uint128_t *IsEqualToMe,
uint128_t ReplaceItWithMe) {
bool DidIt;
uint64_t ax, bx, cx, dx;
ax = *IsEqualToMe;
dx = *IsEqualToMe >> 64;
bx = ReplaceItWithMe;
cx = ReplaceItWithMe >> 64;
asm volatile(ZFLAG_ASM("lock cmpxchg16b\t%1")
: ZFLAG_CONSTRAINT(DidIt), "+m"(*IfThing), "+a"(ax), "+d"(dx)
: "b"(bx), "c"(cx));
if (!DidIt) {
*IsEqualToMe = ax | (uint128_t)dx << 64;
}
return DidIt;
}
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_LOCKCMPXCHG16B_INTERNAL_H_ */

View file

@ -0,0 +1,16 @@
#ifndef COSMOPOLITAN_LIBC_BITS_LOCKXADD_INTERNAL_H_
#define COSMOPOLITAN_LIBC_BITS_LOCKXADD_INTERNAL_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define _lockxadd(PTR, VAL) \
({ \
typeof(*(PTR)) Res; \
typeof(Res) Val = (VAL); \
asm volatile("lock xadd\t%0,%1" : "=r"(Res), "+m"(*(PTR)) : "0"(Val)); \
Res; /* contains *PTR before addition cf. InterlockedAdd() */ \
})
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_LOCKXADD_INTERNAL_H_ */

View file

@ -36,5 +36,5 @@ textwindows int sys_close_nt(struct Fd *fd) {
if (fd->kind == kFdConsole && fd->extra && fd->extra != -1) { if (fd->kind == kFdConsole && fd->extra && fd->extra != -1) {
ok &= CloseHandle(fd->extra); ok &= CloseHandle(fd->extra);
} }
return ok ? 0 : __winerr(); return ok ? 0 : -1;
} }

View file

@ -30,7 +30,7 @@ textwindows noasan struct DirectMap sys_mmap_nt(void *addr, size_t size,
int64_t handle, int64_t off) { int64_t handle, int64_t off) {
size_t i; size_t i;
struct DirectMap dm; struct DirectMap dm;
uint32_t flags1, flags2; struct ProtectNt fl;
const struct NtSecurityAttributes *sec; const struct NtSecurityAttributes *sec;
if (flags & MAP_PRIVATE) { if (flags & MAP_PRIVATE) {
@ -42,37 +42,19 @@ textwindows noasan struct DirectMap sys_mmap_nt(void *addr, size_t size,
if ((prot & PROT_WRITE) && (flags & MAP_PRIVATE) && handle != -1) { if ((prot & PROT_WRITE) && (flags & MAP_PRIVATE) && handle != -1) {
// windows has cow pages but they can't propagate across fork() // windows has cow pages but they can't propagate across fork()
if (prot & PROT_EXEC) { if (prot & PROT_EXEC) {
flags1 = kNtPageExecuteWritecopy; fl = (struct ProtectNt){kNtPageExecuteWritecopy,
flags2 = kNtFileMapCopy | kNtFileMapExecute; kNtFileMapCopy | kNtFileMapExecute};
} else { } else {
flags1 = kNtPageWritecopy; fl = (struct ProtectNt){kNtPageWritecopy, kNtFileMapCopy};
flags2 = kNtFileMapCopy;
}
} else if (prot & PROT_WRITE) {
if (prot & PROT_EXEC) {
flags1 = kNtPageExecuteReadwrite;
flags2 = kNtFileMapWrite | kNtFileMapExecute;
} else {
flags1 = kNtPageReadwrite;
flags2 = kNtFileMapWrite;
}
} else if (prot & PROT_READ) {
if (prot & PROT_EXEC) {
flags1 = kNtPageExecuteRead;
flags2 = kNtFileMapRead | kNtFileMapExecute;
} else {
flags1 = kNtPageReadonly;
flags2 = kNtFileMapRead;
} }
} else { } else {
flags1 = kNtPageNoaccess; fl = __nt2prot(prot);
flags2 = 0;
} }
if ((dm.maphandle = CreateFileMapping(handle, sec, flags1, (size + off) >> 32, if ((dm.maphandle = CreateFileMapping(handle, sec, fl.flags1,
(size + off), 0))) { (size + off) >> 32, (size + off), 0))) {
if ((dm.addr = MapViewOfFileEx(dm.maphandle, flags2, off >> 32, off, size, if ((dm.addr = MapViewOfFileEx(dm.maphandle, fl.flags2, off >> 32, off,
addr))) { size, addr))) {
return dm; return dm;
} }
CloseHandle(dm.maphandle); CloseHandle(dm.maphandle);

View file

@ -22,10 +22,5 @@
textwindows int sys_fdatasync_nt(int fd) { textwindows int sys_fdatasync_nt(int fd) {
if (!__isfdkind(fd, kFdFile)) return ebadf(); if (!__isfdkind(fd, kFdFile)) return ebadf();
/* return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : -1;
* XXX: On Windows NT this might be more analagous to fflush() and
* Microsoft docs say to do manual block i/o for database-ish
* guarantees on disk persistence. Consider: Really good UPS.
*/
return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : __winerr();
} }

View file

@ -27,6 +27,7 @@
* This function is typically regarded as a libc implementation detail; * This function is typically regarded as a libc implementation detail;
* thus, the source code is the documentation. * thus, the source code is the documentation.
* *
* @return aux val or 0 if not available
* @see libc/sysv/consts.sh * @see libc/sysv/consts.sh
* @see System Five Application Binary Interface § 3.4.3 * @see System Five Application Binary Interface § 3.4.3
* @asyncsignalsafe * @asyncsignalsafe

View file

@ -226,7 +226,6 @@ void sys_exit(int) hidden;
void __onfork(void) hidden; void __onfork(void) hidden;
i32 __fixupnewfd(i32, i32) hidden; i32 __fixupnewfd(i32, i32) hidden;
u32 __prot2nt(i32, i32) privileged;
void __restore_rt() hidden; void __restore_rt() hidden;
int sys_utimensat_xnu(int, const char *, const struct timespec *, int) hidden; int sys_utimensat_xnu(int, const char *, const struct timespec *, int) hidden;
int sys_nanosleep_xnu(const struct timespec *, struct timespec *) hidden; int sys_nanosleep_xnu(const struct timespec *, struct timespec *) hidden;
@ -284,7 +283,7 @@ int sys_linkat_nt(int, const char *, int, const char *) hidden;
int sys_lstat_nt(const char *, struct stat *) hidden; int sys_lstat_nt(const char *, struct stat *) hidden;
int sys_madvise_nt(void *, size_t, int) hidden; int sys_madvise_nt(void *, size_t, int) hidden;
int sys_mkdirat_nt(int, const char *, uint32_t) hidden; int sys_mkdirat_nt(int, const char *, uint32_t) hidden;
int sys_msync_nt(void *, size_t, int) hidden; int sys_msync_nt(char *, size_t, int) hidden;
int sys_nanosleep_nt(const struct timespec *, struct timespec *) hidden; int sys_nanosleep_nt(const struct timespec *, struct timespec *) hidden;
int sys_pipe_nt(int[hasatleast 2], unsigned) hidden; int sys_pipe_nt(int[hasatleast 2], unsigned) hidden;
int sys_renameat_nt(int, const char *, int, const char *) hidden; int sys_renameat_nt(int, const char *, int, const char *) hidden;

View file

@ -23,6 +23,7 @@
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/nt/memory.h" #include "libc/nt/memory.h"
#include "libc/nt/thunk/msabi.h" #include "libc/nt/thunk/msabi.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/runtime/memtrack.internal.h" #include "libc/runtime/memtrack.internal.h"
#include "libc/sysv/consts/nr.h" #include "libc/sysv/consts/nr.h"

View file

@ -50,11 +50,8 @@ textwindows int sys_pipe_nt(int pipefd[2], unsigned flags) {
pipefd[1] = writer; pipefd[1] = writer;
return 0; return 0;
} else { } else {
__winerr();
CloseHandle(hin); CloseHandle(hin);
} }
} else {
__winerr();
} }
__releasefd(writer); __releasefd(writer);
__releasefd(reader); __releasefd(reader);

View file

@ -63,7 +63,7 @@ struct Signals {
struct Signal mem[__SIG_QUEUE_LENGTH]; struct Signal mem[__SIG_QUEUE_LENGTH];
}; };
struct Signals __sig; struct Signals __sig; // TODO(jart): Need TLS
/** /**
* Allocates piece of memory for storing pending signal. * Allocates piece of memory for storing pending signal.

View file

@ -51,7 +51,7 @@ static textwindows int SyncDirectory(int df, char16_t path[PATH_MAX], int n) {
if (FlushFileBuffers(df)) { if (FlushFileBuffers(df)) {
return 0; return 0;
} else { } else {
return __winerr(); return -1;
} }
} }
path[0] = '.'; path[0] = '.';
@ -65,11 +65,11 @@ static textwindows int SyncDirectory(int df, char16_t path[PATH_MAX], int n) {
if (FlushFileBuffers(fh)) { if (FlushFileBuffers(fh)) {
rc = 0; rc = 0;
} else { } else {
rc = __winerr(); rc = -1;
} }
CloseHandle(fh); CloseHandle(fh);
} else { } else {
rc = __winerr(); rc = -1;
} }
return rc; return rc;
} }

View file

@ -23,6 +23,7 @@
#include "libc/calls/strace.internal.h" #include "libc/calls/strace.internal.h"
#include "libc/calls/struct/rusage.h" #include "libc/calls/struct/rusage.h"
#include "libc/fmt/conv.h" #include "libc/fmt/conv.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/nt/accounting.h" #include "libc/nt/accounting.h"
#include "libc/nt/enum/accessmask.h" #include "libc/nt/enum/accessmask.h"

View file

@ -0,0 +1,36 @@
/*-*- 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 2022 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/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/nt/runtime.h"
#include "libc/nt/thunk/msabi.h"
extern typeof(CloseHandle) *const __imp_CloseHandle __msabi;
/**
* Closes an open object handle.
* @note this wrapper takes care of ABI, STRACE(), and __winerr()
*/
textwindows bool32 CloseHandle(int64_t hObject) {
bool32 ok;
ok = __imp_CloseHandle(hObject);
if (!ok) __winerr();
STRACE("CloseHandle(%ld) → %hhhd% m", hObject, ok);
return ok;
}

View file

@ -0,0 +1,55 @@
/*-*- 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 2022 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/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/nt/ipc.h"
#include "libc/nt/struct/securityattributes.h"
#include "libc/nt/thunk/msabi.h"
extern typeof(CreateNamedPipe) *const __imp_CreateNamedPipeW __msabi;
/**
* Creates pipe.
*
* @return handle to server end
* @note this wrapper takes care of ABI, STRACE(), and __winerr()
*/
textwindows int64_t CreateNamedPipe(
const char16_t *lpName, uint32_t dwOpenMode, uint32_t dwPipeMode,
uint32_t nMaxInstances, uint32_t nOutBufferSize, uint32_t nInBufferSize,
uint32_t nDefaultTimeOutMs,
const struct NtSecurityAttributes *opt_lpSecurityAttributes) {
int64_t hServer;
hServer = __imp_CreateNamedPipeW(lpName, dwOpenMode, dwPipeMode,
nMaxInstances, nOutBufferSize, nInBufferSize,
nDefaultTimeOutMs, opt_lpSecurityAttributes);
if (hServer == -1) __winerr();
STRACE("CreateNamedPipe(%#hs,"
" dwOpenMode=%u,"
" dwPipeMode=%u,"
" nMaxInstances=%u,"
" nOutBufferSize=%'u,"
" nInBufferSize=%'u,"
" nDefaultTimeOutMs=%'u,"
" lpSecurity=%p) → "
"%ld% m",
lpName, dwOpenMode, dwPipeMode, nMaxInstances, nOutBufferSize,
nInBufferSize, nDefaultTimeOutMs, opt_lpSecurityAttributes, hServer);
return hServer;
}

View file

@ -0,0 +1,41 @@
/*-*- 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 2022 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/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/nt/ipc.h"
#include "libc/nt/struct/securityattributes.h"
#include "libc/nt/thunk/msabi.h"
extern typeof(CreatePipe) *const __imp_CreatePipe __msabi;
/**
* Creates anonymous pipe.
* @note this wrapper takes care of ABI, STRACE(), and __winerr()
*/
textwindows bool32 CreatePipe(
int64_t *out_hReadPipe, int64_t *out_hWritePipe,
const struct NtSecurityAttributes *opt_lpPipeAttributes, uint32_t nSize) {
bool32 ok;
ok = __imp_CreatePipe(out_hReadPipe, out_hWritePipe, opt_lpPipeAttributes,
nSize);
if (!ok) __winerr();
STRACE("CreatePipe([%ld], [%ld], %p, %'zu) → %hhhd% m", *out_hReadPipe,
*out_hWritePipe, opt_lpPipeAttributes, nSize, ok);
return ok;
}

View file

@ -26,6 +26,7 @@ extern typeof(CreateThread) *const __imp_CreateThread __msabi;
/** /**
* Opens file on the New Technology. * Opens file on the New Technology.
* *
* @param dwStackSize may be 0 for default per executable
* @return thread handle, or 0 on failure * @return thread handle, or 0 on failure
* @note this wrapper takes care of ABI, STRACE(), and __winerr() * @note this wrapper takes care of ABI, STRACE(), and __winerr()
*/ */

View file

@ -0,0 +1,43 @@
/*-*- 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 2022 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/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/nt/files.h"
extern typeof(FlushFileBuffers) *const __imp_FlushFileBuffers __msabi;
/**
* Flushes buffers of specified file to disk.
*
* This provides a stronger degree of assurance and blocking for things
* to be sent to a physical medium, but it's not guaranteed unless your
* file is opened in a direct non-caching mode. One main advantage here
* seems to be coherency.
*
* @note this wrapper takes care of ABI, STRACE(), and __winerr()
* @note consider buying a ups
* @see FlushViewOfFile()
*/
textwindows bool32 FlushFileBuffers(int64_t hFile) {
bool32 ok;
ok = __imp_FlushFileBuffers(hFile);
if (!ok) __winerr();
STRACE("FlushFileBuffers(%ld) → %hhhd% m", hFile, ok);
return ok;
}

View file

@ -0,0 +1,43 @@
/*-*- 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 2022 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/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/nt/memory.h"
extern typeof(FlushViewOfFile) *const __imp_FlushViewOfFile __msabi;
/**
* Syncs memory created by MapViewOfFileEx().
*
* This doesn't wait until the pages are written out to the physical
* medium. This doesn't update timestamps or file/dir metadata.
*
* @note this wrapper takes care of ABI, STRACE(), and __winerr()
* @note consider buying a ups
* @see FlushFileBuffers()
*/
textwindows bool32 FlushViewOfFile(const void *lpBaseAddress,
size_t dwNumberOfBytesToFlush) {
bool32 ok;
ok = __imp_FlushViewOfFile(lpBaseAddress, dwNumberOfBytesToFlush);
if (!ok) __winerr();
STRACE("FlushViewOfFile(%p, %'zu) → %hhhd% m", lpBaseAddress,
dwNumberOfBytesToFlush, ok);
return ok;
}

View file

@ -64,7 +64,14 @@ o/$(MODE)/libc/intrin/kprintf.greg.o: \
$(NO_MAGIC) $(NO_MAGIC)
o/$(MODE)/libc/intrin/createfile.greg.o \ o/$(MODE)/libc/intrin/createfile.greg.o \
o/$(MODE)/libc/intrin/createpipe.greg.o \
o/$(MODE)/libc/intrin/closehandle.greg.o \
o/$(MODE)/libc/intrin/createthread.greg.o \
o/$(MODE)/libc/intrin/describeflags.greg.o \ o/$(MODE)/libc/intrin/describeflags.greg.o \
o/$(MODE)/libc/intrin/createnamedpipe.greg.o \
o/$(MODE)/libc/intrin/unmapviewoffile.greg.o \
o/$(MODE)/libc/intrin/flushviewoffile.greg.o \
o/$(MODE)/libc/intrin/flushfilebuffers.greg.o \
o/$(MODE)/libc/intrin/mapviewoffileexnuma.greg.o \ o/$(MODE)/libc/intrin/mapviewoffileexnuma.greg.o \
o/$(MODE)/libc/intrin/createfilemappingnuma.greg.o \ o/$(MODE)/libc/intrin/createfilemappingnuma.greg.o \
o/$(MODE)/libc/intrin/kstarttsc.o \ o/$(MODE)/libc/intrin/kstarttsc.o \

View file

@ -0,0 +1,42 @@
/*-*- 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 2020 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/nt/enum/filemapflags.h"
#include "libc/nt/enum/pageflags.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/sysv/consts/prot.h"
privileged struct ProtectNt __nt2prot(int prot) {
if (prot & PROT_WRITE) {
if (prot & PROT_EXEC) {
return (struct ProtectNt){kNtPageExecuteReadwrite,
kNtFileMapWrite | kNtFileMapExecute};
} else {
return (struct ProtectNt){kNtPageReadwrite, kNtFileMapWrite};
}
} else if (prot & PROT_READ) {
if (prot & PROT_EXEC) {
return (struct ProtectNt){kNtPageExecuteRead,
kNtFileMapRead | kNtFileMapExecute};
} else {
return (struct ProtectNt){kNtPageReadonly, kNtFileMapRead};
}
} else {
return (struct ProtectNt){kNtPageNoaccess};
}
}

View file

@ -0,0 +1,35 @@
/*-*- 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 2022 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/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/nt/memory.h"
extern typeof(UnmapViewOfFile) *const __imp_UnmapViewOfFile __msabi;
/**
* Unmaps memory created by MapViewOfFileEx().
* @note this wrapper takes care of ABI, STRACE(), and __winerr()
*/
textwindows bool32 UnmapViewOfFile(const void *lpBaseAddress) {
bool32 ok;
ok = __imp_UnmapViewOfFile(lpBaseAddress);
if (!ok) __winerr();
STRACE("UnmapViewOfFile(%p) → %hhhd% m", lpBaseAddress, ok);
return ok;
}

View file

@ -171,27 +171,14 @@ void ShowBacktrace(int fd, const struct StackFrame *bp) {
#ifdef __FNO_OMIT_FRAME_POINTER__ #ifdef __FNO_OMIT_FRAME_POINTER__
/* asan runtime depends on this function */ /* asan runtime depends on this function */
int st, ft; int st, ft;
static bool noreentry; st = __strace, __strace = 0;
if (!noreentry) { ft = g_ftrace, g_ftrace = 0;
noreentry = true; if (!bp) bp = __builtin_frame_address(0);
st = __strace; PrintBacktrace(fd, bp);
__strace = 0;
ft = g_ftrace; __strace = st;
g_ftrace = 0; g_ftrace = ft;
if (!bp) {
bp = __builtin_frame_address(0);
}
PrintBacktrace(fd, bp);
__strace = st;
g_ftrace = ft;
noreentry = false;
}
#else #else
kprintf("ShowBacktrace() needs these flags to show C backtrace:%n" kprintf("ShowBacktrace() needs these flags to show C backtrace:%n"
"\t-D__FNO_OMIT_FRAME_POINTER__%n" "\t-D__FNO_OMIT_FRAME_POINTER__%n"

View file

@ -20,6 +20,7 @@
#include "libc/bits/weaken.h" #include "libc/bits/weaken.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/sigbits.h" #include "libc/calls/sigbits.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/sigaction.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/intrin/asan.internal.h" #include "libc/intrin/asan.internal.h"
@ -296,10 +297,11 @@ static wontreturn relegated noinstrument void __minicrash(int sig,
relegated noinstrument void __oncrash(int sig, struct siginfo *si, relegated noinstrument void __oncrash(int sig, struct siginfo *si,
ucontext_t *ctx) { ucontext_t *ctx) {
intptr_t rip; intptr_t rip;
int gdbpid, err; int gdbpid, err, st, ft;
static bool noreentry, notpossible; static bool noreentry, notpossible;
--g_ftrace; st = __strace, __strace = 0;
if (cmpxchg(&noreentry, false, true)) { ft = g_ftrace, g_ftrace = 0;
if (lockcmpxchg(&noreentry, false, true)) {
if (!__vforked) { if (!__vforked) {
rip = ctx ? ctx->uc_mcontext.rip : 0; rip = ctx ? ctx->uc_mcontext.rip : 0;
err = errno; err = errno;
@ -326,9 +328,10 @@ relegated noinstrument void __oncrash(int sig, struct siginfo *si,
} }
} else if (sig == SIGTRAP) { } else if (sig == SIGTRAP) {
/* chances are IsDebuggerPresent() confused strace w/ gdb */ /* chances are IsDebuggerPresent() confused strace w/ gdb */
++g_ftrace; g_ftrace = ft;
__strace = st;
return; return;
} else if (cmpxchg(&notpossible, false, true)) { } else if (lockcmpxchg(&notpossible, false, true)) {
__minicrash(sig, si, ctx, "WHILE CRASHING"); __minicrash(sig, si, ctx, "WHILE CRASHING");
} else { } else {
for (;;) { for (;;) {

View file

@ -1,2 +0,0 @@
.include "o/libc/nt/codegen.inc"
.imp KernelBase,__imp_UnmapViewOfFile2,UnmapViewOfFile2,1696

View file

@ -1,2 +0,0 @@
.include "o/libc/nt/codegen.inc"
.imp KernelBase,__imp_UnmapViewOfFileEx,UnmapViewOfFileEx,1697

View file

@ -2,7 +2,7 @@
.imp kernel32,__imp_CloseHandle,CloseHandle,0 .imp kernel32,__imp_CloseHandle,CloseHandle,0
.text.windows .text.windows
CloseHandle: __CloseHandle:
push %rbp push %rbp
mov %rsp,%rbp mov %rsp,%rbp
.profilable .profilable
@ -11,5 +11,5 @@ CloseHandle:
call *__imp_CloseHandle(%rip) call *__imp_CloseHandle(%rip)
leave leave
ret ret
.endfn CloseHandle,globl .endfn __CloseHandle,globl
.previous .previous

View file

@ -2,11 +2,11 @@
.imp kernel32,__imp_CreateNamedPipeW,CreateNamedPipeW,0 .imp kernel32,__imp_CreateNamedPipeW,CreateNamedPipeW,0
.text.windows .text.windows
CreateNamedPipe: __CreateNamedPipe:
push %rbp push %rbp
mov %rsp,%rbp mov %rsp,%rbp
.profilable .profilable
mov __imp_CreateNamedPipeW(%rip),%rax mov __imp_CreateNamedPipeW(%rip),%rax
jmp __sysv2nt8 jmp __sysv2nt8
.endfn CreateNamedPipe,globl .endfn __CreateNamedPipe,globl
.previous .previous

View file

@ -2,11 +2,11 @@
.imp kernel32,__imp_CreatePipe,CreatePipe,0 .imp kernel32,__imp_CreatePipe,CreatePipe,0
.text.windows .text.windows
CreatePipe: __CreatePipe:
push %rbp push %rbp
mov %rsp,%rbp mov %rsp,%rbp
.profilable .profilable
mov __imp_CreatePipe(%rip),%rax mov __imp_CreatePipe(%rip),%rax
jmp __sysv2nt jmp __sysv2nt
.endfn CreatePipe,globl .endfn __CreatePipe,globl
.previous .previous

View file

@ -2,7 +2,7 @@
.imp kernel32,__imp_FlushFileBuffers,FlushFileBuffers,0 .imp kernel32,__imp_FlushFileBuffers,FlushFileBuffers,0
.text.windows .text.windows
FlushFileBuffers: __FlushFileBuffers:
push %rbp push %rbp
mov %rsp,%rbp mov %rsp,%rbp
.profilable .profilable
@ -11,5 +11,5 @@ FlushFileBuffers:
call *__imp_FlushFileBuffers(%rip) call *__imp_FlushFileBuffers(%rip)
leave leave
ret ret
.endfn FlushFileBuffers,globl .endfn __FlushFileBuffers,globl
.previous .previous

View file

@ -2,11 +2,11 @@
.imp kernel32,__imp_FlushViewOfFile,FlushViewOfFile,0 .imp kernel32,__imp_FlushViewOfFile,FlushViewOfFile,0
.text.windows .text.windows
FlushViewOfFile: __FlushViewOfFile:
push %rbp push %rbp
mov %rsp,%rbp mov %rsp,%rbp
.profilable .profilable
mov __imp_FlushViewOfFile(%rip),%rax mov __imp_FlushViewOfFile(%rip),%rax
jmp __sysv2nt jmp __sysv2nt
.endfn FlushViewOfFile,globl .endfn __FlushViewOfFile,globl
.previous .previous

View file

@ -2,7 +2,7 @@
.imp kernel32,__imp_UnmapViewOfFile,UnmapViewOfFile,0 .imp kernel32,__imp_UnmapViewOfFile,UnmapViewOfFile,0
.text.windows .text.windows
UnmapViewOfFile: __UnmapViewOfFile:
push %rbp push %rbp
mov %rsp,%rbp mov %rsp,%rbp
.profilable .profilable
@ -11,5 +11,5 @@ UnmapViewOfFile:
call *__imp_UnmapViewOfFile(%rip) call *__imp_UnmapViewOfFile(%rip)
leave leave
ret ret
.endfn UnmapViewOfFile,globl .endfn __UnmapViewOfFile,globl
.previous .previous

View file

@ -0,0 +1,12 @@
.include "o/libc/nt/codegen.inc"
.imp kernel32,__imp_UnmapViewOfFile2,UnmapViewOfFile2,0
.text.windows
UnmapViewOfFile2:
push %rbp
mov %rsp,%rbp
.profilable
mov __imp_UnmapViewOfFile2(%rip),%rax
jmp __sysv2nt
.endfn UnmapViewOfFile2,globl
.previous

View file

@ -0,0 +1,12 @@
.include "o/libc/nt/codegen.inc"
.imp kernel32,__imp_UnmapViewOfFileEx,UnmapViewOfFileEx,0
.text.windows
UnmapViewOfFileEx:
push %rbp
mov %rsp,%rbp
.profilable
mov __imp_UnmapViewOfFileEx(%rip),%rax
jmp __sysv2nt
.endfn UnmapViewOfFileEx,globl
.previous

View file

@ -418,7 +418,7 @@ imp 'CloseEventLog' CloseEventLog advapi32 1102
imp 'CloseFigure' CloseFigure gdi32 1045 imp 'CloseFigure' CloseFigure gdi32 1045
imp 'CloseGestureInfoHandle' CloseGestureInfoHandle user32 1589 imp 'CloseGestureInfoHandle' CloseGestureInfoHandle user32 1589
imp 'CloseGlobalizationUserSettingsKey' CloseGlobalizationUserSettingsKey KernelBase 133 imp 'CloseGlobalizationUserSettingsKey' CloseGlobalizationUserSettingsKey KernelBase 133
imp 'CloseHandle' CloseHandle kernel32 0 1 # KernelBase imp '__CloseHandle' CloseHandle kernel32 0 1 # KernelBase
imp 'CloseMetaFile' CloseMetaFile gdi32 1046 imp 'CloseMetaFile' CloseMetaFile gdi32 1046
imp 'ClosePackageInfo' ClosePackageInfo kernel32 0 # KernelBase imp 'ClosePackageInfo' ClosePackageInfo kernel32 0 # KernelBase
imp 'ClosePrivateNamespace' ClosePrivateNamespace kernel32 0 # KernelBase imp 'ClosePrivateNamespace' ClosePrivateNamespace kernel32 0 # KernelBase
@ -624,7 +624,7 @@ imp 'CreateMutex' CreateMutexW kernel32 0 # KernelBase
imp 'CreateMutexA' CreateMutexA kernel32 0 # KernelBase imp 'CreateMutexA' CreateMutexA kernel32 0 # KernelBase
imp 'CreateMutexEx' CreateMutexExW kernel32 0 # KernelBase imp 'CreateMutexEx' CreateMutexExW kernel32 0 # KernelBase
imp 'CreateMutexExA' CreateMutexExA kernel32 0 # KernelBase imp 'CreateMutexExA' CreateMutexExA kernel32 0 # KernelBase
imp 'CreateNamedPipe' CreateNamedPipeW kernel32 0 8 # KernelBase imp '__CreateNamedPipe' CreateNamedPipeW kernel32 0 8 # KernelBase
imp 'CreateNamedPipeA' CreateNamedPipeA kernel32 219 8 imp 'CreateNamedPipeA' CreateNamedPipeA kernel32 219 8
imp 'CreateOPMProtectedOutput' CreateOPMProtectedOutput gdi32 1089 imp 'CreateOPMProtectedOutput' CreateOPMProtectedOutput gdi32 1089
imp 'CreateOPMProtectedOutputs' CreateOPMProtectedOutputs gdi32 1090 imp 'CreateOPMProtectedOutputs' CreateOPMProtectedOutputs gdi32 1090
@ -633,7 +633,7 @@ imp 'CreatePalmRejectionDelayZone' CreatePalmRejectionDelayZone user32 15
imp 'CreatePatternBrush' CreatePatternBrush gdi32 1092 imp 'CreatePatternBrush' CreatePatternBrush gdi32 1092
imp 'CreatePen' CreatePen gdi32 1093 imp 'CreatePen' CreatePen gdi32 1093
imp 'CreatePenIndirect' CreatePenIndirect gdi32 1094 imp 'CreatePenIndirect' CreatePenIndirect gdi32 1094
imp 'CreatePipe' CreatePipe kernel32 0 4 # KernelBase imp '__CreatePipe' CreatePipe kernel32 0 4 # KernelBase
imp 'CreatePolyPolygonRgn' CreatePolyPolygonRgn gdi32 1095 imp 'CreatePolyPolygonRgn' CreatePolyPolygonRgn gdi32 1095
imp 'CreatePolygonRgn' CreatePolygonRgn gdi32 1096 imp 'CreatePolygonRgn' CreatePolygonRgn gdi32 1096
imp 'CreatePopupMenu' CreatePopupMenu user32 1622 0 imp 'CreatePopupMenu' CreatePopupMenu user32 1622 0
@ -1677,11 +1677,11 @@ imp 'FlsGetValue' FlsGetValue kernel32 0 # KernelBase
imp 'FlsSetValue' FlsSetValue kernel32 0 # KernelBase imp 'FlsSetValue' FlsSetValue kernel32 0 # KernelBase
imp 'FlushConsoleInputBuffer' FlushConsoleInputBuffer kernel32 0 1 # KernelBase imp 'FlushConsoleInputBuffer' FlushConsoleInputBuffer kernel32 0 1 # KernelBase
imp 'FlushEfsCache' FlushEfsCache advapi32 1303 imp 'FlushEfsCache' FlushEfsCache advapi32 1303
imp 'FlushFileBuffers' FlushFileBuffers kernel32 0 1 # KernelBase imp '__FlushFileBuffers' FlushFileBuffers kernel32 0 1 # KernelBase
imp 'FlushInstructionCache' FlushInstructionCache kernel32 0 # KernelBase imp 'FlushInstructionCache' FlushInstructionCache kernel32 0 # KernelBase
imp 'FlushTraceA' FlushTraceA advapi32 1304 imp 'FlushTraceA' FlushTraceA advapi32 1304
imp 'FlushTrace' FlushTraceW advapi32 1305 imp 'FlushTrace' FlushTraceW advapi32 1305
imp 'FlushViewOfFile' FlushViewOfFile kernel32 0 2 # KernelBase imp '__FlushViewOfFile' FlushViewOfFile kernel32 0 2 # KernelBase
imp 'FoldStringA' FoldStringA kernel32 424 imp 'FoldStringA' FoldStringA kernel32 424
imp 'FoldString' FoldStringW kernel32 0 # KernelBase imp 'FoldString' FoldStringW kernel32 0 # KernelBase
imp 'FontIsLinked' FontIsLinked gdi32 1484 imp 'FontIsLinked' FontIsLinked gdi32 1484
@ -6714,9 +6714,9 @@ imp 'UnlockFile' UnlockFile kernel32 0 5 # KernelBase
imp 'UnlockFileEx' UnlockFileEx kernel32 0 5 # KernelBase imp 'UnlockFileEx' UnlockFileEx kernel32 0 5 # KernelBase
imp 'UnlockServiceDatabase' UnlockServiceDatabase advapi32 1820 imp 'UnlockServiceDatabase' UnlockServiceDatabase advapi32 1820
imp 'UnlockWindowStation' UnlockWindowStation user32 2456 imp 'UnlockWindowStation' UnlockWindowStation user32 2456
imp 'UnmapViewOfFile' UnmapViewOfFile kernel32 0 1 # KernelBase imp '__UnmapViewOfFile' UnmapViewOfFile kernel32 0 1 # KernelBase
imp 'UnmapViewOfFile2' UnmapViewOfFile2 KernelBase 1696 imp 'UnmapViewOfFile2' UnmapViewOfFile2 kernel32 0 2 # KernelBase
imp 'UnmapViewOfFileEx' UnmapViewOfFileEx KernelBase 1697 imp 'UnmapViewOfFileEx' UnmapViewOfFileEx kernel32 0 3 # KernelBase
imp 'UnpackDDElParam' UnpackDDElParam user32 2457 imp 'UnpackDDElParam' UnpackDDElParam user32 2457
imp 'UnrealizeObject' UnrealizeObject gdi32 1934 imp 'UnrealizeObject' UnrealizeObject gdi32 1934
imp 'UnregisterApplicationRecoveryCallback' UnregisterApplicationRecoveryCallback kernel32 1466 imp 'UnregisterApplicationRecoveryCallback' UnregisterApplicationRecoveryCallback kernel32 1466

View file

@ -1,8 +1,5 @@
#define CopyFile(...) __imp_CopyFileW(__VA_ARGS__) #define CopyFile(...) __imp_CopyFileW(__VA_ARGS__)
extern typeof(CopyFile) *const __imp_CopyFileW __msabi; extern typeof(CopyFile) *const __imp_CopyFileW __msabi;
#define FlushFileBuffers(...) __imp_FlushFileBuffers(__VA_ARGS__)
extern typeof(FlushFileBuffers) *const __imp_FlushFileBuffers __msabi;
#define GetFileType(...) __imp_GetFileType(__VA_ARGS__) #define GetFileType(...) __imp_GetFileType(__VA_ARGS__)
extern typeof(GetFileType) *const __imp_GetFileType __msabi; extern typeof(GetFileType) *const __imp_GetFileType __msabi;

View file

@ -1,6 +1 @@
#define FlushViewOfFile(...) __imp_FlushViewOfFile(__VA_ARGS__)
#define UnmapViewOfFile(...) __imp_UnmapViewOfFile(__VA_ARGS__)
extern typeof(LocalFree) *const __imp_LocalFree __msabi; extern typeof(LocalFree) *const __imp_LocalFree __msabi;
extern typeof(UnmapViewOfFile) *const __imp_UnmapViewOfFile __msabi;
extern typeof(FlushViewOfFile) *const __imp_FlushViewOfFile __msabi;

View file

@ -43,7 +43,7 @@ static bool have_getrandom;
/** /**
* Returns cryptographic random data. * Returns cryptographic random data.
* *
* This random number seed generator blends information from: * This random number seed generator obtains information from:
* *
* - getrandom() on Linux * - getrandom() on Linux
* - RtlGenRandom() on Windows * - RtlGenRandom() on Windows
@ -61,6 +61,9 @@ static bool have_getrandom;
* This function is safe to use with fork() and vfork(). It will also * This function is safe to use with fork() and vfork(). It will also
* close any file descriptor it ends up needing before it returns. * close any file descriptor it ends up needing before it returns.
* *
* @note this function could block a nontrivial time on old computers
* @note this function is indeed intended for cryptography
* @note this function takes around 900 cycles
* @asyncsignalsafe * @asyncsignalsafe
* @restartable * @restartable
* @vforksafe * @vforksafe

View file

@ -7,7 +7,7 @@ forceinline uint64_t KnuthLinearCongruentialGenerator(uint64_t prev[1]) {
Seminumerical Algorithms, Third Edition, Addison-Wesley, 1998, Seminumerical Algorithms, Third Edition, Addison-Wesley, 1998,
p. 106 (line 26) & p. 108 */ p. 106 (line 26) & p. 108 */
prev[0] = prev[0] * 6364136223846793005 + 1442695040888963407; prev[0] = prev[0] * 6364136223846793005 + 1442695040888963407;
return prev[0]; return prev[0]; /* be sure to shift! */
} }
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

45
libc/rand/lemur64.c Normal file
View file

@ -0,0 +1,45 @@
/*-*- 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 2022 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/rand/rand.h"
/**
* Returns linear congruential deterministic pseudorandom data, e.g.
*
* uint64_t x = lemur64();
*
* You can generate different types of numbers as follows:
*
* int64_t x = lemur64() >> 1; // make positive signed integer
* double x = _real1(lemur64()); // make float on [0,1]-interval
*
* If you want a fast pseudorandom number generator that seeds itself
* automatically on startup and fork() then consider rand64(). If you
* want true random data then consider rdseed, rdrand, and getrandom.
*
* @return 64 bits of pseudorandom data
* @note this is Lemire's Lehmer generator
* @note this function takes at minimum 1 cycle
* @note this function passes bigcrush and practrand
* @note this function is not intended for cryptography
* @see rand64(), rngset(), _real1(), _real2(), _real3()
*/
uint64_t lemur64(void) {
static uint128_t s = 2131259787901769494;
return (s *= 15750249268501108917ull) >> 64;
}

View file

@ -21,11 +21,18 @@
#include "libc/rand/rand.h" #include "libc/rand/rand.h"
/** /**
* Returns 31-bit random number using a linear congruential generator. * Returns 31-bit linear congruential pseudorandom number, e.g.
* *
* Please note that, unlike rand32(), the rand() function uses the same * int x = rand();
* seed at startup by default, unless srand() is called. This makes it * assert(x >= 0);
* useful in cases where deterministic behavior is needed. *
* This function always returns a positive number. If srand() isn't
* called, then it'll return the same sequence each time your program
* runs. Faster and more modern alternatives exist to this function.
*
* @note this function does well on bigcrush and practrand
* @note this function is not intended for cryptography
* @see lemur64(), rand64(), rdrand()
*/ */
int rand(void) { int rand(void) {
return KnuthLinearCongruentialGenerator(&g_rando) >> 33; return KnuthLinearCongruentialGenerator(&g_rando) >> 33;

View file

@ -23,12 +23,13 @@ char *setstate(char *);
long random(void); long random(void);
void srandom(unsigned); void srandom(unsigned);
uint64_t lemur64(void);
uint64_t rand64(void);
uint64_t vigna(void); uint64_t vigna(void);
uint64_t vigna_r(uint64_t[hasatleast 1]); uint64_t vigna_r(uint64_t[hasatleast 1]);
void svigna(uint64_t); void svigna(uint64_t);
uint64_t rdrand(void); uint64_t rdrand(void);
uint64_t rdseed(void); uint64_t rdseed(void);
uint64_t rand64(void);
void _smt19937(uint64_t); void _smt19937(uint64_t);
void _Smt19937(uint64_t[], size_t); void _Smt19937(uint64_t[], size_t);
uint64_t _mt19937(void); uint64_t _mt19937(void);

View file

@ -16,59 +16,80 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/assert.h"
#include "libc/bits/bits.h" #include "libc/bits/bits.h"
#include "libc/bits/xadd.h" #include "libc/bits/lockcmpxchg16b.internal.h"
#include "libc/bits/lockxadd.internal.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/intrin/kprintf.h"
#include "libc/nexgen32e/rdtsc.h" #include "libc/nexgen32e/rdtsc.h"
#include "libc/nexgen32e/x86feature.h" #include "libc/nt/thread.h"
#include "libc/rand/rand.h" #include "libc/rand/rand.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/sysv/consts/auxv.h" #include "libc/sysv/consts/auxv.h"
#include "libc/thread/create.h"
static uint64_t thepool; extern int __pid;
static int thepid;
static int thecount;
static uint128_t thepool;
/** /**
* Returns nondeterministic random data. * Returns nondeterministic random data.
* *
* This function automatically seeds itself on startup and reseeds * This function is similar to lemur64() except it'thepool intended to
* itself after fork() and vfork(). It takes about nanosecond to run. * be unpredictable. This PRNG automatically seeds itself on startup
* That makes it much slower than vigna() and rand() but much faster * using a much stronger and faster random source than `srand(time(0))`.
* than rdrand() and rdseed(). * This function will automatically reseed itself when new processes and
* threads are spawned. This function is thread safe in the sense that a
* race condition can't happen where two threads return the same result.
* *
* @see rdseed(), rdrand(), rand(), random(), rngset() * @see rdseed(), rdrand(), rand(), random(), rngset()
* @note based on vigna's algorithm * @note this function is not intended for cryptography
* @note this function passes bigcrush and practrand
* @note this function takes at minimum 30 cycles
* @asyncsignalsafe * @asyncsignalsafe
* @threadsafe
* @vforksafe * @vforksafe
*/ */
uint64_t rand64(void) { uint64_t rand64(void) {
bool cf; void *d;
register uint64_t t; int c1, p1, p2;
if (X86_HAVE(RDSEED)) { uint128_t s1, s2;
asm volatile(CFLAG_ASM("rdseed\t%1") do {
: CFLAG_CONSTRAINT(cf), "=r"(t) p1 = __pid;
: /* no inputs */ p2 = thepid;
: "cc"); c1 = thecount;
if (cf) { asm volatile("" ::: "memory");
thepool ^= t; s1 = thepool;
return t; if (p1 == p2) {
// fast path
s2 = s1;
} else {
// slow path
if (!p2) {
// first call so get some cheap entropy
if ((d = (void *)getauxval(AT_RANDOM))) {
memcpy(&s2, d, 16); // kernel entropy
} else {
s2 = kStartTsc; // rdtsc() @ _start()
}
} else {
// process contention so blend a timestamp
s2 = s1 ^ rdtsc();
}
// toss the new pid in there
s2 ^= p1;
// ordering for thepid probably doesn't matter
thepid = p1;
} }
} // lemur64 pseudorandom number generator
t = _xadd(&thepool, 0x9e3779b97f4a7c15); s2 *= 15750249268501108917ull;
t ^= (getpid() * 0x1001111111110001ull + 0xdeaadead) >> 31; // sadly 128-bit values aren't atomic on x86
t = (t ^ (t >> 30)) * 0xbf58476d1ce4e5b9; _lockcmpxchg16b(&thepool, &s1, s2);
t = (t ^ (t >> 27)) * 0x94d049bb133111eb; // do it again if there's thread contention
return t ^ (t >> 31); } while (_lockxadd(&thecount, 1) != c1);
// the most important step in the prng
return s2 >> 64;
} }
static textstartup void rand64_init(int argc, char **argv, char **envp,
intptr_t *auxv) {
for (; auxv[0]; auxv += 2) {
if (auxv[0] == AT_RANDOM) {
thepool = READ64LE((const char *)auxv[1]);
return;
}
}
thepool = kStartTsc;
}
const void *const g_rand64_init[] initarray = {rand64_init};

View file

@ -55,9 +55,12 @@ static dontinline uint64_t rdrand_failover(void) {
* aren't available then we try /dev/urandom and if that fails, we try * aren't available then we try /dev/urandom and if that fails, we try
* getauxval(AT_RANDOM), and if not we finally use RDTSC and getpid(). * getauxval(AT_RANDOM), and if not we finally use RDTSC and getpid().
* *
* This function takes between 10 nanoseconds to several microseconds. * @note this function could block a nontrivial time on old computers
* * @note this function is indeed intended for cryptography
* @note this function takes around 300 cycles
* @see rngset(), rdseed(), rand64() * @see rngset(), rdseed(), rand64()
* @asyncsignalsafe
* @vforksafe
*/ */
uint64_t rdrand(void) { uint64_t rdrand(void) {
int i; int i;

View file

@ -31,9 +31,12 @@
* sysctl(KERN_ARND). If those aren't available then we try /dev/urandom * sysctl(KERN_ARND). If those aren't available then we try /dev/urandom
* and if that fails, we use RDTSC and getpid(). * and if that fails, we use RDTSC and getpid().
* *
* This function takes about 32 nanoseconds. * @note this function could block a nontrivial time on old computers
* * @note this function is indeed intended for cryptography
* @note this function takes around 800 cycles
* @see rngset(), rdrand(), rand64() * @see rngset(), rdrand(), rand64()
* @asyncsignalsafe
* @vforksafe
*/ */
uint64_t rdseed(void) { uint64_t rdseed(void) {
int i; int i;

View file

@ -21,9 +21,9 @@
/** /**
* Generates number on [0,1]-real-interval, e.g. * Generates number on [0,1]-real-interval, e.g.
* *
* double x = _real1(vigna()) * double x = _real1(lemur64())
* *
* @see vigna(), mt19937() * @see lemur64(), mt19937()
*/ */
double _real1(uint64_t x) { double _real1(uint64_t x) {
return 1. / 9007199254740991. * (x >> 11); return 1. / 9007199254740991. * (x >> 11);

View file

@ -21,9 +21,9 @@
/** /**
* Generates number on [0,1)-real-interval, e.g. * Generates number on [0,1)-real-interval, e.g.
* *
* double x = _real2(vigna()) * double x = _real2(lemur64())
* *
* @see vigna(), mt19937() * @see lemur64(), mt19937()
*/ */
double _real2(uint64_t x) { double _real2(uint64_t x) {
return 1. / 9007199254740992. * (x >> 11); return 1. / 9007199254740992. * (x >> 11);

View file

@ -21,9 +21,9 @@
/** /**
* Generates number on (0,1)-real-interval, e.g. * Generates number on (0,1)-real-interval, e.g.
* *
* double x = _real3(vigna()) * double x = _real3(lemur64())
* *
* @see vigna(), mt19937() * @see lemur64(), mt19937()
*/ */
double _real3(uint64_t x) { double _real3(uint64_t x) {
return 1. / 4503599627370496. * ((x >> 12) + .5); return 1. / 4503599627370496. * ((x >> 12) + .5);

View file

@ -16,7 +16,6 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/bits/xadd.h"
#include "libc/rand/rand.h" #include "libc/rand/rand.h"
static uint64_t g_vigna; static uint64_t g_vigna;
@ -40,9 +39,8 @@ static uint64_t g_vigna;
* static uint64_t s = 0; * static uint64_t s = 0;
* uint64_t x = svigna_r(&s); * uint64_t x = svigna_r(&s);
* *
* This function is the fastest way to generate good scalar pseudorandom * If you want to fill a buffer with data then rngset() implements
* numbers that aren't truncated. If you want to fill a buffer with data * vigna's algorithm to do that extremely well:
* then rngset() implements vigna's algorithm to do that extremely well:
* *
* char buf[4096]; * char buf[4096];
* rngset(buf, sizeof(buf), vigna, 0); * rngset(buf, sizeof(buf), vigna, 0);
@ -52,6 +50,9 @@ static uint64_t g_vigna;
* want true random data then consider rdseed, rdrand, and getrandom. * want true random data then consider rdseed, rdrand, and getrandom.
* *
* @return 64 bits of pseudorandom data * @return 64 bits of pseudorandom data
* @note this function is not intended for cryptography
* @note this function passes bigcrush and practrand
* @note this function takes at minimum 4 cycles
*/ */
uint64_t vigna(void) { uint64_t vigna(void) {
return vigna_r(&g_vigna); return vigna_r(&g_vigna);

View file

@ -29,7 +29,9 @@ textwindows wontreturn void sys_abort_nt(void) {
info.si_signo = SIGABRT; info.si_signo = SIGABRT;
rva = __sighandrvas[SIGABRT]; rva = __sighandrvas[SIGABRT];
if (rva >= kSigactionMinRva) { if (rva >= kSigactionMinRva) {
((sigaction_f)(_base + rva))(SIGABRT, &info, NULL); if (((sigaction_f)(_base + rva))) {
((sigaction_f)(_base + rva))(SIGABRT, &info, NULL);
}
} }
_Exit(128 + SIGABRT); _Exit(128 + SIGABRT);
} }

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/nexgen32e/nt2sysv.h" #include "libc/nexgen32e/nt2sysv.h"
#include "libc/nexgen32e/stackframe.h" #include "libc/nexgen32e/stackframe.h"
@ -24,6 +25,8 @@
#include "libc/nt/thread.h" #include "libc/nt/thread.h"
#include "libc/sysv/consts/clone.h" #include "libc/sysv/consts/clone.h"
#include "libc/sysv/consts/nr.h" #include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
struct WinThread { struct WinThread {
@ -32,7 +35,7 @@ struct WinThread {
void *stack; void *stack;
}; };
static noasan textwindows uint32_t winthread(void *param) { static noasan textwindows uint32_t WinThreadMain(void *param) {
struct WinThread *wt = param; struct WinThread *wt = param;
asm volatile("mov\t%%rbp,%%r14\n\t" asm volatile("mov\t%%rbp,%%r14\n\t"
"mov\t%%rsp,%%r15\n\t" "mov\t%%rsp,%%r15\n\t"
@ -50,15 +53,19 @@ static noasan textwindows uint32_t winthread(void *param) {
/** /**
* Creates thread. * Creates thread.
* *
* @note CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND creates thread * @param flags usually has one of
* @note CLONE_VFORK|CLONE_VM|SIGCHLD does vfork() * - `CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND` for threads
* @note SIGCHLD does fork() * - `CLONE_VFORK|CLONE_VM|SIGCHLD` for vfork()
* - `SIGCHLD` for fork()
* as part high bytes, and the low order byte may optionally contain
* a signal e.g. SIGCHLD, to enable parent notification on terminate
*/ */
privileged int clone(int (*f)(void *), void *stack, int flags, void *arg, ...) { privileged int clone(int (*f)(void *), void *stack, int flags, void *arg, ...) {
int64_t h; int tidfd;
va_list va; va_list va;
intptr_t ax; intptr_t ax;
uint32_t tid; uint32_t tid;
int64_t hand;
int32_t *ptid; int32_t *ptid;
register void *tls asm("r8"); register void *tls asm("r8");
register int32_t *ctid asm("r10"); register int32_t *ctid asm("r10");
@ -90,11 +97,16 @@ privileged int clone(int (*f)(void *), void *stack, int flags, void *arg, ...) {
: "memory"); : "memory");
unreachable; unreachable;
} else if (IsWindows()) { } else if (IsWindows()) {
if (flags == (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND)) { if ((tidfd = __reservefd()) == -1) return -1;
if ((h = CreateThread(0, PAGESIZE, NT2SYSV(winthread), if (flags == CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND) {
&(struct WinThread){f, arg, stack}, 0, &tid))) { if ((hand = CreateThread(&kNtIsInheritable, 0, NT2SYSV(WinThreadMain),
CloseHandle(h); &(struct WinThread){f, arg, stack}, 0, &tid))) {
return tid; // XXX: this should be tracked in a separate data structure
g_fds.p[tidfd].kind = kFdProcess;
g_fds.p[tidfd].handle = hand;
g_fds.p[tidfd].flags = O_CLOEXEC;
g_fds.p[tidfd].zombie = false;
return tidfd;
} else { } else {
return -1; return -1;
} }

View file

@ -3,6 +3,11 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
struct ProtectNt {
uint32_t flags1;
uint32_t flags2;
};
struct DirectMap { struct DirectMap {
void *addr; void *addr;
int64_t maphandle; int64_t maphandle;
@ -12,6 +17,8 @@ struct DirectMap sys_mmap(void *, size_t, int, int, int, int64_t);
struct DirectMap sys_mmap_nt(void *, size_t, int, int, int64_t, int64_t); struct DirectMap sys_mmap_nt(void *, size_t, int, int, int64_t, int64_t);
struct DirectMap sys_mmap_metal(void *, size_t, int, int, int, int64_t); struct DirectMap sys_mmap_metal(void *, size_t, int, int, int, int64_t);
int sys_munmap_metal(void *, size_t); int sys_munmap_metal(void *, size_t);
uint32_t __prot2nt(int, int);
struct ProtectNt __nt2prot(int);
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -177,23 +177,8 @@ textwindows void WinMainForked(void) {
} }
} else { } else {
// we can however safely inherit MAP_SHARED with zero copy // we can however safely inherit MAP_SHARED with zero copy
if (maps[i].prot & PROT_WRITE) { if (!MapViewOfFileEx(maps[i].h, __nt2prot(maps[i].prot).flags2,
if (maps[i].prot & PROT_EXEC) { maps[i].offset >> 32, maps[i].offset, size, addr)) {
flags2 = kNtFileMapWrite | kNtFileMapExecute;
} else {
flags2 = kNtFileMapWrite;
}
} else if (maps[i].prot & PROT_READ) {
if (maps[i].prot & PROT_EXEC) {
flags2 = kNtFileMapRead | kNtFileMapExecute;
} else {
flags2 = kNtFileMapRead;
}
} else {
flags2 = 0;
}
if (!MapViewOfFileEx(maps[i].h, flags2, maps[i].offset >> 32,
maps[i].offset, size, addr)) {
ExitProcess(45); ExitProcess(45);
} }
} }
@ -216,29 +201,14 @@ textwindows void WinMainForked(void) {
_mmi.n = specialz / sizeof(_mmi.p[0]); _mmi.n = specialz / sizeof(_mmi.p[0]);
for (i = 0; i < mapcount; ++i) { for (i = 0; i < mapcount; ++i) {
if ((maps[i].flags & MAP_PRIVATE) && (~maps[i].prot & PROT_WRITE)) { if ((maps[i].flags & MAP_PRIVATE) && (~maps[i].prot & PROT_WRITE)) {
if (maps[i].prot & PROT_WRITE) {
if (maps[i].prot & PROT_EXEC) {
flags1 = kNtPageExecuteReadwrite;
} else {
flags1 = kNtPageReadwrite;
}
} else if (maps[i].prot & PROT_READ) {
if (maps[i].prot & PROT_EXEC) {
flags1 = kNtPageExecuteRead;
} else {
flags1 = kNtPageReadonly;
}
} else {
flags1 = kNtPageNoaccess;
}
VirtualProtect((void *)((uint64_t)maps[i].x << 16), VirtualProtect((void *)((uint64_t)maps[i].x << 16),
ROUNDUP(maps[i].size, FRAMESIZE), flags1, &oldprot); ROUNDUP(maps[i].size, FRAMESIZE),
__nt2prot(maps[i].prot).flags1, &oldprot);
} }
} }
// we're all done reading! // we're all done reading!
if (!CloseHandle(reader)) { if (!CloseHandle(reader)) {
STRACE("CloseHandle(reader) failed %m");
ExitProcess(47); ExitProcess(47);
} }
@ -309,7 +279,6 @@ textwindows int sys_fork_nt(void) {
if (ok) ok = WriteAll(writer, __bss_start, __bss_end - __bss_start); if (ok) ok = WriteAll(writer, __bss_start, __bss_end - __bss_start);
if (ok) { if (ok) {
if (!CloseHandle(writer)) { if (!CloseHandle(writer)) {
STRACE("CloseHandle(writer) failed %m");
ok = false; ok = false;
} }
} }
@ -332,7 +301,7 @@ textwindows int sys_fork_nt(void) {
} }
} else { } else {
STRACE("CreatePipe() failed %m"); STRACE("CreatePipe() failed %m");
rc = __winerr(); rc = -1;
CloseHandle(writer); CloseHandle(writer);
} }
} else { } else {

View file

@ -37,11 +37,7 @@ noasan void ReleaseMemoryNt(struct MemoryIntervals *mm, int l, int r) {
for (i = l; i <= r; ++i) { for (i = l; i <= r; ++i) {
addr = GetFrameAddr(mm->p[i].x); addr = GetFrameAddr(mm->p[i].x);
last = GetFrameAddr(mm->p[i].y); last = GetFrameAddr(mm->p[i].y);
STRACE("UnmapViewOfFile(%p, size:%'zu, hand:%ld)", addr, UnmapViewOfFile(addr);
last - addr + FRAMESIZE, mm->p[i].h); CloseHandle(mm->p[i].h);
ok = UnmapViewOfFile(addr);
assert(ok);
ok = CloseHandle(mm->p[i].h);
assert(ok);
} }
} }

View file

@ -17,22 +17,40 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/nt/files.h" #include "libc/nt/files.h"
#include "libc/nt/memory.h" #include "libc/nt/memory.h"
#include "libc/runtime/memtrack.internal.h" #include "libc/runtime/memtrack.internal.h"
#include "libc/sysv/consts/msync.h"
noasan textwindows int sys_msync_nt(void *addr, size_t size, int flags) { #define ADDR(x) ((char *)((int64_t)((uint64_t)(x) << 32) >> 16))
int x, y, l, r, i;
x = ROUNDDOWN((intptr_t)addr, FRAMESIZE) >> 16; noasan textwindows int sys_msync_nt(char *addr, size_t size, int flags) {
y = ROUNDDOWN((intptr_t)addr + size - 1, FRAMESIZE) >> 16; char *a, *b;
for (i = FindMemoryInterval(&_mmi, x); i < _mmi.i; ++i) { int rc, x, y, l, r, i;
if ((x >= _mmi.p[i].x && x <= _mmi.p[i].y) || rc = 0;
(y >= _mmi.p[i].x && y <= _mmi.p[i].y)) { for (i = FindMemoryInterval(&_mmi, (intptr_t)addr >> 16); i < _mmi.i; ++i) {
FlushFileBuffers(_mmi.p[i].h); if ((ADDR(_mmi.p[i].x) <= addr && addr < ADDR(_mmi.p[i].y + 1)) ||
(ADDR(_mmi.p[i].x) < addr + size &&
addr + size <= ADDR(_mmi.p[i].y + 1)) ||
(addr < ADDR(_mmi.p[i].x) && ADDR(_mmi.p[i].y + 1) < addr + size)) {
a = MIN(MAX(addr, ADDR(_mmi.p[i].x)), ADDR(_mmi.p[i].y + 1));
b = MAX(MIN(addr + size, ADDR(_mmi.p[i].y + 1)), ADDR(_mmi.p[i].x));
if (!FlushViewOfFile(a, b - a)) {
rc = -1;
break;
}
if (flags & MS_SYNC) {
if (!FlushFileBuffers(_mmi.p[i].h)) {
// TODO(jart): what's up with this?
// rc = -1;
// break;
}
}
} else { } else {
break; break;
} }
} }
return 0; return rc;
} }

View file

@ -59,7 +59,6 @@ textwindows int sys_socketpair_nt(int family, int type, int proto, int sv[2]) {
} }
if ((hpipe = CreateNamedPipe(pipename, kNtPipeAccessDuplex, mode, 1, 65536, if ((hpipe = CreateNamedPipe(pipename, kNtPipeAccessDuplex, mode, 1, 65536,
65536, 0, &kNtIsInheritable)) == -1) { 65536, 0, &kNtIsInheritable)) == -1) {
__winerr();
__releasefd(writer); __releasefd(writer);
__releasefd(reader); __releasefd(reader);
return -1; return -1;

View file

@ -909,6 +909,14 @@ syscon ptrace PTRACE_EVENT_EXEC 4 -1 -1 -1 -1 -1
syscon ptrace PTRACE_EVENT_VFORK_DONE 5 -1 -1 -1 -1 -1 syscon ptrace PTRACE_EVENT_VFORK_DONE 5 -1 -1 -1 -1 -1
syscon ptrace PTRACE_EVENT_EXIT 6 -1 -1 -1 -1 -1 syscon ptrace PTRACE_EVENT_EXIT 6 -1 -1 -1 -1 -1
# clone() codes
#
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
syscon clone CLONE_VM 0x00000100 0x00000100 0x00000100 0x00000100 0x00000100 0x00000100 # intentionally symbolic so we can tell if clone() is being used to create threads
# IPPROTO_*
#
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
syscon iproto IPPROTO_IP 0 0 0 0 0 0 # consensus syscon iproto IPPROTO_IP 0 0 0 0 0 0 # consensus
syscon iproto IPPROTO_ICMP 1 1 1 1 1 1 # consensus syscon iproto IPPROTO_ICMP 1 1 1 1 1 1 # consensus
syscon iproto IPPROTO_TCP 6 6 6 6 6 6 # consensus syscon iproto IPPROTO_TCP 6 6 6 6 6 6 # consensus

View file

@ -0,0 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon clone,CLONE_VM,0x00000100,0x00000100,0x00000100,0x00000100,0x00000100,0x00000100

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h" #include "libc/sysv/consts/syscon.internal.h"
.syscon nr,__NR_sigprocmask,0x000e,0x2000030,0x0154,0x0030,0x125,0xfff .syscon nr,__NR_sigprocmask,0x000e,0x2000149,0x0154,0x0030,0x125,0xfff

View file

@ -1,9 +1,15 @@
#ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_CLONE_H_ #ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_CLONE_H_
#define COSMOPOLITAN_LIBC_SYSV_CONSTS_CLONE_H_ #define COSMOPOLITAN_LIBC_SYSV_CONSTS_CLONE_H_
#include "libc/runtime/symbolic.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
#define CLONE_VM 0x00000100 extern const long CLONE_VM;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#define CLONE_VM SYMBOLIC(CLONE_VM)
#define CLONE_FS 0x00000200 #define CLONE_FS 0x00000200
#define CLONE_FILES 0x00000400 #define CLONE_FILES 0x00000400
#define CLONE_SIGHAND 0x00000800 #define CLONE_SIGHAND 0x00000800
@ -21,6 +27,4 @@ COSMOPOLITAN_C_START_
#define CLONE_CHILD_SETTID 0x01000000 #define CLONE_CHILD_SETTID 0x01000000
#define CLONE_STOPPED 0x02000000 #define CLONE_STOPPED 0x02000000
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_CLONE_H_ */ #endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_CLONE_H_ */

View file

@ -42,7 +42,7 @@
*/ */
static uint64_t Rando(void) { static uint64_t Rando(void) {
uint64_t x; uint64_t x;
do x = vigna(); do x = lemur64();
while (((x ^ READ64LE("!!!!!!!!")) - 0x0101010101010101) & while (((x ^ READ64LE("!!!!!!!!")) - 0x0101010101010101) &
~(x ^ READ64LE("!!!!!!!!")) & 0x8080808080808080); ~(x ^ READ64LE("!!!!!!!!")) & 0x8080808080808080);
return x; return x;
@ -225,7 +225,7 @@ TEST(ksnprintf, fuzzTheUnbreakable) {
x = Rando(); x = Rando();
memcpy(f + 8, &x, sizeof(x)); memcpy(f + 8, &x, sizeof(x));
f[Rando() & 15] = '%'; f[Rando() & 15] = '%';
ksnprintf(b, sizeof(b), f, vigna(), vigna(), vigna()); ksnprintf(b, sizeof(b), f, lemur64(), lemur64(), lemur64());
} }
EXPECT_SYS(0, 0, mprotect(f, PAGESIZE, PROT_READ)); EXPECT_SYS(0, 0, mprotect(f, PAGESIZE, PROT_READ));
} }

View file

@ -121,17 +121,17 @@ BENCH(bcmp, bench) {
EZBENCH_N("bcmp", 256, v = buncmp(a, b, 256)); EZBENCH_N("bcmp", 256, v = buncmp(a, b, 256));
a = gc(malloc(16 * 1024)); a = gc(malloc(16 * 1024));
b = gc(malloc(16 * 1024)); b = gc(malloc(16 * 1024));
rngset(a, 16 * 1024, vigna, -1); rngset(a, 16 * 1024, lemur64, -1);
memcpy(b, a, 16 * 1024); memcpy(b, a, 16 * 1024);
EZBENCH_N("bcmp", 16384, v = buncmp(a, b, 16384)); EZBENCH_N("bcmp", 16384, v = buncmp(a, b, 16384));
a = gc(malloc(32 * 1024)); a = gc(malloc(32 * 1024));
b = gc(malloc(32 * 1024)); b = gc(malloc(32 * 1024));
rngset(a, 32 * 1024, vigna, -1); rngset(a, 32 * 1024, lemur64, -1);
memcpy(b, a, 32 * 1024); memcpy(b, a, 32 * 1024);
EZBENCH_N("bcmp", 32768, v = buncmp(a, b, 32768)); EZBENCH_N("bcmp", 32768, v = buncmp(a, b, 32768));
a = gc(malloc(128 * 1024)); a = gc(malloc(128 * 1024));
b = gc(malloc(128 * 1024)); b = gc(malloc(128 * 1024));
rngset(a, 128 * 1024, vigna, -1); rngset(a, 128 * 1024, lemur64, -1);
memcpy(b, a, 128 * 1024); memcpy(b, a, 128 * 1024);
EZBENCH_N("bcmp", 131072, v = buncmp(a, b, 131072)); EZBENCH_N("bcmp", 131072, v = buncmp(a, b, 131072));
} }
@ -166,17 +166,17 @@ BENCH(memcmp, bench) {
EZBENCH_N("memcmp", 256, v = funcmp(a, b, 256)); EZBENCH_N("memcmp", 256, v = funcmp(a, b, 256));
a = gc(malloc(16 * 1024)); a = gc(malloc(16 * 1024));
b = gc(malloc(16 * 1024)); b = gc(malloc(16 * 1024));
rngset(a, 16 * 1024, vigna, -1); rngset(a, 16 * 1024, lemur64, -1);
memcpy(b, a, 16 * 1024); memcpy(b, a, 16 * 1024);
EZBENCH_N("memcmp", 16384, v = funcmp(a, b, 16384)); EZBENCH_N("memcmp", 16384, v = funcmp(a, b, 16384));
a = gc(malloc(32 * 1024)); a = gc(malloc(32 * 1024));
b = gc(malloc(32 * 1024)); b = gc(malloc(32 * 1024));
rngset(a, 32 * 1024, vigna, -1); rngset(a, 32 * 1024, lemur64, -1);
memcpy(b, a, 32 * 1024); memcpy(b, a, 32 * 1024);
EZBENCH_N("memcmp", 32768, v = funcmp(a, b, 32768)); EZBENCH_N("memcmp", 32768, v = funcmp(a, b, 32768));
a = gc(malloc(128 * 1024)); a = gc(malloc(128 * 1024));
b = gc(malloc(128 * 1024)); b = gc(malloc(128 * 1024));
rngset(a, 128 * 1024, vigna, -1); rngset(a, 128 * 1024, lemur64, -1);
memcpy(b, a, 128 * 1024); memcpy(b, a, 128 * 1024);
EZBENCH_N("memcmp", 131072, v = funcmp(a, b, 131072)); EZBENCH_N("memcmp", 131072, v = funcmp(a, b, 131072));
} }
@ -211,17 +211,17 @@ BENCH(timingsafe_memcmp, bench) {
EZBENCH_N("timingsafe_memcmp", 256, v = timingsafe_memcmp(a, b, 256)); EZBENCH_N("timingsafe_memcmp", 256, v = timingsafe_memcmp(a, b, 256));
a = gc(malloc(16 * 1024)); a = gc(malloc(16 * 1024));
b = gc(malloc(16 * 1024)); b = gc(malloc(16 * 1024));
rngset(a, 16 * 1024, vigna, -1); rngset(a, 16 * 1024, lemur64, -1);
memcpy(b, a, 16 * 1024); memcpy(b, a, 16 * 1024);
EZBENCH_N("timingsafe_memcmp", 16384, v = timingsafe_memcmp(a, b, 16384)); EZBENCH_N("timingsafe_memcmp", 16384, v = timingsafe_memcmp(a, b, 16384));
a = gc(malloc(32 * 1024)); a = gc(malloc(32 * 1024));
b = gc(malloc(32 * 1024)); b = gc(malloc(32 * 1024));
rngset(a, 32 * 1024, vigna, -1); rngset(a, 32 * 1024, lemur64, -1);
memcpy(b, a, 32 * 1024); memcpy(b, a, 32 * 1024);
EZBENCH_N("timingsafe_memcmp", 32768, v = timingsafe_memcmp(a, b, 32768)); EZBENCH_N("timingsafe_memcmp", 32768, v = timingsafe_memcmp(a, b, 32768));
a = gc(malloc(128 * 1024)); a = gc(malloc(128 * 1024));
b = gc(malloc(128 * 1024)); b = gc(malloc(128 * 1024));
rngset(a, 128 * 1024, vigna, -1); rngset(a, 128 * 1024, lemur64, -1);
memcpy(b, a, 128 * 1024); memcpy(b, a, 128 * 1024);
EZBENCH_N("timingsafe_memcmp", 131072, v = timingsafe_memcmp(a, b, 131072)); EZBENCH_N("timingsafe_memcmp", 131072, v = timingsafe_memcmp(a, b, 131072));
} }
@ -256,17 +256,17 @@ BENCH(timingsafe_bcmp, bench) {
EZBENCH_N("timingsafe_bcmp", 256, v = timingsafe_bcmp(a, b, 256)); EZBENCH_N("timingsafe_bcmp", 256, v = timingsafe_bcmp(a, b, 256));
a = gc(malloc(16 * 1024)); a = gc(malloc(16 * 1024));
b = gc(malloc(16 * 1024)); b = gc(malloc(16 * 1024));
rngset(a, 16 * 1024, vigna, -1); rngset(a, 16 * 1024, lemur64, -1);
memcpy(b, a, 16 * 1024); memcpy(b, a, 16 * 1024);
EZBENCH_N("timingsafe_bcmp", 16384, v = timingsafe_bcmp(a, b, 16384)); EZBENCH_N("timingsafe_bcmp", 16384, v = timingsafe_bcmp(a, b, 16384));
a = gc(malloc(32 * 1024)); a = gc(malloc(32 * 1024));
b = gc(malloc(32 * 1024)); b = gc(malloc(32 * 1024));
rngset(a, 32 * 1024, vigna, -1); rngset(a, 32 * 1024, lemur64, -1);
memcpy(b, a, 32 * 1024); memcpy(b, a, 32 * 1024);
EZBENCH_N("timingsafe_bcmp", 32768, v = timingsafe_bcmp(a, b, 32768)); EZBENCH_N("timingsafe_bcmp", 32768, v = timingsafe_bcmp(a, b, 32768));
a = gc(malloc(128 * 1024)); a = gc(malloc(128 * 1024));
b = gc(malloc(128 * 1024)); b = gc(malloc(128 * 1024));
rngset(a, 128 * 1024, vigna, -1); rngset(a, 128 * 1024, lemur64, -1);
memcpy(b, a, 128 * 1024); memcpy(b, a, 128 * 1024);
EZBENCH_N("timingsafe_bcmp", 131072, v = timingsafe_bcmp(a, b, 131072)); EZBENCH_N("timingsafe_bcmp", 131072, v = timingsafe_bcmp(a, b, 131072));
} }
@ -301,17 +301,17 @@ BENCH(memcasecmp, bench) {
EZBENCH_N("memcasecmp", 256, v = memcasecmp(a, b, 256)); EZBENCH_N("memcasecmp", 256, v = memcasecmp(a, b, 256));
a = gc(malloc(16 * 1024)); a = gc(malloc(16 * 1024));
b = gc(malloc(16 * 1024)); b = gc(malloc(16 * 1024));
rngset(a, 16 * 1024, vigna, -1); rngset(a, 16 * 1024, lemur64, -1);
memcpy(b, a, 16 * 1024); memcpy(b, a, 16 * 1024);
EZBENCH_N("memcasecmp", 16384, v = memcasecmp(a, b, 16384)); EZBENCH_N("memcasecmp", 16384, v = memcasecmp(a, b, 16384));
a = gc(malloc(32 * 1024)); a = gc(malloc(32 * 1024));
b = gc(malloc(32 * 1024)); b = gc(malloc(32 * 1024));
rngset(a, 32 * 1024, vigna, -1); rngset(a, 32 * 1024, lemur64, -1);
memcpy(b, a, 32 * 1024); memcpy(b, a, 32 * 1024);
EZBENCH_N("memcasecmp", 32768, v = memcasecmp(a, b, 32768)); EZBENCH_N("memcasecmp", 32768, v = memcasecmp(a, b, 32768));
a = gc(malloc(128 * 1024)); a = gc(malloc(128 * 1024));
b = gc(malloc(128 * 1024)); b = gc(malloc(128 * 1024));
rngset(a, 128 * 1024, vigna, -1); rngset(a, 128 * 1024, lemur64, -1);
memcpy(b, a, 128 * 1024); memcpy(b, a, 128 * 1024);
EZBENCH_N("memcasecmp", 131072, v = memcasecmp(a, b, 131072)); EZBENCH_N("memcasecmp", 131072, v = memcasecmp(a, b, 131072));
} }
@ -320,7 +320,7 @@ BENCH(timingsafe_memcmp, demonstration) {
int bcmp_(const void *, const void *, size_t) asm("bcmp"); int bcmp_(const void *, const void *, size_t) asm("bcmp");
int memcmp_(const void *, const void *, size_t) asm("memcmp"); int memcmp_(const void *, const void *, size_t) asm("memcmp");
char a[256], b[256]; char a[256], b[256];
rngset(a, 256, vigna, -1); rngset(a, 256, lemur64, -1);
memcpy(b, a, 256); memcpy(b, a, 256);
++a[0]; ++a[0];
EZBENCH_N("bcmp ne", 256, bcmp_(a, b, 256)); EZBENCH_N("bcmp ne", 256, bcmp_(a, b, 256));

View file

@ -39,7 +39,7 @@ TEST(memset, hug) {
b = gc(malloc(1025 * 2)); b = gc(malloc(1025 * 2));
for (i = 0; i < 1025; ++i) { for (i = 0; i < 1025; ++i) {
for (j = 0; j < 1025 - i; ++j) { for (j = 0; j < 1025 - i; ++j) {
c = vigna(); c = lemur64();
rngset(a, i + j, 0, 0); rngset(a, i + j, 0, 0);
memcpy(b, a, i + j); memcpy(b, a, i + j);
ASSERT_EQ(a + i, golden(a + i, c, j)); ASSERT_EQ(a + i, golden(a + i, c, j));

View file

@ -155,6 +155,8 @@ TEST(mt19937, test) {
BENCH(mt19937, bench8) { BENCH(mt19937, bench8) {
volatile uint64_t x; volatile uint64_t x;
EZBENCH2("lemur64", donothing, x = lemur64());
EZBENCH2("rand64", donothing, x = rand64());
EZBENCH2("vigna", donothing, x = vigna()); EZBENCH2("vigna", donothing, x = vigna());
EZBENCH2("vigna_r", donothing, vigna_r(&x)); EZBENCH2("vigna_r", donothing, vigna_r(&x));
EZBENCH2("xorshift", donothing, x = xorshift()); EZBENCH2("xorshift", donothing, x = xorshift());

View file

@ -0,0 +1,103 @@
/*-*- 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 2022 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/sigbits.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/sigset.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/macros.internal.h"
#include "libc/rand/rand.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/clone.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
#include "libc/testlib/testlib.h"
#define THREADS 1
#define ENTRIES 10
volatile bool ready;
volatile uint64_t A[THREADS * ENTRIES];
void OnChld(int sig) {
// do nothing
}
int Thrasher(void *arg) {
int i, id = (intptr_t)arg;
while (!ready) asm("pause");
for (i = 0; i < ENTRIES; ++i) {
A[id * ENTRIES + i] = rand64();
}
return 0;
}
TEST(rand64, testLcg_doesntProduceIdenticalValues) {
int i, j;
bzero(A, sizeof(A));
for (i = 0; i < ARRAYLEN(A); ++i) {
A[i] = rand64();
}
for (i = 0; i < ARRAYLEN(A); ++i) {
EXPECT_NE(0, A[i], "i=%d", i);
for (j = 0; j < ARRAYLEN(A); ++j) {
if (i == j) continue;
EXPECT_NE(A[i], A[j], "i=%d j=%d", i, j);
}
}
}
TEST(rand64, testThreadSafety_doesntProduceIdenticalValues) {
char *stack;
sigset_t ss, oldss;
int i, j, rc, ws, tid[THREADS], ptid[THREADS], ctid[THREADS], tls[THREADS];
if (!IsLinux() && !IsNetbsd()) return;
struct sigaction oldsa;
struct sigaction sa = {.sa_handler = OnChld, .sa_flags = SA_RESTART};
EXPECT_NE(-1, sigaction(SIGCHLD, &sa, &oldsa));
bzero(A, sizeof(A));
rand64(); // for effect
sigemptyset(&ss);
sigaddset(&ss, SIGCHLD);
EXPECT_EQ(0, sigprocmask(SIG_BLOCK, &ss, &oldss));
ready = false;
for (i = 0; i < THREADS; ++i) {
stack = gc(malloc(FRAMESIZE));
tid[i] = clone(Thrasher, stack + FRAMESIZE,
CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD,
(void *)(intptr_t)i, ptid + i, tls + i, ctid + i);
EXPECT_NE(-1, tid[i]);
}
ready = true;
for (i = 0; i < THREADS; ++i) {
EXPECT_NE(-1, (rc = waitpid(0, &ws, 0)));
EXPECT_TRUE(WIFEXITED(ws));
EXPECT_EQ(0, WEXITSTATUS(ws));
}
EXPECT_EQ(0, sigaction(SIGCHLD, &oldsa, 0));
EXPECT_EQ(0, sigprocmask(SIG_BLOCK, &oldss, 0));
for (i = 0; i < ARRAYLEN(A); ++i) {
EXPECT_NE(0, A[i], "i=%d", i);
for (j = 0; j < ARRAYLEN(A); ++j) {
if (i == j) continue;
EXPECT_NE(A[i], A[j], "i=%d j=%d", i, j);
}
}
}

View file

@ -37,7 +37,7 @@ TEST(clone, test) {
if (!IsLinux() && !IsNetbsd() && !IsWindows()) return; if (!IsLinux() && !IsNetbsd() && !IsWindows()) return;
char *stack; char *stack;
long double t; long double t;
int tid, ptid, ctid, tls, ws; int tid, ptid, ctid, tls;
t = nowl(); t = nowl();
stack = gc(malloc(FRAMESIZE)); stack = gc(malloc(FRAMESIZE));
EXPECT_NE(-1, (tid = clone(thread, stack + FRAMESIZE, EXPECT_NE(-1, (tid = clone(thread, stack + FRAMESIZE,

View file

@ -42,7 +42,7 @@ TEST(mmap, testMapFile) {
int fd; int fd;
char *p; char *p;
char path[PATH_MAX]; char path[PATH_MAX];
sprintf(path, "%s%s.%ld", kTmpPath, program_invocation_short_name, vigna()); sprintf(path, "%s%s.%ld", kTmpPath, program_invocation_short_name, lemur64());
ASSERT_NE(-1, (fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0644))); ASSERT_NE(-1, (fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0644)));
EXPECT_EQ(5, write(fd, "hello", 5)); EXPECT_EQ(5, write(fd, "hello", 5));
EXPECT_NE(-1, fdatasync(fd)); EXPECT_NE(-1, fdatasync(fd));
@ -56,7 +56,7 @@ TEST(mmap, testMapFile) {
TEST(mmap, testMapFile_fdGetsClosed_makesNoDifference) { TEST(mmap, testMapFile_fdGetsClosed_makesNoDifference) {
int fd; int fd;
char *p, buf[16], path[PATH_MAX]; char *p, buf[16], path[PATH_MAX];
sprintf(path, "%s%s.%ld", kTmpPath, program_invocation_short_name, vigna()); sprintf(path, "%s%s.%ld", kTmpPath, program_invocation_short_name, lemur64());
ASSERT_NE(-1, (fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0644))); ASSERT_NE(-1, (fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0644)));
EXPECT_EQ(5, write(fd, "hello", 5)); EXPECT_EQ(5, write(fd, "hello", 5));
EXPECT_NE(-1, fdatasync(fd)); EXPECT_NE(-1, fdatasync(fd));
@ -163,7 +163,7 @@ TEST(mmap, cow) {
int fd; int fd;
char *p; char *p;
char path[PATH_MAX]; char path[PATH_MAX];
sprintf(path, "%s%s.%ld", kTmpPath, program_invocation_short_name, vigna()); sprintf(path, "%s%s.%ld", kTmpPath, program_invocation_short_name, lemur64());
ASSERT_NE(-1, (fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0644))); ASSERT_NE(-1, (fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0644)));
EXPECT_EQ(5, write(fd, "hello", 5)); EXPECT_EQ(5, write(fd, "hello", 5));
EXPECT_NE(-1, fdatasync(fd)); EXPECT_NE(-1, fdatasync(fd));
@ -182,7 +182,7 @@ TEST(mmap, cowFileMapReadonlyFork) {
char *p; char *p;
int fd, pid, ws; int fd, pid, ws;
char path[PATH_MAX], lol[6]; char path[PATH_MAX], lol[6];
sprintf(path, "%s%s.%ld", kTmpPath, program_invocation_short_name, vigna()); sprintf(path, "%s%s.%ld", kTmpPath, program_invocation_short_name, lemur64());
ASSERT_NE(-1, (fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0644))); ASSERT_NE(-1, (fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0644)));
EXPECT_EQ(6, write(fd, "hello", 6)); EXPECT_EQ(6, write(fd, "hello", 6));
EXPECT_NE(-1, close(fd)); EXPECT_NE(-1, close(fd));
@ -206,7 +206,7 @@ TEST(mmap, cowFileMapFork) {
char *p; char *p;
int fd, pid, ws; int fd, pid, ws;
char path[PATH_MAX], lol[6]; char path[PATH_MAX], lol[6];
sprintf(path, "%s%s.%ld", kTmpPath, program_invocation_short_name, vigna()); sprintf(path, "%s%s.%ld", kTmpPath, program_invocation_short_name, lemur64());
ASSERT_NE(-1, (fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0644))); ASSERT_NE(-1, (fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0644)));
EXPECT_EQ(6, write(fd, "parnt", 6)); EXPECT_EQ(6, write(fd, "parnt", 6));
EXPECT_NE(-1, fdatasync(fd)); EXPECT_NE(-1, fdatasync(fd));
@ -256,7 +256,7 @@ TEST(mmap, sharedFileMapFork) {
char *p; char *p;
int fd, pid, ws; int fd, pid, ws;
char path[PATH_MAX], lol[6]; char path[PATH_MAX], lol[6];
sprintf(path, "%s%s.%ld", kTmpPath, program_invocation_short_name, vigna()); sprintf(path, "%s%s.%ld", kTmpPath, program_invocation_short_name, lemur64());
ASSERT_NE(-1, (fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0644))); ASSERT_NE(-1, (fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0644)));
EXPECT_EQ(6, write(fd, "parnt", 6)); EXPECT_EQ(6, write(fd, "parnt", 6));
EXPECT_NE(-1, fdatasync(fd)); EXPECT_NE(-1, fdatasync(fd));

View file

@ -49,5 +49,5 @@ BENCH(asin, bench) {
EZBENCH2("asin(-0)", donothing, asin(-0.)); EZBENCH2("asin(-0)", donothing, asin(-0.));
EZBENCH2("asin(NAN)", donothing, asin(NAN)); EZBENCH2("asin(NAN)", donothing, asin(NAN));
EZBENCH2("asin(INFINITY)", donothing, asin(INFINITY)); EZBENCH2("asin(INFINITY)", donothing, asin(INFINITY));
EZBENCH_C("asin", _real1(vigna()), asin(_real1(vigna()))); EZBENCH_C("asin", _real1(lemur64()), asin(_real1(lemur64())));
} }

View file

@ -1128,7 +1128,7 @@ static unsigned ct_lt_mpi_uint( const mbedtls_mpi_uint x,
* the two input MPIs is not the same. * the two input MPIs is not the same.
*/ */
int mbedtls_mpi_lt_mpi_ct( const mbedtls_mpi *X, const mbedtls_mpi *Y, int mbedtls_mpi_lt_mpi_ct( const mbedtls_mpi *X, const mbedtls_mpi *Y,
unsigned *ret ) unsigned *ret )
{ {
size_t i; size_t i;
/* The value of any of these variables is either 0 or 1 at all times. */ /* The value of any of these variables is either 0 or 1 at all times. */
@ -1949,8 +1949,8 @@ static void mpi_montg_init( mbedtls_mpi_uint *mm, const mbedtls_mpi *N )
* Note that unlike the usual convention in the library * Note that unlike the usual convention in the library
* for `const mbedtls_mpi*`, the content of T can change. * for `const mbedtls_mpi*`, the content of T can change.
*/ */
static void mpi_montmul( mbedtls_mpi *A, const mbedtls_mpi *B, const mbedtls_mpi *N, mbedtls_mpi_uint mm, static void mpi_montmul( mbedtls_mpi *A, const mbedtls_mpi *B, const mbedtls_mpi *N,
const mbedtls_mpi *T ) mbedtls_mpi_uint mm, const mbedtls_mpi *T )
{ {
size_t i, n, m; size_t i, n, m;
mbedtls_mpi_uint u0, u1, *d, *Ap, *Bp, *Np; mbedtls_mpi_uint u0, u1, *d, *Ap, *Bp, *Np;

View file

@ -381,10 +381,10 @@ static int ccm_auth_crypt( mbedtls_ccm_context *ctx, int mode, size_t length,
* \return A CCM or cipher-specific error code on failure. * \return A CCM or cipher-specific error code on failure.
*/ */
int mbedtls_ccm_star_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length, int mbedtls_ccm_star_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len, const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len, const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output, const unsigned char *input, unsigned char *output,
unsigned char *tag, size_t tag_len ) unsigned char *tag, size_t tag_len )
{ {
CCM_VALIDATE_RET( ctx ); CCM_VALIDATE_RET( ctx );
CCM_VALIDATE_RET( iv ); CCM_VALIDATE_RET( iv );
@ -433,10 +433,10 @@ int mbedtls_ccm_star_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length,
* \return A CCM or cipher-specific error code on failure. * \return A CCM or cipher-specific error code on failure.
*/ */
int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length, int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len, const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len, const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output, const unsigned char *input, unsigned char *output,
unsigned char *tag, size_t tag_len ) unsigned char *tag, size_t tag_len )
{ {
CCM_VALIDATE_RET( ctx ); CCM_VALIDATE_RET( ctx );
CCM_VALIDATE_RET( iv ); CCM_VALIDATE_RET( iv );
@ -448,7 +448,7 @@ int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length,
return( MBEDTLS_ERR_CCM_BAD_INPUT ); return( MBEDTLS_ERR_CCM_BAD_INPUT );
return( mbedtls_ccm_star_encrypt_and_tag( ctx, length, iv, iv_len, add, return( mbedtls_ccm_star_encrypt_and_tag( ctx, length, iv, iv_len, add,
add_len, input, output, tag, tag_len ) ); add_len, input, output, tag, tag_len ) );
} }
/** /**
@ -491,10 +491,10 @@ int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length,
* \return A cipher-specific error code on calculation failure. * \return A cipher-specific error code on calculation failure.
*/ */
int mbedtls_ccm_star_auth_decrypt( mbedtls_ccm_context *ctx, size_t length, int mbedtls_ccm_star_auth_decrypt( mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len, const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len, const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output, const unsigned char *input, unsigned char *output,
const unsigned char *tag, size_t tag_len ) const unsigned char *tag, size_t tag_len )
{ {
int ret = MBEDTLS_ERR_THIS_CORRUPTION; int ret = MBEDTLS_ERR_THIS_CORRUPTION;
unsigned char check_tag[16]; unsigned char check_tag[16];

View file

@ -456,7 +456,7 @@ static void OpCmpxchg16b(struct Machine *m, uint32_t rde) {
} }
static void OpRdrand(struct Machine *m, uint32_t rde) { static void OpRdrand(struct Machine *m, uint32_t rde) {
WriteRegister(rde, RegRexbRm(m, rde), rand64()); WriteRegister(rde, RegRexbRm(m, rde), rdrand());
m->flags = SetFlag(m->flags, FLAGS_CF, true); m->flags = SetFlag(m->flags, FLAGS_CF, true);
} }

View file

@ -204,6 +204,15 @@
"scp $f $f.dbg win7:" "scp $f $f.dbg win7:"
"ssh win7 ./%s.com")) "ssh win7 ./%s.com"))
mode name (file-name-nondirectory name))) mode name (file-name-nondirectory name)))
((eq kind 'run-win10)
(format
(cosmo-join
" && "
`("m=%s; f=o/$m/%s.com"
,(concat "make -j8 -O $f MODE=$m")
"scp $f $f.dbg win10:"
"ssh win10 ./%s.com"))
mode name (file-name-nondirectory name)))
((and (equal suffix "") ((and (equal suffix "")
(cosmo-contains "_test." (buffer-file-name))) (cosmo-contains "_test." (buffer-file-name)))
(format "m=%s; make -j8 -O MODE=$m %s" (format "m=%s; make -j8 -O MODE=$m %s"
@ -643,6 +652,22 @@
('t ('t
(error "cosmo-run: unknown major mode"))))))) (error "cosmo-run: unknown major mode")))))))
(defun cosmo-run-win10 (arg)
(interactive "P")
(let* ((this (or (buffer-file-name) dired-directory))
(proj (locate-dominating-file this "Makefile"))
(root (or proj default-directory))
(file (file-relative-name this root)))
(when root
(let ((default-directory root))
(save-buffer)
(cond ((memq major-mode '(c-mode c++-mode asm-mode fortran-mode))
(let* ((mode (cosmo--make-mode arg ""))
(compile-command (cosmo--compile-command this root 'run-win10 mode "" "" "")))
(compile compile-command)))
('t
(error "cosmo-run: unknown major mode")))))))
(progn (progn
(define-key asm-mode-map (kbd "C-c C-r") 'cosmo-run) (define-key asm-mode-map (kbd "C-c C-r") 'cosmo-run)
(define-key c-mode-base-map (kbd "C-c C-r") 'cosmo-run) (define-key c-mode-base-map (kbd "C-c C-r") 'cosmo-run)
@ -650,7 +675,7 @@
(define-key sh-mode-map (kbd "C-c C-r") 'cosmo-run) (define-key sh-mode-map (kbd "C-c C-r") 'cosmo-run)
(define-key python-mode-map (kbd "C-c C-r") 'cosmo-run) (define-key python-mode-map (kbd "C-c C-r") 'cosmo-run)
(define-key c-mode-map (kbd "C-c C-s") 'cosmo-run-test) (define-key c-mode-map (kbd "C-c C-s") 'cosmo-run-test)
(define-key c-mode-map (kbd "C-c C-_") 'cosmo-run-win7)) (define-key c-mode-map (kbd "C-c C-_") 'cosmo-run-win10))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;