Convert a map into a keyword list in Elixir

I have a map of the form:

%{"browser_name" => "Chrome", "platform" => "linux"}

and I need to convert it to a keyword list:

[browser_name: "Chrome", platform: "linux"]

What's the best way of achieving this?

2 answers

  • answered 2019-02-10 12:33 NiteRain

    Wouldn't this work:

     def ConvertMapToKList(dict) do
         Enum.map(dict, fn({key, value}) -> {String.to_atom(key), value} end)
     end
    

    Keys need to be strings, probably would add a check perhaps?

  • answered 2019-02-11 06:35 Aleksei Matiushkin

    I would put it here for the sake of future readers.

    While one surely might blindly call String.to_atom/1 here and there, that approach is strongly discouraged due to its vulnerability to atom DoS attacks.

    Here is the excerpt from Erlang docs:

    Atoms are not garbage-collected. Once an atom is created, it is never removed. The emulator terminates if the limit for the number of atoms (1,048,576 by default) is reached.

    Therefore, converting arbitrary input strings to atoms can be dangerous in a system that runs continuously. If only certain well-defined atoms are allowed as input, list_to_existing_atom/1 can be used to guard against a denial-of-service attack. (All atoms that are allowed must have been created earlier, for example, by simply using all of them in a module and loading that module.)

    http://erlang.org/doc/efficiency_guide/commoncaveats.html#list_to_atom-1

    That said, whether you receive the map from the external untrusted source (e. g. it’s the parameters in the call to your API or something,) you must not use String.to_atom/1 and should use String.to_existing_atom/1 instead.

    Otherwise, the intruder with a simple random generator for keys would blow up your ErlangVM without any issue.