Skip to content

Commit

Permalink
Fix: avoid wrapping whole getrandom file in macro
Browse files Browse the repository at this point in the history
  • Loading branch information
ysbaddaden committed Oct 8, 2024
1 parent 337a6d2 commit 6744811
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 34 deletions.
7 changes: 6 additions & 1 deletion src/crystal/system/random.cr
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ end
{% if flag?(:wasi) %}
require "./wasi/random"
{% elsif flag?(:linux) %}
require "./unix/getrandom"
require "c/sys/random"
\{% if LibC.has_method?(:getrandom) %}
require "./unix/getrandom"
\{% else %}
require "./unix/urandom"
\{% end %}
{% elsif flag?(:bsd) || flag?(:darwin) %}
require "./unix/arc4random"
{% elsif flag?(:unix) %}
Expand Down
61 changes: 28 additions & 33 deletions src/crystal/system/unix/getrandom.cr
Original file line number Diff line number Diff line change
@@ -1,44 +1,39 @@
require "c/sys/random"

{% if !LibC.has_method?(:getrandom) %}
# getrandom isn't available in android before API LEVEL 28
require "./urandom"
{% else %}
module Crystal::System::Random
# Reads n random bytes using the Linux `getrandom(2)` syscall.
def self.random_bytes(buffer : Bytes) : Nil
getrandom(buffer)
end

def self.next_u : UInt8
buffer = uninitialized UInt8
getrandom(pointerof(buffer).to_slice(1))
buffer
end
module Crystal::System::Random
# Reads n random bytes using the Linux `getrandom(2)` syscall.
def self.random_bytes(buffer : Bytes) : Nil
getrandom(buffer)
end

# Reads n random bytes using the Linux `getrandom(2)` syscall.
private def self.getrandom(buffer)
# getrandom(2) may only read up to 256 bytes at once without being
# interrupted or returning early
chunk_size = 256
def self.next_u : UInt8
buffer = uninitialized UInt8
getrandom(pointerof(buffer).to_slice(1))
buffer
end

while buffer.size > 0
read_bytes = 0
# Reads n random bytes using the Linux `getrandom(2)` syscall.
private def self.getrandom(buffer)
# getrandom(2) may only read up to 256 bytes at once without being
# interrupted or returning early
chunk_size = 256

loop do
# pass GRND_NONBLOCK flag so that it fails with EAGAIN if the requested
# entropy was not available
read_bytes = LibC.getrandom(buffer, buffer.size.clamp(..chunk_size), LibC::GRND_NONBLOCK)
break unless read_bytes == -1
while buffer.size > 0
read_bytes = 0

err = Errno.value
raise RuntimeError.from_os_error("getrandom", err) unless err.in?(Errno::EINTR, Errno::EAGAIN)
loop do
# pass GRND_NONBLOCK flag so that it fails with EAGAIN if the requested
# entropy was not available
read_bytes = LibC.getrandom(buffer, buffer.size.clamp(..chunk_size), LibC::GRND_NONBLOCK)
break unless read_bytes == -1

::Fiber.yield
end
err = Errno.value
raise RuntimeError.from_os_error("getrandom", err) unless err.in?(Errno::EINTR, Errno::EAGAIN)

buffer += read_bytes
::Fiber.yield
end

buffer += read_bytes
end
end
{% end %}
end

0 comments on commit 6744811

Please sign in to comment.