Skip to content

Commit

Permalink
Fix: LibC bindings and std specs on NetBSD 10 (#15115)
Browse files Browse the repository at this point in the history
The LibC bindings for NetBSD were a bit wrong and some std specs also didn't work as expected. The segfault handler is also broken on NetBSD (the process crashes with SIGILL after receiving SIGSEGV).

With these fixes + pending specs I can run the std and compiler test suites in a NetBSD 10.0 VM.

**Caveat**: the pkgsrc for LLVM enforces partial RELRO and linking the std specs from crystal fails. You must pass `--single-module` for the executable to be able to start without missing runtime symbols from libxml2. See #11046.
  • Loading branch information
ysbaddaden authored Oct 23, 2024
1 parent f2a6628 commit b847563
Show file tree
Hide file tree
Showing 10 changed files with 55 additions and 41 deletions.
2 changes: 1 addition & 1 deletion spec/std/io/io_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,7 @@ describe IO do
it "says invalid byte sequence" do
io = SimpleIOMemory.new(Slice.new(1, 255_u8))
io.set_encoding("EUC-JP")
expect_raises ArgumentError, {% if flag?(:musl) || flag?(:freebsd) %}"Incomplete multibyte sequence"{% else %}"Invalid multibyte sequence"{% end %} do
expect_raises ArgumentError, {% if flag?(:musl) || flag?(:freebsd) || flag?(:netbsd) %}"Incomplete multibyte sequence"{% else %}"Invalid multibyte sequence"{% end %} do
io.read_char
end
end
Expand Down
62 changes: 34 additions & 28 deletions spec/std/kernel_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -254,38 +254,44 @@ describe "hardware exception" do
error.should_not contain("Stack overflow")
end

it "detects stack overflow on the main stack", tags: %w[slow] do
# This spec can take some time under FreeBSD where
# the default stack size is 0.5G. Setting a
# smaller stack size with `ulimit -s 8192`
# will address this.
status, _, error = compile_and_run_source <<-'CRYSTAL'
def foo
y = StaticArray(Int8, 512).new(0)
{% if flag?(:netbsd) %}
# FIXME: on netbsd the process crashes with SIGILL after receiving SIGSEGV
pending "detects stack overflow on the main stack"
pending "detects stack overflow on a fiber stack"
{% else %}
it "detects stack overflow on the main stack", tags: %w[slow] do
# This spec can take some time under FreeBSD where
# the default stack size is 0.5G. Setting a
# smaller stack size with `ulimit -s 8192`
# will address this.
status, _, error = compile_and_run_source <<-'CRYSTAL'
def foo
y = StaticArray(Int8, 512).new(0)
foo
end
foo
end
foo
CRYSTAL
CRYSTAL

status.success?.should be_false
error.should contain("Stack overflow")
end
status.success?.should be_false
error.should contain("Stack overflow")
end

it "detects stack overflow on a fiber stack", tags: %w[slow] do
status, _, error = compile_and_run_source <<-'CRYSTAL'
def foo
y = StaticArray(Int8, 512).new(0)
foo
end
it "detects stack overflow on a fiber stack", tags: %w[slow] do
status, _, error = compile_and_run_source <<-'CRYSTAL'
def foo
y = StaticArray(Int8, 512).new(0)
foo
end

spawn do
foo
end
spawn do
foo
end

sleep 60.seconds
CRYSTAL
sleep 60.seconds
CRYSTAL

status.success?.should be_false
error.should contain("Stack overflow")
end
status.success?.should be_false
error.should contain("Stack overflow")
end
{% end %}
end
4 changes: 2 additions & 2 deletions spec/std/socket/tcp_server_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ describe TCPServer, tags: "network" do
# FIXME: Resolve special handling for win32. The error code handling should be identical.
{% if flag?(:win32) %}
[WinError::WSAHOST_NOT_FOUND, WinError::WSATRY_AGAIN].should contain err.os_error
{% elsif flag?(:android) %}
{% elsif flag?(:android) || flag?(:netbsd) %}
err.os_error.should eq(Errno.new(LibC::EAI_NODATA))
{% else %}
[Errno.new(LibC::EAI_NONAME), Errno.new(LibC::EAI_AGAIN)].should contain err.os_error
Expand All @@ -110,7 +110,7 @@ describe TCPServer, tags: "network" do
# FIXME: Resolve special handling for win32. The error code handling should be identical.
{% if flag?(:win32) %}
[WinError::WSAHOST_NOT_FOUND, WinError::WSATRY_AGAIN].should contain err.os_error
{% elsif flag?(:android) %}
{% elsif flag?(:android) || flag?(:netbsd) %}
err.os_error.should eq(Errno.new(LibC::EAI_NODATA))
{% else %}
[Errno.new(LibC::EAI_NONAME), Errno.new(LibC::EAI_AGAIN)].should contain err.os_error
Expand Down
6 changes: 3 additions & 3 deletions spec/std/socket/tcp_socket_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ describe TCPSocket, tags: "network" do
# FIXME: Resolve special handling for win32. The error code handling should be identical.
{% if flag?(:win32) %}
[WinError::WSAHOST_NOT_FOUND, WinError::WSATRY_AGAIN].should contain err.os_error
{% elsif flag?(:android) %}
{% elsif flag?(:android) || flag?(:netbsd) %}
err.os_error.should eq(Errno.new(LibC::EAI_NODATA))
{% else %}
[Errno.new(LibC::EAI_NONAME), Errno.new(LibC::EAI_AGAIN)].should contain err.os_error
Expand All @@ -93,7 +93,7 @@ describe TCPSocket, tags: "network" do
# FIXME: Resolve special handling for win32. The error code handling should be identical.
{% if flag?(:win32) %}
[WinError::WSAHOST_NOT_FOUND, WinError::WSATRY_AGAIN].should contain err.os_error
{% elsif flag?(:android) %}
{% elsif flag?(:android) || flag?(:netbsd) %}
err.os_error.should eq(Errno.new(LibC::EAI_NODATA))
{% else %}
[Errno.new(LibC::EAI_NONAME), Errno.new(LibC::EAI_AGAIN)].should contain err.os_error
Expand Down Expand Up @@ -142,7 +142,7 @@ describe TCPSocket, tags: "network" do
(client.tcp_nodelay = false).should be_false
client.tcp_nodelay?.should be_false

{% unless flag?(:openbsd) %}
{% unless flag?(:openbsd) || flag?(:netbsd) %}
(client.tcp_keepalive_idle = 42).should eq 42
client.tcp_keepalive_idle.should eq 42
(client.tcp_keepalive_interval = 42).should eq 42
Expand Down
3 changes: 3 additions & 0 deletions spec/std/socket/udp_socket_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ describe UDPSocket, tags: "network" do
elsif {{ flag?(:freebsd) }} && family == Socket::Family::INET6
# FIXME: fails with "Error sending datagram to [ipv6]:port: Network is unreachable"
pending "joins and transmits to multicast groups"
elsif {{ flag?(:netbsd) }} && family == Socket::Family::INET6
# FIXME: fails with "setsockopt: EADDRNOTAVAIL"
pending "joins and transmits to multicast groups"
else
it "joins and transmits to multicast groups" do
udp = UDPSocket.new(family)
Expand Down
8 changes: 4 additions & 4 deletions spec/std/string_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2830,7 +2830,7 @@ describe "String" do
bytes.to_a.should eq([72, 0, 101, 0, 108, 0, 108, 0, 111, 0])
end

{% unless flag?(:musl) || flag?(:solaris) || flag?(:freebsd) || flag?(:dragonfly) %}
{% unless flag?(:musl) || flag?(:solaris) || flag?(:freebsd) || flag?(:dragonfly) || flag?(:netbsd) %}
it "flushes the shift state (#11992)" do
"\u{00CA}".encode("BIG5-HKSCS").should eq(Bytes[0x88, 0x66])
"\u{00CA}\u{0304}".encode("BIG5-HKSCS").should eq(Bytes[0x88, 0x62])
Expand All @@ -2839,7 +2839,7 @@ describe "String" do

# FreeBSD iconv encoder expects ISO/IEC 10646 compatibility code points,
# see https://www.ccli.gov.hk/doc/e_hkscs_2008.pdf for details.
{% if flag?(:freebsd) || flag?(:dragonfly) %}
{% if flag?(:freebsd) || flag?(:dragonfly) || flag?(:netbsd) %}
it "flushes the shift state (#11992)" do
"\u{F329}".encode("BIG5-HKSCS").should eq(Bytes[0x88, 0x66])
"\u{F325}".encode("BIG5-HKSCS").should eq(Bytes[0x88, 0x62])
Expand Down Expand Up @@ -2883,7 +2883,7 @@ describe "String" do
String.new(bytes, "UTF-16LE").should eq("Hello")
end

{% unless flag?(:solaris) || flag?(:freebsd) || flag?(:dragonfly) %}
{% unless flag?(:solaris) || flag?(:freebsd) || flag?(:dragonfly) || flag?(:netbsd) %}
it "decodes with shift state" do
String.new(Bytes[0x88, 0x66], "BIG5-HKSCS").should eq("\u{00CA}")
String.new(Bytes[0x88, 0x62], "BIG5-HKSCS").should eq("\u{00CA}\u{0304}")
Expand All @@ -2892,7 +2892,7 @@ describe "String" do

# FreeBSD iconv decoder returns ISO/IEC 10646-1:2000 code points,
# see https://www.ccli.gov.hk/doc/e_hkscs_2008.pdf for details.
{% if flag?(:freebsd) || flag?(:dragonfly) %}
{% if flag?(:freebsd) || flag?(:dragonfly) || flag?(:netbsd) %}
it "decodes with shift state" do
String.new(Bytes[0x88, 0x66], "BIG5-HKSCS").should eq("\u{00CA}")
String.new(Bytes[0x88, 0x62], "BIG5-HKSCS").should eq("\u{F325}")
Expand Down
7 changes: 6 additions & 1 deletion src/crystal/system/unix/dir.cr
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@ module Crystal::System::Dir
end

def self.info(dir, path) : ::File::Info
Crystal::System::FileDescriptor.system_info LibC.dirfd(dir)
fd = {% if flag?(:netbsd) %}
dir.value.dd_fd
{% else %}
LibC.dirfd(dir)
{% end %}
Crystal::System::FileDescriptor.system_info(fd)
end

def self.close(dir, path) : Nil
Expand Down
1 change: 0 additions & 1 deletion src/lib_c/x86_64-netbsd/c/dirent.cr
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,4 @@ lib LibC
fun opendir = __opendir30(x0 : Char*) : DIR*
fun readdir = __readdir30(x0 : DIR*) : Dirent*
fun rewinddir(x0 : DIR*) : Void
fun dirfd(dirp : DIR*) : Int
end
1 change: 1 addition & 0 deletions src/lib_c/x86_64-netbsd/c/netdb.cr
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ lib LibC
EAI_FAIL = 4
EAI_FAMILY = 5
EAI_MEMORY = 6
EAI_NODATA = 7
EAI_NONAME = 8
EAI_SERVICE = 9
EAI_SOCKTYPE = 10
Expand Down
2 changes: 1 addition & 1 deletion src/lib_c/x86_64-netbsd/c/sys/time.cr
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ lib LibC

fun gettimeofday = __gettimeofday50(x0 : Timeval*, x1 : Timezone*) : Int
fun utimes = __utimes50(path : Char*, times : Timeval[2]) : Int
fun futimens = __futimens50(fd : Int, times : Timespec[2]) : Int
fun futimens(fd : Int, times : Timespec[2]) : Int
end

0 comments on commit b847563

Please sign in to comment.