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

NLS crashes on recursive definitions #1875

Closed
uhlajs opened this issue Mar 28, 2024 · 11 comments · Fixed by #1878 or #1881
Closed

NLS crashes on recursive definitions #1875

uhlajs opened this issue Mar 28, 2024 · 11 comments · Fixed by #1878 or #1881

Comments

@uhlajs
Copy link

uhlajs commented Mar 28, 2024

Describe the bug
nls crashes with stack overflow error when parsing nickel source with recursive definition.

To Reproduce

Open file with following content in text editor with LSP support and running nls.
I can reproduce it with lunarvim, but this should be easily reproduce with vanilla neovim or any other text editor.

{
  applications = {
    apps | not_exported = applications,
    message = "message",
  }
} 

Expected behavior

Since this is a valid nickel source code, I would expect no nls crashes.

$ nickel export test.ncl
{
  "applications": {
    "message": "message"
  }
}

Environment

  • OS name + version:
NAME="Fedora Linux"
VERSION="39.20240327.0 (Sericea)"
  • Version of the code: From nixpkgs (unstable branch).
nickel-lang-cli nickel 1.5.0 (rev cargore)

Additional logs

[START][2024-03-28 10:20:49] LSP logging initiated
[INFO][2024-03-28 10:20:49] .../vim/lsp/rpc.lua:662	"Starting RPC client"	{  args = {},  cmd = "nls",  extra = {    cwd = "/tmp/nickel"  }}
[DEBUG][2024-03-28 10:20:49] .../vim/lsp/rpc.lua:284	"rpc.send"	{  id = 1,  jsonrpc = "2.0",  method = "initialize",  params = {    capabilities = {      textDocument = {        callHierarchy = {          dynamicRegistration = false        },        codeAction = {          codeActionLiteralSupport = {            codeActionKind = {              valueSet = { "", "quickfix", "refactor", "refactor.extract", "refactor.inline", "refactor.rewrite", "source", "source.organizeImports" }            }          },          dataSupport = true,          dynamicRegistration = false,          isPreferredSupport = true,          resolveSupport = {            properties = { "edit" }          }        },        completion = {          completionItem = {            commitCharactersSupport = true,            deprecatedSupport = true,            documentationFormat = { "markdown", "plaintext" },            insertReplaceSupport = true,            insertTextModeSupport = {              valueSet = { 1, 2 }            },            labelDetailsSupport = true,            preselectSupport = true,            resolveSupport = {              properties = { "documentation", "detail", "additionalTextEdits" }            },            snippetSupport = true,            tagSupport = {              valueSet = { 1 }            }          },          completionItemKind = {            valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 }          },          completionList = {            itemDefaults = { "commitCharacters", "editRange", "insertTextFormat", "insertTextMode", "data" }          },          contextSupport = true,          dynamicRegistration = false,          insertTextMode = 1        },        declaration = {          linkSupport = true        },        definition = {          linkSupport = true        },        documentHighlight = {          dynamicRegistration = false        },        documentSymbol = {          dynamicRegistration = false,          hierarchicalDocumentSymbolSupport = true,          symbolKind = {            valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 }          }        },        hover = {          contentFormat = { "markdown", "plaintext" },          dynamicRegistration = false        },        implementation = {          linkSupport = true        },        publishDiagnostics = {          relatedInformation = true,          tagSupport = {            valueSet = { 1, 2 }          }        },        references = {          dynamicRegistration = false        },        rename = {          dynamicRegistration = false,          prepareSupport = true        },        semanticTokens = {          augmentsSyntaxTokens = true,          dynamicRegistration = false,          formats = { "relative" },          multilineTokenSupport = false,          overlappingTokenSupport = true,          requests = {            full = {              delta = true            },            range = false          },          serverCancelSupport = false,          tokenModifiers = { "declaration", "definition", "readonly", "static", "deprecated", "abstract", "async", "modification", "documentation", "defaultLibrary" },          tokenTypes = { "namespace", "type", "class", "enum", "interface", "struct", "typeParameter", "parameter", "variable", "property", "enumMember", "event", "function", "method", "macro", "keyword", "modifier", "comment", "string", "number", "regexp", "operator", "decorator" }        },        signatureHelp = {          dynamicRegistration = false,          signatureInformation = {            activeParameterSupport = true,            documentationFormat = { "markdown", "plaintext" },            parameterInformation = {              labelOffsetSupport = true            }          }        },        synchronization = {          didSave = true,          dynamicRegistration = false,          willSave = true,          willSaveWaitUntil = true        },        typeDefinition = {          linkSupport = true        }      },      window = {        showDocument = {          support = true        },        showMessage = {          messageActionItem = {            additionalPropertiesSupport = false          }        },        workDoneProgress = true      },      workspace = {        applyEdit = true,        configuration = true,        didChangeWatchedFiles = {          dynamicRegistration = false,          relativePatternSupport = true        },        semanticTokens = {          refreshSupport = true        },        symbol = {          dynamicRegistration = false,          hierarchicalWorkspaceSymbolSupport = true,          symbolKind = {            valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 }          }        },        workspaceEdit = {          resourceOperations = { "rename", "create", "delete" }        },        workspaceFolders = true      }    },    clientInfo = {      name = "Neovim",      version = "0.9.5"    },    initializationOptions = vim.empty_dict(),    processId = 2230809,    rootPath = "/tmp/nickel",    rootUri = "file:///tmp/nickel",    trace = "off",    workspaceFolders = { {        name = "/tmp/nickel",        uri = "file:///tmp/nickel"      } }  }}
[DEBUG][2024-03-28 10:20:49] .../vim/lsp/rpc.lua:387	"rpc.receive"	{  id = 1,  jsonrpc = "2.0",  result = {    capabilities = {      codeActionProvider = true,      completionProvider = {        triggerCharacters = { ".", '"', "/" }      },      definitionProvider = true,      documentFormattingProvider = true,      documentSymbolProvider = true,      executeCommandProvider = {        commands = { "eval" }      },      hoverProvider = {        workDoneProgress = false      },      referencesProvider = true,      renameProvider = true,      textDocumentSync = {        change = 1,        openClose = true      }    }  }}
[DEBUG][2024-03-28 10:20:49] .../vim/lsp/rpc.lua:284	"rpc.send"	{  jsonrpc = "2.0",  method = "initialized",  params = vim.empty_dict()}
[INFO][2024-03-28 10:20:49] .../lua/vim/lsp.lua:1344	"LSP[nickel_ls]"	"server_capabilities"	{  server_capabilities = {    codeActionProvider = true,    completionProvider = {      triggerCharacters = { ".", '"', "/" }    },    definitionProvider = true,    documentFormattingProvider = true,    documentSymbolProvider = true,    executeCommandProvider = {      commands = { "eval" }    },    hoverProvider = {      workDoneProgress = false    },    referencesProvider = true,    renameProvider = true,    textDocumentSync = {      change = 1,      openClose = true    }  }}
[DEBUG][2024-03-28 10:20:49] .../vim/lsp/rpc.lua:284	"rpc.send"	{  jsonrpc = "2.0",  method = "textDocument/didOpen",  params = {    textDocument = {      languageId = "nickel",      text = '{\n  applications = {\n    apps | not_exported = applications,\n    message = "message",\n  }\n} \n',      uri = "file:///tmp/nickel/test.ncl",      version = 0    }  }}
[DEBUG][2024-03-28 10:20:49] .../lua/vim/lsp.lua:1391	"LSP[nickel_ls]"	"client.request"	1	"textDocument/documentSymbol"	{  textDocument = {    uri = "file:///tmp/nickel/test.ncl"  }}	<function 1>	1
[DEBUG][2024-03-28 10:20:49] .../vim/lsp/rpc.lua:284	"rpc.send"	{  id = 2,  jsonrpc = "2.0",  method = "textDocument/documentSymbol",  params = {    textDocument = {      uri = "file:///tmp/nickel/test.ncl"    }  }}
[DEBUG][2024-03-28 10:20:49] .../vim/lsp/rpc.lua:387	"rpc.receive"	{  jsonrpc = "2.0",  method = "textDocument/publishDiagnostics",  params = {    diagnostics = {},    uri = "file:///tmp/nickel/test.ncl"  }}
[ERROR][2024-03-28 10:20:49] .../vim/lsp/rpc.lua:734	"rpc"	"nls"	"stderr"	"\nthread 'main' has overflowed its stack\nfatal runtime error: stack overflow\n"
[ERROR][2024-03-28 10:20:49] .../vim/lsp/rpc.lua:734	"rpc"	"nls"	"stderr"	"\nthread 'main' has overflowed its stack\nfatal runtime error: stack overflow\n"
[DEBUG][2024-03-28 10:20:49] .../lua/vim/lsp.lua:1391	"LSP[nickel_ls]"	"client.request"	1	"textDocument/documentSymbol"	{  textDocument = {    uri = "file:///tmp/nickel/test.ncl"  }}	<function 1>	1
[DEBUG][2024-03-28 10:20:49] .../vim/lsp/rpc.lua:284	"rpc.send"	{  id = 3,  jsonrpc = "2.0",  method = "textDocument/documentSymbol",  params = {    textDocument = {      uri = "file:///tmp/nickel/test.ncl"    }  }}
@uhlajs uhlajs changed the title NLS Crashes on recursive definitions nls Crashes on recursive definitions Mar 28, 2024
@uhlajs uhlajs changed the title nls Crashes on recursive definitions NLS crashes on recursive definitions Mar 28, 2024
@yannham
Copy link
Member

yannham commented Mar 28, 2024

This is a tough one, because while nickel export work, nickel eval does loop as well. That being said nickel eval doesn't crash, it just loops forever, so I wonder if the background thread is doing something different, or if it's another part of NLS that should be protected against such cyclic definitions.

@jneem
Copy link
Member

jneem commented Mar 28, 2024

Yes, the background thread is doing it a little differently: its eval function (eval_permissive) recurses in places where the original one doesn't. The same thing happens in the example in #1815: nickel eval loops and eats all my memory, while nls crashes with a stack overflow.

Having said that, for me it looks like nls's protection against problems in eval is kicking in as expected: the background eval process crashes (and so we lose eval diagnostics, which is sad), but the main nls process keeps running.

@yannham
Copy link
Member

yannham commented Mar 28, 2024

@uhlajs can you confirm that even after the crash, normal NLS functions are still working as expected (like goto definition or show information on hover)? If this is just the background evaluation process crashing, this is not ideal, but less critical.

@uhlajs
Copy link
Author

uhlajs commented Mar 28, 2024

Negative (goto definition does not work), I am getting following message and there is no nls process running.

Client 1 quit with exit code 0 and signal 6

I also tried to comment out the problematic line, then open editor and uncomment it. Here is result:

$  pgrep nls
2863627
2863634

$ ps 2863627 2863634
    PID TTY      STAT   TIME COMMAND
2863627 ?        Ssl    0:00 nls
2863634 ?        S      0:00 /nix/store/xjynz8qzh3abmsxa0yi0g8gh6am250dz-nickel-1.5.0-nls/bin/nls --main-server /tmp/nix-shell.

# Now I have uncommented and saved file.

$ pgrep nls
# Empty result

@jneem
Copy link
Member

jneem commented Mar 28, 2024

Interesting. Here is what happens for me:

nls.mp4

On uncommenting that line, you can see a zombie process appear in htop (that's the crashed background process), but typechecking still works in the editor afterwards.

Is there any way you can get a backtrace of the crashing nls? If nvim propagates its environment to nls, it should be enough to set RUST_BACKTRACE=1. (If nvim doesn't propagate its environment, it might require a wrapper script...)

Regarding trying to detect the recursion, the problem I'm having is that the environment is different each time we recurse so it isn't an obvious infinite loop to the interpreter. Probably for nls it's ok to bound the recursion depth?

@uhlajs
Copy link
Author

uhlajs commented Apr 3, 2024

@jneem Here I am running similar commands:

nls.mp4

As you can see the nls is completely terminated after saving changes. Here are generated coredumps if that helps.

I also tried to run latest code with #1878 changes, but the result is still the same.

Unfortunately, I wasn't able to get backtrace with RUST_BACKTRACE=1. I also tried to create a wrapper script (see below), but there is still not backtrace in the logs.

Content of /home/honza/tmp/nls-test/nls:

#!/bin/bash

export RUST_BACKTRACE=1
/home/honza/git/github/nickel/target/debug/nls "$@"

Full log:

[START][2024-04-03 11:16:37] LSP logging initiated
[INFO][2024-04-03 11:16:37] .../vim/lsp/rpc.lua:662	"Starting RPC client"	{  args = {},  cmd = "nls",  extra = {    cwd = "/var/home/honza/tmp/nls-test"  }}
[DEBUG][2024-04-03 11:16:37] .../vim/lsp/rpc.lua:284	"rpc.send"	{  id = 1,  jsonrpc = "2.0",  method = "initialize",  params = {    capabilities = {      textDocument = {        callHierarchy = {          dynamicRegistration = false        },        codeAction = {          codeActionLiteralSupport = {            codeActionKind = {              valueSet = { "", "quickfix", "refactor", "refactor.extract", "refactor.inline", "refactor.rewrite", "source", "source.organizeImports" }            }          },          dataSupport = true,          dynamicRegistration = false,          isPreferredSupport = true,          resolveSupport = {            properties = { "edit" }          }        },        completion = {          completionItem = {            commitCharactersSupport = true,            deprecatedSupport = true,            documentationFormat = { "markdown", "plaintext" },            insertReplaceSupport = true,            insertTextModeSupport = {              valueSet = { 1, 2 }            },            labelDetailsSupport = true,            preselectSupport = true,            resolveSupport = {              properties = { "documentation", "detail", "additionalTextEdits" }            },            snippetSupport = true,            tagSupport = {              valueSet = { 1 }            }          },          completionItemKind = {            valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 }          },          completionList = {            itemDefaults = { "commitCharacters", "editRange", "insertTextFormat", "insertTextMode", "data" }          },          contextSupport = true,          dynamicRegistration = false,          insertTextMode = 1        },        declaration = {          linkSupport = true        },        definition = {          linkSupport = true        },        documentHighlight = {          dynamicRegistration = false        },        documentSymbol = {          dynamicRegistration = false,          hierarchicalDocumentSymbolSupport = true,          symbolKind = {            valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 }          }        },        hover = {          contentFormat = { "markdown", "plaintext" },          dynamicRegistration = false        },        implementation = {          linkSupport = true        },        publishDiagnostics = {          relatedInformation = true,          tagSupport = {            valueSet = { 1, 2 }          }        },        references = {          dynamicRegistration = false        },        rename = {          dynamicRegistration = false,          prepareSupport = true        },        semanticTokens = {          augmentsSyntaxTokens = true,          dynamicRegistration = false,          formats = { "relative" },          multilineTokenSupport = false,          overlappingTokenSupport = true,          requests = {            full = {              delta = true            },            range = false          },          serverCancelSupport = false,          tokenModifiers = { "declaration", "definition", "readonly", "static", "deprecated", "abstract", "async", "modification", "documentation", "defaultLibrary" },          tokenTypes = { "namespace", "type", "class", "enum", "interface", "struct", "typeParameter", "parameter", "variable", "property", "enumMember", "event", "function", "method", "macro", "keyword", "modifier", "comment", "string", "number", "regexp", "operator", "decorator" }        },        signatureHelp = {          dynamicRegistration = false,          signatureInformation = {            activeParameterSupport = true,            documentationFormat = { "markdown", "plaintext" },            parameterInformation = {              labelOffsetSupport = true            }          }        },        synchronization = {          didSave = true,          dynamicRegistration = false,          willSave = true,          willSaveWaitUntil = true        },        typeDefinition = {          linkSupport = true        }      },      window = {        showDocument = {          support = true        },        showMessage = {          messageActionItem = {            additionalPropertiesSupport = false          }        },        workDoneProgress = true      },      workspace = {        applyEdit = true,        configuration = true,        didChangeWatchedFiles = {          dynamicRegistration = false,          relativePatternSupport = true        },        semanticTokens = {          refreshSupport = true        },        symbol = {          dynamicRegistration = false,          hierarchicalWorkspaceSymbolSupport = true,          symbolKind = {            valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 }          }        },        workspaceEdit = {          resourceOperations = { "rename", "create", "delete" }        },        workspaceFolders = true      }    },    clientInfo = {      name = "Neovim",      version = "0.9.5"    },    initializationOptions = vim.empty_dict(),    processId = 613557,    rootPath = "/var/home/honza/tmp/nls-test",    rootUri = "file:///var/home/honza/tmp/nls-test",    trace = "off",    workspaceFolders = { {        name = "/var/home/honza/tmp/nls-test",        uri = "file:///var/home/honza/tmp/nls-test"      } }  }}
[DEBUG][2024-04-03 11:16:37] .../vim/lsp/rpc.lua:387	"rpc.receive"	{  id = 1,  jsonrpc = "2.0",  result = {    capabilities = {      codeActionProvider = true,      completionProvider = {        triggerCharacters = { ".", '"', "/" }      },      definitionProvider = true,      documentFormattingProvider = true,      documentSymbolProvider = true,      executeCommandProvider = {        commands = { "eval" }      },      hoverProvider = {        workDoneProgress = false      },      referencesProvider = true,      renameProvider = true,      textDocumentSync = {        change = 1,        openClose = true      }    }  }}
[DEBUG][2024-04-03 11:16:37] .../vim/lsp/rpc.lua:284	"rpc.send"	{  jsonrpc = "2.0",  method = "initialized",  params = vim.empty_dict()}
[INFO][2024-04-03 11:16:37] .../lua/vim/lsp.lua:1344	"LSP[nickel_ls]"	"server_capabilities"	{  server_capabilities = {    codeActionProvider = true,    completionProvider = {      triggerCharacters = { ".", '"', "/" }    },    definitionProvider = true,    documentFormattingProvider = true,    documentSymbolProvider = true,    executeCommandProvider = {      commands = { "eval" }    },    hoverProvider = {      workDoneProgress = false    },    referencesProvider = true,    renameProvider = true,    textDocumentSync = {      change = 1,      openClose = true    }  }}
[DEBUG][2024-04-03 11:16:37] .../vim/lsp/rpc.lua:284	"rpc.send"	{  jsonrpc = "2.0",  method = "textDocument/didOpen",  params = {    textDocument = {      languageId = "nickel",      text = '{\n  applications = {\n    # apps | not_exported = applications,\n    message = "message",\n    blah | String = 5,\n  }\n}\n',      uri = "file:///var/home/honza/tmp/nls-test/test.ncl",      version = 0    }  }}
[DEBUG][2024-04-03 11:16:37] .../lua/vim/lsp.lua:1391	"LSP[nickel_ls]"	"client.request"	1	"textDocument/documentSymbol"	{  textDocument = {    uri = "file:///var/home/honza/tmp/nls-test/test.ncl"  }}	<function 1>	1
[DEBUG][2024-04-03 11:16:37] .../vim/lsp/rpc.lua:284	"rpc.send"	{  id = 2,  jsonrpc = "2.0",  method = "textDocument/documentSymbol",  params = {    textDocument = {      uri = "file:///var/home/honza/tmp/nls-test/test.ncl"    }  }}
[DEBUG][2024-04-03 11:16:37] .../vim/lsp/rpc.lua:387	"rpc.receive"	{  jsonrpc = "2.0",  method = "textDocument/publishDiagnostics",  params = {    diagnostics = {},    uri = "file:///var/home/honza/tmp/nls-test/test.ncl"  }}
[DEBUG][2024-04-03 11:16:37] .../vim/lsp/rpc.lua:387	"rpc.receive"	{  id = 2,  jsonrpc = "2.0",  result = { {      children = { {          children = {},          detail = "String",          kind = 13,          name = "message",          range = {            ["end"] = {              character = 11,              line = 3            },            start = {              character = 4,              line = 3            }          },          selectionRange = {            ["end"] = {              character = 11,              line = 3            },            start = {              character = 4,              line = 3            }          }        }, {          children = {},          detail = "String",          kind = 13,          name = "blah",          range = {            ["end"] = {              character = 8,              line = 4            },            start = {              character = 4,              line = 4            }          },          selectionRange = {            ["end"] = {              character = 8,              line = 4            },            start = {              character = 4,              line = 4            }          }        } },      detail = "Dyn",      kind = 13,      name = "applications",      range = {        ["end"] = {          character = 14,          line = 1        },        start = {          character = 2,          line = 1        }      },      selectionRange = {        ["end"] = {          character = 14,          line = 1        },        start = {          character = 2,          line = 1        }      }    } }}
[DEBUG][2024-04-03 11:16:37] .../lua/vim/lsp.lua:1391	"LSP[nickel_ls]"	"client.request"	1	"textDocument/documentSymbol"	{  textDocument = {    uri = "file:///var/home/honza/tmp/nls-test/test.ncl"  }}	<function 1>	1
[DEBUG][2024-04-03 11:16:37] .../vim/lsp/rpc.lua:284	"rpc.send"	{  id = 3,  jsonrpc = "2.0",  method = "textDocument/documentSymbol",  params = {    textDocument = {      uri = "file:///var/home/honza/tmp/nls-test/test.ncl"    }  }}
[DEBUG][2024-04-03 11:16:37] .../vim/lsp/rpc.lua:387	"rpc.receive"	{  id = 3,  jsonrpc = "2.0",  result = { {      children = { {          children = {},          detail = "String",          kind = 13,          name = "message",          range = {            ["end"] = {              character = 11,              line = 3            },            start = {              character = 4,              line = 3            }          },          selectionRange = {            ["end"] = {              character = 11,              line = 3            },            start = {              character = 4,              line = 3            }          }        }, {          children = {},          detail = "String",          kind = 13,          name = "blah",          range = {            ["end"] = {              character = 8,              line = 4            },            start = {              character = 4,              line = 4            }          },          selectionRange = {            ["end"] = {              character = 8,              line = 4            },            start = {              character = 4,              line = 4            }          }        } },      detail = "Dyn",      kind = 13,      name = "applications",      range = {        ["end"] = {          character = 14,          line = 1        },        start = {          character = 2,          line = 1        }      },      selectionRange = {        ["end"] = {          character = 14,          line = 1        },        start = {          character = 2,          line = 1        }      }    } }}
[DEBUG][2024-04-03 11:16:37] .../vim/lsp/rpc.lua:387	"rpc.receive"	{  jsonrpc = "2.0",  method = "textDocument/publishDiagnostics",  params = {    diagnostics = { {        message = "contract broken by the value of `blah`",        range = {          ["end"] = {            character = 21,            line = 4          },          start = {            character = 20,            line = 4          }        },        severity = 1      }, {        message = "expected type",        range = {          ["end"] = {            character = 17,            line = 4          },          start = {            character = 11,            line = 4          }        },        severity = 4      }, {        message = "applied to this expression",        range = {          ["end"] = {            character = 21,            line = 4          },          start = {            character = 20,            line = 4          }        },        severity = 4      } },    uri = "file:///var/home/honza/tmp/nls-test/test.ncl"  }}
[DEBUG][2024-04-03 11:16:39] .../vim/lsp/rpc.lua:284	"rpc.send"	{  jsonrpc = "2.0",  method = "textDocument/didChange",  params = {    contentChanges = { {        text = '{\n  applications = {\n     apps | not_exported = applications,\n    message = "message",\n    blah | String = 5,\n  }\n}\n'      } },    textDocument = {      uri = "file:///var/home/honza/tmp/nls-test/test.ncl",      version = 4    }  }}
[DEBUG][2024-04-03 11:16:39] .../lua/vim/lsp.lua:1391	"LSP[nickel_ls]"	"client.request"	1	"textDocument/documentSymbol"	{  textDocument = {    uri = "file:///var/home/honza/tmp/nls-test/test.ncl"  }}	<function 1>	1
[DEBUG][2024-04-03 11:16:39] .../vim/lsp/rpc.lua:284	"rpc.send"	{  id = 4,  jsonrpc = "2.0",  method = "textDocument/documentSymbol",  params = {    textDocument = {      uri = "file:///var/home/honza/tmp/nls-test/test.ncl"    }  }}
[DEBUG][2024-04-03 11:16:39] .../vim/lsp/rpc.lua:387	"rpc.receive"	{  jsonrpc = "2.0",  method = "textDocument/publishDiagnostics",  params = {    diagnostics = {},    uri = "file:///var/home/honza/tmp/nls-test/test.ncl"  }}
[ERROR][2024-04-03 11:16:39] .../vim/lsp/rpc.lua:734	"rpc"	"nls"	"stderr"	"\nthread 'main' has overflowed its stack\nfatal runtime error: stack overflow\n"
[DEBUG][2024-04-03 11:16:39] .../vim/lsp/rpc.lua:284	"rpc.send"	{  jsonrpc = "2.0",  method = "textDocument/didChange",  params = {    contentChanges = { {        text = '{\n  applications = {\n    apps | not_exported = applications,\n    message = "message",\n    blah | String = 5,\n  }\n}\n'      } },    textDocument = {      uri = "file:///var/home/honza/tmp/nls-test/test.ncl",      version = 5    }  }}
[ERROR][2024-04-03 11:16:39] .../vim/lsp/rpc.lua:734	"rpc"	"nls"	"stderr"	'/home/honza/tmp/nls-test/nls: line 4: 613566 Aborted                 (core dumped) /home/honza/git/github/nickel/target/debug/nls "$@"\n'

@jneem
Copy link
Member

jneem commented Apr 3, 2024

Thanks for the core dumps, those are super helpful. One of them is an infinite recursion in eval_permissive::inner, which should be fixed by #1878. The other is an infinite recursion when listing document symbols, which totally makes sense and I can reproduce it. (I guess some editor/lsp configs request document symbols eagerly; mine didn't, so it didn't crash)

@jneem jneem reopened this Apr 3, 2024
@uhlajs
Copy link
Author

uhlajs commented Apr 3, 2024

Great, let me know if I can be more helpful here.

@uhlajs
Copy link
Author

uhlajs commented Apr 5, 2024

Thank you @jneem! I can confirm that #1881 resolves issues with nls crashing.

Unfortunately, the nls behavior is still not correct. With new patch, nls reports the same warning/error multiple times. There are 3 valid diagnostic messages, but after uncommenting the recursive line, nls reports 378 (=3*126).

2024-04-05.08-43-24.mp4

Shall I open new issue or do you want to reuse this one?

@yannham
Copy link
Member

yannham commented Apr 5, 2024

@uhlajs thanks for all the reporting 🙂 that's super useful! If you don't mind, I think opening a new issue is preferable for multiple reasons (searchability, self-containment, etc.), as NLS indeed doesn't crash anymore on recursive definitions.

@uhlajs
Copy link
Author

uhlajs commented Apr 5, 2024

No problem -> moving the further discussion to #1882.

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