@@ -11,6 +11,76 @@ defmodule Mix.Utils do
1111 # For bootstrapping purposes
1212 @ compile { :no_warn_undefined , Logger }
1313
14+ @ doc """
15+ A restricted version of `:erlang.binary_to_term/2` that forbids
16+ *executable* terms, such as anonymous functions.
17+
18+ The `opts` are given to the underlying `:erlang.binary_to_term/2`
19+ call, with an empty list as a default.
20+
21+ By default this function does not restrict atoms, as an atom
22+ interned in one node may not yet have been interned on another
23+ (except for releases, which preload all code).
24+
25+ If you want to avoid atoms from being created, then you can pass
26+ `[:safe]` as options, as that will also enable the safety mechanisms
27+ from `:erlang.binary_to_term/2` itself.
28+ """
29+ @ spec non_executable_binary_to_term ( binary ( ) , [ atom ( ) ] ) :: term ( )
30+ def non_executable_binary_to_term ( binary , opts \\ [ ] ) when is_binary ( binary ) do
31+ term = :erlang . binary_to_term ( binary , opts )
32+ non_executable_terms ( term )
33+ term
34+ end
35+
36+ defp non_executable_terms ( list ) when is_list ( list ) do
37+ non_executable_list ( list )
38+ end
39+
40+ defp non_executable_terms ( tuple ) when is_tuple ( tuple ) do
41+ non_executable_tuple ( tuple , tuple_size ( tuple ) )
42+ end
43+
44+ defp non_executable_terms ( map ) when is_map ( map ) do
45+ folder = fn key , value , acc ->
46+ non_executable_terms ( key )
47+ non_executable_terms ( value )
48+ acc
49+ end
50+
51+ :maps . fold ( folder , map , map )
52+ end
53+
54+ defp non_executable_terms ( other )
55+ when is_atom ( other ) or is_number ( other ) or is_bitstring ( other ) or is_pid ( other ) or
56+ is_reference ( other ) do
57+ other
58+ end
59+
60+ defp non_executable_terms ( other ) do
61+ raise ArgumentError ,
62+ "cannot deserialize #{ inspect ( other ) } , the term is not safe for deserialization"
63+ end
64+
65+ defp non_executable_list ( [ ] ) , do: :ok
66+
67+ defp non_executable_list ( [ h | t ] ) when is_list ( t ) do
68+ non_executable_terms ( h )
69+ non_executable_list ( t )
70+ end
71+
72+ defp non_executable_list ( [ h | t ] ) do
73+ non_executable_terms ( h )
74+ non_executable_terms ( t )
75+ end
76+
77+ defp non_executable_tuple ( _tuple , 0 ) , do: :ok
78+
79+ defp non_executable_tuple ( tuple , n ) do
80+ non_executable_terms ( :erlang . element ( n , tuple ) )
81+ non_executable_tuple ( tuple , n - 1 )
82+ end
83+
1484 @ doc """
1585 Returns the apps of a project with no filtering.
1686
0 commit comments