Skip to content

Commit c9b529a

Browse files
authored
Assert scope is not match/guard when using escaped regexes (#14780)
1 parent 81cd55b commit c9b529a

File tree

3 files changed

+38
-2
lines changed

3 files changed

+38
-2
lines changed

lib/elixir/lib/regex.ex

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1017,6 +1017,9 @@ defmodule Regex do
10171017

10181018
pattern_ast =
10191019
cond do
1020+
is_nil(regex.re_pattern) ->
1021+
nil
1022+
10201023
# TODO: Remove this when we require Erlang/OTP 28+
10211024
# Before OTP 28.0, patterns did not contain any refs and could be safely be escaped
10221025
:erlang.system_info(:otp_release) < [?2, ?8] ->
@@ -1027,8 +1030,10 @@ defmodule Regex do
10271030
{:ok, exported} = :re.compile(regex.source, [:export] ++ regex.opts)
10281031

10291032
quote do
1030-
:re.import(unquote(Macro.escape(exported)))
1033+
Regex.__import_pattern__(unquote(Macro.escape(exported)))
10311034
end
1035+
# we now that the Regex module is defined at this stage, so this macro can be safely called
1036+
|> Macro.update_meta(&([required: true] ++ &1))
10321037

10331038
# TODO: Remove this when we require Erlang/OTP 28.1+
10341039
# OTP 28.0 works in degraded mode performance-wise, we need to recompile from the source
@@ -1050,4 +1055,15 @@ defmodule Regex do
10501055
}
10511056
end
10521057
end
1058+
1059+
@doc false
1060+
defmacro __import_pattern__(pattern) do
1061+
if __CALLER__.context in [:match, :guard] do
1062+
raise ArgumentError, "escaped Regex structs are not allowed in match or guards"
1063+
end
1064+
1065+
quote do
1066+
:re.import(unquote(pattern))
1067+
end
1068+
end
10531069
end

lib/elixir/test/elixir/macro_test.exs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,8 @@ defmodule MacroTest do
168168
[
169169
__struct__: Regex,
170170
re_pattern:
171-
{{:., [], [:re, :import]}, [], [{:{}, [], [:re_exported_pattern | _]}]},
171+
{{:., [], [{:__aliases__, _, [:Regex]}, :__import_pattern__]},
172+
[required: true], [{:{}, [], [:re_exported_pattern | _]}]},
172173
source: "foo",
173174
opts: []
174175
]

lib/elixir/test/elixir/regex_test.exs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,25 @@ defmodule RegexTest do
2828
end
2929
end
3030

31+
@tag :re_import
32+
test "module attribute in match context" do
33+
assert_raise(
34+
ArgumentError,
35+
~r/escaped Regex structs are not allowed in match or guards/,
36+
fn ->
37+
Code.eval_quoted(
38+
quote do
39+
defmodule ModAttrGuard do
40+
@regex ~r/example/
41+
def example?(@regex), do: true
42+
def example?(_), do: false
43+
end
44+
end
45+
)
46+
end
47+
)
48+
end
49+
3150
test "multiline" do
3251
refute Regex.match?(~r/^b$/, "a\nb\nc")
3352
assert Regex.match?(~r/^b$/m, "a\nb\nc")

0 commit comments

Comments
 (0)