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

Infinite loop when nil passed in as graph #73

Closed
aymanosman opened this issue Nov 22, 2023 · 2 comments · Fixed by #77
Closed

Infinite loop when nil passed in as graph #73

aymanosman opened this issue Nov 22, 2023 · 2 comments · Fixed by #77

Comments

@aymanosman
Copy link

The following code results in an infinite loop:

Graph.add_vertex(nil, "A")
@vegabook
Copy link

As of libgraph 1.16 this isn't fixed; Also btw it's not only an infinite loop but a rapid memory leak.
https://asciinema.org/a/HKCGZkPMeTxQcxu4gn083Pse7

@stevensonmt
Copy link
Contributor

stevensonmt commented Mar 10, 2024

This appears to be due to this bit of code:

  @spec add_vertex(t, vertex, label) :: t
  def add_vertex(g, v, labels \\ [])
  def add_vertex(
        %__MODULE__{vertices: vs, vertex_labels: vl, vertex_identifier: vertex_identifier} = g,
        v,
        labels
      )
      when is_list(labels) do
    id = vertex_identifier.(v)

    case Map.get(vs, id) do
      nil ->
        %__MODULE__{g | vertices: Map.put(vs, id, v), vertex_labels: Map.put(vl, id, labels)}

      _ ->
        g
    end
  end

  def add_vertex(g, v, label) do
    add_vertex(g, v, [label])
  end

When you call add_vertex(nil, vertex) a default empty list gets supplied as the label. Because nil does not match the function head that requires g to be %__MODULE__{} it tries to match the next def which is add_vertex(g, v, label) with no guards. So the empty list gets wrapped in another list and supplied to another call for add_vertex(nil, v, [label]). This will still only match the same function head and keep wrapping label in lists for eternity. The easiest fix is likely to just make the last function head also match g on a %__MODULE__{} or to make label match on not is_list.

  def add_vertex(%__MODULE__{} = g, v, label) do
    add_vertex(g, v, [label])
  end

  def add_vertex(g, v, label) when not is_list(label) do
    add_vertex(g, v, [label])
  end

PR here

stevensonmt added a commit to stevensonmt/libgraph that referenced this issue Mar 10, 2024
add_vertex would loop infinitely if passed non-graph value as first parameter b/c it would always match the last function head def for add_vertex/3, which was a recursive call. Making all function heads match first parameter on %Graph{} should solve this issue.
@stevensonmt stevensonmt mentioned this issue Mar 10, 2024
bitwalker pushed a commit that referenced this issue Mar 10, 2024
add_vertex would loop infinitely if passed non-graph value as first parameter b/c it would always match the last function head def for add_vertex/3, which was a recursive call. Making all function heads match first parameter on %Graph{} should solve this issue.
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

Successfully merging a pull request may close this issue.

3 participants