Merge branch 'master' into fastcall-wrapup

merging with 363d2ec436
This commit is contained in:
ahgamut 2022-05-09 13:38:05 +05:30
commit 4b85809dd8
4529 changed files with 199703 additions and 268223 deletions

View file

@ -15,7 +15,7 @@
"alignas(x)", "alignas(x)",
"alignof(x)", "alignof(x)",
"artificial=", "artificial=",
"nodiscard=", "dontdiscard=",
"mayalias=", "mayalias=",
"forceinline=", "forceinline=",
"forcealign(x)=", "forcealign(x)=",
@ -48,7 +48,7 @@
"nosideeffect=", "nosideeffect=",
"unreachable=", "unreachable=",
"thatispacked=", "thatispacked=",
"nothrow=", "dontthrow=",
"nocallback=", "nocallback=",
"relegated=", "relegated=",
"hidden=", "hidden=",

View file

@ -37,7 +37,7 @@
# #
# # basic debugging # # basic debugging
# make -j8 -O MODE=dbg o/dbg/examples/crashreport.com # make -j8 -O MODE=dbg o/dbg/examples/crashreport.com
# o/dbg/examples/crashreport.com # o/examples/crashreport.com
# less examples/crashreport.c # less examples/crashreport.c
# #
# # extremely tiny binaries # # extremely tiny binaries
@ -60,7 +60,7 @@
# build/config.mk # build/config.mk
SHELL = /bin/sh SHELL = /bin/sh
HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 xnu win7 win10 HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 win7 win10 xnu
SANITY := $(shell build/sanitycheck $$PPID) SANITY := $(shell build/sanitycheck $$PPID)
.SUFFIXES: .SUFFIXES:
@ -69,7 +69,10 @@ SANITY := $(shell build/sanitycheck $$PPID)
.PHONY: all o bins check test depend tags .PHONY: all o bins check test depend tags
all: o all: o
o: o/$(MODE)/ape \ o: o/$(MODE)
o/$(MODE): \
o/$(MODE)/ape \
o/$(MODE)/dsp \ o/$(MODE)/dsp \
o/$(MODE)/net \ o/$(MODE)/net \
o/$(MODE)/libc \ o/$(MODE)/libc \
@ -108,13 +111,13 @@ include libc/rand/rand.mk # │
include libc/unicode/unicode.mk # │ include libc/unicode/unicode.mk # │
include third_party/dlmalloc/dlmalloc.mk #─┘ include third_party/dlmalloc/dlmalloc.mk #─┘
include libc/mem/mem.mk #─┐ include libc/mem/mem.mk #─┐
include libc/ohmyplus/ohmyplus.mk # ├──DYNAMIC RUNTIME include libc/zipos/zipos.mk # ├──DYNAMIC RUNTIME
include libc/zipos/zipos.mk # │ You can now use stdio include third_party/gdtoa/gdtoa.mk # │ You can now use stdio
include third_party/gdtoa/gdtoa.mk # │ You can finally call malloc() include libc/time/time.mk # │ You can finally call malloc()
include libc/time/time.mk # │ include libc/thread/thread.mk # │
include libc/alg/alg.mk # │ include libc/alg/alg.mk # │
include libc/stdio/stdio.mk # │ include libc/stdio/stdio.mk # │
include libc/thread/thread.mk # │ include third_party/libcxx/libcxx.mk # │
include net/net.mk # │ include net/net.mk # │
include libc/log/log.mk # │ include libc/log/log.mk # │
include third_party/bzip2/bzip2.mk # │ include third_party/bzip2/bzip2.mk # │
@ -138,14 +141,16 @@ include third_party/third_party.mk
include libc/testlib/testlib.mk include libc/testlib/testlib.mk
include tool/viz/lib/vizlib.mk include tool/viz/lib/vizlib.mk
include third_party/linenoise/linenoise.mk include third_party/linenoise/linenoise.mk
include third_party/maxmind/maxmind.mk
include third_party/lua/lua.mk include third_party/lua/lua.mk
include third_party/make/make.mk include third_party/make/make.mk
include third_party/argon2/argon2.mk include third_party/argon2/argon2.mk
include third_party/smallz4/smallz4.mk
include third_party/sqlite3/sqlite3.mk include third_party/sqlite3/sqlite3.mk
include third_party/mbedtls/test/test.mk include third_party/mbedtls/test/test.mk
include third_party/quickjs/quickjs.mk include third_party/quickjs/quickjs.mk
include third_party/lz4cli/lz4cli.mk include third_party/lz4cli/lz4cli.mk
include third_party/infozip/infozip.mk include third_party/zip/zip.mk
include tool/build/lib/buildlib.mk include tool/build/lib/buildlib.mk
include third_party/chibicc/chibicc.mk include third_party/chibicc/chibicc.mk
include third_party/chibicc/test/test.mk include third_party/chibicc/test/test.mk
@ -157,6 +162,11 @@ include examples/examples.mk
include examples/pyapp/pyapp.mk include examples/pyapp/pyapp.mk
include tool/decode/lib/decodelib.mk include tool/decode/lib/decodelib.mk
include tool/decode/decode.mk include tool/decode/decode.mk
include tool/lambda/lib/lib.mk
include tool/lambda/lambda.mk
include tool/plinko/lib/lib.mk
include tool/plinko/plinko.mk
include test/tool/plinko/test.mk
include tool/hash/hash.mk include tool/hash/hash.mk
include tool/net/net.mk include tool/net/net.mk
include tool/viz/viz.mk include tool/viz/viz.mk
@ -167,6 +177,7 @@ include test/libc/intrin/test.mk
include test/libc/mem/test.mk include test/libc/mem/test.mk
include test/libc/nexgen32e/test.mk include test/libc/nexgen32e/test.mk
include test/libc/runtime/test.mk include test/libc/runtime/test.mk
include test/libc/thread/test.mk
include test/libc/sock/test.mk include test/libc/sock/test.mk
include test/libc/bits/test.mk include test/libc/bits/test.mk
include test/libc/str/test.mk include test/libc/str/test.mk
@ -210,7 +221,7 @@ CHECKS = $(foreach x,$(PKGS),$($(x)_CHECKS))
bins: $(BINS) bins: $(BINS)
check: $(CHECKS) check: $(CHECKS)
test: $(TESTS) all test: $(TESTS)
depend: o/$(MODE)/depend depend: o/$(MODE)/depend
tags: TAGS HTAGS tags: TAGS HTAGS
@ -249,7 +260,6 @@ COSMOPOLITAN_OBJECTS = \
LIBC_NT_WS2_32 \ LIBC_NT_WS2_32 \
LIBC_NT_IPHLPAPI \ LIBC_NT_IPHLPAPI \
LIBC_NT_MSWSOCK \ LIBC_NT_MSWSOCK \
LIBC_OHMYPLUS \
LIBC_X \ LIBC_X \
THIRD_PARTY_GETOPT \ THIRD_PARTY_GETOPT \
LIBC_LOG \ LIBC_LOG \
@ -270,7 +280,9 @@ COSMOPOLITAN_OBJECTS = \
LIBC_CALLS \ LIBC_CALLS \
LIBC_RAND \ LIBC_RAND \
LIBC_SYSV_CALLS \ LIBC_SYSV_CALLS \
LIBC_NT_KERNELBASE \ LIBC_NT_PSAPI \
LIBC_NT_POWRPROF \
LIBC_NT_PDH \
LIBC_NT_SHELL32 \ LIBC_NT_SHELL32 \
LIBC_NT_GDI32 \ LIBC_NT_GDI32 \
LIBC_NT_COMDLG32 \ LIBC_NT_COMDLG32 \
@ -283,6 +295,7 @@ COSMOPOLITAN_OBJECTS = \
THIRD_PARTY_COMPILER_RT \ THIRD_PARTY_COMPILER_RT \
LIBC_THREAD \ LIBC_THREAD \
LIBC_TINYMATH \ LIBC_TINYMATH \
THIRD_PARTY_XED \
LIBC_STR \ LIBC_STR \
LIBC_SYSV \ LIBC_SYSV \
LIBC_INTRIN \ LIBC_INTRIN \
@ -302,11 +315,11 @@ COSMOPOLITAN_HEADERS = \
LIBC_MEM \ LIBC_MEM \
LIBC_NEXGEN32E \ LIBC_NEXGEN32E \
LIBC_NT \ LIBC_NT \
LIBC_OHMYPLUS \
LIBC_RAND \ LIBC_RAND \
LIBC_RUNTIME \ LIBC_RUNTIME \
LIBC_SOCK \ LIBC_SOCK \
LIBC_STDIO \ LIBC_STDIO \
THIRD_PARTY_XED \
LIBC_STR \ LIBC_STR \
LIBC_SYSV \ LIBC_SYSV \
LIBC_THREAD \ LIBC_THREAD \

View file

@ -22,8 +22,8 @@ If you're doing your development work on Linux or BSD then you need just
five files to get started. Here's what you do on Linux: five files to get started. Here's what you do on Linux:
```sh ```sh
wget https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-1.0.zip wget https://justine.lol/cosmopolitan/cosmopolitan.zip
unzip cosmopolitan-amalgamation-1.0.zip unzip cosmopolitan.zip
printf 'main() { printf("hello world\\n"); }\n' >hello.c printf 'main() { printf("hello world\\n"); }\n' >hello.c
gcc -g -Os -static -nostdlib -nostdinc -fno-pie -no-pie -mno-red-zone \ gcc -g -Os -static -nostdlib -nostdinc -fno-pie -no-pie -mno-red-zone \
-fno-omit-frame-pointer -pg -mnop-mcount \ -fno-omit-frame-pointer -pg -mnop-mcount \
@ -72,14 +72,45 @@ repository that bootstraps using a vendored static gcc9 executable.
No further dependencies are required. No further dependencies are required.
```sh ```sh
wget https://justine.lol/cosmopolitan/cosmopolitan-1.0.tar.gz wget https://justine.lol/cosmopolitan/cosmopolitan.tar.gz
tar xf cosmopolitan-1.0.tar.gz # see releases page tar xf cosmopolitan.tar.gz # see releases page
cd cosmopolitan cd cosmopolitan
make -j16 make -j16
o//examples/hello.com o//examples/hello.com
find o -name \*.com | xargs ls -rShal | less find o -name \*.com | xargs ls -rShal | less
``` ```
## GDB
Here's the recommended `~/.gdbinit` config:
```
set host-charset UTF-8
set target-charset UTF-8
set target-wide-charset UTF-8
set osabi none
set complaints 0
set confirm off
set history save on
set history filename ~/.gdb_history
define asm
layout asm
layout reg
end
define src
layout src
layout reg
end
src
```
You normally run the `.com.dbg` file under gdb. If you need to debug the
`.com` file itself, then you can load the debug symbols independently as
```
gdb foo.com -ex 'add-symbol-file foo.com.dbg 0x401000'
```
## Support Vector ## Support Vector
| Platform | Min Version | Circa | | Platform | Min Version | Circa |

View file

@ -660,6 +660,7 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
#if SupportsSystemv() || SupportsMetal() #if SupportsSystemv() || SupportsMetal()
.section .elf.phdrs,"a",@progbits .section .elf.phdrs,"a",@progbits
.long PT_LOAD .long PT_LOAD
.long PF_R|PF_X .long PF_R|PF_X
.stub ape_rom_offset,quad .stub ape_rom_offset,quad
@ -668,6 +669,7 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
.stub ape_rom_filesz,quad .stub ape_rom_filesz,quad
.stub ape_rom_memsz,quad .stub ape_rom_memsz,quad
.stub ape_rom_align,quad .stub ape_rom_align,quad
.long PT_LOAD .long PT_LOAD
.long PF_R|PF_W .long PF_R|PF_W
.stub ape_ram_offset,quad .stub ape_ram_offset,quad
@ -676,14 +678,32 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
.stub ape_ram_filesz,quad .stub ape_ram_filesz,quad
.stub ape_ram_memsz,quad .stub ape_ram_memsz,quad
.stub ape_ram_align,quad .stub ape_ram_align,quad
// APE Stack Configuration
//
// We actually respect this when allocating a deterministically
// addressed stack on Windows and other operating systems. However
// there's a few caveats:
//
// - If ape_stack_pf has PF_X then OpenBSD probably won't work
// - We don't bother creating a deterministic stack in MODE=tiny
//
// With that said, here's some examples of configuration:
//
// STATIC_SYMBOL("ape_stack_pf", "7"); // RWX
// STATIC_STACK_ADDR(0x6fffffff0000);
// STATIC_STACK_SIZE(65536);
//
// @see ape.lds for defaults
.long PT_GNU_STACK .long PT_GNU_STACK
.long PF_R|PF_W .stub ape_stack_pf,long # override w/ PF_X for execstack
.stub ape_stack_offset,quad .stub ape_stack_offset,quad # ignored
.stub ape_stack_vaddr,quad .stub ape_stack_vaddr,quad # is mmap()'d with MAP_FIXED
.stub ape_stack_paddr,quad .stub ape_stack_paddr,quad # ignored
.stub ape_stack_filesz,quad .stub ape_stack_filesz,quad # ignored
.stub ape_stack_memsz,quad .stub ape_stack_memsz,quad # is mmap(size) argument
.stub ape_stack_align,quad .stub ape_stack_align,quad # must be 16+
#if SupportsOpenbsd() || SupportsNetbsd() #if SupportsOpenbsd() || SupportsNetbsd()
.long PT_NOTE .long PT_NOTE
.long PF_R .long PF_R
@ -1070,18 +1090,12 @@ str.error:
str.crlf: str.crlf:
.asciz "\r\n" .asciz "\r\n"
.endobj str.crlf .endobj str.crlf
str.cpuid:
.asciz "cpuid"
.endobj str.cpuid
str.oldskool:
.asciz "oldskool"
.endobj str.oldskool
str.e820: str.e820:
.asciz "e820" .asciz "e820"
.endobj str.e820 .endobj str.e820
str.long: str.oldcpu:
.asciz "nolong" .asciz "oldcpu"
.endobj str.long .endobj str.oldcpu
// Serial Line Configuration (8250 UART 16550) // Serial Line Configuration (8250 UART 16550)
// If it's hacked, it'll at least get hacked very slowly. // If it's hacked, it'll at least get hacked very slowly.
@ -1264,7 +1278,7 @@ longmodeloader:
lcheck: pushf # check for i8086 / i8088 / i80186 lcheck: pushf # check for i8086 / i8088 / i80186
pop %ax pop %ax
test $0x80,%ah # see intel manual volume 1 20.1.2 test $0x80,%ah # see intel manual volume 1 20.1.2
jnz 9f # we now assume 32bit is supported jnz 10f # we now assume 32bit is supported
pushfl # now check for i386 or early i486 pushfl # now check for i386 or early i486
pop %eax # test ability to change cpuid bit pop %eax # test ability to change cpuid bit
mov %eax,%ecx mov %eax,%ecx
@ -1275,7 +1289,7 @@ lcheck: pushf # check for i8086 / i8088 / i80186
pushfl pushfl
pop %eax pop %eax
cmp %eax,%ecx cmp %eax,%ecx
je 12f # we assume cpuid inst is available je 10f # we assume cpuid inst is available
or %ebx,%eax # puts cpuid bit in the on position or %ebx,%eax # puts cpuid bit in the on position
push %eax push %eax
popfl popfl
@ -1293,11 +1307,7 @@ lcheck: pushf # check for i8086 / i8088 / i80186
jne 10f jne 10f
xor %ax,%ax xor %ax,%ax
1: ret 1: ret
9: mov $REAL(str.oldskool),%di 10: mov $REAL(str.oldcpu),%di
jmp 20f
10: mov $REAL(str.long),%di
jmp 20f
12: mov $REAL(str.cpuid),%di
20: call rldie 20: call rldie
.endfn lcheck .endfn lcheck
@ -1615,5 +1625,26 @@ ape_idata_ro:
__data_start: __data_start:
.previous .previous
.section .dataepilogue,"aw",@progbits
.type __data_end,@object
.globl __data_end
.hidden __data_end
__data_end:
.previous
.section .bssprologue,"aw",@nobits
.type __bss_start,@object
.globl __bss_start
.hidden __bss_start
__bss_start:
.previous
.section .bssepilogue,"aw",@nobits
.type __bss_end,@object
.globl __bss_end
.hidden __bss_end
__bss_end:
.previous
.end .end
 

View file

@ -177,6 +177,8 @@
#include "ape/macros.internal.h" #include "ape/macros.internal.h"
#include "ape/relocations.h" #include "ape/relocations.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/elf/def.h"
#include "libc/elf/pf2prot.internal.h"
#include "libc/nt/pedef.internal.h" #include "libc/nt/pedef.internal.h"
#include "libc/zip.h" #include "libc/zip.h"
@ -358,6 +360,8 @@ SECTIONS {
.data . : { .data . : {
/*BEGIN: Read/Write Data */ /*BEGIN: Read/Write Data */
KEEP(*(SORT_BY_NAME(.piro.data.sort.iat.*)))
/*BEGIN: NT FORK COPYING */
KEEP(*(.dataprologue)) KEEP(*(.dataprologue))
*(.data .data.*) *(.data .data.*)
KEEP(*(SORT_BY_NAME(.sort.data.*))) KEEP(*(SORT_BY_NAME(.sort.data.*)))
@ -378,6 +382,8 @@ SECTIONS {
. = ALIGN(__SIZEOF_POINTER__); . = ALIGN(__SIZEOF_POINTER__);
KEEP(*(SORT_BY_NAME(.piro.data.sort.*))) KEEP(*(SORT_BY_NAME(.piro.data.sort.*)))
KEEP(*(.piro.pad.data)) KEEP(*(.piro.pad.data))
KEEP(*(.dataepilogue))
/*END: NT FORK COPYING */
. = ALIGN(PAGESIZE); . = ALIGN(PAGESIZE);
HIDDEN(_edata = .); HIDDEN(_edata = .);
PROVIDE_HIDDEN(edata = .); PROVIDE_HIDDEN(edata = .);
@ -404,6 +410,8 @@ SECTIONS {
/*BEGIN: bss memory that's addressable */ /*BEGIN: bss memory that's addressable */
.bss ALIGN(64) : { .bss ALIGN(64) : {
/*BEGIN: NT FORK COPYING */
KEEP(*(.bssprologue))
KEEP(*(SORT_BY_NAME(.piro.bss.init.*))) KEEP(*(SORT_BY_NAME(.piro.bss.init.*)))
*(.piro.bss) *(.piro.bss)
KEEP(*(SORT_BY_NAME(.piro.bss.sort.*))) KEEP(*(SORT_BY_NAME(.piro.bss.sort.*)))
@ -418,6 +426,8 @@ SECTIONS {
KEEP(*(SORT_BY_NAME(.sort.bss.*))) KEEP(*(SORT_BY_NAME(.sort.bss.*)))
KEEP(*(.bssepilogue))
/*END: NT FORK COPYING */
. = ALIGN(FRAMESIZE); /* for brk()/sbrk() allocation */ . = ALIGN(FRAMESIZE); /* for brk()/sbrk() allocation */
HIDDEN(_end = .); HIDDEN(_end = .);
PROVIDE_HIDDEN(end = .); PROVIDE_HIDDEN(end = .);
@ -497,6 +507,8 @@ HIDDEN(ape_ram_memsz = ADDR(.bss) + SIZEOF(.bss) - ape_ram_vaddr);
HIDDEN(ape_ram_align = PAGESIZE); HIDDEN(ape_ram_align = PAGESIZE);
HIDDEN(ape_ram_rva = RVA(ape_ram_vaddr)); HIDDEN(ape_ram_rva = RVA(ape_ram_vaddr));
HIDDEN(ape_stack_pf = DEFINED(ape_stack_pf) ? ape_stack_pf : PF_R | PF_W);
HIDDEN(ape_stack_prot = _PF2PROT(ape_stack_pf));
HIDDEN(ape_stack_offset = ape_ram_offset + ape_ram_filesz); HIDDEN(ape_stack_offset = ape_ram_offset + ape_ram_filesz);
HIDDEN(ape_stack_vaddr = DEFINED(ape_stack_vaddr) ? ape_stack_vaddr : 0x700000000000 - STACKSIZE); HIDDEN(ape_stack_vaddr = DEFINED(ape_stack_vaddr) ? ape_stack_vaddr : 0x700000000000 - STACKSIZE);
HIDDEN(ape_stack_paddr = ape_ram_paddr + ape_ram_filesz); HIDDEN(ape_stack_paddr = ape_ram_paddr + ape_ram_filesz);

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -5,6 +5,7 @@
# #
# - `make` # - `make`
# - Backtraces # - Backtraces
# - Syscall tracing
# - Function tracing # - Function tracing
# - Reasonably small # - Reasonably small
# - Reasonably optimized # - Reasonably optimized
@ -13,6 +14,7 @@ ifeq ($(MODE),)
CONFIG_CCFLAGS += \ CONFIG_CCFLAGS += \
$(BACKTRACES) \ $(BACKTRACES) \
$(FTRACE) \ $(FTRACE) \
-DSYSDEBUG \
-Og -Og
TARGET_ARCH ?= \ TARGET_ARCH ?= \
-msse3 -msse3
@ -23,6 +25,8 @@ endif
# - `make MODE=opt` # - `make MODE=opt`
# - Backtraces # - Backtraces
# - More optimized # - More optimized
# - Syscall tracing
# - Function tracing
# - Reasonably small # - Reasonably small
# - No memory corruption detection # - No memory corruption detection
# - assert() / CHECK_xx() may leak code into binary for debuggability # - assert() / CHECK_xx() may leak code into binary for debuggability
@ -35,7 +39,9 @@ CONFIG_CPPFLAGS += \
CONFIG_CCFLAGS += \ CONFIG_CCFLAGS += \
$(BACKTRACES) \ $(BACKTRACES) \
$(FTRACE) \ $(FTRACE) \
-O3 -DSYSDEBUG \
-O3 \
-fmerge-all-constants
TARGET_ARCH ?= \ TARGET_ARCH ?= \
-march=native -march=native
endif endif
@ -55,7 +61,7 @@ CONFIG_CPPFLAGS += \
-Wa,-msse2avx \ -Wa,-msse2avx \
-DSUPPORT_VECTOR=1 -DSUPPORT_VECTOR=1
CONFIG_CCFLAGS += \ CONFIG_CCFLAGS += \
-O3 -O3 -fmerge-all-constants
DEFAULT_COPTS += \ DEFAULT_COPTS += \
-mred-zone -mred-zone
TARGET_ARCH ?= \ TARGET_ARCH ?= \
@ -122,10 +128,12 @@ CONFIG_CPPFLAGS += \
CONFIG_CCFLAGS += \ CONFIG_CCFLAGS += \
$(BACKTRACES) \ $(BACKTRACES) \
$(FTRACE) \ $(FTRACE) \
-DSYSDEBUG \
-O2 \ -O2 \
-fno-inline -fno-inline
CONFIG_COPTS += \ CONFIG_COPTS += \
-fsanitize=address -fsanitize=address \
-fsanitize=undefined
TARGET_ARCH ?= \ TARGET_ARCH ?= \
-msse3 -msse3
OVERRIDE_CCFLAGS += \ OVERRIDE_CCFLAGS += \
@ -287,7 +295,7 @@ endif
# LLVM Mode # LLVM Mode
ifeq ($(MODE), llvm) ifeq ($(MODE), llvm)
TARGET_ARCH ?= -msse3 TARGET_ARCH ?= -msse3
CONFIG_CCFLAGS += $(BACKTRACES) $(FTRACE) -O2 CONFIG_CCFLAGS += $(BACKTRACES) $(FTRACE) -DSYSDEBUG -O2
AS = clang AS = clang
CC = clang CC = clang
CXX = clang++ CXX = clang++

View file

@ -100,7 +100,8 @@ SANITIZER = \
NO_MAGIC = \ NO_MAGIC = \
-mno-fentry \ -mno-fentry \
-fno-stack-protector \ -fno-stack-protector \
-fwrapv -fwrapv \
-fno-sanitize=all
OLD_CODE = \ OLD_CODE = \
-fno-strict-aliasing \ -fno-strict-aliasing \
@ -148,7 +149,6 @@ DEFAULT_CFLAGS = \
-std=gnu2x -std=gnu2x
DEFAULT_CXXFLAGS = \ DEFAULT_CXXFLAGS = \
-std=gnu++11 \
-fno-rtti \ -fno-rtti \
-fno-exceptions \ -fno-exceptions \
-fuse-cxa-atexit \ -fuse-cxa-atexit \
@ -169,7 +169,7 @@ DEFAULT_LDFLAGS = \
--gc-sections \ --gc-sections \
--build-id=none \ --build-id=none \
--no-dynamic-linker \ --no-dynamic-linker \
-zmax-page-size=0x1000 -zmax-page-size=0x1000 #--cref -Map=$@.map
ZIPOBJ_FLAGS = \ ZIPOBJ_FLAGS = \
-b$(IMAGE_BASE_VIRTUAL) -b$(IMAGE_BASE_VIRTUAL)
@ -301,6 +301,9 @@ OBJECTIFY.greg.c = \
-fno-instrument-functions \ -fno-instrument-functions \
-fno-optimize-sibling-calls \ -fno-optimize-sibling-calls \
-fno-sanitize=all \ -fno-sanitize=all \
-ffreestanding \
-mno-fentry \
-fwrapv \
-c -c
OBJECTIFY.ansi.c = $(CC) $(OBJECTIFY.c.flags) -ansi -Wextra -Werror -pedantic-errors -c OBJECTIFY.ansi.c = $(CC) $(OBJECTIFY.c.flags) -ansi -Wextra -Werror -pedantic-errors -c

View file

@ -48,7 +48,7 @@
set -- --regex-c='/^\(\(hidden\|extern\|const\) \)*[_[:alpha:]][_[:alnum:]]*[ *][ *]*\([_[:alpha:]][_[:alnum:]]*[ *][ *]*\)*\([_[:alpha:]][_$[:alnum:]]*\)/\4/b' "$@" set -- --regex-c='/^\(\(hidden\|extern\|const\) \)*[_[:alpha:]][_[:alnum:]]*[ *][ *]*\([_[:alpha:]][_[:alnum:]]*[ *][ *]*\)*\([_[:alpha:]][_$[:alnum:]]*\)/\4/b' "$@"
# ctags doesn't understand function prototypes, e.g. # ctags doesn't understand function prototypes, e.g.
# bool isheap(void *p) nothrow nocallback; # bool isheap(void *p) dontthrow nocallback;
set -- --regex-c='/^[_[:alpha:]][_[:alnum:]]*[ *][ *]*\([_[:alpha:]][_[:alnum:]]*[ *][ *]*\)*\([_[:alpha:]][_$[:alnum:]]*\)(.*/\2/b' "$@" set -- --regex-c='/^[_[:alpha:]][_[:alnum:]]*[ *][ *]*\([_[:alpha:]][_[:alnum:]]*[ *][ *]*\)*\([_[:alpha:]][_$[:alnum:]]*\)(.*/\2/b' "$@"
# ctags doesn't understand function pointers, e.g. # ctags doesn't understand function pointers, e.g.

View file

@ -31,7 +31,7 @@ o/%.lds: %.lds ; @$(COMPILE) -APREPROCESS $(PREPROCESS.lds)
o/%.inc: %.h ; @$(COMPILE) -APREPROCESS $(PREPROCESS) $(OUTPUT_OPTION) -D__ASSEMBLER__ -P $< o/%.inc: %.h ; @$(COMPILE) -APREPROCESS $(PREPROCESS) $(OUTPUT_OPTION) -D__ASSEMBLER__ -P $<
o/%.pkg: ; @$(COMPILE) -APACKAGE -T$@ $(PKG) $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) $(filter %.o,$^) o/%.pkg: ; @$(COMPILE) -APACKAGE -T$@ $(PKG) $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) $(filter %.o,$^)
o/%.h.ok: %.h ; @$(COMPILE) -ACHECK.h $(COMPILE.c) -xc -g0 -o $@ $< o/%.h.ok: %.h ; @$(COMPILE) -ACHECK.h $(COMPILE.c) -xc -g0 -o $@ $<
o/%.h.okk: %.h ; @$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $< o/%.okk: % ; @$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
o/%.greg.o: %.greg.c ; @$(COMPILE) -AOBJECTIFY.greg $(OBJECTIFY.greg.c) $(OUTPUT_OPTION) $< o/%.greg.o: %.greg.c ; @$(COMPILE) -AOBJECTIFY.greg $(OBJECTIFY.greg.c) $(OUTPUT_OPTION) $<
o/%.zip.o: o/% ; @$(COMPILE) -AZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $< o/%.zip.o: o/% ; @$(COMPILE) -AZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $<
@ -60,7 +60,8 @@ o/$(MODE)/%.o: %.cc ; @$(COMPILE) -AOBJECTIFY.cxx $(OBJECTIFY.cxx
o/$(MODE)/%.o: o/$(MODE)/%.cc ; @$(COMPILE) -AOBJECTIFY.cxx $(OBJECTIFY.cxx) $(OUTPUT_OPTION) $< o/$(MODE)/%.o: o/$(MODE)/%.cc ; @$(COMPILE) -AOBJECTIFY.cxx $(OBJECTIFY.cxx) $(OUTPUT_OPTION) $<
o/$(MODE)/%.lds: %.lds ; @$(COMPILE) -APREPROCESS $(PREPROCESS.lds) $(OUTPUT_OPTION) $< o/$(MODE)/%.lds: %.lds ; @$(COMPILE) -APREPROCESS $(PREPROCESS.lds) $(OUTPUT_OPTION) $<
o/$(MODE)/%.h.ok: %.h ; @$(COMPILE) -ACHECK.h $(COMPILE.c) -xc -g0 -o $@ $< o/$(MODE)/%.h.ok: %.h ; @$(COMPILE) -ACHECK.h $(COMPILE.c) -xc -g0 -o $@ $<
o/$(MODE)/%.h.okk: %.h ; @$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $< o/$(MODE)/%.hh.ok: %.hh ; @$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
o/$(MODE)/%.okk: % ; @$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
o/$(MODE)/%.cxx.o: %.c ; @$(COMPILE) -AOBJECTIFY.cxx $(OBJECTIFY.cxx) -xc++ $(OUTPUT_OPTION) $< o/$(MODE)/%.cxx.o: %.c ; @$(COMPILE) -AOBJECTIFY.cxx $(OBJECTIFY.cxx) -xc++ $(OUTPUT_OPTION) $<
o/$(MODE)/%.o: %.greg.c ; @$(COMPILE) -AOBJECTIFY.greg $(OBJECTIFY.greg.c) $(OUTPUT_OPTION) $< o/$(MODE)/%.o: %.greg.c ; @$(COMPILE) -AOBJECTIFY.greg $(OBJECTIFY.greg.c) $(OUTPUT_OPTION) $<
o/$(MODE)/%.greg.o: %.greg.c ; @$(COMPILE) -AOBJECTIFY.greg $(OBJECTIFY.greg.c) $(OUTPUT_OPTION) $< o/$(MODE)/%.greg.o: %.greg.c ; @$(COMPILE) -AOBJECTIFY.greg $(OBJECTIFY.greg.c) $(OUTPUT_OPTION) $<
@ -77,7 +78,9 @@ o/$(MODE)/%.runs: o/$(MODE)/% ; @$(COMPILE) -ACHECK -tT$@ $< $(TESTARGS)
o/$(MODE)/%.pkg: ; @$(COMPILE) -APACKAGE -T$@ $(PKG) $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) $(filter %.o,$^) o/$(MODE)/%.pkg: ; @$(COMPILE) -APACKAGE -T$@ $(PKG) $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) $(filter %.o,$^)
o/$(MODE)/%.zip.o: % ; @$(COMPILE) -AZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $< o/$(MODE)/%.zip.o: % ; @$(COMPILE) -AZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $<
o/$(MODE)/%-gcc.asm: %.c ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $< o/$(MODE)/%-gcc.asm: %.c ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
o/$(MODE)/%-gcc.asm: %.cc ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.cxx) -S -g0 $(OUTPUT_OPTION) $<
o/$(MODE)/%-clang.asm: %.c ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $< o/$(MODE)/%-clang.asm: %.c ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
o/$(MODE)/%-clang.asm: %.cc ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.cxx) -S -g0 $(OUTPUT_OPTION) $<
o/$(MODE)/%-clang.asm: CC = $(CLANG) o/$(MODE)/%-clang.asm: CC = $(CLANG)
o/%.a: o/%.a:

View file

@ -37,4 +37,3 @@ sad16x8n:
jnz 0b jnz 0b
1: .leafepilogue 1: .leafepilogue
.endfn sad16x8n,globl,hidden .endfn sad16x8n,globl,hidden
.source __FILE__

View file

@ -17,7 +17,6 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
.source __FILE__
clamp4int256$core: clamp4int256$core:
.leafprologue .leafprologue

View file

@ -72,7 +72,8 @@ static const float PLM_VIDEO_PIXEL_ASPECT_RATIO[] = {
0.6735, /* 3:4? */ 0.6735, /* 3:4? */
0.7031, /* MPEG-1 / MPEG-2 video encoding divergence? */ 0.7031, /* MPEG-1 / MPEG-2 video encoding divergence? */
0.7615, 0.8055, 0.8437, 0.8935, 0.9157, 0.9815, 0.7615, 0.8055, 0.8437, 0.8935, 0.9157, 0.9815,
1.0255, 1.0695, 1.0950, 1.1575, 1.2051}; 1.0255, 1.0695, 1.0950, 1.1575, 1.2051,
};
static const float PLM_VIDEO_PICTURE_RATE[] = { static const float PLM_VIDEO_PICTURE_RATE[] = {
23.976, /* NTSC-Film */ 23.976, /* NTSC-Film */

View file

@ -101,7 +101,7 @@ struct SamplingSolution *ComputeSamplingSolution(long dn, long sn, double dar,
if (!off) off = (dar - 1) / 2; if (!off) off = (dar - 1) / 2;
f = dar < 1 ? 1 / dar : dar; f = dar < 1 ? 1 / dar : dar;
s = 3 * f + 4; s = 3 * f + 4;
fweights = gc(xcalloc(s, sizeof(double))); fweights = gc(xcalloc(s + /*xxx*/ 2, sizeof(double)));
res = NewSamplingSolution(dn, s); res = NewSamplingSolution(dn, s);
weights = res->weights; weights = res->weights;
indices = res->indices; indices = res->indices;

View file

@ -19,6 +19,7 @@
#include "dsp/tty/tty.h" #include "dsp/tty/tty.h"
#include "libc/bits/pushpop.h" #include "libc/bits/pushpop.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/log/internal.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/nt/console.h" #include "libc/nt/console.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
@ -30,7 +31,7 @@
static int ttysetcursor(int fd, bool visible) { static int ttysetcursor(int fd, bool visible) {
struct NtConsoleCursorInfo ntcursor; struct NtConsoleCursorInfo ntcursor;
char code[8] = "\e[?25l"; char code[8] = "\e[?25l";
if (IsTerminalInarticulate()) return 0; if (__nocolor) return 0;
if (visible) code[5] = 'h'; if (visible) code[5] = 'h';
if (SupportsWindows()) { if (SupportsWindows()) {
GetConsoleCursorInfo(GetStdHandle(kNtStdOutputHandle), &ntcursor); GetConsoleCursorInfo(GetStdHandle(kNtStdOutputHandle), &ntcursor);

View file

@ -31,13 +31,6 @@ int ttysetraw(struct termios *conf, int64_t flags) {
conf->c_cflag &= ~(CSIZE | PARENB); conf->c_cflag &= ~(CSIZE | PARENB);
conf->c_cflag |= CS8; conf->c_cflag |= CS8;
conf->c_iflag |= IUTF8; conf->c_iflag |= IUTF8;
/* if (flags & kTtyLfToCrLf) { */
/* /\* conf->c_oflag &= ~(OLCUC | OCRNL | ONLRET | OFILL | OFDEL); *\/ */
/* /\* conf->c_oflag |= ONLCR | ONOCR; *\/ */
/* conf->c_oflag |= ONLCR; */
/* } else { */
/* conf->c_oflag &= ~OPOST; */
/* } */
if (!(flags & kTtySigs)) { if (!(flags & kTtySigs)) {
conf->c_iflag &= ~(IGNBRK | BRKINT); conf->c_iflag &= ~(IGNBRK | BRKINT);
conf->c_lflag &= ~(ISIG); conf->c_lflag &= ~(ISIG);

View file

@ -731,11 +731,11 @@ static bool ChunkEq(struct TtyRgb c[hasatleast 4],
} }
static struct TtyRgb *CopyChunk(struct TtyRgb chunk[hasatleast 4], static struct TtyRgb *CopyChunk(struct TtyRgb chunk[hasatleast 4],
const struct TtyRgb *c, size_t n) { const struct TtyRgb *c, size_t xn) {
chunk[TL] = c[0 + 0]; chunk[TL] = c[00 + 0];
chunk[TR] = c[0 + 1]; chunk[TR] = c[00 + 1];
chunk[BL] = c[n + 0]; chunk[BL] = c[xn + 0];
chunk[BR] = c[n + 1]; chunk[BR] = c[xn + 1];
return chunk; return chunk;
} }
@ -766,17 +766,18 @@ static dontinline char *CopyRun(char *v, size_t n,
/** /**
* Maps 2×2 pixel chunks onto ANSI UNICODE cells. * Maps 2×2 pixel chunks onto ANSI UNICODE cells.
* @note h/t Nick Black for his quadrant blitting work on notcurses * @note h/t Nick Black for his quadrant blitting work on notcurses
* @note yn and xn need to be even
*/ */
char *ttyraster(char *v, const struct TtyRgb *c, size_t yn, size_t n, char *ttyraster(char *v, const struct TtyRgb *c, size_t yn, size_t xn,
struct TtyRgb bg, struct TtyRgb fg) { struct TtyRgb bg, struct TtyRgb fg) {
unsigned y, x; unsigned y, x;
struct Pick p; struct Pick p;
struct Glyph glyph; struct Glyph glyph;
struct TtyRgb chun[4], lastchunk[4]; struct TtyRgb chun[4], lastchunk[4];
for (y = 0; y < yn; y += 2, c += n) { for (y = 0; y < yn; y += 2, c += xn) {
if (y) *v++ = '\r', *v++ = '\n'; if (y) *v++ = '\r', *v++ = '\n';
for (x = 0; x < n; x += 2, c += 2) { for (x = 0; x < xn; x += 2, c += 2) {
CopyChunk(chun, c, n); CopyChunk(chun, c, xn);
if (ttyquant()->alg == kTtyQuantTrue) { if (ttyquant()->alg == kTtyQuantTrue) {
if (ttyquant()->blocks == kTtyBlocksCp437) { if (ttyquant()->blocks == kTtyBlocksCp437) {
p = PickBlockCp437True(chun[TL], chun[TR], chun[BL], chun[BR]); p = PickBlockCp437True(chun[TL], chun[TR], chun[BL], chun[BR]);

View file

@ -17,7 +17,6 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
.source __FILE__
// Returns index of minimum uint16 in array. // Returns index of minimum uint16 in array.
// //

View file

@ -17,7 +17,6 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
.source __FILE__
// Returns index of minimum positive int16 in array. // Returns index of minimum positive int16 in array.
// //

View file

@ -18,7 +18,6 @@
*/ */
#include "libc/nexgen32e/x86feature.h" #include "libc/nexgen32e/x86feature.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
.source __FILE__
// Dispatches to fastest windex() implementation. // Dispatches to fastest windex() implementation.
.initbss 300,_init_windex .initbss 300,_init_windex

View file

@ -18,9 +18,12 @@
* make -j12 o//examples/auto-launch-gdb-on-crash.com * make -j12 o//examples/auto-launch-gdb-on-crash.com
* o//examples/auto-launch-gdb-on-crash.com * o//examples/auto-launch-gdb-on-crash.com
* *
* Backtrace is logged instead if run outside interactive terminal. * Backtrace is logged instead if run outside interactive terminal. We
* Environmental factors such as GDB, MAKEFLAGS, ADDR2LINE, TERM, and * also don't auto-launch GDB on non-Linux since the development tools
* isatty(STDERR_FILENO) should also be taken into consideration: * on other platforms generally can't be relied upon to correctly debug
* binaries built with a Linux toolchain. Environmental factors such as
* GDB, MAKEFLAGS, ADDR2LINE, TERM, and isatty(STDERR_FILENO) should
* also be taken into consideration:
* *
* $ export GDB=eoatuhshtuone * $ export GDB=eoatuhshtuone
* $ o//examples/auto-launch-gdb-on-crash.com * $ o//examples/auto-launch-gdb-on-crash.com
@ -37,7 +40,7 @@
*/ */
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
showcrashreports(); ShowCrashReports();
asm("int3"); /* cf. __die(), perror("msg"), abort(), exit(1), _Exit(1) */ asm("int3"); /* cf. __die(), perror("msg"), abort(), exit(1), _Exit(1) */
return 0; return 0;
} }

View file

@ -0,0 +1,62 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/bits/bits.h"
#include "libc/dce.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
/**
* ASAN static memory safety crash example.
*
* make -j8 MODE=dbg o/dbg/examples/auto-memory-safety-crash.com
* o/dbg/examples/auto-memory-safety-crash.com
*
* You should see:
*
* global redzone 1-byte store at 0x42700d shadow 0x8007ce01
* ./o/dbg/examples/auto-memory-safety-crash.com
* x
* ........................................GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
* |0 |0 |0 |0 |5 |-18 |-18 |-18 |-18
*  f.ä     f.ä     fD  hello                                                
* 000000400000-000000427000 .text
* 000000427000-000000429000 .data address
* 00007fff0000-00008000ffff
* 000080070000-00008008ffff shadow
* 0e007fff0000-0e008000ffff
* 100047d20000-100047d3ffff
* 6ffffffe0000-6fffffffffff
* the memory in question belongs to the symbols
* buffer [0x427000,0x42700c] size 13
* the crash was caused by
* 0x00000000004046f3: __die at libc/log/die.c:40
* 0x0000000000404aed: __asan_report_store at libc/intrin/asan.c:1183
* 0x0000000000402552: main at examples/auto-memory-safety-crash.c:27
* 0x000000000040268d: cosmo at libc/runtime/cosmo.S:64
* 0x00000000004021ae: _start at libc/crt/crt.S:77
*
* @see libc/intrin/asancodes.h for meaning of G, etc. and negative numbers
* @see libc/nexgen32e/kcp437.S for meaning of symbols
*/
char buffer[13] = "hello";
int main(int argc, char *argv[]) {
if (!IsAsan()) {
printf("this example is intended for MODE=asan or MODE=dbg\n");
exit(1);
}
ShowCrashReports(); /* not needed but yoinks appropriate symbols */
int i = 13;
asm("" : "+r"(i)); /* prevent compiler being smart */
buffer[i] = 1;
return 0;
}

View file

@ -0,0 +1,74 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/bits/bits.h"
#include "libc/dce.h"
#include "libc/log/log.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
/**
* ASAN heap memory safety crash example.
*
* make -j8 MODE=dbg o/dbg/examples/auto-memory-safety-crash2.com
* o/dbg/examples/auto-memory-safety-crash2.com
*
* You should see:
*
* heap overrun 1-byte store at 0x10008004002d shadow 0x20090000005
* ./o/dbg/examples/auto-memory-safety-crash2.com
* x
* OOOOOOOOOOOUUUUUUUUUUUUUUUU.............OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
* |-7 |-6 |-6 |0 |5 |-7 |-7 |-7 |-7
*    »!@     ÿ:Y= S       hello                 GT&@     á+@     »!@  
* 000000400000-00000042b000 .text
* 00000042b000-00000042d000 .data
* 00007fff0000-00008000ffff
* 000080070000-00008008ffff
* 02008fff0000-02009000ffff shadow
* 0e007fff0000-0e008000ffff
* 10003ab90000-10003abaffff
* 100080000000-10008000ffff address
* 6ffffffe0000-6fffffffffff
*
* the memory was allocated by
* 0x100080040020 64 bytes [dlmalloc]
* 0x100080040030 13 bytes [actual]
* 402608 main
* 402ba0 cosmo
* 4021af _start
*
* the crash was caused by
* 0x0000000000404793: __die at libc/log/die.c:40
* 0x0000000000404f56: __asan_report_store at libc/intrin/asan.c:1183
* 0x0000000000402579: main at examples/auto-memory-safety-crash2.c:30
* 0x000000000040270f: cosmo at libc/runtime/cosmo.S:64
* 0x00000000004021ae: _start at libc/crt/crt.S:77
*
* @see libc/intrin/asancodes.h for meaning of U, O, etc. and negative numbers
* @see libc/nexgen32e/kcp437.S for meaning of symbols
*/
int main(int argc, char *argv[]) {
if (!IsAsan()) {
printf("this example is intended for MODE=asan or MODE=dbg\n");
exit(1);
}
char *buffer;
ShowCrashReports(); /* not needed but yoinks appropriate symbols */
buffer = malloc(13);
strcpy(buffer, "hello");
int i = 13;
asm("" : "+r"(i)); /* prevent compiler being smart */
buffer[i] = 1;
asm("" : "+r"(buffer)); /* prevent compiler being smart */
return 0;
}

View file

@ -0,0 +1,39 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/bits/bits.h"
#include "libc/dce.h"
#include "libc/log/log.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
/**
* ASAN use-after-free memory safety crash example.
*
* make -j8 MODE=dbg o/dbg/examples/auto-memory-safety-crash3.com
* o/dbg/examples/auto-memory-safety-crash3.com
*
*/
int main(int argc, char *argv[]) {
if (!IsAsan()) {
printf("this example is intended for MODE=asan or MODE=dbg\n");
exit(1);
}
char *buffer;
ShowCrashReports(); /* not needed but yoinks appropriate symbols */
buffer = malloc(13);
strcpy(buffer, "hello");
free(buffer);
asm("" : "+r"(buffer)); /* prevent compiler being smart */
buffer[0] = 1;
return 0;
}

View file

@ -7,19 +7,30 @@
http://creativecommons.org/publicdomain/zero/1.0/ │ http://creativecommons.org/publicdomain/zero/1.0/ │
*/ */
#endif #endif
#include "libc/intrin/kprintf.h"
#include "libc/log/backtrace.internal.h" #include "libc/log/backtrace.internal.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h" #include "libc/runtime/symbols.internal.h"
#include "libc/stdio/stdio.h"
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
showcrashreports(); ShowCrashReports();
if (IsDebuggerPresent(false)) { if (IsDebuggerPresent(false)) {
printf("debugger found!\r\n"); kprintf("debugger found!%n");
DebugBreak(); } else {
kprintf("try running: gdb %s%n", argv[0]);
kprintf("try running: o//tool/build/strace.com %s%n", argv[0]);
}
asm volatile("mov\t%4,%%r10\n\t"
"mov\t%5,%%r8\n\t"
"mov\t%6,%%r9\n\t"
"int3"
: /* no outputs */
: "a"(0), "D"(1), "S"(2), "d"(3), "g"(4), "g"(5), "g"(6)
: "r8", "r9", "r10");
printf("recovered from SIGTRAP without handler\r\n");
return 0; return 0;
} }
printf("try running: gdb %s\r\n", argv[0]);
return 1;
}

View file

@ -73,14 +73,14 @@ void GetOpts(int argc, char *argv[]) {
int cp(const char *src, const char *dst) { int cp(const char *src, const char *dst) {
if (endswith(dst, "/") || isdirectory(dst)) { if (endswith(dst, "/") || isdirectory(dst)) {
dst = _gc(xasprintf("%s/%s", dst, basename)); dst = _gc(xasprintf("%s/%s", dst, basename(src)));
} }
if (!force && access(dst, W_OK) == -1 && errno != ENOENT) goto OnFail; if (!force && access(dst, W_OK) == -1 && errno != ENOENT) goto OnFail;
if (copyfile(src, dst, flags) == -1) goto OnFail; if (copyfile(src, dst, flags) == -1) goto OnFail;
return 0; return 0;
OnFail: OnFail:
fprintf(stderr, "%s %s %s: %s\n", "error: cp", src, dst, strerror(errno)); fprintf(stderr, "%s %s %s: %s\n", "error: cp", src, dst, strerror(errno));
return 1; return -1;
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {

38
examples/cplusplus-stl.cc Normal file
View file

@ -0,0 +1,38 @@
/*-*-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/stdio/stdio.h"
#include "third_party/libcxx/map"
#include "third_party/libcxx/string"
int main(int argc, char *argv[]) {
printf("std::map + std::string example\n");
std::map<std::string, int> m{
{"CPU", 10},
{"GPU", 15},
{"RAM", 20},
};
printf("m[\"CPU\"] is %d\n", m["CPU"]);
printf("m[\"RAM\"] is %d\n", m["RAM"]);
printf("m[\"GPU\"] is %d\n", m["GPU"]);
printf("setting cpu to 25\n");
m["CPU"] = 25; // update an existing value
printf("m[\"CPU\"] is %d\n", m["CPU"]);
printf("m[\"RAM\"] is %d\n", m["RAM"]);
printf("m[\"GPU\"] is %d\n", m["GPU"]);
}

View file

@ -24,6 +24,6 @@
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
volatile int64_t x; volatile int64_t x;
showcrashreports(); ShowCrashReports();
return 1 / (x = 0); return 1 / (x = 0);
} }

52
examples/crashreport2.c Normal file
View file

@ -0,0 +1,52 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/log/log.h"
#include "libc/stdio/stdio.h"
/**
* @fileoverview CTRL+\ debugging example
*
* make -j8 -O o//examples/crashreport2.com
* o//examples/crashreport2.com
*
* Assuming you call ShowCrashReports() from main(), you can press
* `CTRL+\` at anny time to generate a `SIGQUIT` message that lets you
* debug wrongness and freezups.
*
* On supported platforms, this will cause GDB to automatically attach.
* The nice thing about this, is you can start stepping through your
* code at the precice instruction where the interrupt happened. See
* `libc/log/attachdebugger.c` to see how it works.
*
* If you wish to suppress the auto-GDB behavior, then:
*
* export GDB=
*
* Or alternatively:
*
* extern int __isworker;
* __isworker = true;
*
* Will cause your `SIGQUIT` handler to just print a crash report
* instead. This is useful for production software that might be running
* in a terminal environment like GNU Screen, but it's not desirable to
* have ten worker processes trying to attach GDB at once.
*/
int main(int argc, char *argv[]) {
volatile int64_t x;
ShowCrashReports();
printf("please press ctrl+\\ and see what happens...\n");
sigsuspend(0);
printf("\n\n");
printf("congratulations! your program is now resuming\n");
return 0;
}

View file

@ -36,7 +36,7 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "This echos stdio until Ctrl+C is pressed.\n"); fprintf(stderr, "This echos stdio until Ctrl+C is pressed.\n");
CHECK_NE(-1, sigaction(SIGINT, &saint, NULL)); CHECK_NE(-1, sigaction(SIGINT, &saint, NULL));
for (;;) { for (;;) {
rc = read(0, buf, BUFSIZ); rc = read(0, buf, 512);
if (rc != -1) { if (rc != -1) {
got = rc; got = rc;
} else { } else {

View file

@ -65,11 +65,26 @@
#define HeaderEqualCase(H, S) \ #define HeaderEqualCase(H, S) \
SlicesEqualCase(S, strlen(S), HeaderData(H), HeaderLength(H)) SlicesEqualCase(S, strlen(S), HeaderData(H), HeaderLength(H))
int sock;
static bool TuneSocket(int fd, int a, int b, int x) { static bool TuneSocket(int fd, int a, int b, int x) {
if (!b) return false; if (!b) return false;
return setsockopt(fd, a, b, &x, sizeof(x)) != -1; return setsockopt(fd, a, b, &x, sizeof(x)) != -1;
} }
static void Write(const void *p, size_t n) {
ssize_t rc;
rc = write(1, p, n);
if (rc == -1 && errno == EPIPE) {
close(sock);
exit(128 + SIGPIPE);
}
if (rc != n) {
fprintf(stderr, "write failed: %m\n");
exit(1);
}
}
static int TlsSend(void *c, const unsigned char *p, size_t n) { static int TlsSend(void *c, const unsigned char *p, size_t n) {
int rc; int rc;
NOISEF("begin send %zu", n); NOISEF("begin send %zu", n);
@ -106,8 +121,7 @@ static wontreturn void PrintUsage(FILE *f, int rc) {
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
if (!NoDebug()) showcrashreports(); if (!NoDebug()) ShowCrashReports();
xsigaction(SIGPIPE, SIG_IGN, 0, 0, 0);
/* /*
* Read flags. * Read flags.
@ -226,19 +240,17 @@ int main(int argc, char *argv[]) {
*/ */
mbedtls_ssl_config conf; mbedtls_ssl_config conf;
mbedtls_ssl_context ssl; mbedtls_ssl_context ssl;
mbedtls_x509_crt *cachain = 0;
mbedtls_ctr_drbg_context drbg; mbedtls_ctr_drbg_context drbg;
if (usessl) { if (usessl) {
mbedtls_ssl_init(&ssl); mbedtls_ssl_init(&ssl);
mbedtls_ctr_drbg_init(&drbg); mbedtls_ctr_drbg_init(&drbg);
mbedtls_ssl_config_init(&conf); mbedtls_ssl_config_init(&conf);
cachain = GetSslRoots();
CHECK_EQ(0, mbedtls_ctr_drbg_seed(&drbg, GetEntropy, 0, "justine", 7)); CHECK_EQ(0, mbedtls_ctr_drbg_seed(&drbg, GetEntropy, 0, "justine", 7));
CHECK_EQ(0, mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, CHECK_EQ(0, mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT)); MBEDTLS_SSL_PRESET_DEFAULT));
mbedtls_ssl_conf_authmode(&conf, authmode); mbedtls_ssl_conf_authmode(&conf, authmode);
mbedtls_ssl_conf_ca_chain(&conf, cachain, 0); mbedtls_ssl_conf_ca_chain(&conf, GetSslRoots(), 0);
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &drbg); mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &drbg);
if (!IsTiny()) mbedtls_ssl_conf_dbg(&conf, TlsDebug, 0); if (!IsTiny()) mbedtls_ssl_conf_dbg(&conf, TlsDebug, 0);
CHECK_EQ(0, mbedtls_ssl_setup(&ssl, &conf)); CHECK_EQ(0, mbedtls_ssl_setup(&ssl, &conf));
@ -258,7 +270,7 @@ int main(int argc, char *argv[]) {
/* /*
* Connect to server. * Connect to server.
*/ */
int ret, sock; int ret;
CHECK_NE(-1, (sock = GoodSocket(addr->ai_family, addr->ai_socktype, CHECK_NE(-1, (sock = GoodSocket(addr->ai_family, addr->ai_socktype,
addr->ai_protocol, false, addr->ai_protocol, false,
&(struct timeval){-60}))); &(struct timeval){-60})));
@ -283,6 +295,8 @@ int main(int argc, char *argv[]) {
CHECK_EQ(n, write(sock, request, n)); CHECK_EQ(n, write(sock, request, n));
} }
xsigaction(SIGPIPE, SIG_IGN, 0, 0, 0);
/* /*
* Handle response. * Handle response.
*/ */
@ -330,7 +344,7 @@ int main(int argc, char *argv[]) {
break; break;
} }
if (method == kHttpHead) { if (method == kHttpHead) {
CHECK_EQ(hdrlen, write(1, p, hdrlen)); Write(p, hdrlen);
goto Finished; goto Finished;
} else if (msg.status == 204 || msg.status == 304) { } else if (msg.status == 204 || msg.status == 304) {
goto Finished; goto Finished;
@ -348,32 +362,32 @@ int main(int argc, char *argv[]) {
t = kHttpClientStateBodyLengthed; t = kHttpClientStateBodyLengthed;
paylen = rc; paylen = rc;
if (paylen > i - hdrlen) { if (paylen > i - hdrlen) {
CHECK_EQ(i - hdrlen, write(1, p + hdrlen, i - hdrlen)); Write(p + hdrlen, i - hdrlen);
} else { } else {
CHECK_EQ(paylen, write(1, p + hdrlen, paylen)); Write(p + hdrlen, paylen);
goto Finished; goto Finished;
} }
} else { } else {
t = kHttpClientStateBody; t = kHttpClientStateBody;
CHECK_EQ(i - hdrlen, write(1, p + hdrlen, i - hdrlen)); Write(p + hdrlen, i - hdrlen);
} }
} }
break; break;
case kHttpClientStateBody: case kHttpClientStateBody:
if (!g) goto Finished; if (!g) goto Finished;
CHECK_EQ(g, write(1, p + i - g, g)); Write(p + i - g, g);
break; break;
case kHttpClientStateBodyLengthed: case kHttpClientStateBodyLengthed:
CHECK(g); CHECK(g);
if (i - hdrlen > paylen) g = hdrlen + paylen - (i - g); if (i - hdrlen > paylen) g = hdrlen + paylen - (i - g);
CHECK_EQ(g, write(1, p + i - g, g)); Write(p + i - g, g);
if (i - hdrlen >= paylen) goto Finished; if (i - hdrlen >= paylen) goto Finished;
break; break;
case kHttpClientStateBodyChunked: case kHttpClientStateBodyChunked:
Chunked: Chunked:
CHECK_NE(-1, (rc = Unchunk(&u, p + hdrlen, i - hdrlen, &paylen))); CHECK_NE(-1, (rc = Unchunk(&u, p + hdrlen, i - hdrlen, &paylen)));
if (rc) { if (rc) {
CHECK_EQ(paylen, write(1, p + hdrlen, paylen)); Write(p + hdrlen, paylen);
goto Finished; goto Finished;
} }
break; break;
@ -397,7 +411,6 @@ Finished:
mbedtls_ssl_free(&ssl); mbedtls_ssl_free(&ssl);
mbedtls_ctr_drbg_free(&drbg); mbedtls_ctr_drbg_free(&drbg);
mbedtls_ssl_config_free(&conf); mbedtls_ssl_config_free(&conf);
mbedtls_x509_crt_free(cachain);
mbedtls_ctr_drbg_free(&drbg); mbedtls_ctr_drbg_free(&drbg);
} }

62
examples/datauri.c Normal file
View file

@ -0,0 +1,62 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/log/log.h"
#include "libc/runtime/gc.internal.h"
#include "libc/stdio/stdio.h"
#include "libc/x/x.h"
#include "net/http/escape.h"
#include "net/http/http.h"
#include "third_party/getopt/getopt.h"
#include "third_party/stb/stb_image.h"
#define USAGE \
" [FLAGS] FILE...\n\
Utility for printing data:base64 URIs.\n\
\n\
FLAGS\n\
\n\
-h Help\n"
void PrintUsage(int rc, FILE *f) {
fputs("Usage: ", f);
fputs(program_invocation_name, f);
fputs(USAGE, f);
exit(rc);
}
void PrintUri(const char *path) {
size_t n;
void *img, *src, *mime;
int opt, i;
if (!(img = gc(xslurp(path, &n)))) exit(2);
fputs("data:", stdout);
fputs(FindContentType(path, -1), stdout);
fputs(";base64,", stdout);
fputs(gc(EncodeBase64(img, n, 0)), stdout);
}
int main(int argc, char *argv[]) {
int i;
while ((i = getopt(argc, argv, "?h")) != -1) {
switch (i) {
case '?':
case 'h':
PrintUsage(0, stdout);
default:
PrintUsage(1, stderr);
}
}
if (optind == argc) {
PrintUsage(1, stderr);
}
for (i = optind; i < argc; ++i) {
PrintUri(argv[i]);
}
}

View file

@ -51,7 +51,6 @@ EXAMPLES_DIRECTDEPS = \
LIBC_NT_USER32 \ LIBC_NT_USER32 \
LIBC_NT_WS2_32 \ LIBC_NT_WS2_32 \
LIBC_NT_ADVAPI32 \ LIBC_NT_ADVAPI32 \
LIBC_OHMYPLUS \
LIBC_RAND \ LIBC_RAND \
LIBC_RUNTIME \ LIBC_RUNTIME \
LIBC_SOCK \ LIBC_SOCK \
@ -73,6 +72,7 @@ EXAMPLES_DIRECTDEPS = \
THIRD_PARTY_DLMALLOC \ THIRD_PARTY_DLMALLOC \
THIRD_PARTY_GDTOA \ THIRD_PARTY_GDTOA \
THIRD_PARTY_GETOPT \ THIRD_PARTY_GETOPT \
THIRD_PARTY_LIBCXX \
THIRD_PARTY_LINENOISE \ THIRD_PARTY_LINENOISE \
THIRD_PARTY_LUA \ THIRD_PARTY_LUA \
THIRD_PARTY_MBEDTLS \ THIRD_PARTY_MBEDTLS \
@ -93,7 +93,8 @@ o/$(MODE)/examples/examples.pkg: \
o/$(MODE)/examples/unbourne.o: \ o/$(MODE)/examples/unbourne.o: \
OVERRIDE_CPPFLAGS += \ OVERRIDE_CPPFLAGS += \
-DSTACK_FRAME_UNLIMITED -DSTACK_FRAME_UNLIMITED \
-fpie
o/$(MODE)/examples/%.com.dbg: \ o/$(MODE)/examples/%.com.dbg: \
$(EXAMPLES_DEPS) \ $(EXAMPLES_DEPS) \
@ -132,6 +133,16 @@ o/$(MODE)/examples/nesemu1.com.dbg: \
$(APE) $(APE)
@$(APELINK) @$(APELINK)
o/$(MODE)/examples/nesemu1.com: \
o/$(MODE)/examples/nesemu1.com.dbg \
o/$(MODE)/third_party/zip/zip.com \
o/$(MODE)/tool/build/symtab.com
@$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
-o o/$(MODE)/examples/.nesemu1/.symtab $<
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
o/$(MODE)/examples/.nesemu1/.symtab
o/$(MODE)/examples/hello.com.dbg: \ o/$(MODE)/examples/hello.com.dbg: \
$(EXAMPLES_DEPS) \ $(EXAMPLES_DEPS) \
o/$(MODE)/examples/hello.o \ o/$(MODE)/examples/hello.o \

View file

@ -8,14 +8,26 @@
*/ */
#endif #endif
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/sigbits.h"
#include "libc/calls/struct/sigset.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/sysv/consts/sig.h"
STATIC_YOINK("strerror");
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
if (argc < 3) { sigset_t ss;
fputs("USAGE: EXEC.COM PROG ARGV₀ [ARGV₁...]\n", stderr); if (argc < 2) {
fputs("USAGE: EXEC.COM PROG [ARGV₀...]\n", stderr);
return 1; return 1;
} }
// block arbitrary signal so __printargs() looks cooler
sigemptyset(&ss);
sigaddset(&ss, SIGPWR);
sigprocmask(SIG_BLOCK, &ss, 0);
execv(argv[1], argv + 2); execv(argv[1], argv + 2);
return 127; return 127;
} }

23
examples/forkexec.c Normal file
View file

@ -0,0 +1,23 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/stdio/stdio.h"
int main(int argc, char *argv[]) {
int pid;
if (argc < 3) {
fputs("USAGE: FORKEXEC.COM PROG ARGV₀ [ARGV₁...]\n", stderr);
return 1;
}
if (!fork()) {
execv(argv[1], argv + 2);
return 127;
}
}

25
examples/forkexecwait.c Normal file
View file

@ -0,0 +1,25 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/stdio/stdio.h"
int main(int argc, char *argv[]) {
int pid;
volatile void *p;
if (argc < 3) {
fputs("USAGE: FORKEXECWAIT.COM PROG ARGV₀ [ARGV₁...]\n", stderr);
return 1;
}
if (!fork()) {
execv(argv[1], argv + 2);
return 127;
}
wait(0);
}

View file

@ -8,13 +8,17 @@
*/ */
#endif #endif
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/check.h" #include "libc/log/check.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/nt/nt/process.h" #include "libc/nt/nt/process.h"
#include "libc/rand/rand.h" #include "libc/rand/rand.h"
#include "libc/runtime/gc.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/time/time.h" #include "libc/time/time.h"
#include "libc/x/x.h"
dontinline void dostuff(const char *s) { dontinline void dostuff(const char *s) {
int i, us; int i, us;

View file

@ -14,11 +14,11 @@
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
int c, n; int c, n;
char a[22]; char a[22], *p;
if ((c = GetCpuCount())) { if ((c = GetCpuCount())) {
n = int64toarray_radix10(c, a); p = FormatInt64(a, c);
a[n++] = '\n'; *p++ = '\n';
return write(1, a, n) == n ? 0 : 1; return write(1, a, p - a) == p - a ? 0 : 1;
} else { } else {
return 1; return 1;
} }

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

@ -44,8 +44,8 @@
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/time/time.h" #include "libc/time/time.h"
#include "third_party/zlib/zlib.h" #include "third_party/zlib/zlib.h"
// clang-format off
/* clang-format off */
#define DICT "usr/share/dict/hangman" #define DICT "usr/share/dict/hangman"
#define MAXERR 7 #define MAXERR 7
#define MINSCORE 0 #define MINSCORE 0

View file

@ -9,6 +9,8 @@
#endif #endif
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
STATIC_YOINK("mmap"); // TODO: fix bandaid for MODE=asan
int main() { int main() {
printf("%s\n", "hello world"); printf("%s\n", "hello world");
return 0; return 0;

View file

@ -7,23 +7,98 @@
http://creativecommons.org/publicdomain/zero/1.0/ │ http://creativecommons.org/publicdomain/zero/1.0/ │
*/ */
#endif #endif
#include "libc/dce.h"
#include "libc/log/log.h"
#include "libc/runtime/gc.internal.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/x/x.h" #include "libc/x/x.h"
#include "net/http/escape.h"
#include "net/http/http.h"
#include "third_party/getopt/getopt.h"
#include "third_party/stb/stb_image.h" #include "third_party/stb/stb_image.h"
/** #define USAGE \
* @fileoverview Utility for printing HTML <img> tags. " [FLAGS] IMG...\n\
*/ Utility for printing HTML <img> tags.\n\
\n\
FLAGS\n\
\n\
-h Help\n\
-a Wrap with <a> tag\n\
-u Embed data:base64 URI\n"
int scale;
bool linktag;
bool datauri;
bool sizeonly;
void PrintUsage(int rc, FILE *f) {
fputs("Usage: ", f);
fputs(program_invocation_name, f);
fputs(USAGE, f);
exit(rc);
}
void PrintImg(const char *path) {
size_t n;
int opt, i, yn, xn, cn, w, h;
void *img, *pix, *src, *mime;
if (!(img = gc(xslurp(path, &n)))) exit(2);
if (!(pix = gc(stbi_load_from_memory(img, n, &xn, &yn, &cn, 0)))) exit(3);
if (linktag) {
printf("<a href=\"%s\"\n >", path);
}
src = path;
if (datauri) {
src = xasprintf("data:%s;base64,%s", FindContentType(path, -1),
gc(EncodeBase64(img, n, &n)));
}
w = (xn + (1 << scale) / 2) >> scale;
h = (yn + (1 << scale) / 2) >> scale;
if (sizeonly) {
printf("width=\"%d\" height=\"%d\"", w, h);
} else {
printf("<img width=\"%d\" height=\"%d\" alt=\"[%s]\"\n src=\"%s\">", w,
h, path, src);
}
if (linktag) {
printf("</a>");
}
printf("\n");
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
void *p; if (!NoDebug()) ShowCrashReports();
size_t n; int i;
int yn, xn, cn; while ((i = getopt(argc, argv, "?huas01234")) != -1) {
if (argc != 2) return 1; switch (i) {
if (!(p = xslurp(argv[1], &n))) return 2; case '0':
if (!(p = stbi_load_from_memory(p, n, &xn, &yn, &cn, 0))) return 3; case '1':
printf("<img src=\"%s\" width=\"%d\" height=\"%d\"\n" case '2':
" alt=\"[%s]\">\n", case '3':
argv[1], (xn + 1) >> 1, (yn + 1) >> 1, argv[1]); case '4':
return 0; scale = i - '0';
break;
case 's':
sizeonly = true;
break;
case 'a':
linktag = true;
break;
case 'u':
datauri = true;
break;
case '?':
case 'h':
PrintUsage(0, stdout);
default:
PrintUsage(1, stderr);
}
}
if (optind == argc) {
PrintUsage(1, stderr);
}
for (i = optind; i < argc; ++i) {
PrintImg(argv[i]);
}
} }

View file

@ -121,7 +121,7 @@ void SpellChecker(void) {
printf("word: "); printf("word: ");
fflush(stdout); fflush(stdout);
if (getline(&line, &linesize, stdin) > 0) { if (getline(&line, &linesize, stdin) > 0) {
query = strtolower(chomp(line)); query = strtolower(_chomp(line));
if (critbit0_contains(&words, query)) { if (critbit0_contains(&words, query)) {
printf("ok\r\n"); printf("ok\r\n");
} else { } else {
@ -147,13 +147,13 @@ void SpellChecker(void) {
void LoadWords(void) { void LoadWords(void) {
CHECK_NOTNULL((f = fopen("/zip/usr/share/dict/words", "r"))); CHECK_NOTNULL((f = fopen("/zip/usr/share/dict/words", "r")));
while (getline(&line, &linesize, f) > 0) { while (getline(&line, &linesize, f) > 0) {
critbit0_insert(&words, strtolower(chomp(line))); critbit0_insert(&words, strtolower(_chomp(line)));
} }
CHECK_NE(-1, fclose(f)); CHECK_NE(-1, fclose(f));
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
showcrashreports(); if (!NoDebug()) ShowCrashReports();
LoadWords(); LoadWords();
SpellChecker(); SpellChecker();
return 0; return 0;

View file

@ -154,7 +154,7 @@ void editorSetStatusMessage(const char *fmt, ...);
* matches and keywords. The file name matches are used in order to match * matches and keywords. The file name matches are used in order to match
* a given syntax with a given file name: if a match pattern starts with a * a given syntax with a given file name: if a match pattern starts with a
* dot, it is matched as the last past of the filename, for example ".c". * dot, it is matched as the last past of the filename, for example ".c".
* Otherwise the pattern is just searched inside the filenme, like "Makefile"). * Otherwise the pattern is just searched inside the filename, like "Makefile").
* *
* The list of keywords to highlight is just a list of words, however if they * The list of keywords to highlight is just a list of words, however if they
* a trailing '|' character is added at the end, they are highlighted in * a trailing '|' character is added at the end, they are highlighted in
@ -249,7 +249,10 @@ fatal:
int editorReadKey(int64_t fd) { int editorReadKey(int64_t fd) {
int nread; int nread;
char c, seq[3]; char c, seq[3];
if ((nread = read(fd, &c, 1)) == -1) exit(1); do {
nread = read(fd, &c, 1);
if (nread == -1) exit(1);
} while (!nread);
while (1) { while (1) {
switch (c) { switch (c) {
@ -390,7 +393,7 @@ int is_separator(int c) {
/* Return true if the specified row last char is part of a multi line comment /* Return true if the specified row last char is part of a multi line comment
* that starts at this row or at one before, and does not end at the end * that starts at this row or at one before, and does not end at the end
* of the row but spawns to the next row. */ * of the row but spans to the next row. */
int editorRowHasOpenComment(erow *row) { int editorRowHasOpenComment(erow *row) {
if (row->hl && row->rsize && row->hl[row->rsize - 1] == HL_MLCOMMENT && if (row->hl && row->rsize && row->hl[row->rsize - 1] == HL_MLCOMMENT &&
(row->rsize < 2 || (row->render[row->rsize - 2] != '*' || (row->rsize < 2 || (row->render[row->rsize - 2] != '*' ||
@ -651,7 +654,7 @@ void editorFreeRow(erow *row) {
free(row->hl); free(row->hl);
} }
/* Remove the row at the specified position, shifting the remainign on the /* Remove the row at the specified position, shifting the remaining on the
* top. */ * top. */
void editorDelRow(int at) { void editorDelRow(int at) {
erow *row; erow *row;
@ -667,7 +670,7 @@ void editorDelRow(int at) {
/* Turn the editor rows into a single heap-allocated string. /* Turn the editor rows into a single heap-allocated string.
* Returns the pointer to the heap-allocated string and populate the * Returns the pointer to the heap-allocated string and populate the
* integer pointed by 'buflen' with the size of the string, escluding * integer pointed by 'buflen' with the size of the string, excluding
* the final nulterm. */ * the final nulterm. */
char *editorRowsToString(int *buflen) { char *editorRowsToString(int *buflen) {
char *buf = NULL, *p; char *buf = NULL, *p;

23
examples/linenoise.c Normal file
View file

@ -0,0 +1,23 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "third_party/linenoise/linenoise.h"
int main(int argc, char *argv[]) {
char *line;
while ((line = linenoiseWithHistory("IN> ", "foo"))) {
fputs("OUT> ", stdout);
fputs(line, stdout);
fputs("\n", stdout);
free(line);
}
return 0;
}

20
examples/loadavg.c Normal file
View file

@ -0,0 +1,20 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/log/check.h"
#include "libc/stdio/stdio.h"
#include "libc/time/time.h"
int main(int argc, char *argv[]) {
double x[3];
CHECK_NE(-1, getloadavg(x, 3));
printf("%g %g %g\n", x[0], x[1], x[2]);
return 0;
}

View file

@ -26,7 +26,6 @@
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/math.h" #include "libc/math.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/ohmyplus/vector.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/sock/sock.h" #include "libc/sock/sock.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
@ -43,6 +42,7 @@
#include "libc/zip.h" #include "libc/zip.h"
#include "libc/zipos/zipos.internal.h" #include "libc/zipos/zipos.internal.h"
#include "third_party/getopt/getopt.h" #include "third_party/getopt/getopt.h"
#include "third_party/libcxx/vector"
#include "tool/viz/lib/knobs.h" #include "tool/viz/lib/knobs.h"
STATIC_YOINK("zip_uri_support"); STATIC_YOINK("zip_uri_support");
@ -1673,7 +1673,7 @@ char* GetLine(void) {
static char* line; static char* line;
static size_t linesize; static size_t linesize;
if (getline(&line, &linesize, stdin) > 0) { if (getline(&line, &linesize, stdin) > 0) {
return chomp(line); return _chomp(line);
} else { } else {
return NULL; return NULL;
} }
@ -1703,7 +1703,7 @@ int PlayGame(const char* romfile, const char* opt_tasfile) {
if ((ffplay = commandvenv("FFPLAY", "ffplay"))) { if ((ffplay = commandvenv("FFPLAY", "ffplay"))) {
devnull = open("/dev/null", O_WRONLY | O_CLOEXEC); devnull = open("/dev/null", O_WRONLY | O_CLOEXEC);
pipe2(pipefds, O_CLOEXEC); pipe2(pipefds, O_CLOEXEC);
if (!(playpid_ = vfork())) { if (!(playpid_ = fork())) {
const char* const args[] = { const char* const args[] = {
"ffplay", "-nodisp", "-loglevel", "quiet", "-fflags", "ffplay", "-nodisp", "-loglevel", "quiet", "-fflags",
"nobuffer", "-ac", "1", "-ar", "1789773", "nobuffer", "-ac", "1", "-ar", "1789773",

View file

@ -12,6 +12,7 @@
#include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/termios.h" #include "libc/calls/struct/termios.h"
#include "libc/calls/struct/winsize.h" #include "libc/calls/struct/winsize.h"
#include "libc/dce.h"
#include "libc/log/check.h" #include "libc/log/check.h"
#include "libc/log/gdb.h" #include "libc/log/gdb.h"
#include "libc/log/log.h" #include "libc/log/log.h"
@ -152,7 +153,7 @@ void Draw(void) {
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
struct sigaction sa[2] = {{.sa_handler = OnShutdown}, struct sigaction sa[2] = {{.sa_handler = OnShutdown},
{.sa_handler = OnInvalidate}}; {.sa_handler = OnInvalidate}};
showcrashreports(); if (!NoDebug()) ShowCrashReports();
Setup(); Setup();
Enter(); Enter();
GetTtySize(); GetTtySize();

View file

@ -7,94 +7,8 @@
http://creativecommons.org/publicdomain/zero/1.0/ │ http://creativecommons.org/publicdomain/zero/1.0/ │
*/ */
#endif #endif
#include "libc/calls/calls.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/nt/process.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/auxv.h"
const struct AuxiliaryValue { int main() {
const char *fmt; __printargs("");
long *id;
const char *name;
const char *description;
} kAuxiliaryValues[] = {
{"%012lx", &AT_EXECFD, "AT_EXECFD", "file descriptor of program"},
{"%012lx", &AT_PHDR, "AT_PHDR", "address of elf program headers"},
{"%012lx", &AT_PHENT, "AT_PHENT", "size of program header entry"},
{"%012lx", &AT_PHNUM, "AT_PHNUM", "number of program headers"},
{"%012lx", &AT_PAGESZ, "AT_PAGESZ", "system page size"},
{"%012lx", &AT_BASE, "AT_BASE", "base address of the program interpreter"},
{"%012lx", &AT_ENTRY, "AT_ENTRY", "entry address of executable"},
{"%012lx", &AT_NOTELF, "AT_NOTELF", "set if not an elf"},
{"%-12d", &AT_UID, "AT_UID", "real user id of thread"},
{"%-12d", &AT_EUID, "AT_EUID", "effective user id of thread"},
{"%-12d", &AT_GID, "AT_GID", "real group id of thread"},
{"%-12d", &AT_EGID, "AT_EGID", "effective group id of thread"},
{"%-12d", &AT_CLKTCK, "AT_CLKTCK", "frequency of times() counts"},
{"%012lx", &AT_OSRELDATE, "AT_OSRELDATE",
"freebsd release number, e.g. 1200086"},
{"%012lx", &AT_PLATFORM, "AT_PLATFORM",
"string identifying hardware platform"},
{"%012lx", &AT_DCACHEBSIZE, "AT_DCACHEBSIZE", "data cache block size"},
{"%012lx", &AT_ICACHEBSIZE, "AT_ICACHEBSIZE",
"instruction cache block size"},
{"%012lx", &AT_UCACHEBSIZE, "AT_UCACHEBSIZE", "unified cache block size"},
{"%012lx", &AT_SECURE, "AT_SECURE",
"for set{u,g}id binz & security blankets"},
{"%-12s", &AT_BASE_PLATFORM, "AT_BASE_PLATFORM",
"string identifying real platform"},
{"%012lx", &AT_RANDOM, "AT_RANDOM", "address of sixteen random bytes"},
{"%-12s", &AT_EXECFN, "AT_EXECFN", "pathname used to execute program"},
{"%012lx", &AT_SYSINFO_EHDR, "AT_SYSINFO_EHDR",
"linux virtual dso page address"},
{"%012lx", &AT_FLAGS, "AT_FLAGS", "unused?"},
{"%012lx", &AT_HWCAP, "AT_HWCAP", "cpu stuff"},
{"%012lx", &AT_HWCAP2, "AT_HWCAP2", "more cpu stuff"},
};
const struct AuxiliaryValue *DescribeAuxv(unsigned long x) {
int i;
for (i = 0; i < ARRAYLEN(kAuxiliaryValues); ++i) {
if (x == *kAuxiliaryValues[i].id) {
return kAuxiliaryValues + i;
}
}
return NULL;
}
int main(int argc, char *argv[], char **envp) {
long key;
unsigned i;
unsigned long *auxp;
char fmt[64], **env;
struct AuxiliaryValue *auxinfo;
uint32_t varlen;
char16_t var[PATH_MAX];
printf("\nArguments:\n");
for (i = 0; i < __argc; ++i) {
printf(" ☼ %s\n", argv[i]);
}
printf("\nEnvironment:\n");
for (env = envp; *env; ++env) {
printf(" ☼ %s\n", *env);
}
printf("\nAuxiliary Values:\n");
for (auxp = __auxv; *auxp; auxp += 2) {
if ((auxinfo = DescribeAuxv(auxp[0]))) {
stpcpy(stpcpy(stpcpy(fmt, "%16s[%4ld] = "), auxinfo->fmt), " # %s\n");
printf(fmt, auxinfo->name, auxp[0], auxp[1], auxinfo->description);
} else {
printf("%16s[%4ld] = %012lx\n", "unknown", auxp[0], auxp[1]);
}
}
printf("\nSpecial Directories:\n");
printf(" ☼ kTmpPath = %`'s\n", kTmpPath);
printf(" ☼ kNtSystemDirectory = %`'s\n", kNtSystemDirectory);
printf(" ☼ kNtWindowsDirectory = %`'s\n", kNtWindowsDirectory);
printf(" ☼ program_executable_name = %`'s\n", program_executable_name);
return 0;
} }

View file

@ -27,7 +27,7 @@ int main(int argc, char *argv[]) {
} }
} }
if (isprime) { if (isprime) {
int64toarray_radix10(i, buf); FormatInt64(buf, i);
fputs(buf, stdout); fputs(buf, stdout);
fputc('\n', stdout); fputc('\n', stdout);
if (k++ % 100 == 0) { if (k++ % 100 == 0) {

72
examples/rlimit.c Normal file
View file

@ -0,0 +1,72 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/rlimit.h"
#include "libc/errno.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/color.internal.h"
#include "libc/macros.internal.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/rlim.h"
#include "libc/sysv/consts/rlimit.h"
/**
* @fileoverview tool for printing and changing system resource limits
*
* This is what you do if you want to not accidentally bomb your system
* with runaway code. If you haven't accidentally bombed your UNIX
* system before then you're not pushing it hard enough.
*/
static void SetLimit(int resource, uint64_t soft, uint64_t hard) {
struct rlimit old;
struct rlimit lim = {soft, hard};
if (resource == 127) return;
if (setrlimit(resource, &lim) == -1) {
if (!getrlimit(resource, &old)) {
lim.rlim_max = MIN(hard, old.rlim_max);
lim.rlim_cur = MIN(soft, lim.rlim_max);
if (!setrlimit(resource, &lim)) {
fprintf(stderr, "%sNOTE: SETRLIMIT(%s) DOWNGRADED TO {%,ld, %,ld}\n",
__strace_rlimit_name(resource), lim.rlim_cur, lim.rlim_max);
return;
}
}
fprintf(stderr, "ERROR: SETRLIMIT(%s, %,ld, %,ld) FAILED %m%n",
__strace_rlimit_name(resource), soft, hard);
exit(1);
}
}
int main(int argc, char *argv[]) {
int i, rc;
struct rlimit rlim;
// // example of how you might change the limits
// SetLimit(RLIMIT_CPU, 3, 33);
// SetLimit(RLIMIT_NPROC, 4, 128);
// SetLimit(RLIMIT_NOFILE, 32, 128);
// SetLimit(RLIMIT_SIGPENDING, 16, 1024);
// SetLimit(RLIMIT_AS, 8 * 1024 * 1024, 1l * 1024 * 1024 * 1024);
// SetLimit(RLIMIT_RSS, 8 * 1024 * 1024, 1l * 1024 * 1024 * 1024);
// SetLimit(RLIMIT_DATA, 8 * 1024 * 1024, 1l * 1024 * 1024 * 1024);
// SetLimit(RLIMIT_FSIZE, 8 * 1000 * 1000, 1l * 1000 * 1000 * 1000);
for (i = 0; i < RLIM_NLIMITS; ++i) {
rc = getrlimit(i, &rlim);
printf("SETRLIMIT(%-20s, %,16ld, %,16ld) → %d %s\n",
__strace_rlimit_name(i), rlim.rlim_cur, rlim.rlim_max, rc,
!rc ? "" : strerror(errno));
}
return 0;
}

View file

@ -101,7 +101,7 @@ int main(int argc, char *argv[]) {
sigaddset(&chldmask, SIGCHLD); sigaddset(&chldmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &chldmask, &savemask); sigprocmask(SIG_BLOCK, &chldmask, &savemask);
ts1 = nowl(); ts1 = nowl();
CHECK_NE(-1, (pid = vfork())); CHECK_NE(-1, (pid = fork()));
if (!pid) { if (!pid) {
sigaction(SIGINT, &dflt, 0); sigaction(SIGINT, &dflt, 0);
sigaction(SIGQUIT, &dflt, 0); sigaction(SIGQUIT, &dflt, 0);

View file

@ -7,8 +7,9 @@
http://creativecommons.org/publicdomain/zero/1.0/ │ http://creativecommons.org/publicdomain/zero/1.0/ │
*/ */
#endif #endif
#include "libc/calls/calls.h"
#include "libc/fmt/conv.h" #include "libc/fmt/conv.h"
#include "libc/stdio/stdio.h" #include "libc/fmt/itoa.h"
/** /**
* @fileoverview Prints sequence of numbers. * @fileoverview Prints sequence of numbers.
@ -16,6 +17,7 @@
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
long a, b, i; long a, b, i;
char buf[21], *p;
switch (argc) { switch (argc) {
case 2: case 2:
a = 1; a = 1;
@ -29,6 +31,9 @@ int main(int argc, char *argv[]) {
return 1; return 1;
} }
for (i = a; i <= b; ++i) { for (i = a; i <= b; ++i) {
printf("%ld\n", i); p = buf;
p = FormatInt64(p, i);
*p++ = '\n';
write(1, buf, p - buf);
} }
} }

72
examples/setitimer.c Normal file
View file

@ -0,0 +1,72 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/calls/struct/itimerval.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/calls/ucontext.h"
#include "libc/log/check.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/itimer.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
#include "libc/time/time.h"
volatile bool gotalrm;
void OnSigAlrm(int sig, siginfo_t *si, ucontext_t *ctx) {
gotalrm = true;
}
int main() {
//////////////////////////////////////////////////////////////////////////////
printf("first tutorial: set singleshot alarm for 1.5 seconds from now\n");
// setup alarm in 1.5 seconds
// this timer tears itself down once it's handled
struct itimerval shot = {{0, 0}, {1, 500000}};
struct sigaction handler = {.sa_sigaction = OnSigAlrm,
.sa_flags = SA_RESETHAND | SA_SIGINFO};
CHECK_EQ(0, sigaction(SIGALRM, &handler, 0));
CHECK_EQ(0, setitimer(ITIMER_REAL, &shot, 0));
// wait for alarm
pause();
printf("got singleshot alarm!\n\n");
//////////////////////////////////////////////////////////////////////////////
printf("second tutorial: interval timer\n");
// setup timer every 1.5 seconds
struct sigaction oldalrm;
struct sigaction sigalrm = {.sa_sigaction = OnSigAlrm,
.sa_flags = SA_SIGINFO};
CHECK_EQ(0, sigaction(SIGALRM, &sigalrm, &oldalrm));
struct itimerval oldtimer;
struct itimerval timer = {{1, 500000}, {1, 500000}};
CHECK_EQ(0, setitimer(ITIMER_REAL, &timer, &oldtimer));
// wait for three timeouts
int i = 0;
int n = 3;
while (i < n) {
pause();
if (gotalrm) {
++i;
printf("got timeout %d out of %d\n", i, n);
gotalrm = false;
}
}
// teardown timer
CHECK_EQ(0, setitimer(ITIMER_REAL, &oldtimer, 0));
CHECK_EQ(0, sigaction(SIGALRM, &oldalrm, 0));
}

View file

@ -47,8 +47,8 @@ void PrintMetric(const char *name, long double d) {
mils = fmodl(d * 1000, 1000); mils = fmodl(d * 1000, 1000);
mics = fmodl(d * 1000000, 1000); mics = fmodl(d * 1000000, 1000);
p = stpcpy(p, name), *p++ = '\t'; p = stpcpy(p, name), *p++ = '\t';
p += int64toarray_radix10(mins, p), *p++ = 'm'; p = FormatInt64(p, mins), *p++ = 'm';
p += int64toarray_radix10(secs, p), *p++ = '.'; p = FormatInt64(p, secs), *p++ = '.';
*p++ = '0' + mils / 100; *p++ = '0' + mils / 100;
*p++ = '0' + mils / 10 % 10; *p++ = '0' + mils / 10 % 10;
*p++ = '0' + mils % 10; *p++ = '0' + mils % 10;
@ -69,7 +69,7 @@ int main(int argc, char *argv[]) {
long double real; long double real;
char exebuf[PATH_MAX]; char exebuf[PATH_MAX];
if (argc >= 2) { if (argc >= 2) {
if ((exepath = commandv(argv[1], exebuf))) { if ((exepath = commandv(argv[1], exebuf, sizeof(exebuf)))) {
real = nowl(); real = nowl();
argv[1] = exepath; argv[1] = exepath;
if ((ws = xvspawn(OnChild, argv + 1, &r)) != -1) { if ((ws = xvspawn(OnChild, argv + 1, &r)) != -1) {

View file

@ -20,7 +20,7 @@
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
int i; int i;
for (i = 1; i < argc; ++i) { for (i = 1; i < argc; ++i) {
if (touch(argv[i], 0644) == -1) { if (touch(argv[i], 0666) == -1) {
fprintf(stderr, "ERROR: %s: %s\n", argv[i], strerror(errno)); fprintf(stderr, "ERROR: %s: %s\n", argv[i], strerror(errno));
exit(1); exit(1);
} }

View file

@ -27,6 +27,7 @@
#include "libc/x/x.h" #include "libc/x/x.h"
#define CTRL(C) ((C) ^ 0b01000000) #define CTRL(C) ((C) ^ 0b01000000)
#define WRITE(FD, SLIT) write(FD, SLIT, strlen(SLIT))
#define ENABLE_SAFE_PASTE "\e[?2004h" #define ENABLE_SAFE_PASTE "\e[?2004h"
#define ENABLE_MOUSE_TRACKING "\e[?1000;1002;1015;1006h" #define ENABLE_MOUSE_TRACKING "\e[?1000;1002;1015;1006h"
#define DISABLE_MOUSE_TRACKING "\e[?1000;1002;1015;1006l" #define DISABLE_MOUSE_TRACKING "\e[?1000;1002;1015;1006l"
@ -46,7 +47,7 @@ void onkilled(int sig) {
} }
void restoretty(void) { void restoretty(void) {
write(1, DISABLE_MOUSE_TRACKING, strlen(DISABLE_MOUSE_TRACKING)); WRITE(1, DISABLE_MOUSE_TRACKING);
ioctl(1, TCSETS, &oldterm); ioctl(1, TCSETS, &oldterm);
} }
@ -72,9 +73,9 @@ int rawmode(void) {
t.c_cflag |= CS8; t.c_cflag |= CS8;
t.c_iflag |= IUTF8; t.c_iflag |= IUTF8;
ioctl(1, TCSETS, &t); ioctl(1, TCSETS, &t);
write(1, ENABLE_SAFE_PASTE, strlen(ENABLE_SAFE_PASTE)); WRITE(1, ENABLE_SAFE_PASTE);
write(1, ENABLE_MOUSE_TRACKING, strlen(ENABLE_MOUSE_TRACKING)); WRITE(1, ENABLE_MOUSE_TRACKING);
write(1, PROBE_DISPLAY_SIZE, strlen(PROBE_DISPLAY_SIZE)); WRITE(1, PROBE_DISPLAY_SIZE);
return 0; return 0;
} }

View file

@ -16,12 +16,22 @@
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
#include "third_party/xed/x86.h" #include "third_party/xed/x86.h"
/**
* @fileoverview How to change CPU state on signal delivery
*
* This program redefines division by zero so that it has a definition.
* The definition is the meaning of life, the universe, and everything.
* Normally crash signals like `SIGSEGV`, `SIGILL`, and `SIGFPE` aren't
* recoverable. This example shows how it actually can be done with Xed
* and this example should work on all supported platforms even Windows
*/
void handler(int sig, siginfo_t *si, ucontext_t *ctx) { void handler(int sig, siginfo_t *si, ucontext_t *ctx) {
struct XedDecodedInst xedd; struct XedDecodedInst xedd;
xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64); xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64);
xed_instruction_length_decode(&xedd, (void *)ctx->uc_mcontext.rip, 15); xed_instruction_length_decode(&xedd, (void *)ctx->uc_mcontext.rip, 15);
ctx->uc_mcontext.rip += xedd.length; ctx->uc_mcontext.rip += xedd.length;
ctx->uc_mcontext.rax = 42; ctx->uc_mcontext.rax = 42; // set the DIV result registers rdx:rax
ctx->uc_mcontext.rdx = 0; ctx->uc_mcontext.rdx = 0;
} }

24
examples/uname.c Normal file
View file

@ -0,0 +1,24 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/calls/struct/utsname.h"
#include "libc/stdio/stdio.h"
int main(int argc, char *argv[]) {
struct utsname names;
if (uname(&names)) return 1;
printf("%-10s %s\n", "sysname", names.sysname);
printf("%-10s %s\n", "nodename", names.nodename);
printf("%-10s %s\n", "release", names.release);
printf("%-10s %s\n", "version", names.version);
printf("%-10s %s\n", "machine", names.machine);
printf("%-10s %s\n", "domainname", names.domainname);
return 0;
}

View file

@ -5731,7 +5731,7 @@ retry:
linenoiseSetFreeHintsCallback(free); linenoiseSetFreeHintsCallback(free);
linenoiseSetHintsCallback(ShellHint); linenoiseSetHintsCallback(ShellHint);
linenoiseSetCompletionCallback(ShellCompletion); linenoiseSetCompletionCallback(ShellCompletion);
if ((p = linenoiseWithHistory("$ ", "unbourne"))) { if ((p = linenoiseWithHistory(">: ", "unbourne"))) {
nr = min(strlen(p), IBUFSIZ - 2); nr = min(strlen(p), IBUFSIZ - 2);
memcpy(buf, p, nr); memcpy(buf, p, nr);
buf[nr++] = '\n'; buf[nr++] = '\n';

View file

@ -55,8 +55,8 @@ int fgethex(FILE *f) {
} }
int main(int argc, char *argv[argc]) { int main(int argc, char *argv[argc]) {
int err;
unsigned c, i, j, l; unsigned c, i, j, l;
enum XedError err;
struct XedDecodedInst xedd; struct XedDecodedInst xedd;
unsigned char buf[XED_MAX_INSTRUCTION_BYTES]; unsigned char buf[XED_MAX_INSTRUCTION_BYTES];
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));

View file

@ -8,10 +8,10 @@ COSMOPOLITAN_C_START_
void *bsearch(const void *, const void *, size_t, size_t, void *bsearch(const void *, const void *, size_t, size_t,
int cmp(const void *, const void *)) int cmp(const void *, const void *))
paramsnonnull() nothrow nosideeffect; paramsnonnull() dontthrow nosideeffect;
void *bsearch_r(const void *, const void *, size_t, size_t, void *bsearch_r(const void *, const void *, size_t, size_t,
int cmp(const void *, const void *, void *), void *) int cmp(const void *, const void *, void *), void *)
paramsnonnull((1, 2, 5)) nothrow nosideeffect; paramsnonnull((1, 2, 5)) dontthrow nosideeffect;
void djbsort(int32_t *, size_t); void djbsort(int32_t *, size_t);
void qsort(void *, size_t, size_t, int (*)(const void *, const void *)) void qsort(void *, size_t, size_t, int (*)(const void *, const void *))
paramsnonnull(); paramsnonnull();
@ -19,9 +19,9 @@ void qsort_r(void *, size_t, size_t,
int cmp(const void *, const void *, void *), void *arg) int cmp(const void *, const void *, void *), void *arg)
paramsnonnull((1, 4)); paramsnonnull((1, 4));
int tarjan(int, const int (*)[2], int, int[], int[], int *) int tarjan(int, const int (*)[2], int, int[], int[], int *)
paramsnonnull((2, 4)) nocallback nothrow; paramsnonnull((2, 4)) nocallback dontthrow;
#define __algalloc returnspointerwithnoaliases nothrow nocallback nodiscard #define __algalloc returnspointerwithnoaliases dontthrow nocallback dontdiscard
char *replacestr(const char *, const char *, const char *) char *replacestr(const char *, const char *, const char *)
paramsnonnull() __algalloc; paramsnonnull() __algalloc;

View file

@ -14,7 +14,7 @@ forceinline void *bisect(const void *k, const void *data, size_t n, size_t size,
r = n - 1; r = n - 1;
p = data; p = data;
while (l <= r) { while (l <= r) {
m = (l + r) >> 1; m = (l & r) + ((l ^ r) >> 1);
c = cmp(k, p + m * size, arg); c = cmp(k, p + m * size, arg);
if (c > 0) { if (c > 0) {
l = m + 1; l = m + 1;

View file

@ -11,15 +11,15 @@ struct critbit0 {
size_t count; size_t count;
}; };
bool critbit0_contains(struct critbit0 *, const char *) nothrow nosideeffect bool critbit0_contains(struct critbit0 *, const char *) dontthrow nosideeffect
paramsnonnull(); paramsnonnull();
bool critbit0_insert(struct critbit0 *, const char *) paramsnonnull(); bool critbit0_insert(struct critbit0 *, const char *) paramsnonnull();
bool critbit0_delete(struct critbit0 *, const char *) nothrow paramsnonnull(); bool critbit0_delete(struct critbit0 *, const char *) dontthrow paramsnonnull();
void critbit0_clear(struct critbit0 *) nothrow paramsnonnull(); void critbit0_clear(struct critbit0 *) dontthrow paramsnonnull();
char *critbit0_get(struct critbit0 *, const char *); char *critbit0_get(struct critbit0 *, const char *);
intptr_t critbit0_allprefixed(struct critbit0 *, const char *, intptr_t critbit0_allprefixed(struct critbit0 *, const char *,
intptr_t (*)(const char *, void *), void *) intptr_t (*)(const char *, void *), void *)
paramsnonnull((1, 2, 3)) nothrow; paramsnonnull((1, 2, 3)) dontthrow;
bool critbit0_emplace(struct critbit0 *, char *, size_t) paramsnonnull(); bool critbit0_emplace(struct critbit0 *, char *, size_t) paramsnonnull();
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_

View file

@ -12,7 +12,9 @@ void __assert_fail(const char *, const char *, int) hidden wontreturn relegated;
((void)((EXPR) || (__assert_fail(#EXPR, __FILE__, __LINE__), 0))) ((void)((EXPR) || (__assert_fail(#EXPR, __FILE__, __LINE__), 0)))
#endif #endif
#ifndef __cplusplus
#define static_assert _Static_assert #define static_assert _Static_assert
#endif
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

34
libc/bits/asmflag.h Normal file
View file

@ -0,0 +1,34 @@
#ifndef COSMOPOLITAN_LIBC_BITS_ASMFLAG_H_
#define COSMOPOLITAN_LIBC_BITS_ASMFLAG_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
/*
* Constraints for virtual machine flags.
* @note we beseech clang devs for flag constraints
*/
#ifdef __GCC_ASM_FLAG_OUTPUTS__ /* GCC6+ CLANG10+ */
#define CFLAG_CONSTRAINT "=@ccc"
#define CFLAG_ASM(OP) OP
#define ZFLAG_CONSTRAINT "=@ccz"
#define ZFLAG_ASM(OP) OP
#define OFLAG_CONSTRAINT "=@cco"
#define OFLAG_ASM(OP) OP
#define SFLAG_CONSTRAINT "=@ccs"
#define SFLAG_ASM(SP) SP
#define ABOVE_CONSTRAINT "=@cca" /* i.e. !ZF && !CF */
#define ABOVEFLAG_ASM(OP) OP
#else
#define CFLAG_CONSTRAINT "=q"
#define CFLAG_ASM(OP) OP "\n\tsetc\t%b0"
#define ZFLAG_CONSTRAINT "=q"
#define ZFLAG_ASM(OP) OP "\n\tsetz\t%b0"
#define OFLAG_CONSTRAINT "=q"
#define OFLAG_ASM(OP) OP "\n\tseto\t%b0"
#define SFLAG_CONSTRAINT "=q"
#define SFLAG_ASM(SP) OP "\n\tsets\t%b0"
#define ABOVE_CONSTRAINT "=@cca"
#define ABOVEFLAG_ASM(OP) OP "\n\tseta\t%b0"
#endif
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_ASMFLAG_H_ */

View file

@ -1,6 +1,7 @@
#ifndef COSMOPOLITAN_LIBC_BITS_ATOMIC_H_ #ifndef COSMOPOLITAN_LIBC_BITS_ATOMIC_H_
#define COSMOPOLITAN_LIBC_BITS_ATOMIC_H_ #define COSMOPOLITAN_LIBC_BITS_ATOMIC_H_
#include "libc/bits/bits.h" #include "libc/bits/bits.h"
#include "libc/intrin/lockcmpxchg.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
@ -31,8 +32,8 @@ COSMOPOLITAN_C_START_
}) })
#define atomic_init(PTR, VAL) atomic_store(PTR, VAL) #define atomic_init(PTR, VAL) atomic_store(PTR, VAL)
#define atomic_exchange(PTR, VAL) lockxchg(PTR, &(VAL)) #define atomic_exchange(PTR, VAL) lockxchg(PTR, &(VAL))
#define atomic_compare_exchange_strong(X, Y, Z) lockcmpxchg(X, Y, Z) #define atomic_compare_exchange_strong(X, Y, Z) _lockcmpxchg(X, Y, Z)
#define atomic_compare_exchange_weak(X, Y, Z) lockcmpxchg(X, Y, Z) #define atomic_compare_exchange_weak(X, Y, Z) _lockcmpxchg(X, Y, Z)
#define atomic_load_explicit(PTR, ORDER) atomic_load(PTR) #define atomic_load_explicit(PTR, ORDER) atomic_load(PTR)
#define atomic_store_explicit(PTR, VAL, ORDER) atomic_store(PTR, VAL) #define atomic_store_explicit(PTR, VAL, ORDER) atomic_store(PTR, VAL)
#define atomic_flag_clear_explicit(PTR, ORDER) atomic_store(PTR, 0) #define atomic_flag_clear_explicit(PTR, ORDER) atomic_store(PTR, 0)

45
libc/bits/bitop.h Normal file
View file

@ -0,0 +1,45 @@
#ifndef COSMOPOLITAN_LIBC_BITS_BITOP_H_
#define COSMOPOLITAN_LIBC_BITS_BITOP_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define bts(MEM, BIT) __BitOp("bts", BIT, MEM) /** bit test and set */
#define btr(MEM, BIT) __BitOp("btr", BIT, MEM) /** bit test and reset */
#define btc(MEM, BIT) __BitOp("btc", BIT, MEM) /** bit test and complement */
#define lockbts(MEM, BIT) __BitOp("lock bts", BIT, MEM)
#define lockbtr(MEM, BIT) __BitOp("lock btr", BIT, MEM)
#define lockbtc(MEM, BIT) __BitOp("lock btc", BIT, MEM)
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
#define __BitOp(OP, BIT, MEM) \
({ \
bool OldBit; \
if (__builtin_constant_p(BIT)) { \
asm(CFLAG_ASM(OP "%z1\t%2,%1") \
: CFLAG_CONSTRAINT(OldBit), \
"+m"((MEM)[(BIT) / (sizeof((MEM)[0]) * CHAR_BIT)]) \
: "J"((BIT) % (sizeof((MEM)[0]) * CHAR_BIT)) \
: "cc"); \
} else if (sizeof((MEM)[0]) == 2) { \
asm(CFLAG_ASM(OP "\t%w2,%1") \
: CFLAG_CONSTRAINT(OldBit), "+m"((MEM)[0]) \
: "r"(BIT) \
: "cc"); \
} else if (sizeof((MEM)[0]) == 4) { \
asm(CFLAG_ASM(OP "\t%k2,%1") \
: CFLAG_CONSTRAINT(OldBit), "+m"((MEM)[0]) \
: "r"(BIT) \
: "cc"); \
} else if (sizeof((MEM)[0]) == 8) { \
asm(CFLAG_ASM(OP "\t%q2,%1") \
: CFLAG_CONSTRAINT(OldBit), "+m"((MEM)[0]) \
: "r"(BIT) \
: "cc"); \
} \
OldBit; \
})
#endif /* __GNUC__ && !__STRICT_ANSI__ */
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_BITOP_H_ */

View file

@ -21,11 +21,6 @@ unsigned long roundup2pow(unsigned long) libcesque pureconst;
unsigned long roundup2log(unsigned long) libcesque pureconst; unsigned long roundup2log(unsigned long) libcesque pureconst;
unsigned long rounddown2pow(unsigned long) libcesque pureconst; unsigned long rounddown2pow(unsigned long) libcesque pureconst;
unsigned long hamming(unsigned long, unsigned long) pureconst; unsigned long hamming(unsigned long, unsigned long) pureconst;
intptr_t lockxchg(void *, void *, size_t);
bool cmpxchg(void *, intptr_t, intptr_t, size_t);
bool lockcmpxchg(void *, intptr_t, intptr_t, size_t);
intptr_t atomic_load(void *, size_t);
intptr_t atomic_store(void *, intptr_t, size_t);
unsigned bextra(const unsigned *, size_t, char); unsigned bextra(const unsigned *, size_t, char);
/*───────────────────────────────────────────────────────────────────────────│─╗ /*───────────────────────────────────────────────────────────────────────────│─╗
@ -136,84 +131,6 @@ unsigned bextra(const unsigned *, size_t, char);
*/ */
#if defined(__GNUC__) && !defined(__STRICT_ANSI__) #if defined(__GNUC__) && !defined(__STRICT_ANSI__)
/*
* Constraints for virtual machine flags.
* @note we beseech clang devs for flag constraints
*/
#ifdef __GCC_ASM_FLAG_OUTPUTS__ /* GCC6+ CLANG10+ */
#define CFLAG_CONSTRAINT "=@ccc"
#define CFLAG_ASM(OP) OP
#define ZFLAG_CONSTRAINT "=@ccz"
#define ZFLAG_ASM(OP) OP
#define OFLAG_CONSTRAINT "=@cco"
#define OFLAG_ASM(OP) OP
#define SFLAG_CONSTRAINT "=@ccs"
#define SFLAG_ASM(SP) SP
#define ABOVE_CONSTRAINT "=@cca" /* i.e. !ZF && !CF */
#define ABOVEFLAG_ASM(OP) OP
#else
#define CFLAG_CONSTRAINT "=q"
#define CFLAG_ASM(OP) OP "\n\tsetc\t%b0"
#define ZFLAG_CONSTRAINT "=q"
#define ZFLAG_ASM(OP) OP "\n\tsetz\t%b0"
#define OFLAG_CONSTRAINT "=q"
#define OFLAG_ASM(OP) OP "\n\tseto\t%b0"
#define SFLAG_CONSTRAINT "=q"
#define SFLAG_ASM(SP) OP "\n\tsets\t%b0"
#define ABOVE_CONSTRAINT "=@cca"
#define ABOVEFLAG_ASM(OP) OP "\n\tseta\t%b0"
#endif
/**
* Reads scalar from memory w/ one operation.
*
* @param MEM is alignas(𝑘) uint𝑘_t[hasatleast 1] where 𝑘 {8,16,32,64}
* @return *(MEM)
* @note defeats compiler load tearing optimizations
* @note alignas(𝑘) is implied if compiler knows type
* @note alignas(𝑘) only avoids multi-core / cross-page edge cases
* @see Intel's Six-Thousand Page Manual V.3A §8.2.3.1
* @see atomic_store()
*/
#define atomic_load(MEM) \
({ \
autotype(MEM) Mem = (MEM); \
typeof(*Mem) Reg; \
asm("mov\t%1,%0" : "=r"(Reg) : "m"(*Mem)); \
Reg; \
})
/**
* Saves scalar to memory w/ one operation.
*
* This is guaranteed to happen in either one or zero operations,
* depending on whether or not it's possible for *(MEM) to be read
* afterwards. This macro only forbids compiler from using >1 ops.
*
* @param MEM is alignas(𝑘) uint𝑘_t[hasatleast 1] where 𝑘 {8,16,32,64}
* @param VAL is uint𝑘_t w/ better encoding for immediates (constexpr)
* @return VAL
* @note alignas(𝑘) on nexgen32e only needed for end of page gotcha
* @note alignas(𝑘) is implied if compiler knows type
* @note needed to defeat store tearing optimizations
* @see Intel Six-Thousand Page Manual Manual V.3A §8.2.3.1
* @see atomic_load()
*/
#define atomic_store(MEM, VAL) \
({ \
autotype(VAL) Val = (VAL); \
typeof(&Val) Mem = (MEM); \
asm("mov%z1\t%1,%0" : "=m"(*Mem) : "r"(Val)); \
Val; \
})
#define bts(MEM, BIT) __BitOp("bts", BIT, MEM) /** bit test and set */
#define btr(MEM, BIT) __BitOp("btr", BIT, MEM) /** bit test and reset */
#define btc(MEM, BIT) __BitOp("btc", BIT, MEM) /** bit test and complement */
#define lockbts(MEM, BIT) __BitOp("lock bts", BIT, MEM)
#define lockbtr(MEM, BIT) __BitOp("lock btr", BIT, MEM)
#define lockbtc(MEM, BIT) __BitOp("lock btc", BIT, MEM)
#define lockinc(MEM) __ArithmeticOp1("lock inc", MEM) #define lockinc(MEM) __ArithmeticOp1("lock inc", MEM)
#define lockdec(MEM) __ArithmeticOp1("lock dec", MEM) #define lockdec(MEM) __ArithmeticOp1("lock dec", MEM)
#define locknot(MEM) __ArithmeticOp1("lock not", MEM) #define locknot(MEM) __ArithmeticOp1("lock not", MEM)
@ -225,66 +142,6 @@ unsigned bextra(const unsigned *, size_t, char);
#define lockandeq(MEM, VAL) __ArithmeticOp2("lock and", VAL, MEM) #define lockandeq(MEM, VAL) __ArithmeticOp2("lock and", VAL, MEM)
#define lockoreq(MEM, VAL) __ArithmeticOp2("lock or", VAL, MEM) #define lockoreq(MEM, VAL) __ArithmeticOp2("lock or", VAL, MEM)
/**
* Exchanges *MEMORY into *LOCALVAR w/ one operation.
*
* @param MEMORY is uint𝑘_t[hasatleast 1] where 𝑘 {8,16,32,64}
* @param LOCALVAR is uint𝑘_t[hasatleast 1]
* @return LOCALVAR[0]
* @see xchg()
*/
#define lockxchg(MEMORY, LOCALVAR) \
({ \
asm("xchg\t%0,%1" : "+%m"(*(MEMORY)), "+r"(*(LOCALVAR))); \
*(LOCALVAR); \
})
/**
* Compares and exchanges.
*
* @param IFTHING is uint𝑘_t[hasatleast 1] where 𝑘 {8,16,32,64}
* @return true if value was exchanged, otherwise false
* @see lockcmpxchg()
*/
#define cmpxchg(IFTHING, ISEQUALTOME, REPLACEITWITHME) \
({ \
bool DidIt; \
autotype(IFTHING) IfThing = (IFTHING); \
typeof(*IfThing) IsEqualToMe = (ISEQUALTOME); \
typeof(*IfThing) ReplaceItWithMe = (REPLACEITWITHME); \
asm volatile(ZFLAG_ASM("cmpxchg\t%3,%1") \
: ZFLAG_CONSTRAINT(DidIt), "+m"(*IfThing), "+a"(IsEqualToMe) \
: "r"(ReplaceItWithMe) \
: "cc"); \
DidIt; \
})
/**
* Compares and exchanges w/ one operation.
*
* @param IFTHING is uint𝑘_t[hasatleast 1] where 𝑘 {8,16,32,64}
* @return true if value was exchanged, otherwise false
* @see lockcmpxchg()
*/
#define lockcmpxchg(IFTHING, ISEQUALTOME, REPLACEITWITHME) \
({ \
bool DidIt; \
autotype(IFTHING) IfThing = (IFTHING); \
typeof(*IfThing) IsEqualToMe = (ISEQUALTOME); \
typeof(*IfThing) ReplaceItWithMe = (REPLACEITWITHME); \
asm volatile(ZFLAG_ASM("lock cmpxchg\t%3,%1") \
: ZFLAG_CONSTRAINT(DidIt), "+m"(*IfThing), "+a"(IsEqualToMe) \
: "r"(ReplaceItWithMe) \
: "cc"); \
DidIt; \
})
#define IsAddressCanonicalForm(P) \
({ \
intptr_t p2 = (intptr_t)(P); \
(0xffff800000000000l <= p2 && p2 <= 0x00007fffffffffffl); \
})
/*───────────────────────────────────────────────────────────────────────────│─╗ /*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § bits » implementation details cosmopolitan § bits » implementation details
*/ */
@ -301,44 +158,6 @@ unsigned bextra(const unsigned *, size_t, char);
MEM; \ MEM; \
}) })
#define __BitOp(OP, BIT, MEM) \
({ \
bool OldBit; \
if (__builtin_constant_p(BIT)) { \
asm(CFLAG_ASM(OP "%z1\t%2,%1") \
: CFLAG_CONSTRAINT(OldBit), \
"+m"((MEM)[(BIT) / (sizeof((MEM)[0]) * CHAR_BIT)]) \
: "J"((BIT) % (sizeof((MEM)[0]) * CHAR_BIT)) \
: "cc"); \
} else if (sizeof((MEM)[0]) == 2) { \
asm(CFLAG_ASM(OP "\t%w2,%1") \
: CFLAG_CONSTRAINT(OldBit), "+m"((MEM)[0]) \
: "r"(BIT) \
: "cc"); \
} else if (sizeof((MEM)[0]) == 4) { \
asm(CFLAG_ASM(OP "\t%k2,%1") \
: CFLAG_CONSTRAINT(OldBit), "+m"((MEM)[0]) \
: "r"(BIT) \
: "cc"); \
} else if (sizeof((MEM)[0]) == 8) { \
asm(CFLAG_ASM(OP "\t%q2,%1") \
: CFLAG_CONSTRAINT(OldBit), "+m"((MEM)[0]) \
: "r"(BIT) \
: "cc"); \
} \
OldBit; \
})
#else
#define cmpxchg(MEM, CMP, VAL) \
cmpxchg(MEM, (intptr_t)(CMP), (intptr_t)(VAL), sizeof(*(MEM)))
#define lockcmpxchg(MEM, CMP, VAL) \
lockcmpxchg(MEM, (intptr_t)(CMP), (intptr_t)(VAL), sizeof(*(MEM)))
#define lockxchg(MEM, VAR) \
lockxchg(MEM, VAR, sizeof(*(MEM)) / (sizeof(*(MEM)) == sizeof(*(VAR))))
#define atomic_store(MEM, VAL) \
atomic_store(MEM, VAL, sizeof(*(MEM)) / (sizeof(*(MEM)) == sizeof(*(VAL))))
#define atomic_load(MEM) atomic_load(MEM, sizeof(*(MEM)))
#endif /* __GNUC__ && !__STRICT_ANSI__ */ #endif /* __GNUC__ && !__STRICT_ANSI__ */
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

32
libc/bits/midpoint.h Normal file
View file

@ -0,0 +1,32 @@
#ifndef COSMOPOLITAN_LIBC_BITS_MIDPOINT_H_
#define COSMOPOLITAN_LIBC_BITS_MIDPOINT_H_
#include "libc/assert.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
#if defined(__GNUC__) && !defined(__STRICT_ANSI__) && defined(__x86__)
/**
* Computes `(a + b) / 2` assuming unsigned.
*
* This implementation is the fastest on AMD Zen architecture.
*/
#define _midpoint(a, b) \
({ \
typeof((a) + (b)) a_ = (a); \
typeof(a_) b_ = (b); \
assert(a_ >= 0); \
assert(b_ >= 0); \
asm("add\t%1,%0\n\t" \
"rcr\t%0" \
: "+r"(a_) \
: "r"(b_)); \
a_; \
})
#else
/**
* Computes `(a + b) / 2` assuming unsigned.
*/
#define _midpoint(a, b) (((a) & (b)) + ((a) ^ (b)) / 2)
#endif /* __GNUC__ && !__STRICT_ANSI__ && x86 */
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_MIDPOINT_H_ */

View file

@ -19,7 +19,7 @@
#include "libc/calls/math.h" #include "libc/calls/math.h"
/** /**
* Adds two microsecond timestamps. * Adds two nanosecond timestamps.
*/ */
struct timespec AddTimespec(struct timespec x, struct timespec y) { struct timespec AddTimespec(struct timespec x, struct timespec y) {
x.tv_sec += y.tv_sec; x.tv_sec += y.tv_sec;

View file

@ -16,7 +16,7 @@
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/bits.h" #include "libc/intrin/cmpxchg.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
@ -41,7 +41,7 @@ int atfork(void *fn, void *arg) {
for (;;) { for (;;) {
i = g_atfork.i; i = g_atfork.i;
if (i == ARRAYLEN(g_atfork.p)) return enomem(); if (i == ARRAYLEN(g_atfork.p)) return enomem();
if (cmpxchg(&g_atfork.i, i, i + 1)) { if (_cmpxchg(&g_atfork.i, i, i + 1)) {
g_atfork.p[i] = (struct AtForkCallback){.fn = fn, .arg = arg}; g_atfork.p[i] = (struct AtForkCallback){.fn = fn, .arg = arg};
return 0; return 0;
} }

View file

@ -17,6 +17,10 @@
#include "libc/sysv/consts/s.h" #include "libc/sysv/consts/s.h"
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
#define _POSIX_VERSION 200809L
#define _POSIX2_VERSION _POSIX_VERSION
#define _XOPEN_VERSION 700
#define EOF -1 /* end of file */ #define EOF -1 /* end of file */
#define WEOF -1u /* end of file (multibyte) */ #define WEOF -1u /* end of file (multibyte) */
#define _IOFBF 0 /* fully buffered */ #define _IOFBF 0 /* fully buffered */
@ -48,14 +52,14 @@
#define S_ISLNK(mode) (((mode)&S_IFMT) == S_IFLNK) #define S_ISLNK(mode) (((mode)&S_IFMT) == S_IFLNK)
#define S_ISSOCK(mode) (((mode)&S_IFMT) == S_IFSOCK) #define S_ISSOCK(mode) (((mode)&S_IFMT) == S_IFSOCK)
#define WCOREDUMP(s) ((s)&0x80) #define WCOREDUMP(s) (0x80 & (s))
#define WEXITSTATUS(s) (((s)&0xff00) >> 8) #define WEXITSTATUS(s) ((0xff00 & (s)) >> 8)
#define WIFCONTINUED(s) ((s) == 0xffff) #define WIFCONTINUED(s) ((s) == 0xffff)
#define WIFEXITED(s) (!WTERMSIG(s)) #define WIFEXITED(s) (!WTERMSIG(s))
#define WIFSIGNALED(s) (((s)&0xffff) - 1u < 0xffu) #define WIFSIGNALED(s) ((0xffff & (s)) - 1u < 0xffu)
#define WIFSTOPPED(s) ((short)((((s)&0xffff) * 0x10001) >> 8) > 0x7f00) #define WIFSTOPPED(s) ((short)(((0xffff & (s)) * 0x10001) >> 8) > 0x7f00)
#define WSTOPSIG(s) WEXITSTATUS(s) #define WSTOPSIG(s) WEXITSTATUS(s)
#define WTERMSIG(s) ((s)&0x7f) #define WTERMSIG(s) (127 & (s))
#define W_STOPCODE(s) ((s) << 8 | 0177) #define W_STOPCODE(s) ((s) << 8 | 0177)
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
@ -66,8 +70,8 @@ COSMOPOLITAN_C_START_
typedef int sig_atomic_t; typedef int sig_atomic_t;
DIR *fdopendir(int) nodiscard; DIR *fdopendir(int) dontdiscard;
DIR *opendir(const char *) nodiscard; DIR *opendir(const char *) dontdiscard;
bool fileexists(const char *); bool fileexists(const char *);
bool isdirectory(const char *); bool isdirectory(const char *);
bool isexecutable(const char *); bool isexecutable(const char *);
@ -75,19 +79,18 @@ bool isregularfile(const char *);
bool issymlink(const char *); bool issymlink(const char *);
bool32 isatty(int) nosideeffect; bool32 isatty(int) nosideeffect;
bool32 ischardev(int) nosideeffect; bool32 ischardev(int) nosideeffect;
char *commandv(const char *, char[hasatleast PATH_MAX]); char *commandv(const char *, char *, size_t);
char *get_current_dir_name(void) nodiscard; char *get_current_dir_name(void) dontdiscard;
char *getcwd(char *, size_t); char *getcwd(char *, size_t);
char *realpath(const char *, char *); char *realpath(const char *, char *);
char *replaceuser(const char *) nodiscard; char *replaceuser(const char *) dontdiscard;
char *ttyname(int); char *ttyname(int);
int access(const char *, int) nothrow; int access(const char *, int) dontthrow;
int arch_prctl(); int arch_prctl();
int chdir(const char *); int chdir(const char *);
int chmod(const char *, uint32_t); int chmod(const char *, uint32_t);
int chown(const char *, uint32_t, uint32_t); int chown(const char *, uint32_t, uint32_t);
int chroot(const char *); int chroot(const char *);
int clone(int (*)(void *), void *, int, void *, ...);
int close(int); int close(int);
int closedir(DIR *); int closedir(DIR *);
int creat(const char *, uint32_t); int creat(const char *, uint32_t);
@ -105,7 +108,7 @@ int execvpe(const char *, char *const[], char *const[]);
int faccessat(int, const char *, int, uint32_t); int faccessat(int, const char *, int, uint32_t);
int fadvise(int, uint64_t, uint64_t, int); int fadvise(int, uint64_t, uint64_t, int);
int fchdir(int); int fchdir(int);
int fchmod(int, uint32_t) nothrow; int fchmod(int, uint32_t) dontthrow;
int fchmodat(int, const char *, uint32_t, int); int fchmodat(int, const char *, uint32_t, int);
int fchown(int, uint32_t, uint32_t); int fchown(int, uint32_t, uint32_t);
int fchownat(int, const char *, uint32_t, uint32_t, int); int fchownat(int, const char *, uint32_t, uint32_t, int);
@ -120,16 +123,24 @@ int fsync(int);
int ftruncate(int, int64_t); int ftruncate(int, int64_t);
int getdents(unsigned, void *, unsigned, long *); int getdents(unsigned, void *, unsigned, long *);
int getdomainname(char *, size_t); int getdomainname(char *, size_t);
int getegid(void) nosideeffect;
int geteuid(void) nosideeffect;
int getgid(void) nosideeffect;
int gethostname(char *, size_t); int gethostname(char *, size_t);
int getloadavg(double *, int);
int getpgid(int); int getpgid(int);
int getpgrp(void) nosideeffect;
int getpid(void); int getpid(void);
int getppid(void); int getppid(void);
int getpriority(int, unsigned); int getpriority(int, unsigned);
int getrlimit(int, struct rlimit *); int getrlimit(int, struct rlimit *);
int getrusage(int, struct rusage *); int getrusage(int, struct rusage *);
int getsid(int) nosideeffect;
int gettid(void);
int getuid(void) nosideeffect;
int kill(int, int); int kill(int, int);
int killpg(int, int); int killpg(int, int);
int link(const char *, const char *) nothrow; int link(const char *, const char *) dontthrow;
int linkat(int, const char *, int, const char *, int); int linkat(int, const char *, int, const char *, int);
int lstat(const char *, struct stat *); int lstat(const char *, struct stat *);
int lutimes(const char *, const struct timeval[2]); int lutimes(const char *, const struct timeval[2]);
@ -147,7 +158,6 @@ int munlock(const void *, size_t);
int munlockall(void); int munlockall(void);
int nice(int); int nice(int);
int open(const char *, int, ...); int open(const char *, int, ...);
int openanon(char *, unsigned);
int openat(int, const char *, int, ...); int openat(int, const char *, int, ...);
int pause(void); int pause(void);
int personality(uint64_t); int personality(uint64_t);
@ -155,7 +165,7 @@ int pipe(int[hasatleast 2]);
int pipe2(int[hasatleast 2], int); int pipe2(int[hasatleast 2], int);
int posix_fadvise(int, uint64_t, uint64_t, int); int posix_fadvise(int, uint64_t, uint64_t, int);
int posix_madvise(void *, uint64_t, int); int posix_madvise(void *, uint64_t, int);
int prctl(); int prctl(int, ...);
int raise(int); int raise(int);
int reboot(int); int reboot(int);
int remove(const char *); int remove(const char *);
@ -166,18 +176,22 @@ int rmdir(const char *);
int sched_getaffinity(int, uint64_t, void *); int sched_getaffinity(int, uint64_t, void *);
int sched_setaffinity(int, uint64_t, const void *); int sched_setaffinity(int, uint64_t, const void *);
int sched_yield(void); int sched_yield(void);
int seccomp(unsigned, unsigned, void *);
int setegid(uint32_t); int setegid(uint32_t);
int seteuid(uint32_t); int seteuid(uint32_t);
int setgid(uint32_t); int setgid(int);
int setpgid(int, int); int setpgid(int, int);
int setpgrp(void);
int setpriority(int, unsigned, int); int setpriority(int, unsigned, int);
int setregid(uint32_t, uint32_t); int setregid(uint32_t, uint32_t);
int setresgid(uint32_t, uint32_t, uint32_t); int setresgid(uint32_t, uint32_t, uint32_t);
int setresuid(uint32_t, uint32_t, uint32_t); int setresuid(uint32_t, uint32_t, uint32_t);
int getresgid(uint32_t *, uint32_t *, uint32_t *);
int getresuid(uint32_t *, uint32_t *, uint32_t *);
int setreuid(uint32_t, uint32_t); int setreuid(uint32_t, uint32_t);
int setrlimit(int, const struct rlimit *); int setrlimit(int, const struct rlimit *);
int setsid(void); int setsid(void);
int setuid(uint32_t); int setuid(int);
int sigignore(int); int sigignore(int);
int siginterrupt(int, int); int siginterrupt(int, int);
int sigprocmask(int, const struct sigset *, struct sigset *); int sigprocmask(int, const struct sigset *, struct sigset *);
@ -192,6 +206,7 @@ int sysinfo(struct sysinfo *);
int touch(const char *, uint32_t); int touch(const char *, uint32_t);
int truncate(const char *, uint64_t); int truncate(const char *, uint64_t);
int ttyname_r(int, char *, size_t); int ttyname_r(int, char *, size_t);
int umask(int);
int uname(struct utsname *); int uname(struct utsname *);
int unlink(const char *); int unlink(const char *);
int unlink_s(const char **); int unlink_s(const char **);
@ -202,13 +217,13 @@ int wait3(int *, int, struct rusage *);
int wait4(int, int *, int, struct rusage *); int wait4(int, int *, int, struct rusage *);
int waitpid(int, int *, int); int waitpid(int, int *, int);
intptr_t syscall(int, ...); intptr_t syscall(int, ...);
long ptrace(int, int, void *, void *); long ptrace(int, ...);
long telldir(DIR *); long telldir(DIR *);
long times(struct tms *); long times(struct tms *);
size_t GetFileSize(const char *); size_t GetFileSize(const char *);
size_t getfiledescriptorsize(int);
ssize_t copy_file_range(int, long *, int, long *, size_t, uint32_t); ssize_t copy_file_range(int, long *, int, long *, size_t, uint32_t);
ssize_t copyfd(int, int64_t *, int, int64_t *, size_t, uint32_t); ssize_t copyfd(int, int64_t *, int, int64_t *, size_t, uint32_t);
ssize_t getfiledescriptorsize(int);
ssize_t lseek(int, int64_t, unsigned); ssize_t lseek(int, int64_t, unsigned);
ssize_t pread(int, void *, size_t, int64_t); ssize_t pread(int, void *, size_t, int64_t);
ssize_t preadv(int, struct iovec *, int, int64_t); ssize_t preadv(int, struct iovec *, int, int64_t);
@ -222,16 +237,12 @@ ssize_t splice(int, int64_t *, int, int64_t *, size_t, uint32_t);
ssize_t vmsplice(int, const struct iovec *, int64_t, uint32_t); ssize_t vmsplice(int, const struct iovec *, int64_t, uint32_t);
ssize_t write(int, const void *, size_t); ssize_t write(int, const void *, size_t);
struct dirent *readdir(DIR *); struct dirent *readdir(DIR *);
uint32_t getegid(void) nosideeffect;
uint32_t geteuid(void) nosideeffect;
uint32_t getgid(void) nosideeffect;
uint32_t getpgrp(void) nosideeffect;
uint32_t getsid(int) nosideeffect;
uint32_t gettid(void) nosideeffect;
uint32_t getuid(void) nosideeffect;
uint32_t umask(int32_t);
void rewinddir(DIR *); void rewinddir(DIR *);
void sync(void); void sync(void);
int pledge(const char *, const char *);
int clone(int (*)(void *), void *, size_t, int, void *, int *, void *, size_t,
int *);
/*───────────────────────────────────────────────────────────────────────────│─╗ /*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § system calls » formatting cosmopolitan § system calls » formatting

View file

@ -44,7 +44,9 @@ LIBC_CALLS_A_DIRECTDEPS = \
LIBC_NT_IPHLPAPI \ LIBC_NT_IPHLPAPI \
LIBC_NT_KERNEL32 \ LIBC_NT_KERNEL32 \
LIBC_NT_NTDLL \ LIBC_NT_NTDLL \
LIBC_NT_POWERPROF \ LIBC_NT_PDH \
LIBC_NT_PSAPI \
LIBC_NT_POWRPROF \
LIBC_NT_WS2_32 \ LIBC_NT_WS2_32 \
LIBC_STR \ LIBC_STR \
LIBC_STUBS \ LIBC_STUBS \
@ -63,8 +65,12 @@ $(LIBC_CALLS_A).pkg: \
$(LIBC_CALLS_A_OBJS) \ $(LIBC_CALLS_A_OBJS) \
$(foreach x,$(LIBC_CALLS_A_DIRECTDEPS),$($(x)_A).pkg) $(foreach x,$(LIBC_CALLS_A_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/libc/calls/vdsofunc.greg.o \
o/$(MODE)/libc/calls/directmap.o \
o/$(MODE)/libc/calls/directmap-nt.o \
o/$(MODE)/libc/calls/raise.o: \ o/$(MODE)/libc/calls/raise.o: \
OVERRIDE_COPTS += \ OVERRIDE_COPTS += \
-ffreestanding \
$(NO_MAGIC) $(NO_MAGIC)
o/$(MODE)/libc/calls/termios2linux.o \ o/$(MODE)/libc/calls/termios2linux.o \
@ -78,6 +84,9 @@ o/$(MODE)/libc/calls/ntcontext2linux.o: \
-O3 -O3
# TODO(jart): make va_arg optimize well in default mode # TODO(jart): make va_arg optimize well in default mode
o//libc/calls/open.o \
o//libc/calls/openat.o \
o//libc/calls/prctl.o \
o//libc/calls/ioctl.o \ o//libc/calls/ioctl.o \
o//libc/calls/ioctl_default.o \ o//libc/calls/ioctl_default.o \
o//libc/calls/ioctl_fioclex-nt.o \ o//libc/calls/ioctl_fioclex-nt.o \
@ -96,11 +105,18 @@ o//libc/calls/fcntl.o: \
OVERRIDE_CFLAGS += \ OVERRIDE_CFLAGS += \
-Os -Os
# must use alloca() or path_max*2*2
o/$(MODE)/libc/calls/execl.o \ o/$(MODE)/libc/calls/execl.o \
o/$(MODE)/libc/calls/execle.o \ o/$(MODE)/libc/calls/execle.o \
o/$(MODE)/libc/calls/execlp.o \ o/$(MODE)/libc/calls/execlp.o \
o/$(MODE)/libc/calls/copyfile.o \
o/$(MODE)/libc/calls/execve-nt.o \ o/$(MODE)/libc/calls/execve-nt.o \
o/$(MODE)/libc/calls/linkat-nt.o \
o/$(MODE)/libc/calls/renameat-nt.o \
o/$(MODE)/libc/calls/execve-sysv.o \ o/$(MODE)/libc/calls/execve-sysv.o \
o/$(MODE)/libc/calls/symlinkat-nt.o \
o/$(MODE)/libc/calls/readlinkat-nt.o \
o/$(MODE)/libc/calls/describeopenflags.greg.o \
o/$(MODE)/libc/calls/mkntenvblock.o: \ o/$(MODE)/libc/calls/mkntenvblock.o: \
OVERRIDE_CPPFLAGS += \ OVERRIDE_CPPFLAGS += \
-DSTACK_FRAME_UNLIMITED -DSTACK_FRAME_UNLIMITED

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/errno.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/nt/errors.h" #include "libc/nt/errors.h"
#include "libc/nt/files.h" #include "libc/nt/files.h"
@ -27,9 +28,10 @@
textwindows int sys_chdir_nt(const char *path) { textwindows int sys_chdir_nt(const char *path) {
uint32_t n; uint32_t n;
int e, ms, len; int e, ms, err, len;
char16_t path16[PATH_MAX], var[4]; char16_t path16[PATH_MAX], var[4];
if ((len = __mkntpath(path, path16)) == -1) return -1; if ((len = __mkntpath(path, path16)) == -1) return -1;
if (!len) return enoent();
if (len && path16[len - 1] != u'\\') { if (len && path16[len - 1] != u'\\') {
if (len + 2 > PATH_MAX) return enametoolong(); if (len + 2 > PATH_MAX) return enametoolong();
path16[len + 0] = u'\\'; path16[len + 0] = u'\\';
@ -39,7 +41,7 @@ textwindows int sys_chdir_nt(const char *path) {
* chdir() seems flaky on windows 7 * chdir() seems flaky on windows 7
* in a similar way to rmdir() sigh * in a similar way to rmdir() sigh
*/ */
for (ms = 1;; ms *= 2) { for (err = errno, ms = 1;; ms *= 2) {
if (SetCurrentDirectory(path16)) { if (SetCurrentDirectory(path16)) {
/* /*
* Now we need to set a magic environment variable. * Now we need to set a magic environment variable.
@ -68,12 +70,12 @@ textwindows int sys_chdir_nt(const char *path) {
if (ms <= 512 && if (ms <= 512 &&
(e == kNtErrorFileNotFound || e == kNtErrorAccessDenied)) { (e == kNtErrorFileNotFound || e == kNtErrorAccessDenied)) {
Sleep(ms); Sleep(ms);
errno = err;
continue; continue;
} else { } else {
break; break;
} }
} }
} }
errno = e; return __fix_enotdir(-1, path16);
return -1;
} }

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/strace.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/asan.internal.h" #include "libc/intrin/asan.internal.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
@ -30,10 +31,14 @@
* @see fchdir() * @see fchdir()
*/ */
int chdir(const char *path) { int chdir(const char *path) {
if (IsAsan() && !__asan_is_valid(path, 1)) return efault(); int rc;
if (!IsWindows()) { if (!path || (IsAsan() && !__asan_is_valid(path, 1))) {
return sys_chdir(path); rc = efault();
} else if (!IsWindows()) {
rc = sys_chdir(path);
} else { } else {
return sys_chdir_nt(path); rc = sys_chdir_nt(path);
} }
STRACE("%s(%#s) → %d% m", "chdir", path, rc);
return rc;
} }

33
libc/calls/chroot.c Normal file
View file

@ -0,0 +1,33 @@
/*-*- 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/internal.h"
#include "libc/calls/strace.internal.h"
/**
* Changes root directory.
*
* @raise ENOSYS on Windows
*/
int chroot(const char *path) {
int rc;
rc = sys_chroot(path);
STRACE("chroot(%s) → %d% m", path, rc);
return rc;
}

View file

@ -18,6 +18,7 @@
*/ */
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/timeval.h" #include "libc/calls/struct/timeval.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/fmt/conv.h" #include "libc/fmt/conv.h"
@ -25,6 +26,8 @@
#include "libc/nt/synchronization.h" #include "libc/nt/synchronization.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
static typeof(sys_clock_gettime) *__clock_gettime = sys_clock_gettime;
/** /**
* Returns nanosecond time. * Returns nanosecond time.
* *
@ -39,14 +42,20 @@
* @see strftime(), gettimeofday() * @see strftime(), gettimeofday()
* @asyncsignalsafe * @asyncsignalsafe
*/ */
int clock_gettime(int clockid, struct timespec *ts) { noinstrument int clock_gettime(int clockid, struct timespec *ts) {
int rc; int rc, e;
axdx_t ad; axdx_t ad;
if (!ts) return efault(); char buf[45];
if (IsAsan() && !__asan_is_valid(ts, sizeof(*ts))) return efault(); if (!ts) {
if (clockid == -1) return einval(); rc = efault();
if (!IsWindows()) { } else if (IsAsan() && !__asan_is_valid(ts, sizeof(*ts))) {
if ((rc = sys_clock_gettime(clockid, ts)) == -1 && errno == ENOSYS) { rc = efault();
} else if (clockid == -1) {
rc = einval();
} else if (!IsWindows()) {
e = errno;
if ((rc = __clock_gettime(clockid, ts))) {
errno = e;
ad = sys_gettimeofday((struct timeval *)ts, NULL, NULL); ad = sys_gettimeofday((struct timeval *)ts, NULL, NULL);
assert(ad.ax != -1); assert(ad.ax != -1);
if (SupportsXnu() && ad.ax) { if (SupportsXnu() && ad.ax) {
@ -56,8 +65,32 @@ int clock_gettime(int clockid, struct timespec *ts) {
ts->tv_nsec *= 1000; ts->tv_nsec *= 1000;
rc = 0; rc = 0;
} }
return rc;
} else { } else {
return sys_clock_gettime_nt(clockid, ts); rc = sys_clock_gettime_nt(clockid, ts);
} }
if (!__time_critical) {
STRACE("clock_gettime(%d, [%s]) → %d% m", clockid,
__strace_timespec(buf, sizeof(buf), rc, ts), rc);
} }
return rc;
}
/**
* Returns fast system clock_gettime() if it exists.
*/
void *__get_clock_gettime(void) {
void *vdso;
static bool once;
static void *result;
if (!once) {
if ((vdso = __vdsofunc("__vdso_clock_gettime"))) {
__clock_gettime = result = vdso;
}
once = true;
}
return result;
}
const void *const __clock_gettime_ctor[] initarray = {
__get_clock_gettime,
};

View file

@ -16,25 +16,41 @@
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/weaken.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/nt/enum/filetype.h" #include "libc/nt/enum/filetype.h"
#include "libc/nt/files.h" #include "libc/nt/files.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/sock/ntstdin.internal.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
textwindows int sys_close_nt(struct Fd *fd) { textwindows int sys_close_nt(struct Fd *fd) {
bool32 ok; int e;
if (fd->kind == kFdFile && GetFileType(fd->handle) == kNtFileTypeDisk) { bool ok = true;
/*
* Like Linux, closing a file on Windows doesn't guarantee it's if (fd->kind == kFdFile && ((fd->flags & O_ACCMODE) != O_RDONLY &&
* immediately synced to disk. But unlike Linux, this could cause GetFileType(fd->handle) == kNtFileTypeDisk)) {
* subsequent operations, e.g. unlink() to break w/ access error. // Like Linux, closing a file on Windows doesn't guarantee it's
*/ // immediately synced to disk. But unlike Linux, this could cause
// subsequent operations, e.g. unlink() to break w/ access error.
e = errno;
FlushFileBuffers(fd->handle); FlushFileBuffers(fd->handle);
errno = e;
}
// if this file descriptor is wrapped in a named pipe worker thread
// then we need to close our copy of the worker thread handle. it's
// also required that whatever install a worker use malloc, so free
if (fd->worker) {
if (!weaken(UnrefNtStdinWorker)(fd->worker)) ok = false;
fd->worker = 0;
} else {
if (!CloseHandle(fd->handle)) ok = false;
} }
ok = CloseHandle(fd->handle);
if (fd->kind == kFdConsole && fd->extra && fd->extra != -1) { if (fd->kind == kFdConsole && fd->extra && fd->extra != -1) {
ok &= CloseHandle(fd->extra); if (!CloseHandle(fd->extra)) ok = false;
} }
return ok ? 0 : __winerr();
return ok ? 0 : -1;
} }

View file

@ -19,7 +19,7 @@
#include "libc/bits/weaken.h" #include "libc/bits/weaken.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h" #include "libc/calls/strace.internal.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
@ -31,14 +31,26 @@
* This function may be used for file descriptors returned by socket, * This function may be used for file descriptors returned by socket,
* accept, epoll_create, and zipos file descriptors too. * accept, epoll_create, and zipos file descriptors too.
* *
* This function should never be called twice for the same file
* descriptor, regardless of whether or not an error happened. However
* that doesn't mean the error should be ignored.
*
* @return 0 on success, or -1 w/ errno * @return 0 on success, or -1 w/ errno
* @error EINTR means a signal was received while closing (possibly
* because linger is enabled) in which case close() does not need to
* be called again, since the fd will close in the background, and
* chances are that on linux, the fd is already closed, even if the
* underlying resource isn't closed yet
* @asyncsignalsafe * @asyncsignalsafe
* @vforksafe * @vforksafe
*/ */
int close(int fd) { int close(int fd) {
int rc; int rc;
if (fd == -1) return 0; if (fd == -1) {
if (fd < 0) return einval(); rc = 0;
} else if (fd < 0) {
rc = einval();
} else {
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) { if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
rc = weaken(__zipos_close)(fd); rc = weaken(__zipos_close)(fd);
} else { } else {
@ -56,11 +68,15 @@ int close(int fd) {
g_fds.p[fd].kind == kFdProcess)) { g_fds.p[fd].kind == kFdProcess)) {
rc = sys_close_nt(g_fds.p + fd); rc = sys_close_nt(g_fds.p + fd);
} else { } else {
STRACE("close(%d) unknown kind: %d", fd, g_fds.p[fd].kind);
rc = ebadf(); rc = ebadf();
} }
} }
} }
if (!__vforked) {
__releasefd(fd); __releasefd(fd);
SYSDEBUG("close(%d) -> %d", fd, rc); }
}
STRACE("%s(%d) → %d% m", "close", fd, rc);
return rc; return rc;
} }

View file

@ -16,60 +16,69 @@
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/bits.h"
#include "libc/bits/safemacros.internal.h" #include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/log/libfatal.internal.h" #include "libc/log/libfatal.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/ok.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
static noasan bool EndsWithIgnoreCase(const char *p, size_t n, const char *s) { static bool IsExePath(const char *s, size_t n) {
size_t i, m; return n >= 4 && (READ32LE(s + n - 4) == READ32LE(".exe") ||
m = __strlen(s); READ32LE(s + n - 4) == READ32LE(".EXE"));
if (n >= m) {
for (i = n - m; i < n; ++i) {
if (kToLower[p[i] & 255] != (*s++ & 255)) {
return false;
}
}
return true;
} else {
return false;
}
} }
static noasan bool AccessCommand(const char *name, static bool IsComPath(const char *s, size_t n) {
char path[hasatleast PATH_MAX], size_t namelen, return n >= 4 && (READ32LE(s + n - 4) == READ32LE(".com") ||
const char *suffix, size_t pathlen) { READ32LE(s + n - 4) == READ32LE(".COM"));
}
static bool IsComDbgPath(const char *s, size_t n) {
return n >= 8 && (READ64LE(s + n - 8) == READ64LE(".com.dbg") ||
READ64LE(s + n - 8) == READ64LE(".COM.DBG"));
}
static bool AccessCommand(const char *name, char *path, size_t pathsz,
size_t namelen, int *err, const char *suffix,
size_t pathlen) {
size_t suffixlen; size_t suffixlen;
suffixlen = __strlen(suffix); suffixlen = strlen(suffix);
if (pathlen + 1 + namelen + suffixlen + 1 > PATH_MAX) return -1; if (pathlen + 1 + namelen + suffixlen + 1 > pathsz) return false;
if (pathlen && (path[pathlen - 1] != '/' && path[pathlen - 1] != '\\')) { if (pathlen && (path[pathlen - 1] != '/' && path[pathlen - 1] != '\\')) {
path[pathlen] = !IsWindows() ? '/' path[pathlen] = !IsWindows() ? '/'
: __memchr(path, '\\', pathlen) ? '\\' : memchr(path, '\\', pathlen) ? '\\'
: '/'; : '/';
pathlen++; pathlen++;
} }
__repmovsb(path + pathlen, name, namelen); memcpy(path + pathlen, name, namelen);
__repmovsb(path + pathlen + namelen, suffix, suffixlen + 1); memcpy(path + pathlen + namelen, suffix, suffixlen + 1);
return isexecutable(path); if (!access(path, X_OK)) return true;
if (errno == EACCES || *err != EACCES) *err = errno;
return false;
} }
static noasan bool SearchPath(const char *name, char path[hasatleast PATH_MAX], static bool SearchPath(const char *name, char *path, size_t pathsz,
size_t namelen, const char *suffix) { size_t namelen, int *err, const char *suffix) {
char sep;
size_t i; size_t i;
const char *p; const char *p;
p = firstnonnull(emptytonull(getenv("PATH")), "/bin:/usr/local/bin:/usr/bin"); if (!(p = getenv("PATH"))) p = "/bin:/usr/local/bin:/usr/bin";
sep = IsWindows() && strchr(p, ';') ? ';' : ':';
for (;;) { for (;;) {
for (i = 0; p[i] && p[i] != ':' && p[i] != ';'; ++i) { for (i = 0; p[i] && p[i] != sep; ++i) {
if (i < PATH_MAX) { if (i < pathsz) {
path[i] = p[i]; path[i] = p[i];
} }
} }
if (AccessCommand(name, path, namelen, suffix, i)) { if (AccessCommand(name, path, pathsz, namelen, err, suffix, i)) {
return true; return true;
} }
if (p[i] == ':' || p[i] == ';') { if (p[i] == sep) {
p += i + 1; p += i + 1;
} else { } else {
break; break;
@ -78,21 +87,36 @@ static noasan bool SearchPath(const char *name, char path[hasatleast PATH_MAX],
return false; return false;
} }
static noasan bool FindCommand(const char *name, static bool FindCommand(const char *name, char *pb, size_t pbsz, size_t namelen,
char pathbuf[hasatleast PATH_MAX], bool pri, const char *suffix, int *err) {
size_t namelen, const char *suffix) { if (pri && (memchr(name, '/', namelen) || memchr(name, '\\', namelen))) {
if (memchr(name, '/', namelen) || memchr(name, '\\', namelen)) { pb[0] = 0;
pathbuf[0] = 0; return AccessCommand(name, pb, pbsz, namelen, err, suffix, 0);
return AccessCommand(name, pathbuf, namelen, suffix, 0);
} }
return ((IsWindows() && if (IsWindows() && pri &&
(AccessCommand(name, pathbuf, namelen, suffix, pbsz > max(strlen(kNtSystemDirectory), strlen(kNtWindowsDirectory))) {
stpcpy(pathbuf, kNtSystemDirectory) - pathbuf) || return AccessCommand(name, pb, pbsz, namelen, err, suffix,
AccessCommand(name, pathbuf, namelen, suffix, stpcpy(pb, kNtSystemDirectory) - pb) ||
stpcpy(pathbuf, kNtWindowsDirectory) - pathbuf) || AccessCommand(name, pb, pbsz, namelen, err, suffix,
AccessCommand(name, pathbuf, namelen, suffix, stpcpy(pb, kNtWindowsDirectory) - pb);
stpcpy(pathbuf, ".") - pathbuf))) || }
SearchPath(name, pathbuf, namelen, suffix)); return (IsWindows() &&
(pbsz > 1 && AccessCommand(name, pb, pbsz, namelen, err, suffix,
stpcpy(pb, ".") - pb))) ||
SearchPath(name, pb, pbsz, namelen, err, suffix);
}
static bool FindVerbatim(const char *name, char *pb, size_t pbsz,
size_t namelen, bool pri, int *err) {
return FindCommand(name, pb, pbsz, namelen, pri, "", err);
}
static bool FindSuffixed(const char *name, char *pb, size_t pbsz,
size_t namelen, bool pri, int *err) {
return !IsExePath(name, namelen) && !IsComPath(name, namelen) &&
!IsComDbgPath(name, namelen) &&
(FindCommand(name, pb, pbsz, namelen, pri, ".com", err) ||
FindCommand(name, pb, pbsz, namelen, pri, ".exe", err));
} }
/** /**
@ -104,29 +128,36 @@ static noasan bool FindCommand(const char *name,
* @asyncsignalsafe * @asyncsignalsafe
* @vforksafe * @vforksafe
*/ */
noasan char *commandv(const char *name, char pathbuf[hasatleast PATH_MAX]) { char *commandv(const char *name, char *pathbuf, size_t pathbufsz) {
int olderr; int e, f;
char *res;
size_t namelen; size_t namelen;
res = 0;
if (!name) { if (!name) {
efault(); efault();
return 0; } else if (!(namelen = strlen(name))) {
}
if (!(namelen = __strlen(name))) {
enoent(); enoent();
return 0; } else if (namelen + 1 > pathbufsz) {
}
if (namelen + 1 > PATH_MAX) {
enametoolong(); enametoolong();
return 0;
}
if (FindCommand(name, pathbuf, namelen, "") ||
(!EndsWithIgnoreCase(name, namelen, ".exe") &&
!EndsWithIgnoreCase(name, namelen, ".com") &&
!EndsWithIgnoreCase(name, namelen, ".com.dbg") &&
(FindCommand(name, pathbuf, namelen, ".com") ||
FindCommand(name, pathbuf, namelen, ".exe")))) {
return pathbuf;
} else { } else {
return 0; e = errno;
f = ENOENT;
if ((IsWindows() &&
(FindSuffixed(name, pathbuf, pathbufsz, namelen, true, &f) ||
FindVerbatim(name, pathbuf, pathbufsz, namelen, true, &f) ||
FindSuffixed(name, pathbuf, pathbufsz, namelen, false, &f) ||
FindVerbatim(name, pathbuf, pathbufsz, namelen, false, &f))) ||
(!IsWindows() &&
(FindVerbatim(name, pathbuf, pathbufsz, namelen, true, &f) ||
FindSuffixed(name, pathbuf, pathbufsz, namelen, true, &f) ||
FindVerbatim(name, pathbuf, pathbufsz, namelen, false, &f) ||
FindSuffixed(name, pathbuf, pathbufsz, namelen, false, &f)))) {
errno = e;
res = pathbuf;
} else {
errno = f;
} }
} }
STRACE("commandv(%#s, %p, %'zu) → %#s% m", name, pathbuf, pathbufsz, res);
return res;
}

View file

@ -20,6 +20,7 @@
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/stat.h" #include "libc/calls/struct/stat.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/kprintf.h"
#include "libc/nt/createfile.h" #include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.h" #include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/creationdisposition.h" #include "libc/nt/enum/creationdisposition.h"
@ -27,6 +28,7 @@
#include "libc/nt/enum/filesharemode.h" #include "libc/nt/enum/filesharemode.h"
#include "libc/nt/files.h" #include "libc/nt/files.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/nt/struct/filetime.h"
#include "libc/sysv/consts/at.h" #include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/madv.h" #include "libc/sysv/consts/madv.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
@ -66,12 +68,12 @@ static int sys_copyfile(const char *src, const char *dst, int flags) {
int64_t inoffset, outoffset; int64_t inoffset, outoffset;
int rc, srcfd, dstfd, oflags, omode; int rc, srcfd, dstfd, oflags, omode;
rc = -1; rc = -1;
if ((srcfd = sys_openat(AT_FDCWD, src, O_RDONLY, 0)) != -1) { if ((srcfd = openat(AT_FDCWD, src, O_RDONLY, 0)) != -1) {
if (sys_fstat(srcfd, &st) != -1) { if (fstat(srcfd, &st) != -1) {
omode = st.st_mode & 0777; omode = st.st_mode & 0777;
oflags = O_WRONLY | O_CREAT; oflags = O_WRONLY | O_CREAT;
if (flags & COPYFILE_NOCLOBBER) oflags |= O_EXCL; if (flags & COPYFILE_NOCLOBBER) oflags |= O_EXCL;
if ((dstfd = sys_openat(AT_FDCWD, dst, oflags, omode)) != -1) { if ((dstfd = openat(AT_FDCWD, dst, oflags, omode)) != -1) {
remaining = st.st_size; remaining = st.st_size;
ftruncate(dstfd, remaining); ftruncate(dstfd, remaining);
inoffset = 0; inoffset = 0;
@ -86,13 +88,13 @@ static int sys_copyfile(const char *src, const char *dst, int flags) {
if (flags & COPYFILE_PRESERVE_TIMESTAMPS) { if (flags & COPYFILE_PRESERVE_TIMESTAMPS) {
amtime[0] = st.st_atim; amtime[0] = st.st_atim;
amtime[1] = st.st_mtim; amtime[1] = st.st_mtim;
sys_utimensat(dstfd, NULL, amtime, 0); utimensat(dstfd, NULL, amtime, 0);
} }
} }
rc |= sys_close(dstfd); rc |= close(dstfd);
} }
} }
rc |= sys_close(srcfd); rc |= close(srcfd);
} }
return rc; return rc;
} }
@ -108,7 +110,7 @@ static int sys_copyfile(const char *src, const char *dst, int flags) {
* @return 0 on success, or -1 w/ errno * @return 0 on success, or -1 w/ errno
*/ */
int copyfile(const char *src, const char *dst, int flags) { int copyfile(const char *src, const char *dst, int flags) {
if (!IsWindows()) { if (!IsWindows() || startswith(src, "/zip/") || startswith(dst, "/zip/")) {
return sys_copyfile(src, dst, flags); return sys_copyfile(src, dst, flags);
} else { } else {
return sys_copyfile_nt(src, dst, flags); return sys_copyfile_nt(src, dst, flags);

View file

@ -35,6 +35,6 @@
* @see open(), touch() * @see open(), touch()
* @asyncsignalsafe * @asyncsignalsafe
*/ */
nodiscard int creat(const char *file, uint32_t mode) { dontdiscard int creat(const char *file, uint32_t mode) {
return openat(AT_FDCWD, file, O_CREAT | O_WRONLY | O_TRUNC, mode); return openat(AT_FDCWD, file, O_CREAT | O_WRONLY | O_TRUNC, mode);
} }

View file

@ -0,0 +1,110 @@
/*-*- 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/assert.h"
#include "libc/calls/calls.h"
#include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/creationdisposition.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/enum/filesharemode.h"
#include "libc/sysv/consts/o.h"
// code size optimization
// <sync libc/sysv/consts.sh>
#define _O_APPEND 0x00000400 // kNtFileAppendData
#define _O_CREAT 0x00000040 // kNtOpenAlways
#define _O_EXCL 0x00000080 // kNtCreateNew
#define _O_TRUNC 0x00000200 // kNtCreateAlways
#define _O_DIRECTORY 0x00010000 // kNtFileFlagBackupSemantics
#define _O_TMPFILE 0x00410000 // AttributeTemporary|FlagDeleteOnClose
#define _O_DIRECT 0x00004000 // kNtFileFlagNoBuffering
#define _O_NDELAY 0x00000800 // kNtFileFlagWriteThrough
#define _O_RANDOM 0x80000000 // kNtFileFlagRandomAccess
#define _O_SEQUENTIAL 0x40000000 // kNtFileFlagSequentialScan
#define _O_COMPRESSED 0x20000000 // kNtFileAttributeCompressed
#define _O_INDEXED 0x10000000 // !kNtFileAttributeNotContentIndexed
#define _O_NONBLOCK 0x00000800
#define _O_CLOEXEC 0x00080000
// </sync libc/sysv/consts.sh>
textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm,
uint32_t *out_share, uint32_t *out_disp,
uint32_t *out_attr) {
uint32_t perm, share, disp, attr;
switch (flags & O_ACCMODE) {
case O_RDONLY:
perm = kNtFileGenericRead | kNtGenericExecute;
break;
case O_WRONLY:
perm = kNtFileGenericWrite | kNtGenericExecute;
break;
case O_RDWR:
perm = kNtFileGenericRead | kNtFileGenericWrite | kNtGenericExecute;
break;
default:
return -1;
}
if (flags & _O_APPEND) {
perm = kNtFileAppendData;
}
if (flags & _O_EXCL) {
share = kNtFileShareExclusive;
} else {
share = kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete;
}
if ((flags & _O_CREAT) && (flags & _O_EXCL)) {
disp = kNtCreateNew;
} else if ((flags & _O_CREAT) && (flags & _O_TRUNC)) {
disp = kNtCreateAlways;
} else if (flags & _O_CREAT) {
disp = kNtOpenAlways;
} else if (flags & _O_TRUNC) {
disp = kNtTruncateExisting;
} else {
disp = kNtOpenExisting;
}
if ((flags & _O_TMPFILE) == _O_TMPFILE) {
attr = kNtFileAttributeTemporary | kNtFileFlagDeleteOnClose;
} else {
attr = kNtFileAttributeNormal;
if (flags & _O_DIRECTORY) {
attr |= kNtFileFlagBackupSemantics;
}
if (~mode & 0200) {
attr |= kNtFileAttributeReadonly;
}
}
if (~flags & _O_INDEXED) attr |= kNtFileAttributeNotContentIndexed;
if (flags & _O_COMPRESSED) attr |= kNtFileAttributeCompressed;
if (flags & _O_SEQUENTIAL) attr |= kNtFileFlagSequentialScan;
if (flags & _O_RANDOM) attr |= kNtFileFlagRandomAccess;
if (flags & _O_DIRECT) attr |= kNtFileFlagNoBuffering;
if (flags & _O_NDELAY) attr |= kNtFileFlagWriteThrough;
if (out_perm) *out_perm = perm;
if (out_share) *out_share = share;
if (out_disp) *out_disp = disp;
if (out_attr) *out_attr = attr;
return 0;
}

View file

@ -16,32 +16,35 @@
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/alg/reverse.internal.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/intrin/lockxadd.h"
#include "libc/nt/process.h" #include "libc/nt/process.h"
static const char kPipeNamePrefix[] = "\\\\?\\pipe\\cosmo\\"; static textwindows char16_t *UintToChar16Array(char16_t p[21], uint64_t x) {
char t;
static textwindows size_t UintToChar16Array(char16_t *a, uint64_t i) { size_t a, b, i = 0;
size_t j = 0;
do { do {
a[j++] = i % 10 + '0'; p[i++] = x % 10 + '0';
i /= 10; x = x / 10;
} while (i > 0); } while (x > 0);
a[j] = 0; if (i) {
reverse(a, j); for (a = 0, b = i - 1; a < b; ++a, --b) {
return j; t = p[a];
p[a] = p[b];
p[b] = t;
}
}
return p + i;
} }
textwindows char16_t *CreatePipeName(char16_t *a) { textwindows char16_t *CreatePipeName(char16_t *a) {
static long x; static long x;
unsigned i; char16_t *p = a;
for (i = 0; kPipeNamePrefix[i]; ++i) a[i] = kPipeNamePrefix[i]; const char *q = "\\\\?\\pipe\\cosmo\\";
i += UintToChar16Array(a + i, GetCurrentProcessId()); while (*q) *p++ = *q++;
a[i++] = u'-'; p = UintToChar16Array(p, GetCurrentProcessId());
i += UintToChar16Array(a + i, GetCurrentProcessId()); *p++ = '-';
a[i++] = u'-'; p = UintToChar16Array(p, _lockxadd(&x, 1));
i += UintToChar16Array(a + i, x++); *p = 0;
a[i] = u'\0';
return a; return a;
} }

View file

@ -0,0 +1,38 @@
/*-*- 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/fmt/itoa.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sol.h"
/**
* Describes clock_gettime() clock argument.
*/
char *DescribeClockName(int x) {
int i;
char *s;
_Alignas(char) static char buf[32];
if ((s = GetMagnumStr(kClockNames, x))) {
stpcpy(stpcpy(buf, "CLOCK_"), s);
return buf;
} else {
FormatInt32(buf, x);
return buf;
}
}

View file

@ -16,7 +16,7 @@
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/log/libfatal.internal.h" #include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/runtime/memtrack.internal.h" #include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
@ -28,21 +28,19 @@
noasan const char *DescribeFrame(int x) { noasan const char *DescribeFrame(int x) {
/* asan runtime depends on this function */ /* asan runtime depends on this function */
char *p; char *p;
static char buf[128]; static char buf[32];
if (IsShadowFrame(x)) { if (IsShadowFrame(x)) {
p = buf; ksnprintf(buf, sizeof(buf), " /*shadow:%.12p*/", UNSHADOW(ADDR(x)));
p = __stpcpy(p, " shadow of ");
p = __fixcpy(p, UNSHADOW(ADDR(x)), 48);
return buf; return buf;
return " shadow "; return " /*shadow*/ ";
} else if (IsAutoFrame(x)) { } else if (IsAutoFrame(x)) {
return " automap"; return " /*automap*/";
} else if (IsFixedFrame(x)) { } else if (IsFixedFrame(x)) {
return " fixed "; return " /*fixed*/ ";
} else if (IsArenaFrame(x)) { } else if (IsArenaFrame(x)) {
return " arena "; return " /*arena*/ ";
} else if (IsStaticStackFrame(x)) { } else if (IsStaticStackFrame(x)) {
return " stack "; return " /*stack*/ ";
} else { } else {
return ""; return "";
} }

View file

@ -20,19 +20,32 @@
#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/prot.h"
noasan char *DescribeMapping(int prot, int flags, char p[hasatleast 8]) { static noasan char DescribeMapType(int flags) {
/* asan runtime depends on this function */ switch (flags & MAP_TYPE) {
case MAP_FILE:
return 'f';
case MAP_PRIVATE:
return 'p';
case MAP_SHARED:
return 's';
default:
return '?';
}
}
noasan char *DescribeProt(int prot, char p[hasatleast 4]) {
p[0] = (prot & PROT_READ) ? 'r' : '-'; p[0] = (prot & PROT_READ) ? 'r' : '-';
p[1] = (prot & PROT_WRITE) ? 'w' : '-'; p[1] = (prot & PROT_WRITE) ? 'w' : '-';
p[2] = (prot & PROT_EXEC) ? 'x' : '-'; p[2] = (prot & PROT_EXEC) ? 'x' : '-';
if (flags & MAP_PRIVATE) { p[3] = 0;
p[3] = 'p'; return p;
} else if (flags & MAP_SHARED) {
p[3] = 's';
} else {
p[3] = '?';
} }
p[4] = (flags & MAP_ANONYMOUS) ? 'a' : 'f';
noasan char *DescribeMapping(int prot, int flags, char p[hasatleast 8]) {
/* asan runtime depends on this function */
DescribeProt(prot, p);
p[3] = DescribeMapType(flags);
p[4] = (flags & MAP_ANONYMOUS) ? 'a' : '-';
p[5] = (flags & MAP_GROWSDOWN) ? 'S' : '-'; p[5] = (flags & MAP_GROWSDOWN) ? 'S' : '-';
p[6] = (flags & MAP_FIXED) ? 'F' : '-'; p[6] = (flags & MAP_FIXED) ? 'F' : '-';
p[7] = 0; p[7] = 0;

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/fmt/itoa.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/mem/alloca.h"
#include "libc/sysv/consts/sol.h"
/**
* Describes clock_gettime() clock argument.
*/
char *DescribeOpenFlags(int x) {
char *s;
int i, n;
struct DescribeFlags *d;
_Alignas(char) static char openflags[128];
// TODO(jart): unify DescribeFlags and MagnumStr data structures
for (n = 0; kOpenFlags[n].x != MAGNUM_TERMINATOR;) ++n;
d = alloca(n * sizeof(struct DescribeFlags));
for (i = 0; i < n; ++i) {
d[i].flag = MAGNUM_NUMBER(kOpenFlags, i);
d[i].name = MAGNUM_STRING(kOpenFlags, i);
}
return DescribeFlags(openflags, sizeof(openflags), d, n, "O_", x);
}

102
libc/calls/directmap-nt.c Normal file
View file

@ -0,0 +1,102 @@
/*-*- 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/assert.h"
#include "libc/calls/internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/nt/enum/filemapflags.h"
#include "libc/nt/enum/pageflags.h"
#include "libc/nt/memory.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/processmemorycounters.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
textwindows struct DirectMap sys_mmap_nt(void *addr, size_t size, int prot,
int flags, int fd, int64_t off) {
size_t i;
bool iscow;
int64_t handle;
uint32_t oldprot;
struct DirectMap dm;
struct ProtectNt fl;
const struct NtSecurityAttributes *sec;
struct NtProcessMemoryCountersEx memcount;
if (fd != -1) {
handle = g_fds.p[fd].handle;
} else {
handle = kNtInvalidHandleValue;
}
if (flags & MAP_PRIVATE) {
sec = 0; // MAP_PRIVATE isn't inherited across fork()
} else {
sec = &kNtIsInheritable; // MAP_SHARED gives us zero-copy fork()
}
// nt will whine under many circumstances if we change the execute bit
// later using mprotect(). the workaround is to always request execute
// and then virtualprotect() it away until we actually need it. please
// note that open-nt.c always requests an kNtGenericExecute accessmask
iscow = false;
if (handle != -1) {
if (flags & MAP_PRIVATE) {
// windows has cow pages but they can't propagate across fork()
// that means we only get copy-on-write for the root process :(
fl = (struct ProtectNt){kNtPageExecuteWritecopy,
kNtFileMapCopy | kNtFileMapExecute};
iscow = true;
} else {
assert(flags & MAP_SHARED);
if ((g_fds.p[fd].flags & O_ACCMODE) == O_RDONLY) {
fl = (struct ProtectNt){kNtPageExecuteRead,
kNtFileMapRead | kNtFileMapExecute};
} else {
fl = (struct ProtectNt){kNtPageExecuteReadwrite,
kNtFileMapWrite | kNtFileMapExecute};
}
}
} else {
assert(flags & MAP_ANONYMOUS);
fl = (struct ProtectNt){kNtPageExecuteReadwrite,
kNtFileMapWrite | kNtFileMapExecute};
}
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))) {
if (VirtualProtect(addr, size, __prot2nt(prot, iscow), &oldprot)) {
return dm;
} else {
return dm;
UnmapViewOfFile(dm.addr);
}
}
CloseHandle(dm.maphandle);
}
dm.maphandle = kNtInvalidHandleValue;
dm.addr = (void *)(intptr_t)-1;
return dm;
}

View file

@ -17,8 +17,9 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h" #include "libc/calls/strace.internal.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/runtime/directmap.internal.h" #include "libc/runtime/directmap.internal.h"
#include "libc/runtime/memtrack.internal.h" #include "libc/runtime/memtrack.internal.h"
@ -31,25 +32,24 @@
* support Windows NT and Address Sanitizer. That memory tracking can be * support Windows NT and Address Sanitizer. That memory tracking can be
* bypassed by calling this function. However the caller is responsible * bypassed by calling this function. However the caller is responsible
* for passing the magic memory handle on Windows NT to CloseHandle(). * for passing the magic memory handle on Windows NT to CloseHandle().
*
* @asyncsignalsafe
* @threadsafe
*/ */
noasan struct DirectMap sys_mmap(void *addr, size_t size, int prot, int flags, struct DirectMap sys_mmap(void *addr, size_t size, int prot, int flags, int fd,
int fd, int64_t off) { int64_t off) {
/* asan runtime depends on this function */ /* asan runtime depends on this function */
char mode[8]; struct DirectMap d;
struct DirectMap dm;
if (!IsWindows() && !IsMetal()) { if (!IsWindows() && !IsMetal()) {
dm.addr = __sys_mmap(addr, size, prot, flags, fd, off, off); d.addr = __sys_mmap(addr, size, prot, flags, fd, off, off);
SYSDEBUG("sys_mmap(0x%p%s, 0x%x, %s, %d, %d) -> 0x%p %s", addr, d.maphandle = kNtInvalidHandleValue;
DescribeFrame((intptr_t)addr >> 16), size,
DescribeMapping(prot, flags, mode), (long)fd, off, dm.addr,
dm.addr != MAP_FAILED ? "" : strerror(errno));
dm.maphandle = kNtInvalidHandleValue;
return dm;
} else if (IsMetal()) { } else if (IsMetal()) {
return sys_mmap_metal(addr, size, prot, flags, fd, off); d = sys_mmap_metal(addr, size, prot, flags, fd, off);
} else { } else {
return sys_mmap_nt(addr, size, prot, flags, d = sys_mmap_nt(addr, size, prot, flags, fd, off);
fd != -1 ? g_fds.p[fd].handle : kNtInvalidHandleValue,
off);
} }
KERNTRACE("sys_mmap(%.12p%s, %'zu, %s, %s, %d, %'ld) → {%.12p, %p}% m", addr,
DescribeFrame((intptr_t)addr >> 16), size, DescribeProtFlags(prot),
DescribeMapFlags(flags), fd, off, d.addr, d.maphandle);
return d;
} }

View file

@ -17,38 +17,69 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/bits/bits.h" #include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/nt/files.h" #include "libc/nt/files.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/sock/internal.h"
#include "libc/sock/ntstdin.internal.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
/** /**
* Implements dup(), dup2(), and dup3() for Windows NT. * Implements dup(), dup2(), dup3(), and F_DUPFD for Windows.
*/ */
textwindows int sys_dup_nt(int oldfd, int newfd, int flags) { textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
int64_t proc; int64_t proc, handle;
// validate the api usage
if (oldfd < 0) return einval(); if (oldfd < 0) return einval();
if (flags & ~O_CLOEXEC) return einval();
if (oldfd >= g_fds.n || if (oldfd >= g_fds.n ||
(g_fds.p[oldfd].kind != kFdFile && g_fds.p[oldfd].kind != kFdSocket && (g_fds.p[oldfd].kind != kFdFile && g_fds.p[oldfd].kind != kFdSocket &&
g_fds.p[oldfd].kind != kFdConsole)) { g_fds.p[oldfd].kind != kFdConsole)) {
return ebadf(); return ebadf();
} }
// allocate a new file descriptor
if (newfd == -1) { if (newfd == -1) {
if ((newfd = __reservefd()) == -1) return -1; if ((newfd = __reservefd(start)) == -1) {
return -1;
}
} else { } else {
if (__ensurefds(newfd) == -1) return -1; if (__ensurefds(newfd) == -1) return -1;
if (g_fds.p[newfd].kind) close(newfd); if (g_fds.p[newfd].kind) close(newfd);
g_fds.p[newfd].kind = kFdReserved; g_fds.p[newfd].kind = kFdReserved;
} }
// if this file descriptor is wrapped in a named pipe worker thread
// then we should clone the original authentic handle rather than the
// stdin worker's named pipe. we won't clone the worker, since that
// can always be recreated again on demand.
if (g_fds.p[oldfd].worker) {
handle = g_fds.p[oldfd].worker->reader;
} else {
handle = g_fds.p[oldfd].handle;
}
proc = GetCurrentProcess(); proc = GetCurrentProcess();
if (DuplicateHandle(proc, g_fds.p[oldfd].handle, proc, &g_fds.p[newfd].handle, if (DuplicateHandle(proc, handle, proc, &g_fds.p[newfd].handle, 0, true,
0, true, kNtDuplicateSameAccess)) { kNtDuplicateSameAccess)) {
g_fds.p[newfd].kind = g_fds.p[oldfd].kind; g_fds.p[newfd].kind = g_fds.p[oldfd].kind;
g_fds.p[newfd].mode = g_fds.p[oldfd].mode;
g_fds.p[newfd].flags = g_fds.p[oldfd].flags & ~O_CLOEXEC;
if (flags & O_CLOEXEC) g_fds.p[newfd].flags |= O_CLOEXEC;
if (g_fds.p[oldfd].kind == kFdSocket && weaken(_dupsockfd)) {
g_fds.p[newfd].extra =
(intptr_t)weaken(_dupsockfd)((struct SockFd *)g_fds.p[oldfd].extra);
} else {
g_fds.p[newfd].extra = g_fds.p[oldfd].extra; g_fds.p[newfd].extra = g_fds.p[oldfd].extra;
g_fds.p[newfd].flags = flags; }
if (g_fds.p[oldfd].worker) {
g_fds.p[newfd].worker = weaken(RefNtStdinWorker)(g_fds.p[oldfd].worker);
}
return newfd; return newfd;
} else { } else {
__releasefd(newfd); __releasefd(newfd);

View file

@ -18,7 +18,7 @@
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h" #include "libc/calls/strace.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
/** /**
@ -34,8 +34,8 @@ int dup(int fd) {
if (!IsWindows()) { if (!IsWindows()) {
fd2 = sys_dup(fd); fd2 = sys_dup(fd);
} else { } else {
fd2 = sys_dup_nt(fd, -1, 0); fd2 = sys_dup_nt(fd, -1, 0, -1);
} }
SYSDEBUG("dup(%d) -> %d", fd, fd2); STRACE("%s(%d) → %d% m", "dup", fd, fd2);
return fd2; return fd2;
} }

View file

@ -18,7 +18,7 @@
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h" #include "libc/calls/strace.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
/** /**
@ -32,11 +32,14 @@
* @vforksafe * @vforksafe
*/ */
int dup2(int oldfd, int newfd) { int dup2(int oldfd, int newfd) {
SYSDEBUG("dup2(%d, %d)", oldfd, newfd); int rc;
if (oldfd == newfd) return newfd; if (oldfd == newfd) {
if (!IsWindows()) { rc = newfd;
return sys_dup3(oldfd, newfd, 0); } else if (!IsWindows()) {
rc = sys_dup3(oldfd, newfd, 0);
} else { } else {
return sys_dup_nt(oldfd, newfd, 0); rc = sys_dup_nt(oldfd, newfd, 0, -1);
} }
STRACE("dup2(%d, %d) → %d% m", oldfd, newfd, rc);
return rc;
} }

View file

@ -17,17 +17,17 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/errno.h" #include "libc/errno.h"
#define __NR_dup3_linux 0x0124 /*RHEL5:CVE-2010-3301*/
int32_t sys_dup3(int32_t oldfd, int32_t newfd, int flags) { int32_t sys_dup3(int32_t oldfd, int32_t newfd, int flags) {
static bool once, demodernize; static bool once, demodernize;
int olderr, fd; int olderr, fd;
if (!once) { if (!once) {
olderr = errno; olderr = errno;
fd = __sys_dup3(oldfd, newfd, flags); fd = __sys_dup3(oldfd, newfd, flags);
if ((fd == -1 && errno == ENOSYS) || fd == __NR_dup3_linux) { if (fd == -1 && errno == ENOSYS) {
STRACE("demodernizing %s() due to %s", "dup3", "RHEL5:CVE-2010-3301");
demodernize = true; demodernize = true;
once = true; once = true;
errno = olderr; errno = olderr;

Some files were not shown because too many files have changed in this diff Show more