os-test
os-test is a set of test suites for POSIX operating systems designed to make it easy to compare differences between operating systems and to find operating system bugs. It consists of test suites that focus on different operating system areas.
This page visualizes the results for the free software POSIX operating systems that are relevant today.
Source Code
The os-test source code is available on gitlab. You also can view the source code for each test by clicking the test title in the leftmost entry of each row. os-test is licensed under the ISC license, see the LICENSE file in the source code for details.
Setup
I run os-test on my host Linux system and the rest of the systems run in VirtualBox virtual machines of every other system. The testing harness connects to each virtual machine over ssh and runs tests there. The systems are:
- DragonFly (Twitter thread on installation)
- FreeBSD (Twitter thread on installation)
- Haiku (Twitter thread on installation)
- Hurd (Twitter thread on installation)
- Linux (My development environment)
- macOS (Contributed data - how do I get such a virtual machine?)
- Minix (Twitter thread on installation)
- NetBSD (Twitter thread on installation)
- OpenBSD
- OpenIndiana (Twitter thread on installation) and OmniOS Community Edition (Twitter thread on installation) (the results are identical, so their columns are combined to save space)
- Sortix (Virtual Machine of my own OS)
Legend
Unanimous | Result kind 1 | Result kind 2 | Result kind 3 | Result kind 4 | Result kind 5 | |
---|---|---|---|---|---|---|
Good | Good unanimous | Good result kind 1 | Good result kind 2 | Good result kind 3 | Good result kind 4 | Good result kind 5 |
Unknown | Unknown unanimous | Unknown result kind 1 | Unknown result kind 2 | Unknown result kind 3 | Unknown result kind 4 | Unknown result kind 5 |
Bad | Bad unanimous | Bad result kind 1 | Bad result kind 2 | Bad result kind 3 | Bad result kind 4 | Bad result kind 5 |
Good. A cell is good if its output belongs to the set of expected valid outputs for that test, as determined by the applicable standards, specifications, expected behavior, or the interpretation of the os-test authors. If all the good results in a row have the same output, all the good result cells are colored in the unanimous color. Otherwise, each different kind of good outcome is colored in an unique color.
Unknown. A cell is unknown if the output is known, but it has not yet been determined if the output is a good result. If all the unknown results in a row have the same output, all the unknown result cells are colored in the unanimous color. Otherwise, each different kind of unknown outcome is colored in an unique color.
Bad. A cell is bad if its output is neither good nor unknown. If all the bad results in a row have the same output, all the bad result cells are colored in the unanimous color. Otherwise, each different kind of bad outcome is colored in an unique color.
§. The § link on the left of each row links to that row.
Suites
os-test currently contains these suites:
- io - This suite tests input/output system calls.
- malloc - This suite tests memory allocation.
- udp - This suite tests the UDP stack.
io
This suite tests input/output system calls.
dragonfly DragonFly 5.0-RELEASE x86_64 |
freebsd FreeBSD 11.1-RELEASE amd64 |
haiku Haiku 1 x86_64 |
hurd GNU 0.9 i686-AT386 |
linux Linux 4.4.0-161-generic x86_64 |
macos Darwin 17.4.0 x86_64 |
minix Minix 3.4.0 i386 |
netbsd NetBSD 7.1 amd64 |
openbsd OpenBSD 6.4 amd64 |
openindiana-omnios SunOS 5.11 i86pc |
sortix Sortix 1.1dev x86_64 |
|
---|---|---|---|---|---|---|---|---|---|---|---|
§ open-mkstemp-rdonly | dragonfly: good exit: 0 |
freebsd: good exit: 0 |
haiku: good exit: 0 |
hurd: good exit: 0 |
linux: good exit: 0 |
macos: good exit: 0 |
minix: good exit: 0 |
netbsd: good exit: 0 |
openbsd: good exit: 0 |
openindiana-omnios: good exit: 0 |
sortix: good exit: 0 |
§ open-mkstemp-rdonly-directory | dragonfly: good open: ENOTDIR |
freebsd: good open: ENOTDIR |
haiku: good open: ENOTDIR |
hurd: good open: ENOTDIR |
linux: good open: ENOTDIR |
macos: no data | minix: bad exit: 0 |
netbsd: good open: ENOTDIR |
openbsd: good open: ENOTDIR |
openindiana-omnios: bad O_DIRECTORY is not defined |
sortix: good open: ENOTDIR |
§ open-mkstemp-rdonly-trunc | dragonfly: good open: EACCES |
freebsd: good file was truncated |
haiku: good open: EPERM |
hurd: good open: EINVAL |
linux: good file was truncated |
macos: good file was truncated |
minix: good file was truncated |
netbsd: good file was truncated |
openbsd: good open: EINVAL |
openindiana-omnios: good file was truncated |
sortix: good open: EINVAL |
§ open-mkstemp-rdonly-trunc-directory | dragonfly: good open: EACCES |
freebsd: good open: ENOTDIR |
haiku: good open: ENOTDIR |
hurd: good open: ENOTDIR |
linux: good open: ENOTDIR |
macos: no data | minix: bad file was truncated |
netbsd: good open: ENOTDIR |
openbsd: good open: EINVAL |
openindiana-omnios: bad O_DIRECTORY is not defined |
sortix: good open: EINVAL |
§ open-mkstemp-wronly-directory | dragonfly: good open: ENOTDIR |
freebsd: good open: ENOTDIR |
haiku: good open: ENOTDIR |
hurd: good open: ENOTDIR |
linux: good open: ENOTDIR |
macos: no data | minix: bad exit: 0 |
netbsd: good open: ENOTDIR |
openbsd: good open: ENOTDIR |
openindiana-omnios: bad O_DIRECTORY is not defined |
sortix: good open: ENOTDIR |
§ open-mkstemp-wronly-trunc-directory | dragonfly: good open: ENOTDIR |
freebsd: good open: ENOTDIR |
haiku: good open: ENOTDIR |
hurd: good open: ENOTDIR |
linux: good open: ENOTDIR |
macos: no data | minix: bad file was truncated |
netbsd: good open: ENOTDIR |
openbsd: good open: ENOTDIR |
openindiana-omnios: bad O_DIRECTORY is not defined |
sortix: good open: EINVAL |
§ open-tmpdir-rdonly | dragonfly: good exit: 0 |
freebsd: good exit: 0 |
haiku: good exit: 0 |
hurd: good exit: 0 |
linux: good exit: 0 |
macos: good exit: 0 |
minix: good exit: 0 |
netbsd: good exit: 0 |
openbsd: good exit: 0 |
openindiana-omnios: good exit: 0 |
sortix: good exit: 0 |
§ open-tmpdir-rdonly-append | dragonfly: good exit: 0 |
freebsd: good exit: 0 |
haiku: good exit: 0 |
hurd: good exit: 0 |
linux: good exit: 0 |
macos: good exit: 0 |
minix: good exit: 0 |
netbsd: good exit: 0 |
openbsd: good exit: 0 |
openindiana-omnios: good exit: 0 |
sortix: good exit: 0 |
§ open-tmpdir-rdonly-creat | dragonfly: bad exit: 0 |
freebsd: bad exit: 0 |
haiku: bad exit: 0 |
hurd: bad exit: 0 |
linux: good open: EISDIR |
macos: bad exit: 0 |
minix: bad exit: 0 |
netbsd: bad exit: 0 |
openbsd: bad exit: 0 |
openindiana-omnios: bad exit: 0 |
sortix: good open: EISDIR |
§ open-tmpdir-rdonly-directory | dragonfly: good exit: 0 |
freebsd: good exit: 0 |
haiku: good exit: 0 |
hurd: good exit: 0 |
linux: good exit: 0 |
macos: no data | minix: good exit: 0 |
netbsd: good exit: 0 |
openbsd: good exit: 0 |
openindiana-omnios: bad O_DIRECTORY is not defined |
sortix: good exit: 0 |
§ open-tmpdir-rdonly-trunc | dragonfly: good open: EACCES |
freebsd: good open: EISDIR |
haiku: good open: EPERM |
hurd: good open: EINVAL |
linux: good open: EISDIR |
macos: good open: EISDIR |
minix: good exit: 0 |
netbsd: good open: EISDIR |
openbsd: good open: EINVAL |
openindiana-omnios: good open: EISDIR |
sortix: good open: EINVAL |
§ open-tmpdir-rdwr | dragonfly: good open: EISDIR |
freebsd: good open: EISDIR |
haiku: good open: EISDIR |
hurd: good open: EISDIR |
linux: good open: EISDIR |
macos: good open: EISDIR |
minix: good open: EISDIR |
netbsd: good open: EISDIR |
openbsd: good open: EISDIR |
openindiana-omnios: good open: EISDIR |
sortix: good open: EISDIR |
§ open-tmpdir-rdwr-append | dragonfly: good open: EISDIR |
freebsd: good open: EISDIR |
haiku: good open: EISDIR |
hurd: good open: EISDIR |
linux: good open: EISDIR |
macos: no data | minix: good open: EISDIR |
netbsd: good open: EISDIR |
openbsd: good open: EISDIR |
openindiana-omnios: good open: EISDIR |
sortix: good open: EISDIR |
§ open-tmpdir-rdwr-creat | dragonfly: good open: EISDIR |
freebsd: good open: EISDIR |
haiku: good open: EISDIR |
hurd: good open: EISDIR |
linux: good open: EISDIR |
macos: good open: EISDIR |
minix: good open: EISDIR |
netbsd: good open: EISDIR |
openbsd: good open: EISDIR |
openindiana-omnios: good open: EISDIR |
sortix: good open: EISDIR |
§ open-tmpdir-rdwr-directory | dragonfly: good open: EISDIR |
freebsd: good open: EISDIR |
haiku: good open: EISDIR |
hurd: good open: EISDIR |
linux: good open: EISDIR |
macos: no data | minix: good open: EISDIR |
netbsd: good open: EISDIR |
openbsd: good open: EISDIR |
openindiana-omnios: bad O_DIRECTORY is not defined |
sortix: good open: EISDIR |
§ open-tmpdir-rdwr-trunc | dragonfly: good open: EISDIR |
freebsd: good open: EISDIR |
haiku: good open: EISDIR |
hurd: good open: EISDIR |
linux: good open: EISDIR |
macos: good open: EISDIR |
minix: good open: EISDIR |
netbsd: good open: EISDIR |
openbsd: good open: EISDIR |
openindiana-omnios: good open: EISDIR |
sortix: good open: EISDIR |
§ open-tmpdir-wronly | dragonfly: good open: EISDIR |
freebsd: good open: EISDIR |
haiku: good open: EISDIR |
hurd: good open: EISDIR |
linux: good open: EISDIR |
macos: good open: EISDIR |
minix: good open: EISDIR |
netbsd: good open: EISDIR |
openbsd: good open: EISDIR |
openindiana-omnios: good open: EISDIR |
sortix: good open: EISDIR |
§ open-tmpdir-wronly-append | dragonfly: good open: EISDIR |
freebsd: good open: EISDIR |
haiku: good open: EISDIR |
hurd: good open: EISDIR |
linux: good open: EISDIR |
macos: good open: EISDIR |
minix: good open: EISDIR |
netbsd: good open: EISDIR |
openbsd: good open: EISDIR |
openindiana-omnios: good open: EISDIR |
sortix: good open: EISDIR |
§ open-tmpdir-wronly-creat | dragonfly: good open: EISDIR |
freebsd: good open: EISDIR |
haiku: good open: EISDIR |
hurd: good open: EISDIR |
linux: good open: EISDIR |
macos: good open: EISDIR |
minix: good open: EISDIR |
netbsd: good open: EISDIR |
openbsd: good open: EISDIR |
openindiana-omnios: good open: EISDIR |
sortix: good open: EISDIR |
§ open-tmpdir-wronly-directory | dragonfly: good open: EISDIR |
freebsd: good open: EISDIR |
haiku: good open: EISDIR |
hurd: good open: EISDIR |
linux: good open: EISDIR |
macos: no data | minix: good open: EISDIR |
netbsd: good open: EISDIR |
openbsd: good open: EISDIR |
openindiana-omnios: bad O_DIRECTORY is not defined |
sortix: good open: EISDIR |
§ open-tmpdir-wronly-trunc | dragonfly: good open: EISDIR |
freebsd: good open: EISDIR |
haiku: good open: EISDIR |
hurd: good open: EISDIR |
linux: good open: EISDIR |
macos: good open: EISDIR |
minix: good open: EISDIR |
netbsd: good open: EISDIR |
openbsd: good open: EISDIR |
openindiana-omnios: good open: EISDIR |
sortix: good open: EISDIR |
malloc
This suite tests memory allocation.
dragonfly DragonFly 5.0-RELEASE x86_64 |
freebsd FreeBSD 11.1-RELEASE amd64 |
haiku Haiku 1 x86_64 |
hurd GNU 0.9 i686-AT386 |
linux Linux 4.4.0-161-generic x86_64 |
macos Darwin 17.4.0 x86_64 |
minix Minix 3.4.0 i386 |
netbsd NetBSD 7.1 amd64 |
openbsd OpenBSD 6.4 amd64 |
openindiana-omnios SunOS 5.11 i86pc |
sortix Sortix 1.1dev x86_64 |
|
---|---|---|---|---|---|---|---|---|---|---|---|
§ malloc-0 | dragonfly: good non-NULL |
freebsd: good non-NULL |
haiku: good non-NULL |
hurd: good non-NULL |
linux: good non-NULL |
macos: no data | minix: good non-NULL |
netbsd: good non-NULL |
openbsd: good non-NULL |
openindiana-omnios: good non-NULL |
sortix: good non-NULL |
§ realloc-0 | dragonfly: good non-NULL |
freebsd: good NULL |
haiku: good NULL |
hurd: good NULL |
linux: good NULL |
macos: no data | minix: good non-NULL |
netbsd: good non-NULL |
openbsd: good non-NULL |
openindiana-omnios: good NULL |
sortix: good non-NULL |
§ realloc-null-0 | dragonfly: good non-NULL |
freebsd: good non-NULL |
haiku: good non-NULL |
hurd: good non-NULL |
linux: good non-NULL |
macos: no data | minix: good non-NULL |
netbsd: good non-NULL |
openbsd: good non-NULL |
openindiana-omnios: good non-NULL |
sortix: good non-NULL |
udp
This suite tests the UDP stack.
Open questions:
- What should happen if you bind to the broadcast address 255.255.255.255? It is an explicitly forbidden source address. Should it fail with EADDRNOTAVAIL, or some other error, or succeed (and in which case, what does it mean?). (bind-broadcast-0-getpeername, bind-broadcast-0-getsockname)
- What should happen if you connect to the broadcast address 255.255.255.255? Must SO_BROADCAST be set first? (connect-broadcast-getpeername-so-broadcast, connect-broadcast-getpeername, connect-broadcast-getsockname-so-broadcast, connect-broadcast-getsockname)
- What should happen if you bind to the first address in the lan subnet? (bind-lan-subnet-first)
- What should happen if you connect to the any address 0.0.0.0? Is it the same as connecting to the loopback address? (connect-any-getpeername and connect-any-getsockname)
- What should happen if you connect to port 0? Does connecting to port 0 unconnect the socket on DragonFly and Linux? (connect-any-0-getpeername, connect-any-0-getsockname, connect-loopback-0-getpeername, connect-loopback-0-getsockname)
- What should happen if you send to the any address 0.0.0.0? (sendto-any-so-error)
- What should happen if you send to port 0? (sendto-loopback-0-so-error)
- Should it be possible to shutdown a socket without having connected it?
- Should reading on a socket shutdown for read return 0 or should it fail with EWOULDBLOCK?
- Should writing to socket shutdown for write send SIGPIPE in addition to failing with ESPIPE?
- After shutdown for read, should data already received be avalilable for read? Some systems deliver already received asyncronous errors after shutdown, yet don't deliver already received data after shutdown.
- After shutdown for read, should data be received? Should POLLIN be set if data is received yet recv of it would return 0.
- Should POLLOUT be set after shutdown for write? Should POLLHUP be set?
- Should POLLIN be set after shutdown for write if there's already received data?
- If an asynchronous socket error is pending, which of POLLIN, POLLOUT, POLLERR should be set?
- Should asynchronous socket errors be delivered on connect?
- What should happen if you connect to an address on the loopback interface and then reconnect to the public internet? What happens to the locally bound address? Is the socket rebound? Or does the connect fail because there's no longer a valid route from the loopback interface to the public internet.
- If a socket is connected, can you supply a destination address to sendto? What if the destination address is the current remote address?
- What is the local socket name after connect to loopback and then unconnect?
- How does unconnecting work? Can you pass a
sa_family_t
set toAF_UNSPEC
to connect, or do you need to wrap it in astruct sockaddr
, or astruct sockaddr_in
? - What happens if you bind after unconnect?
- Does unconnect on a freshly made socket bind the socket? (unconnect-getsockname)
- Can you unconnect a socket that hasn't been connected yet? (unconnect-getsockname)
- If a socket is shutdown for read, should recv return any data received after the shutdown.
- If you receive on freshly made socket, what address should getsockname return?
- Can you bind to the any address in the loopback network? (bind-loopback-other)
- Can you bind to the broadcast address in the loopback network? (bind-loopback-broadcast)
- Does SO_REUSEADDR need to set on both sockets or just the second? (bind-conflict-any-loopback-so-reuseaddr, bind-conflict-any-loopback-so-reuseaddr-both)
- Does SO_REUSEADDR allow the same address and port to be bound twice? (bind-conflict-loopback-loopback-so-reuseaddr, bind-conflict-loopback-loopback-so-reuseaddr-both)
Running this suite has the following side effects:
- Datagrams containing just the byte 'x' are sent to 8.8.8.8:53 (Google DNS)
because I needed a legitimate address that would not send back any ICMP
connection refused address. Please configure this address in udp/udp.h using
BLACKHOLE_HOST
andBLACKHOLE_PORT
to a site of your choice. - Datagrams containing just the byte 'x' are sent to port 65534 and port 65535 on the loopback address 127.0.0.1.
- This suite requires port 65535 on the loopback address 127.0.0.1 to be unused.
- UDP sockets will be bound to the loopback interface and on the interface leading to the public internet.
dragonfly DragonFly 5.0-RELEASE x86_64 |
freebsd FreeBSD 11.1-RELEASE amd64 |
haiku Haiku 1 x86_64 |
hurd GNU 0.9 i686-AT386 |
linux Linux 4.4.0-161-generic x86_64 |
macos Darwin 17.4.0 x86_64 |
minix Minix 3.4.0 i386 |
netbsd NetBSD 7.1 amd64 |
openbsd OpenBSD 6.4 amd64 |
openindiana-omnios SunOS 5.11 i86pc |
sortix Sortix 1.1dev x86_64 |
|
---|---|---|---|---|---|---|---|---|---|---|---|
§ accept | dragonfly: bad accept: EINVAL |
freebsd: bad accept: EINVAL |
haiku: bad accept: EINVAL |
hurd: good accept: ENOTSUP |
linux: good accept: ENOTSUP |
macos: good accept: ENOTSUP |
minix: good accept: ENOTSUP |
netbsd: good accept: ENOTSUP |
openbsd: bad accept: EINVAL |
openindiana-omnios: good accept: ENOTSUP |
sortix: good accept: ENOTSUP |
§ accept-nonblock | dragonfly: bad accept: EINVAL |
freebsd: bad accept: EINVAL |
haiku: bad accept: EINVAL |
hurd: good accept: ENOTSUP |
linux: good accept: ENOTSUP |
macos: good accept: ENOTSUP |
minix: good accept: ENOTSUP |
netbsd: good accept: ENOTSUP |
openbsd: bad accept: EINVAL |
openindiana-omnios: good accept: ENOTSUP |
sortix: good accept: ENOTSUP |
§ bind-any-0 | dragonfly: good exit: 0 |
freebsd: good exit: 0 |
haiku: good exit: 0 |
hurd: good exit: 0 |
linux: good exit: 0 |
macos: good exit: 0 |
minix: good exit: 0 |
netbsd: good exit: 0 |
openbsd: good exit: 0 |
openindiana-omnios: good exit: 0 |
sortix: good exit: 0 |
§ bind-any-0-getpeername | dragonfly: good getsockname: ENOTCONN |
freebsd: good getsockname: ENOTCONN |
haiku: good getsockname: ENOTCONN |
hurd: good getsockname: ENOTCONN |
linux: good getsockname: ENOTCONN |
macos: good getsockname: ENOTCONN |
minix: good getsockname: ENOTCONN |
netbsd: good getsockname: ENOTCONN |
openbsd: good getsockname: ENOTCONN |
openindiana-omnios: good getsockname: ENOTCONN |
sortix: good getsockname: ENOTCONN |
§ bind-any-0-getsockname | dragonfly: good 0.0.0.0:non-zero |
freebsd: good 0.0.0.0:non-zero |
haiku: good 0.0.0.0:non-zero |
hurd: good 0.0.0.0:non-zero |
linux: good 0.0.0.0:non-zero |
macos: good 0.0.0.0:non-zero |
minix: good 0.0.0.0:non-zero |
netbsd: good 0.0.0.0:non-zero |
openbsd: good 0.0.0.0:non-zero |
openindiana-omnios: good 0.0.0.0:non-zero |
sortix: good 0.0.0.0:non-zero |
§ bind-any-0-unbind | dragonfly: good bind AF_UNSPEC: EINVAL |
freebsd: good bind AF_UNSPEC: EINVAL |
haiku: good bind AF_UNSPEC: EAFNOSUPPORT |
hurd: good bind AF_UNSPEC: EINVAL |
linux: good bind AF_UNSPEC: EINVAL |
macos: good bind AF_UNSPEC: EINVAL |
minix: good bind AF_UNSPEC: EINVAL |
netbsd: good bind AF_UNSPEC: EINVAL |
openbsd: good bind AF_UNSPEC: EINVAL |
openindiana-omnios: good bind AF_UNSPEC: EINVAL |
sortix: good bind AF_UNSPEC: EINVAL |
§ bind-broadcast-0-getpeername | dragonfly: unknown bind: EADDRNOTAVAIL |
freebsd: unknown bind: EADDRNOTAVAIL |
haiku: bad bind: General system error |
hurd: unknown getpeername: ENOTCONN |
linux: unknown getpeername: ENOTCONN |
macos: unknown bind: EADDRNOTAVAIL |