Skip to content

Commit a0214e9

Browse files
authored
Only make module available after inference to avoid races (#14254)
1 parent e1d171e commit a0214e9

File tree

2 files changed

+19
-28
lines changed

2 files changed

+19
-28
lines changed

Makefile

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ SHARE_PREFIX ?= $(PREFIX)/share
44
MAN_PREFIX ?= $(SHARE_PREFIX)/man
55
CANONICAL := main/
66
ELIXIRC := bin/elixirc --ignore-module-conflict $(ELIXIRC_OPTS)
7+
ELIXIRC_MIN_SIG := $(ELIXIRC) -e 'Code.put_compiler_option :infer_signatures, []'
78
ERLC := erlc -I lib/elixir/include
89
ERL_MAKE := erl -make
910
ERL := erl -I lib/elixir/include -noshell -pa lib/elixir/ebin
@@ -97,17 +98,17 @@ $(KERNEL): lib/elixir/src/* lib/elixir/lib/*.ex lib/elixir/lib/*/*.ex lib/elixir
9798
"$(MAKE)" unicode; \
9899
fi
99100
@ echo "==> elixir (compile)";
100-
$(Q) cd lib/elixir && ../../$(ELIXIRC) "lib/**/*.ex" -o ebin;
101+
$(Q) cd lib/elixir && ../../$(ELIXIRC_MIN_SIG) "lib/**/*.ex" -o ebin;
101102

102103
$(APP): lib/elixir/src/elixir.app.src lib/elixir/ebin VERSION $(GENERATE_APP)
103104
$(Q) $(GENERATE_APP) $(VERSION)
104105

105106
unicode: $(UNICODE)
106107
$(UNICODE): lib/elixir/unicode/*
107108
@ echo "==> unicode (compile)";
108-
$(Q) $(ELIXIRC) lib/elixir/unicode/unicode.ex -o lib/elixir/ebin;
109-
$(Q) $(ELIXIRC) lib/elixir/unicode/tokenizer.ex -o lib/elixir/ebin;
110-
$(Q) $(ELIXIRC) lib/elixir/unicode/security.ex -o lib/elixir/ebin;
109+
$(Q) $(ELIXIRC_MIN_SIG) lib/elixir/unicode/unicode.ex -o lib/elixir/ebin;
110+
$(Q) $(ELIXIRC_MIN_SIG) lib/elixir/unicode/tokenizer.ex -o lib/elixir/ebin;
111+
$(Q) $(ELIXIRC_MIN_SIG) lib/elixir/unicode/security.ex -o lib/elixir/ebin;
111112

112113
$(eval $(call APP_TEMPLATE,ex_unit,ExUnit))
113114
$(eval $(call APP_TEMPLATE,logger,Logger))

lib/elixir/lib/module/parallel_checker.ex

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ defmodule Module.ParallelChecker do
7171
{^ref, :cache} ->
7272
Process.link(pid)
7373

74-
module_tuple =
74+
{mode, module_tuple} =
7575
cond do
7676
is_binary(info) ->
7777
location =
@@ -86,13 +86,15 @@ defmodule Module.ParallelChecker do
8686
{:ok, module_map} <- backend.debug_info(:elixir_v1, module, data, []) do
8787
cache_from_module_map(table, module_map)
8888
else
89-
_ -> nil
89+
_ -> {:not_found, nil}
9090
end
9191

9292
is_tuple(info) ->
9393
info
9494
end
9595

96+
# We only make the module available now, so they are not visible during inference
97+
:ets.insert(table, {module, mode})
9698
send(checker, {ref, :cached})
9799

98100
receive do
@@ -416,21 +418,22 @@ defmodule Module.ParallelChecker do
416418
true ->
417419
{mode, exports} = info_exports(module)
418420
deprecated = info_deprecated(module)
419-
cache_info(table, module, exports, deprecated, %{}, mode)
421+
cache_info(table, module, exports, deprecated, %{})
422+
mode
420423

421424
false ->
422425
# Or load exports from chunk
423426
with {^module, binary, _filename} <- object_code,
424427
{:ok, {^module, [exports: exports]}} <- :beam_lib.chunks(binary, [:exports]) do
425-
cache_info(table, module, exports, %{}, %{}, :erlang)
428+
cache_info(table, module, exports, %{}, %{})
429+
:erlang
426430
else
427-
_ ->
428-
:ets.insert(table, {module, :not_found})
429-
nil
431+
_ -> :not_found
430432
end
431433
end
432434
end
433435

436+
:ets.insert(table, {module, mode})
434437
unlock(checker, module, mode)
435438
end
436439
end
@@ -461,26 +464,15 @@ defmodule Module.ParallelChecker do
461464
behaviour_exports(map) ++
462465
for({function, :def, _meta, _clauses} <- map.definitions, do: function)
463466

464-
cache_info(
465-
table,
466-
map.module,
467-
exports,
468-
Map.new(map.deprecated),
469-
map.signatures,
470-
elixir_mode(map.attributes)
471-
)
472-
473-
module_map_to_module_tuple(map)
467+
cache_info(table, map.module, exports, Map.new(map.deprecated), map.signatures)
468+
{elixir_mode(map.attributes), module_map_to_module_tuple(map)}
474469
end
475470

476-
defp cache_info(table, module, exports, deprecated, sigs, mode) do
471+
defp cache_info(table, module, exports, deprecated, sigs) do
477472
Enum.each(exports, fn fa ->
478473
reason = Map.get(deprecated, fa)
479474
:ets.insert(table, {{module, fa}, reason, Map.get(sigs, fa, :none)})
480475
end)
481-
482-
:ets.insert(table, {module, mode})
483-
mode
484476
end
485477

486478
defp cache_chunk(table, module, contents) do
@@ -497,9 +489,7 @@ defmodule Module.ParallelChecker do
497489
)
498490
end)
499491

500-
mode = Map.get(contents, :mode, :elixir)
501-
:ets.insert(table, {module, mode})
502-
mode
492+
Map.get(contents, :mode, :elixir)
503493
end
504494

505495
defp behaviour_exports(%{defines_behaviour: true}), do: [{:behaviour_info, 1}]

0 commit comments

Comments
 (0)