Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
3fa0b3d
build: the C sysroot names libm, libpthread, libdl and librt
Japabu Sep 30, 2026
1a687a0
libc: the headers are held to the definitions, and the POSIX surface …
Japabu Sep 30, 2026
d3cbc8f
Merge origin/main (#637, the C++ runtime) into wt/toyos-libcllvm
Japabu Sep 30, 2026
8db5348
libc: the signal mask kept and read back, fcntl's commands answered, …
Japabu Sep 30, 2026
616a901
libc: memreq and the mask test pass clippy's lints
Japabu Sep 30, 2026
efe858a
aligned_alloc is std's in a Rust program, and fcntl's F_DUPFD duplicates
Japabu Sep 30, 2026
c0ab03b
Merge origin/main (#644, what stops LLVM building for a ToyOS host) i…
Japabu Oct 1, 2026
e1c2103
libc: #644's issues met and closed; madvise and -lc; each case reads …
Japabu Oct 1, 2026
0674f03
issues: libc's refusals list madvise's discard, and no longer cite me…
Japabu Oct 1, 2026
3f241b2
Merge remote-tracking branch 'origin/main' into wt/toyos-libcllvm
Japabu Oct 1, 2026
a0b9e73
Prose the review removed, and the corpus count the six cases moved
Japabu Oct 1, 2026
08516be
libc: fcntl, dladdr, readdir and logb as the second review has them
Japabu Oct 1, 2026
5e8ac81
Merge remote-tracking branch 'origin/main' into wt/toyos-libcllvm
Japabu Oct 1, 2026
e14f7af
libc: readlink's size refusal host-tested, the signal-set calls, ENOMEM
Japabu Oct 1, 2026
6c653d5
libc copies: one header reader; dup2's close-on-exec clear guest-tested
Japabu Oct 1, 2026
15625e0
libc: a C sysroot links a probe naming each library; fcntl and signal…
Japabu Oct 1, 2026
3ca175c
Merge origin/main (de5f63cc2) into wt/toyos-libcllvm
Japabu Oct 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 0 additions & 30 deletions issues/build/a-rust-std-program-defines-no-aligned-alloc.md

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ step for that target:

The last three are ToyOS arms at existing dispatch sites, written as upstream
would take them. ToyOS joins `bit.h`'s `<endian.h>` list, so libc carries
POSIX's `endian.h` and no BSD name
(`issues/build/toyos-libc-lacks-the-posix-surface-llvm-compiles-against.md`).
POSIX's `endian.h` (`userland/libc/include/endian.h`) and no BSD name. With
those two arms on `849da7d62` and CMake told the system by hand, the 71
libraries rustc links compile against the C sysroot but for objects of
`LLVMSupport`; without them, every object that includes `bit.h` stops.
Bootstrap's arm names the system `ToyOS`, which LLVM's configure refuses,
`Unable to determine platform`, until CMake knows ToyOS and sets `UNIX`
(`issues/build/the-cxx-runtime-names-toyos-to-cmake-as-unix.md`).
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
status: open
kind: defect
opened: 2026-10-01
---

# libc answers EINVAL for every error it does not name

Read from the code, not run. `set_errno` (`userland/libc/src/posix_io.rs`)
sends `Unknown`, `BadAddress`, `ResourceExhausted` and `NotSupported` through
`_ => EINVAL`, so each reaches a C caller as `EINVAL`, which POSIX spells
"invalid argument". A full handle table (`kernel/src/object/handle.rs`)
answers `dup`, `open` and `pipe` `EINVAL` where POSIX has `EMFILE`, a full
bcachefs volume (`kernel/src/bcachefs_adapter.rs`) `write` `EINVAL` where it
has `ENOSPC`, and an operation a filesystem lacks `EINVAL` where it has
`ENOTSUP`. A refusal that is truly `EINVAL` reads the same as each of them, so
a case asserting `EINVAL` passes whichever happened.

**Exit**: `set_errno` matches every `SyscallError` by name, with no catch-all,
each call that can meet `ResourceExhausted` answering the POSIX errno its own
page names for it, and a host test holds each call's mapping.
20 changes: 20 additions & 0 deletions issues/build/libc-close-of-a-socket-ends-the-process.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
status: open
kind: defect
opened: 2026-10-01
---

# libc's close of a socket ends the process

Read from the code, not run. A socket's descriptor is `1024` plus its index in
libc's socket table (`userland/libc/src/socket.rs`, `SOCKET_FD_BASE`), and no
handle. `close` (`userland/libc/src/posix_io.rs`) passes every descriptor to
`SYS_CLOSE`, and the kernel answers a handle its caller does not hold by
ending the caller (`kernel/src/syscall/handles.rs`, `sys_close`, through
`HandleError::refuse`). `close_socket`, which closes the socket's pipes and
tells netd, is exported under `no_mangle` and called by nothing; the header
gate excuses it by this file (`toyos-libc-copies/src/prototypes.rs`).

**Exit**: `close` of a socket's descriptor releases the socket and its pipes
and answers 0, `close_socket` is no export, and a guest C case closes a
connected socket and goes on.
28 changes: 0 additions & 28 deletions issues/build/libc-fcntl-and-fchmod-answer-0-and-do-nothing.md

This file was deleted.

6 changes: 3 additions & 3 deletions issues/build/libc-has-no-alarm.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ opened: 2026-09-30
libc neither declares nor defines `alarm`, and LLVM bounds its wait on a child
with one: a `SIGALRM` handler makes `wait4` answer `EINTR`
(`llvm/lib/Support/Unix/Program.inc`, `Wait`), so an LLVM built for ToyOS does
not link without it
(`issues/build/toyos-libc-lacks-the-posix-surface-llvm-compiles-against.md`
measures that link). POSIX gives `alarm` no refusal, and its `SIGALRM` reaches
not link without it: rustc's LLVM wrapper linked `-shared -z defs` with the
libraries it needs leaves it undefined, beside stage 3's `wait` and `wait4`.
POSIX gives `alarm` no refusal, and its `SIGALRM` reaches
a handler only through the signals libc imitates from stage 3 of
`issues/kernel/a-childs-end-is-an-event-and-a-parent-takes-its-children-down.md`
on; this waits on that stage.
Expand Down
22 changes: 22 additions & 0 deletions issues/build/libc-has-no-pread-or-pwrite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
status: open
kind: defect
opened: 2026-09-30
---

# libc has no pread or pwrite

libc defines neither `pread` nor `pwrite`. The ABI has no positional read or write
(`toyos-abi/src/syscall.rs` has `seek`). With no header declaring `pread`,
LLVM's configure finds none, and LLVM reads a file slice with `lseek` and
`read` instead (`llvm/lib/Support/Unix/Path.inc`, `readNativeFileSlice`), which
moves an offset another thread shares just as they did.

**Exit**: `pread` and `pwrite` are declared and defined and never move the
descriptor's offset, which a guest C case shows over a file whose every 8-byte
word holds its own offset. While one thread `read`s the file through, another
`pread`s it at one offset, and every word either reads holds the offset it was
read from. While one thread `write`s such words through a second file, another
`pwrite`s one at its offset, and every word of that file then holds its own
offset. A seek, read or write, seek-back `pread` and `pwrite` are the negative
control: the case is measured red against them.

This file was deleted.

28 changes: 0 additions & 28 deletions issues/build/libc-mmap-ignores-the-file-it-is-asked-to-map.md

This file was deleted.

This file was deleted.

14 changes: 14 additions & 0 deletions issues/build/libc-printf-ignores-the-alternate-form-flag.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
status: open
kind: defect
opened: 2026-10-01
---

# libc's printf ignores the alternate-form flag

`printf`'s format reader (`userland/libc/src/printf.rs`) steps over `#` and
keeps nothing of it, so `%#x` prints `200` where C has `0x200`, `%#o` no
leading 0, and `%#g` drops the trailing zeros C keeps.

**Exit**: `#` takes C's alternate form for every conversion that has one, and
a corpus case prints each.
19 changes: 0 additions & 19 deletions issues/build/libc-readdir-calls-every-entry-a-regular-file.md

This file was deleted.

48 changes: 48 additions & 0 deletions issues/build/libc-refuses-what-toyos-cannot-yet-answer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
status: open
kind: defect
opened: 2026-10-01
---

# libc refuses what ToyOS cannot yet answer

These answer failure in their POSIX form and do nothing
(`userland/libc/src/refused.rs`, `posix_io.rs`), each asserted by
`tests/testcases/tinycc/206_libc_refusals.c`. Each waits on what it names:

- `link`, `ENOSYS`: no call gives a file a second name.
- `symlink`, `ENOSYS`: `SYS_SYMLINK` displaces what its name held
(`issues/filesystem/a-symbolic-link-on-tmp-displaces-its-name-and-lists-nowhere.md`).
- `chmod` and `fchmod`, `ENOSYS`: a file has no mode bits to set.
- `statvfs` and `fstatvfs`, `ENOSYS`: no call answers a filesystem's size or
free space.
- `getrlimit` and `setrlimit`, `ENOSYS`: no call answers a process's limits.
LLVM's `getDefaultStackSize` (`llvm/lib/Support/ProgramStack.cpp`) ignores
the failure and reads the `rlimit` it did not get.
- `gethostname` and `uname`, `ENOSYS`: no host name, release or version is
published to a process.
- `realpath`, `ENOSYS`: the kernel resolves a path by rules of its own (`..`
read off the text, only the last name's link followed, a relative link read
against its mount), and no call answers where a path leads.
- `msync` and `mprotect`, `ENOSYS`: no call answers which pages of a range are
mapped, and a mapping's protection is fixed when it is made.
- `mmap` of a file, `ENODEV`, and of executable memory, `ENOTSUP`: the kernel
maps neither.
- `madvise`'s `MADV_DONTNEED`, `ENOSYS`: no call discards a range's pages and
keeps it mapped, so it cannot read back as zeros as Linux's does.
- `fcntl`: a record lock, `EINVAL`, POSIX's answer for a file that supports no
locking; `F_DUPFD_CLOEXEC`, `F_GETFL`, `F_SETFL`, `F_GETOWN` and `F_SETOWN`,
`ENOSYS`. `F_DUPFD` answers a duplicate at or above its argument, the first
the kernel hands `dup`, where POSIX has the lowest free number, and refuses
`EINVAL` an argument at or above the slots a handle table has
(`RawHandle::MAX_SLOTS`). `F_GETFD` and `F_SETFD` of a descriptor the
process does not hold answer 0, where POSIX has `EBADF`: the kernel ends a
process that names a handle it does not hold, so libc asks it nothing.

Ruled out, and owed nothing while the ruling stands: `execv` and `execve`, no
call replacing a process's image; `setsid` and `getsid`, no POSIX session;
`fchown`, no owner; `getpwnam_r` and `getpwuid_r`, no user database.

**Exit**: each above either does what POSIX says, asserted by a guest C case
that reads its effect back, or is ruled out by the owner and moved to the list
above.
19 changes: 19 additions & 0 deletions issues/build/libc-stat-answers-one-serial-number-for-every-file.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
status: open
kind: defect
opened: 2026-10-01
---

# libc's stat answers one serial number for every file

`stat`, `fstat` and `lstat` (`userland/libc/src/posix_io.rs`) zero the whole
`struct stat` and fill in the size, the mtime and the mode, so `st_dev` and
`st_ino` are 0 for every file. POSIX names a file by that pair, so every file
is one file to a program that asks: LLVM's `sys::fs::equivalent` and
`UniqueID` (`llvm/lib/Support/Unix/Path.inc`) answer any two paths the same,
and clang's `FileManager` keys every file it opens on the pair. `readdir`'s
`d_ino` is the entry's offset in the listing, which no `st_ino` equals.

**Exit**: `st_dev` and `st_ino` tell two files apart and name one file the
same way through two paths, `d_ino` is its entry's `st_ino`, and a guest C case
reads them for two files and a link.
29 changes: 29 additions & 0 deletions issues/build/the-c-allocators-set-no-errno-where-posix-has-them.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
status: open
kind: defect
opened: 2026-10-01
---

# The C allocators set no errno where POSIX has them

Read from the code, not run. POSIX.1-2024 has `malloc`, `calloc`, `realloc`
and `aligned_alloc` set `ENOMEM` when they answer null for want of memory, and
`aligned_alloc` set `EINVAL` for an alignment it does not support.

In a Rust program, C code allocates through std's C allocator
(`rust/library/std/src/sys/pal/toyos/mod.rs`, `c_allocator`), which sets
`errno` in none of the four. `errno` is libc's (`userland/libc/src/errno.rs`),
and std names no libc symbol: setting it from std puts `__errno_location` in
every Rust program's link.

`realloc(p, 0)` frees `p` and answers null with `errno` untouched, in libc
(`userland/libc/src/memory.rs`) and in std's. POSIX.1-2024 has it answer
either null with `errno` `EINVAL`, or a pointer with `p` freed; its
application usage frees `p` only if `errno` changed, so `EINVAL` beside the
free invites a double free. LLVM's `safe_realloc`
(`llvm/include/llvm/Support/MemAlloc.h`) takes a null answer to size 0 as `p`
freed and allocates afresh, so null with `p` kept leaks it there.

**Exit**: each of the four sets `errno` where POSIX has it in a Rust program,
and a C call there reads `ENOMEM` and `EINVAL` back; `realloc(p, 0)` gives
POSIX's second answer in both allocators: a pointer, with `p` freed.
Loading
Loading