From 2d6d0d81c506dc051b52be1e0fa3e04238ecb2a2 Mon Sep 17 00:00:00 2001 From: Quinton Miller Date: Thu, 26 Sep 2024 01:48:39 +0800 Subject: [PATCH 1/2] Fix Linux `getrandom` failure in interpreted code --- src/crystal/system/unix/getrandom.cr | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/crystal/system/unix/getrandom.cr b/src/crystal/system/unix/getrandom.cr index 229716a3d846..48c27660a19a 100644 --- a/src/crystal/system/unix/getrandom.cr +++ b/src/crystal/system/unix/getrandom.cr @@ -102,7 +102,16 @@ module Crystal::System::Random loop do read_bytes = Syscall.getrandom(buf.to_unsafe, LibC::SizeT.new(buf.size), Syscall::GRND_NONBLOCK) if read_bytes < 0 - err = Errno.new(-read_bytes.to_i) + # TODO: Implement syscall for interpreter + # when using `LibC.getrandom` instead, the return value is always -1 and + # the error is set via `Errno.value` instead + err = + {% if flag?(:interpreted) %} + Errno.value + {% else %} + Errno.new(-read_bytes.to_i) + {% end %} + if err.in?(Errno::EINTR, Errno::EAGAIN) ::Fiber.yield else From 8dd245eacae5fc33bafa96b2d85752f51b1e65c5 Mon Sep 17 00:00:00 2001 From: Quinton Miller Date: Thu, 26 Sep 2024 04:21:24 +0800 Subject: [PATCH 2/2] fixup --- src/crystal/system/unix/getrandom.cr | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/crystal/system/unix/getrandom.cr b/src/crystal/system/unix/getrandom.cr index 48c27660a19a..e759ff0406e6 100644 --- a/src/crystal/system/unix/getrandom.cr +++ b/src/crystal/system/unix/getrandom.cr @@ -13,7 +13,10 @@ require "./syscall" # TODO: Implement syscall for interpreter def self.getrandom(buf : UInt8*, buflen : LibC::SizeT, flags : UInt32) : LibC::SSizeT - LibC.getrandom(buf, buflen, flags) + # the syscall returns the negative of errno directly, the C function + # doesn't, so we mimic the syscall behavior + read_bytes = LibC.getrandom(buf, buflen, flags) + read_bytes >= 0 ? read_bytes : LibC::SSizeT.new(-Errno.value.value) end end {% end %} @@ -102,16 +105,7 @@ module Crystal::System::Random loop do read_bytes = Syscall.getrandom(buf.to_unsafe, LibC::SizeT.new(buf.size), Syscall::GRND_NONBLOCK) if read_bytes < 0 - # TODO: Implement syscall for interpreter - # when using `LibC.getrandom` instead, the return value is always -1 and - # the error is set via `Errno.value` instead - err = - {% if flag?(:interpreted) %} - Errno.value - {% else %} - Errno.new(-read_bytes.to_i) - {% end %} - + err = Errno.new(-read_bytes.to_i) if err.in?(Errno::EINTR, Errno::EAGAIN) ::Fiber.yield else