Skip to content

Commit 29d3b0c

Browse files
committed
Rely on term_to_binary/1 format to protect from incomplete file writes
1 parent ae94e6e commit 29d3b0c

File tree

3 files changed

+5
-56
lines changed

3 files changed

+5
-56
lines changed

lib/mix/lib/mix/compilers/elixir.ex

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -310,8 +310,7 @@ defmodule Mix.Compilers.Elixir do
310310
"""
311311
def read_manifest(manifest) do
312312
try do
313-
{:ok, contents} = Mix.Task.Compiler.read_checksumed_file(manifest)
314-
:erlang.binary_to_term(contents)
313+
manifest |> File.read!() |> :erlang.binary_to_term()
315314
rescue
316315
_ -> {[], []}
317316
else
@@ -888,8 +887,7 @@ defmodule Mix.Compilers.Elixir do
888887
# Similar to read_manifest, but for internal consumption and with data migration support.
889888
defp parse_manifest(manifest, compile_path) do
890889
try do
891-
{:ok, contents} = Mix.Task.Compiler.read_checksumed_file(manifest)
892-
:erlang.binary_to_term(contents)
890+
manifest |> File.read!() |> :erlang.binary_to_term()
893891
rescue
894892
_ ->
895893
@default_manifest
@@ -959,7 +957,7 @@ defmodule Mix.Compilers.Elixir do
959957
project_mtime, config_mtime, protocols_and_impls}
960958

961959
manifest_data = :erlang.term_to_binary(term, [:compressed])
962-
:ok = Mix.Task.Compiler.write_checksumed_file(manifest, manifest_data)
960+
File.write!(manifest, manifest_data)
963961
File.touch!(manifest, timestamp)
964962
delete_checkpoints(manifest)
965963

lib/mix/lib/mix/task.compiler.ex

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -370,51 +370,4 @@ defmodule Mix.Task.Compiler do
370370
Mix.Task.reenable("compile.all")
371371
Enum.each(compilers, &Mix.Task.reenable("compile.#{&1}"))
372372
end
373-
374-
@checksum_version 1
375-
376-
@doc """
377-
Reads a checksumed file.
378-
379-
This function is useful to read files with checksums
380-
and validate they won't get corrupted with time.
381-
"""
382-
def read_checksumed_file(path) do
383-
case File.read(path) do
384-
{:ok, <<@checksum_version, size::64, checksum::binary-size(size), contents::binary>>} ->
385-
if checksum(contents) == checksum do
386-
{:ok, contents}
387-
else
388-
{:error, :echecksum}
389-
end
390-
391-
{:error, reason} ->
392-
{:error, reason}
393-
end
394-
end
395-
396-
@doc """
397-
Writes a checksumed file.
398-
399-
This function is useful to write compilation manifests
400-
and validate they won't get corrupted with time.
401-
"""
402-
def write_checksumed_file(path, contents) do
403-
checksum = checksum(contents)
404-
405-
File.write(
406-
path,
407-
<<@checksum_version, byte_size(checksum)::64, checksum::binary, contents::binary>>
408-
)
409-
end
410-
411-
defp checksum(contents) do
412-
case :erlang.system_info(:wordsize) do
413-
8 -> :crypto.hash(:blake2b, contents)
414-
_ -> :crypto.hash(:blake2s, contents)
415-
end
416-
rescue
417-
# Blake may not be available on all OpenSSL distribution
418-
_ -> :erlang.md5(contents)
419-
end
420373
end

lib/mix/test/mix/tasks/compile.elixir_test.exs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -653,13 +653,11 @@ defmodule Mix.Tasks.Compile.ElixirTest do
653653

654654
manifest = "_build/dev/lib/sample/.mix/compile.elixir"
655655

656-
{:ok, contents} = Mix.Task.Compiler.read_checksumed_file(manifest)
657-
658-
contents
656+
File.read!(manifest)
659657
|> :erlang.binary_to_term()
660658
|> put_elem(0, 9)
661659
|> :erlang.term_to_binary()
662-
|> then(&Mix.Task.Compiler.write_checksumed_file(manifest, &1))
660+
|> then(&File.write!(manifest, &1))
663661

664662
Mix.Task.clear()
665663
assert Mix.Task.run("compile", ["--verbose"]) == {:ok, []}

0 commit comments

Comments
 (0)