Skip to content

Commit 1c42bae

Browse files
Turn SystemError.from_errno into a macro
This ensures we capture `Errno.value` right away and it cannot be influenced by other code producing the arguments.
1 parent 18276e3 commit 1c42bae

File tree

2 files changed

+16
-14
lines changed

2 files changed

+16
-14
lines changed

spec/std/system_error_spec.cr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ describe SystemError do
1919
it "avoid reset from message" do
2020
Errno.value = :ENOENT
2121
error = ::RuntimeError.from_errno(message: "foobar".tap{ Errno.value = :EPERM })
22-
error.os_error.should eq Errno::EPERM # This should be ENOENT
22+
error.os_error.should eq Errno::ENOENT
2323
end
2424
end
2525
end

src/system_error.cr

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,21 @@
4040
module SystemError
4141
macro included
4242
extend ::SystemError::ClassMethods
43+
44+
# Builds an instance of the exception from the current system error value (`Errno.value`).
45+
#
46+
# The system message corresponding to the OS error value amends the *message*.
47+
# Additional keyword arguments are forwarded to the exception initializer `.new_from_os_error`.
48+
macro from_errno(message, **opts)
49+
# This is a macro in order to retrieve `Errno.value` first before evaluating `message` and `opts`.
50+
%errno = Errno.value
51+
::\{{@type}}.from_os_error(\{{ message }}, %errno, \{{ opts.double_splat }})
52+
end
53+
54+
@[Deprecated("Use `.from_os_error` instead")]
55+
macro from_errno(message = nil, errno = nil, **opts)
56+
::\{{@type}}.from_os_error(\{{ message }}, \{{ errno }}, \{{ opts.double_splat }})
57+
end
4358
end
4459

4560
# The original system error wrapped by this exception
@@ -68,19 +83,6 @@ module SystemError
6883
end
6984
end
7085

71-
# Builds an instance of the exception from the current system error value (`Errno.value`).
72-
#
73-
# The system message corresponding to the OS error value amends the *message*.
74-
# Additional keyword arguments are forwarded to the exception initializer `.new_from_os_error`.
75-
def from_errno(message : String, **opts)
76-
from_os_error(message, Errno.value, **opts)
77-
end
78-
79-
@[Deprecated("Use `.from_os_error` instead")]
80-
def from_errno(message : String? = nil, errno : Errno? = nil, **opts)
81-
from_os_error(message, errno, **opts)
82-
end
83-
8486
# Prepares the message that goes before the system error description.
8587
#
8688
# By default it returns the original message unchanged. But that could be

0 commit comments

Comments
 (0)