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}, //
{"inc", inc}, //
{"knuth", knuth}, //
{"lemur64", lemur64}, //
{"libc", libc}, //
{"moby", moby}, //
{"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) {
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) {
size_t i;
struct DirectMap dm;
uint32_t flags1, flags2;
struct ProtectNt fl;
const struct NtSecurityAttributes *sec;
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) {
// windows has cow pages but they can't propagate across fork()
if (prot & PROT_EXEC) {
flags1 = kNtPageExecuteWritecopy;
flags2 = kNtFileMapCopy | kNtFileMapExecute;
fl = (struct ProtectNt){kNtPageExecuteWritecopy,
kNtFileMapCopy | kNtFileMapExecute};
} else {
flags1 = kNtPageWritecopy;
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;
fl = (struct ProtectNt){kNtPageWritecopy, kNtFileMapCopy};
}
} else {
flags1 = kNtPageNoaccess;
flags2 = 0;
fl = __nt2prot(prot);
}
if ((dm.maphandle = CreateFileMapping(handle, sec, flags1, (size + off) >> 32,
(size + off), 0))) {
if ((dm.addr = MapViewOfFileEx(dm.maphandle, flags2, off >> 32, off, size,
addr))) {
if ((dm.maphandle = CreateFileMapping(handle, sec, fl.flags1,
(size + off) >> 32, (size + off), 0))) {
if ((dm.addr = MapViewOfFileEx(dm.maphandle, fl.flags2, off >> 32, off,
size, addr))) {
return dm;
}
CloseHandle(dm.maphandle);

View file

@ -22,10 +22,5 @@
textwindows int sys_fdatasync_nt(int fd) {
if (!__isfdkind(fd, kFdFile)) return ebadf();
/*
* 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();
return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : -1;
}

View file

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

View file

@ -226,7 +226,6 @@ void sys_exit(int) hidden;
void __onfork(void) hidden;
i32 __fixupnewfd(i32, i32) hidden;
u32 __prot2nt(i32, i32) privileged;
void __restore_rt() hidden;
int sys_utimensat_xnu(int, const char *, const struct timespec *, int) 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_madvise_nt(void *, size_t, int) 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_pipe_nt(int[hasatleast 2], unsigned) hidden;
int sys_renameat_nt(int, const char *, int, const char *) hidden;

View file

@ -23,6 +23,7 @@
#include "libc/errno.h"
#include "libc/nt/memory.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/runtime/memtrack.internal.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;
return 0;
} else {
__winerr();
CloseHandle(hin);
}
} else {
__winerr();
}
__releasefd(writer);
__releasefd(reader);

View file

@ -63,7 +63,7 @@ struct Signals {
struct Signal mem[__SIG_QUEUE_LENGTH];
};
struct Signals __sig;
struct Signals __sig; // TODO(jart): Need TLS
/**
* 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)) {
return 0;
} else {
return __winerr();
return -1;
}
}
path[0] = '.';
@ -65,11 +65,11 @@ static textwindows int SyncDirectory(int df, char16_t path[PATH_MAX], int n) {
if (FlushFileBuffers(fh)) {
rc = 0;
} else {
rc = __winerr();
rc = -1;
}
CloseHandle(fh);
} else {
rc = __winerr();
rc = -1;
}
return rc;
}

View file

@ -23,6 +23,7 @@
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/rusage.h"
#include "libc/fmt/conv.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h"
#include "libc/nt/accounting.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.
*
* @param dwStackSize may be 0 for default per executable
* @return thread handle, or 0 on failure
* @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)
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/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/createfilemappingnuma.greg.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__
/* asan runtime depends on this function */
int st, ft;
static bool noreentry;
if (!noreentry) {
noreentry = true;
st = __strace, __strace = 0;
ft = g_ftrace, g_ftrace = 0;
if (!bp) bp = __builtin_frame_address(0);
st = __strace;
__strace = 0;
PrintBacktrace(fd, bp);
ft = g_ftrace;
g_ftrace = 0;
if (!bp) {
bp = __builtin_frame_address(0);
}
PrintBacktrace(fd, bp);
__strace = st;
g_ftrace = ft;
noreentry = false;
}
__strace = st;
g_ftrace = ft;
#else
kprintf("ShowBacktrace() needs these flags to show C backtrace:%n"
"\t-D__FNO_OMIT_FRAME_POINTER__%n"

View file

@ -20,6 +20,7 @@
#include "libc/bits/weaken.h"
#include "libc/calls/internal.h"
#include "libc/calls/sigbits.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/errno.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,
ucontext_t *ctx) {
intptr_t rip;
int gdbpid, err;
int gdbpid, err, st, ft;
static bool noreentry, notpossible;
--g_ftrace;
if (cmpxchg(&noreentry, false, true)) {
st = __strace, __strace = 0;
ft = g_ftrace, g_ftrace = 0;
if (lockcmpxchg(&noreentry, false, true)) {
if (!__vforked) {
rip = ctx ? ctx->uc_mcontext.rip : 0;
err = errno;
@ -326,9 +328,10 @@ relegated noinstrument void __oncrash(int sig, struct siginfo *si,
}
} else if (sig == SIGTRAP) {
/* chances are IsDebuggerPresent() confused strace w/ gdb */
++g_ftrace;
g_ftrace = ft;
__strace = st;
return;
} else if (cmpxchg(&notpossible, false, true)) {
} else if (lockcmpxchg(&notpossible, false, true)) {
__minicrash(sig, si, ctx, "WHILE CRASHING");
} else {
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
.text.windows
CloseHandle:
__CloseHandle:
push %rbp
mov %rsp,%rbp
.profilable
@ -11,5 +11,5 @@ CloseHandle:
call *__imp_CloseHandle(%rip)
leave
ret
.endfn CloseHandle,globl
.endfn __CloseHandle,globl
.previous

View file

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

View file

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

View file

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

View file

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

View file

@ -2,7 +2,7 @@
.imp kernel32,__imp_UnmapViewOfFile,UnmapViewOfFile,0
.text.windows
UnmapViewOfFile:
__UnmapViewOfFile:
push %rbp
mov %rsp,%rbp
.profilable
@ -11,5 +11,5 @@ UnmapViewOfFile:
call *__imp_UnmapViewOfFile(%rip)
leave
ret
.endfn UnmapViewOfFile,globl
.endfn __UnmapViewOfFile,globl
.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 'CloseGestureInfoHandle' CloseGestureInfoHandle user32 1589
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 'ClosePackageInfo' ClosePackageInfo 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 'CreateMutexEx' CreateMutexExW 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 'CreateOPMProtectedOutput' CreateOPMProtectedOutput gdi32 1089
imp 'CreateOPMProtectedOutputs' CreateOPMProtectedOutputs gdi32 1090
@ -633,7 +633,7 @@ imp 'CreatePalmRejectionDelayZone' CreatePalmRejectionDelayZone user32 15
imp 'CreatePatternBrush' CreatePatternBrush gdi32 1092
imp 'CreatePen' CreatePen gdi32 1093
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 'CreatePolygonRgn' CreatePolygonRgn gdi32 1096
imp 'CreatePopupMenu' CreatePopupMenu user32 1622 0
@ -1677,11 +1677,11 @@ imp 'FlsGetValue' FlsGetValue kernel32 0 # KernelBase
imp 'FlsSetValue' FlsSetValue kernel32 0 # KernelBase
imp 'FlushConsoleInputBuffer' FlushConsoleInputBuffer kernel32 0 1 # KernelBase
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 'FlushTraceA' FlushTraceA advapi32 1304
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 'FoldString' FoldStringW kernel32 0 # KernelBase
imp 'FontIsLinked' FontIsLinked gdi32 1484
@ -6714,9 +6714,9 @@ imp 'UnlockFile' UnlockFile kernel32 0 5 # KernelBase
imp 'UnlockFileEx' UnlockFileEx kernel32 0 5 # KernelBase
imp 'UnlockServiceDatabase' UnlockServiceDatabase advapi32 1820
imp 'UnlockWindowStation' UnlockWindowStation user32 2456
imp 'UnmapViewOfFile' UnmapViewOfFile kernel32 0 1 # KernelBase
imp 'UnmapViewOfFile2' UnmapViewOfFile2 KernelBase 1696
imp 'UnmapViewOfFileEx' UnmapViewOfFileEx KernelBase 1697
imp '__UnmapViewOfFile' UnmapViewOfFile kernel32 0 1 # KernelBase
imp 'UnmapViewOfFile2' UnmapViewOfFile2 kernel32 0 2 # KernelBase
imp 'UnmapViewOfFileEx' UnmapViewOfFileEx kernel32 0 3 # KernelBase
imp 'UnpackDDElParam' UnpackDDElParam user32 2457
imp 'UnrealizeObject' UnrealizeObject gdi32 1934
imp 'UnregisterApplicationRecoveryCallback' UnregisterApplicationRecoveryCallback kernel32 1466

View file

@ -1,8 +1,5 @@
#define CopyFile(...) __imp_CopyFileW(__VA_ARGS__)
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__)
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(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.
*
* This random number seed generator blends information from:
* This random number seed generator obtains information from:
*
* - getrandom() on Linux
* - RtlGenRandom() on Windows
@ -61,6 +61,9 @@ static bool have_getrandom;
* This function is safe to use with fork() and vfork(). It will also
* 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
* @restartable
* @vforksafe

View file

@ -7,7 +7,7 @@ forceinline uint64_t KnuthLinearCongruentialGenerator(uint64_t prev[1]) {
Seminumerical Algorithms, Third Edition, Addison-Wesley, 1998,
p. 106 (line 26) & p. 108 */
prev[0] = prev[0] * 6364136223846793005 + 1442695040888963407;
return prev[0];
return prev[0]; /* be sure to shift! */
}
#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"
/**
* 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
* seed at startup by default, unless srand() is called. This makes it
* useful in cases where deterministic behavior is needed.
* int x = rand();
* assert(x >= 0);
*
* 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) {
return KnuthLinearCongruentialGenerator(&g_rando) >> 33;

View file

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

View file

@ -16,59 +16,80 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.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/intrin/kprintf.h"
#include "libc/nexgen32e/rdtsc.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/nt/thread.h"
#include "libc/rand/rand.h"
#include "libc/runtime/runtime.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.
*
* This function automatically seeds itself on startup and reseeds
* itself after fork() and vfork(). It takes about nanosecond to run.
* That makes it much slower than vigna() and rand() but much faster
* than rdrand() and rdseed().
* This function is similar to lemur64() except it'thepool intended to
* be unpredictable. This PRNG automatically seeds itself on startup
* using a much stronger and faster random source than `srand(time(0))`.
* 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()
* @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
* @threadsafe
* @vforksafe
*/
uint64_t rand64(void) {
bool cf;
register uint64_t t;
if (X86_HAVE(RDSEED)) {
asm volatile(CFLAG_ASM("rdseed\t%1")
: CFLAG_CONSTRAINT(cf), "=r"(t)
: /* no inputs */
: "cc");
if (cf) {
thepool ^= t;
return t;
void *d;
int c1, p1, p2;
uint128_t s1, s2;
do {
p1 = __pid;
p2 = thepid;
c1 = thecount;
asm volatile("" ::: "memory");
s1 = thepool;
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;
}
}
t = _xadd(&thepool, 0x9e3779b97f4a7c15);
t ^= (getpid() * 0x1001111111110001ull + 0xdeaadead) >> 31;
t = (t ^ (t >> 30)) * 0xbf58476d1ce4e5b9;
t = (t ^ (t >> 27)) * 0x94d049bb133111eb;
return t ^ (t >> 31);
// lemur64 pseudorandom number generator
s2 *= 15750249268501108917ull;
// sadly 128-bit values aren't atomic on x86
_lockcmpxchg16b(&thepool, &s1, s2);
// do it again if there's thread contention
} 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
* 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()
* @asyncsignalsafe
* @vforksafe
*/
uint64_t rdrand(void) {
int i;

View file

@ -31,9 +31,12 @@
* sysctl(KERN_ARND). If those aren't available then we try /dev/urandom
* 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()
* @asyncsignalsafe
* @vforksafe
*/
uint64_t rdseed(void) {
int i;

View file

@ -21,9 +21,9 @@
/**
* 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) {
return 1. / 9007199254740991. * (x >> 11);

View file

@ -21,9 +21,9 @@
/**
* 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) {
return 1. / 9007199254740992. * (x >> 11);

View file

@ -21,9 +21,9 @@
/**
* 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) {
return 1. / 4503599627370496. * ((x >> 12) + .5);

View file

@ -16,7 +16,6 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/xadd.h"
#include "libc/rand/rand.h"
static uint64_t g_vigna;
@ -40,9 +39,8 @@ static uint64_t g_vigna;
* static uint64_t s = 0;
* uint64_t x = svigna_r(&s);
*
* This function is the fastest way to generate good scalar pseudorandom
* numbers that aren't truncated. If you want to fill a buffer with data
* then rngset() implements vigna's algorithm to do that extremely well:
* If you want to fill a buffer with data then rngset() implements
* vigna's algorithm to do that extremely well:
*
* char buf[4096];
* 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.
*
* @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) {
return vigna_r(&g_vigna);

View file

@ -29,7 +29,9 @@ textwindows wontreturn void sys_abort_nt(void) {
info.si_signo = SIGABRT;
rva = __sighandrvas[SIGABRT];
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);
}

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/dce.h"
#include "libc/nexgen32e/nt2sysv.h"
#include "libc/nexgen32e/stackframe.h"
@ -24,6 +25,8 @@
#include "libc/nt/thread.h"
#include "libc/sysv/consts/clone.h"
#include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/errfuns.h"
struct WinThread {
@ -32,7 +35,7 @@ struct WinThread {
void *stack;
};
static noasan textwindows uint32_t winthread(void *param) {
static noasan textwindows uint32_t WinThreadMain(void *param) {
struct WinThread *wt = param;
asm volatile("mov\t%%rbp,%%r14\n\t"
"mov\t%%rsp,%%r15\n\t"
@ -50,15 +53,19 @@ static noasan textwindows uint32_t winthread(void *param) {
/**
* Creates thread.
*
* @note CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND creates thread
* @note CLONE_VFORK|CLONE_VM|SIGCHLD does vfork()
* @note SIGCHLD does fork()
* @param flags usually has one of
* - `CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND` for threads
* - `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, ...) {
int64_t h;
int tidfd;
va_list va;
intptr_t ax;
uint32_t tid;
int64_t hand;
int32_t *ptid;
register void *tls asm("r8");
register int32_t *ctid asm("r10");
@ -90,11 +97,16 @@ privileged int clone(int (*f)(void *), void *stack, int flags, void *arg, ...) {
: "memory");
unreachable;
} else if (IsWindows()) {
if (flags == (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND)) {
if ((h = CreateThread(0, PAGESIZE, NT2SYSV(winthread),
&(struct WinThread){f, arg, stack}, 0, &tid))) {
CloseHandle(h);
return tid;
if ((tidfd = __reservefd()) == -1) return -1;
if (flags == CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND) {
if ((hand = CreateThread(&kNtIsInheritable, 0, NT2SYSV(WinThreadMain),
&(struct WinThread){f, arg, stack}, 0, &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 {
return -1;
}

View file

@ -3,6 +3,11 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct ProtectNt {
uint32_t flags1;
uint32_t flags2;
};
struct DirectMap {
void *addr;
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_metal(void *, size_t, int, int, int, int64_t);
int sys_munmap_metal(void *, size_t);
uint32_t __prot2nt(int, int);
struct ProtectNt __nt2prot(int);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -177,23 +177,8 @@ textwindows void WinMainForked(void) {
}
} else {
// we can however safely inherit MAP_SHARED with zero copy
if (maps[i].prot & PROT_WRITE) {
if (maps[i].prot & PROT_EXEC) {
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)) {
if (!MapViewOfFileEx(maps[i].h, __nt2prot(maps[i].prot).flags2,
maps[i].offset >> 32, maps[i].offset, size, addr)) {
ExitProcess(45);
}
}
@ -216,29 +201,14 @@ textwindows void WinMainForked(void) {
_mmi.n = specialz / sizeof(_mmi.p[0]);
for (i = 0; i < mapcount; ++i) {
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),
ROUNDUP(maps[i].size, FRAMESIZE), flags1, &oldprot);
ROUNDUP(maps[i].size, FRAMESIZE),
__nt2prot(maps[i].prot).flags1, &oldprot);
}
}
// we're all done reading!
if (!CloseHandle(reader)) {
STRACE("CloseHandle(reader) failed %m");
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) {
if (!CloseHandle(writer)) {
STRACE("CloseHandle(writer) failed %m");
ok = false;
}
}
@ -332,7 +301,7 @@ textwindows int sys_fork_nt(void) {
}
} else {
STRACE("CreatePipe() failed %m");
rc = __winerr();
rc = -1;
CloseHandle(writer);
}
} else {

View file

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

View file

@ -17,22 +17,40 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h"
#include "libc/nt/files.h"
#include "libc/nt/memory.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) {
int x, y, l, r, i;
x = ROUNDDOWN((intptr_t)addr, FRAMESIZE) >> 16;
y = ROUNDDOWN((intptr_t)addr + size - 1, FRAMESIZE) >> 16;
for (i = FindMemoryInterval(&_mmi, x); i < _mmi.i; ++i) {
if ((x >= _mmi.p[i].x && x <= _mmi.p[i].y) ||
(y >= _mmi.p[i].x && y <= _mmi.p[i].y)) {
FlushFileBuffers(_mmi.p[i].h);
#define ADDR(x) ((char *)((int64_t)((uint64_t)(x) << 32) >> 16))
noasan textwindows int sys_msync_nt(char *addr, size_t size, int flags) {
char *a, *b;
int rc, x, y, l, r, i;
rc = 0;
for (i = FindMemoryInterval(&_mmi, (intptr_t)addr >> 16); i < _mmi.i; ++i) {
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 {
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,
65536, 0, &kNtIsInheritable)) == -1) {
__winerr();
__releasefd(writer);
__releasefd(reader);
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_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_ICMP 1 1 1 1 1 1 # 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"
.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_
#define COSMOPOLITAN_LIBC_SYSV_CONSTS_CLONE_H_
#include "libc/runtime/symbolic.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
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_FILES 0x00000400
#define CLONE_SIGHAND 0x00000800
@ -21,6 +27,4 @@ COSMOPOLITAN_C_START_
#define CLONE_CHILD_SETTID 0x01000000
#define CLONE_STOPPED 0x02000000
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_CLONE_H_ */

View file

@ -42,7 +42,7 @@
*/
static uint64_t Rando(void) {
uint64_t x;
do x = vigna();
do x = lemur64();
while (((x ^ READ64LE("!!!!!!!!")) - 0x0101010101010101) &
~(x ^ READ64LE("!!!!!!!!")) & 0x8080808080808080);
return x;
@ -225,7 +225,7 @@ TEST(ksnprintf, fuzzTheUnbreakable) {
x = Rando();
memcpy(f + 8, &x, sizeof(x));
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));
}

View file

@ -121,17 +121,17 @@ BENCH(bcmp, bench) {
EZBENCH_N("bcmp", 256, v = buncmp(a, b, 256));
a = 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);
EZBENCH_N("bcmp", 16384, v = buncmp(a, b, 16384));
a = 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);
EZBENCH_N("bcmp", 32768, v = buncmp(a, b, 32768));
a = 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);
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));
a = 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);
EZBENCH_N("memcmp", 16384, v = funcmp(a, b, 16384));
a = 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);
EZBENCH_N("memcmp", 32768, v = funcmp(a, b, 32768));
a = 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);
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));
a = 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);
EZBENCH_N("timingsafe_memcmp", 16384, v = timingsafe_memcmp(a, b, 16384));
a = 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);
EZBENCH_N("timingsafe_memcmp", 32768, v = timingsafe_memcmp(a, b, 32768));
a = 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);
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));
a = 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);
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, vigna, -1);
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, vigna, -1);
rngset(a, 128 * 1024, lemur64, -1);
memcpy(b, a, 128 * 1024);
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));
a = 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);
EZBENCH_N("memcasecmp", 16384, v = memcasecmp(a, b, 16384));
a = 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);
EZBENCH_N("memcasecmp", 32768, v = memcasecmp(a, b, 32768));
a = 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);
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 memcmp_(const void *, const void *, size_t) asm("memcmp");
char a[256], b[256];
rngset(a, 256, vigna, -1);
rngset(a, 256, lemur64, -1);
memcpy(b, a, 256);
++a[0];
EZBENCH_N("bcmp ne", 256, bcmp_(a, b, 256));

View file

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

View file

@ -155,6 +155,8 @@ TEST(mt19937, test) {
BENCH(mt19937, bench8) {
volatile uint64_t x;
EZBENCH2("lemur64", donothing, x = lemur64());
EZBENCH2("rand64", donothing, x = rand64());
EZBENCH2("vigna", donothing, x = vigna());
EZBENCH2("vigna_r", donothing, vigna_r(&x));
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;
char *stack;
long double t;
int tid, ptid, ctid, tls, ws;
int tid, ptid, ctid, tls;
t = nowl();
stack = gc(malloc(FRAMESIZE));
EXPECT_NE(-1, (tid = clone(thread, stack + FRAMESIZE,

View file

@ -42,7 +42,7 @@ TEST(mmap, testMapFile) {
int fd;
char *p;
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)));
EXPECT_EQ(5, write(fd, "hello", 5));
EXPECT_NE(-1, fdatasync(fd));
@ -56,7 +56,7 @@ TEST(mmap, testMapFile) {
TEST(mmap, testMapFile_fdGetsClosed_makesNoDifference) {
int fd;
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)));
EXPECT_EQ(5, write(fd, "hello", 5));
EXPECT_NE(-1, fdatasync(fd));
@ -163,7 +163,7 @@ TEST(mmap, cow) {
int fd;
char *p;
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)));
EXPECT_EQ(5, write(fd, "hello", 5));
EXPECT_NE(-1, fdatasync(fd));
@ -182,7 +182,7 @@ TEST(mmap, cowFileMapReadonlyFork) {
char *p;
int fd, pid, ws;
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)));
EXPECT_EQ(6, write(fd, "hello", 6));
EXPECT_NE(-1, close(fd));
@ -206,7 +206,7 @@ TEST(mmap, cowFileMapFork) {
char *p;
int fd, pid, ws;
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)));
EXPECT_EQ(6, write(fd, "parnt", 6));
EXPECT_NE(-1, fdatasync(fd));
@ -256,7 +256,7 @@ TEST(mmap, sharedFileMapFork) {
char *p;
int fd, pid, ws;
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)));
EXPECT_EQ(6, write(fd, "parnt", 6));
EXPECT_NE(-1, fdatasync(fd));

View file

@ -49,5 +49,5 @@ BENCH(asin, bench) {
EZBENCH2("asin(-0)", donothing, asin(-0.));
EZBENCH2("asin(NAN)", donothing, asin(NAN));
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.
*/
int mbedtls_mpi_lt_mpi_ct( const mbedtls_mpi *X, const mbedtls_mpi *Y,
unsigned *ret )
unsigned *ret )
{
size_t i;
/* 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
* 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,
const mbedtls_mpi *T )
static void mpi_montmul( mbedtls_mpi *A, const mbedtls_mpi *B, const mbedtls_mpi *N,
mbedtls_mpi_uint mm, const mbedtls_mpi *T )
{
size_t i, n, m;
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.
*/
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 *add, size_t add_len,
const unsigned char *input, unsigned char *output,
unsigned char *tag, size_t tag_len )
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
unsigned char *tag, size_t tag_len )
{
CCM_VALIDATE_RET( ctx );
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.
*/
int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
unsigned char *tag, size_t tag_len )
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
unsigned char *tag, size_t tag_len )
{
CCM_VALIDATE_RET( ctx );
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_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.
*/
int mbedtls_ccm_star_auth_decrypt( mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
const unsigned char *tag, size_t tag_len )
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
const unsigned char *tag, size_t tag_len )
{
int ret = MBEDTLS_ERR_THIS_CORRUPTION;
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) {
WriteRegister(rde, RegRexbRm(m, rde), rand64());
WriteRegister(rde, RegRexbRm(m, rde), rdrand());
m->flags = SetFlag(m->flags, FLAGS_CF, true);
}

View file

@ -204,6 +204,15 @@
"scp $f $f.dbg win7:"
"ssh win7 ./%s.com"))
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 "")
(cosmo-contains "_test." (buffer-file-name)))
(format "m=%s; make -j8 -O MODE=$m %s"
@ -643,6 +652,22 @@
('t
(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
(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)
@ -650,7 +675,7 @@
(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 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))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;