Download Latest Version v0.9.8 source code.zip (1.2 MB) Google Add to Preferred Sources
Home / v0.9.6
Name Modified Size InfoDownloads / Week
Parent folder
README.md 2026-09-03 4.8 kB
v0.9.6 source code.tar.gz 2026-09-03 812.2 kB
v0.9.6 source code.zip 2026-09-03 1.1 MB
Totals: 3 Items   1.9 MB 0

98 commits since v0.9.5, closing the 47 issues of the v0.9.6 milestone. This release is almost entirely correctness work on the kernel, the filesystem and the test harness.

Kernel and memory

  • User-mode page faults on kernel-mapped addresses deliver SIGSEGV to the faulting process instead of panicking the kernel (#237). A null dereference from an unprivileged program no longer takes the system down.
  • Early-boot failure paths no longer return to a garbage address (#243), kmain no longer swallows an FHS initialization failure while printing both [FAIL] and [ OK ] for it (#248).
  • An unregistered in-range syscall number can no longer dispatch through a NULL pointer (#206).
  • /proc/<pid>/stat and /proc/<pid>/cmdline reads honour the caller's buffer size (#194).

Process, exec and signals

  • execve builds the new image transactionally, so a failed load leaves the caller intact (#208). The shebang path lost an out-of-bounds write, a use-after-free and two leaks (#209, [#227]), and the logging no longer dereferences the user filename after the address space is gone (#223).
  • Oversized argv/envp vectors are rejected instead of overflowing the kernel stack (#196), and the early failure paths report real errno values instead of EPERM for everything (#238).
  • Fatal signals encode the terminating signal in the wait status, so WIFSIGNALED works (#234), and the test harness reports the signal number correctly (#233).
  • kill reaches tasks that are not currently scheduled (#143); waitpid waits passively (#57).

Filesystem

  • Sparse holes read as zeros instead of failing the whole read (#192), reads at or beyond end of file behave (#242), and the intermittent boot-time mount failure is gone (#245).
  • Path resolution no longer truncates. A request for a long path could resolve to a shorter existing name, which for execve meant running a file the caller never asked for (#284).
  • mkdir fails and rolls back instead of reporting success for a directory it could not finish (#264).
  • The open-file cache no longer hands a new file the name and permissions of a deleted one that reused its inode number (#297).
  • Block pointers at the direct and indirect boundaries are stored where the reader looks. Before this, block 12 of every guest-written file had its data block repurposed as the file's index block (#301).
  • creat() no longer returns a positive bogus descriptor when path resolution fails (#298).
  • ELF loading rejects files shorter than the header (#241, [#224]) and reports invalid files correctly (#211).

Userspace, libc and video

  • getcwd handles undersized buffers with ERANGE (#230), fgets no longer returns prematurely in non-canonical input mode (#140).
  • sys_uname keeps nodename NUL-terminated (#256) and no longer leaks the hostname file on a read failure (#240).
  • Scrollback no longer pages into never-written history (#274), and a console shrink no longer loses the cursor row (#275).

Build, tests and CI

  • CI used to report success on a kernel panic (#193). It does not any more, which is how much of the above became findable in the first place.
  • The harness no longer hangs on a piped make qemu-test (#218), no longer exits 0 when interrupted (#246), and no longer needs an exact multiboot flags word to enable the suite (#249).
  • The macOS build works (#124, [#268]), build option validation actually fires (#215), and KMEM_TRACE compiles (#228).
  • t_semget no longer races its own child (#255).

Known issues

None of these are regressions: they were present in v0.9.5 too, and each has a reproduction in its issue. They are the scope of the v0.9.7 milestone.

  • [#304] the ext2 directory-entry iterator loops forever on a zeroed directory block, so one rmdir on a corrupt directory hangs the kernel.
  • [#303] write() reports success when it cannot allocate a block, so a full filesystem silently discards data.
  • [#302] the indirect index blocks of an inode are never freed, so deleting a large file leaks them.
  • [#305] ext2_creat leaks the allocated inode and sets no errno when the creation cannot be completed.
  • [#296] returning from a SIGSEGV handler instead of exiting livelocks the process in an unbounded fault loop.
  • [#191] syscalls do not validate user pointers, with [#259] as the concrete instance in sys_uname.

Note on test coverage

t_mkdir_nospace, the regression test for [#264], is registered but kept out of all_tests[]: it fills the image to force an allocation failure, which costs about two minutes of guest time. Run it by hand when touching the ext2 allocation paths. t_big_write and t_periodic1/2/3 remain skipped as before.

Source: README.md, updated 2026-09-03