Navigation Menu

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

credo@1.1.0 crashes, when sourcecode contain unicode heredoc #665

Closed
bencode opened this issue Jun 25, 2019 · 12 comments
Closed

credo@1.1.0 crashes, when sourcecode contain unicode heredoc #665

bencode opened this issue Jun 25, 2019 · 12 comments

Comments

@bencode
Copy link

bencode commented Jun 25, 2019

Environment

  • Credo version (mix credo -v):
    1.1.0

  • Erlang/Elixir version (elixir -v):

Erlang/OTP 22 [erts-10.4.3] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]

Elixir 1.9.0 (compiled with Erlang/OTP 22)
  • Operating system:

MacOS

What were you trying to do?

mix credo

Expected outcome

Actual outcome

Screenshot 2019-06-25 at 9 16 18 PM

may be reason

in function pad_replaced_heredoc length_after_byte_index my be minus

rrrene added a commit that referenced this issue Jun 26, 2019
@rrrene
Copy link
Owner

rrrene commented Jun 26, 2019

@bencode Thx for reporting! 👍

Could you provide the heredoc that caused the crash or is the information sensitive? I tried to reproduce this in 2664240 to no avail.

@bencode
Copy link
Author

bencode commented Jun 28, 2019

@skovmand
Copy link

skovmand commented Jul 2, 2019

I have the same issue in two modules, also on Elixir 1.9.0 and credo 1.1.0. It goes away when I remove all the @doc blocks from the modules or if I disable the MaxLineLength check. There is only text in the doc blocks. The stack traces (with removed code, it's a private project).

** (EXIT from #PID<0.93.0>) an exception was raised:
    ** (FunctionClauseError) no function clause matching in String.slice/3
        (elixir) lib/string.ex:1864: String.slice("<internal code removed>", 1610, -1)
        lib/credo/code/heredocs.ex:253: Credo.Code.Heredocs.pad_replaced_heredoc/2
        lib/credo/code/heredocs.ex:156: Credo.Code.Heredocs.parse_heredoc/5
        lib/credo/check/readability/max_line_length.ex:52: Credo.Check.Readability.MaxLineLength.run/2
        lib/credo/check/runner.ex:168: Credo.Check.Runner.do_run_check_on_single_source_file/3
        lib/credo/check/runner.ex:161: Credo.Check.Runner.run_check_on_single_source_file/3
        (elixir) lib/enum.ex:1336: Enum."-map/2-lists^map/1-0-"/2
        (elixir) lib/enum.ex:1336: Enum."-map/2-lists^map/1-0-"/2

and the other

** (EXIT from #PID<0.93.0>) an exception was raised:
    ** (FunctionClauseError) no function clause matching in String.slice/3
        (elixir) lib/string.ex:1864: String.slice("<internal code removed>", 701, -2)
        lib/credo/code/heredocs.ex:253: Credo.Code.Heredocs.pad_replaced_heredoc/2
        lib/credo/code/heredocs.ex:156: Credo.Code.Heredocs.parse_heredoc/5
        lib/credo/check/readability/max_line_length.ex:52: Credo.Check.Readability.MaxLineLength.run/2
        lib/credo/check/runner.ex:168: Credo.Check.Runner.do_run_check_on_single_source_file/3
        lib/credo/check/runner.ex:161: Credo.Check.Runner.run_check_on_single_source_file/3
        (elixir) lib/enum.ex:1336: Enum."-map/2-lists^map/1-0-"/2
        (elixir) lib/enum.ex:1336: Enum."-map/2-lists^map/1-0-"/2

@skovmand
Copy link

skovmand commented Jul 2, 2019

I have tried to isolate the error, and ended up with this minimal file to reproduce the issue.

The error goes away by doing either one of these things:

  • Deleting @some_utf_8_char
  • Removing æøå from the regular expression
  • Removing the last @doc block
defmodule CredoIssue.FailingFile do
  @some_utf8_char "💩"

  def match_whatever(whatever) do
    case Regex.run(~r/([a-zæøå]+)/, whatever) do
      # Nothing here
    end
  end

  @doc """
  Nothing to see here really
  """
  def nothing_to_nil() do
    nil
  end
end

The stacktrace is:

** (EXIT from #PID<0.93.0>) an exception was raised:
    ** (FunctionClauseError) no function clause matching in String.slice/3
        (elixir) lib/string.ex:1864: String.slice("defmodule CredoIssue.FailingFile do\n  @some_utf8_char \"💩\"\n\n  def match_whatever([whatever]) do\n    case Regex.run(~r/([a-zæøå]+)/, whatever) do\n      # Nothing here\n    end\n  end\n\n  @doc \"\"\"\n\n", 193, -1)
        lib/credo/code/heredocs.ex:253: Credo.Code.Heredocs.pad_replaced_heredoc/2
        lib/credo/code/heredocs.ex:156: Credo.Code.Heredocs.parse_heredoc/5
        lib/credo/check/readability/max_line_length.ex:52: Credo.Check.Readability.MaxLineLength.run/2
        lib/credo/check/runner.ex:168: Credo.Check.Runner.do_run_check_on_single_source_file/3
        lib/credo/check/runner.ex:161: Credo.Check.Runner.run_check_on_single_source_file/3
        (elixir) lib/enum.ex:1336: Enum."-map/2-lists^map/1-0-"/2
        (elixir) lib/enum.ex:1336: Enum."-map/2-lists^map/1-0-"/2

@skovmand
Copy link

skovmand commented Jul 2, 2019

And now the same minimal file reproduced from my other failing module

The weird part here is that the issue can be resolved by removing any of the characters æøå from the @danish_words list. I found that the module only crashes if there are 6 or more characters of type æøå in the @danish_words list, if one is removed, the error disappears.

Try for example to change the @danish_words list to "åååååå", and it still crashes. Change it to five å characters and it the error disappears. Changing it to "💩💩" also makes the test crash.

Removing the @doc block removes the error too.

defmodule CredoIssue.FailingFile2 do
  @danish_words [
    "Rødbede",
    "Æble",
    "Kål",
    "Kålorm",
    "Æblegrød"
  ]

  @doc """
  Just nil it!!
  """
  def nil_it() do
    nil
  end
end

or the smallest example I can get to

defmodule CredoIssue.FailingFile2 do
  @chars "💩💩"

  @doc """
  Just nil it
  """
  def nil_it() do
    nil
  end
end

@skovmand
Copy link

skovmand commented Jul 2, 2019

I suspect that it has something to do with the different byte_sizes of the involved international characters and emojis, since:

iex(5)> byte_size("a") 
1
iex(6)> byte_size("å") 
2
iex(7)> byte_size("💩")
4

@k-cross
Copy link

k-cross commented Jul 2, 2019

I also have this issue on elixir 1.7.3

@robertpeacock22
Copy link

Here is the smallest repro I can come up with for this issue:

defmodule UnicodeTest do
  @x "fédération fédération fédération"

  @doc """
  """
end

This results in a similar stack trace to the one seen above:

** (FunctionClauseError) no function clause matching in String.slice/3
    (elixir) lib/string.ex:1741: String.slice("defmodule UnicodeTest do\n  @x \"fédération fédération fédération\"\n\n  @doc \"\"\"\n", 79, -2)
    lib/credo/code/heredocs.ex:253: Credo.Code.Heredocs.pad_replaced_heredoc/2
    lib/credo/code/heredocs.ex:156: Credo.Code.Heredocs.parse_heredoc/5
    lib/credo/check/readability/max_line_length.ex:52: Credo.Check.Readability.MaxLineLength.run/2
    lib/credo/check/runner.ex:168: Credo.Check.Runner.do_run_check_on_single_source_file/3
    lib/credo/check/runner.ex:161: Credo.Check.Runner.run_check_on_single_source_file/3
    (elixir) lib/enum.ex:1294: Enum."-map/2-lists^map/1-0-"/2
    (elixir) lib/enum.ex:1294: Enum."-map/2-lists^map/1-0-"/2
Function: #Function<9.36871822/0 in Credo.Check.Runner.run/2>
    Args: []

rrrene added a commit that referenced this issue Jul 16, 2019
rrrene added a commit that referenced this issue Jul 16, 2019
@rrrene
Copy link
Owner

rrrene commented Jul 17, 2019

Thx for reporting this (and discussing it in detail)! 👏 It should be be fixed in the latest version of Credo (v1.1.1).

If it is not, please feel free to re-open this issue!

@rrrene rrrene closed this as completed Jul 17, 2019
@jimsynz
Copy link

jimsynz commented Jul 17, 2019

I'm really sorry to report that it's still happening:

$ mix credo --strict
Checking 19 source files ...

info: the following checks were skipped because they're not compatible with
your version of Elixir (1.9.0).

   1) Credo.Check.Refactor.MapInto
   2) Credo.Check.Warning.LazyLogging

Error while running Elixir.Credo.Check.Readability.MaxLineLength on lib/angle/dms.ex

07:56:00.170 [error] Task #PID<0.142.0> started from #PID<0.92.0> terminating
** (FunctionClauseError) no function clause matching in String.slice/3
    (elixir) lib/string.ex:1864: String.slice("defmodule Angle.DMS do\n  import Angle.Utils, only: [string_to_integer: 1, string_to_number: 1]\n  alias Angle.Degree\n\n  @moduledoc \"\"\"\n\n\"\"\"\n\n  @parser ~r/(-?[0-9]+)\n             (?:[\\x{00b0},\\ ]?\\ *)\n             ([0-9]+)\n             (?:[\\x{2032}',\\ ]?\\ *)\n             ([0-9]+(?:\\.[0-9]+)?)\n             [\\x{2033}\"]?/ux\n\n  @doc \"\"\"\n  Initialize an Angle from integer `d` degrees.\n\n  ## Examples\n\n      iex> init(13)\n      #Angle<13°>\n  \"\"\"\n\n\n\n\"\"\"\n  Initialize an Angle from integer `d` degrees, optionally followed by integer\n  `m` minutes.\n\n  ## Examples\n\n      iex> init(13, 30)\n      #Angle<13° 30′>\n  \"\"\"\n\n\n\n\"\"\"\n  Initialize an Angle from integer `d` degrees, followed by integer\n  `m` minutes and `s` seconds.\n\n  ## Examples\n\n      iex> init(13, 30, 45)\n      #Angle<13° 30′ 45″>\n  \"\"\"\n\n\n\n\n", 797, -1)
    lib/credo/code/heredocs.ex:253: Credo.Code.Heredocs.pad_replaced_heredoc/2
    lib/credo/code/heredocs.ex:156: Credo.Code.Heredocs.parse_heredoc/5
    lib/credo/check/readability/max_line_length.ex:52: Credo.Check.Readability.MaxLineLength.run/2
    lib/credo/check/runner.ex:168: Credo.Check.Runner.do_run_check_on_single_source_file/3
    lib/credo/check/runner.ex:161: Credo.Check.Runner.run_check_on_single_source_file/3
    (elixir) lib/enum.ex:1336: Enum."-map/2-lists^map/1-0-"/2
    (elixir) lib/enum.ex:1336: Enum."-map/2-lists^map/1-0-"/2
Function: #Function<9.89825571/0 in Credo.Check.Runner.run/2>
    Args: []
** (EXIT from #PID<0.92.0>) an exception was raised:
    ** (FunctionClauseError) no function clause matching in String.slice/3
        (elixir) lib/string.ex:1864: String.slice("defmodule Angle.DMS do\n  import Angle.Utils, only: [string_to_integer: 1, string_to_number: 1]\n  alias Angle.Degree\n\n  @moduledoc \"\"\"\n\n\"\"\"\n\n  @parser ~r/(-?[0-9]+)\n             (?:[\\x{00b0},\\ ]?\\ *)\n             ([0-9]+)\n             (?:[\\x{2032}',\\ ]?\\ *)\n             ([0-9]+(?:\\.[0-9]+)?)\n             [\\x{2033}\"]?/ux\n\n  @doc \"\"\"\n  Initialize an Angle from integer `d` degrees.\n\n  ## Examples\n\n      iex> init(13)\n      #Angle<13°>\n  \"\"\"\n\n\n\n\"\"\"\n  Initialize an Angle from integer `d` degrees, optionally followed by integer\n  `m` minutes.\n\n  ## Examples\n\n      iex> init(13, 30)\n      #Angle<13° 30′>\n  \"\"\"\n\n\n\n\"\"\"\n  Initialize an Angle from integer `d` degrees, followed by integer\n  `m` minutes and `s` seconds.\n\n  ## Examples\n\n      iex> init(13, 30, 45)\n      #Angle<13° 30′ 45″>\n  \"\"\"\n\n\n\n\n", 797, -1)
        lib/credo/code/heredocs.ex:253: Credo.Code.Heredocs.pad_replaced_heredoc/2
        lib/credo/code/heredocs.ex:156: Credo.Code.Heredocs.parse_heredoc/5
        lib/credo/check/readability/max_line_length.ex:52: Credo.Check.Readability.MaxLineLength.run/2
        lib/credo/check/runner.ex:168: Credo.Check.Runner.do_run_check_on_single_source_file/3
        lib/credo/check/runner.ex:161: Credo.Check.Runner.run_check_on_single_source_file/3
        (elixir) lib/enum.ex:1336: Enum."-map/2-lists^map/1-0-"/2
        (elixir) lib/enum.ex:1336: Enum."-map/2-lists^map/1-0-"/2

@bencode
Copy link
Author

bencode commented Jul 22, 2019

@jamesotron it's ok for me!

use 1.1.1 and dont forget mix deps.get and mix deps.compile

@jimsynz
Copy link

jimsynz commented Jul 23, 2019

You're right. My CI is caching the old version for some reason.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants