zls icon indicating copy to clipboard operation
zls copied to clipboard

assertion failure in positionToIndex

Open david4r4 opened this issue 1 year ago • 6 comments

Zig Version

0.11.0-dev.4191+1bf16b172

Zig Language Server Version

0.11.0-dev.604+fa192c0

Steps to Reproduce

I can't provide any useful steps to reproduce, but I will give you a stack trace later

Expected Behavior

Not a crash

Actual Behavior

I tried to format it as good as possible from the neovim LspLog, don't know how much I achieved it :^)

thread 113218 panic: reached unreachable code
/home/david/dev/zig/lib/std/debug.zig:344:14: 0x3315c7 in positionToIndex 
    if (!ok) unreachable; // assertion failure
/home/david/dev/zls/src/offsets.zig:257:31: 0x2e9ab9 in processMessage
    .end = positionToIndex(text, range.end, encoding),
/home/david/dev/zls/src/Server.zig:1711:33: 0x2ad21d in processJob
    return server.processMessage(message) catch |err| switch (message)
/home/david/dev/zls/src/Server.zig:1558:38: 0x2abcc7 in loop 
    server.processJob(job, null);
/home/david/dev/zls/src/main.zig:389:20: 0x2b3481 in main
    try server.loop();
/home/david/dev/zig/lib/std/start.zig:608:37: 0x 29eca2 in posixCallMainAndExit
 const result = root.main() catch |err| {
/home/david/dev/zig/lib/std/start.zig:367:5: 0x29e7bd in _start
    @call(.never_inline, posixCallMainAndExit, .{});
???:?:?: 0x0 in ??? (???)

david4r4 avatar Jul 24 '23 13:07 david4r4

Without some steps to reproduce this issue, a stack trace is probably not enough to clearly identify the issue. (and i think there are some entries in the stack trace missing) I managed to trigger the same assert while fuzzing ZLS when i send it requests that contain source positions that were outside of the document. (like telling ZLS to give completions on line 20 even though the file is only 10 lines long). If this is the reason for your issue then I'm wondering why the client is sending ZLS invalid source positions. ZLS should detect this and return a InvalidParams error instead of crashing.

Techatrix avatar Jul 28 '23 00:07 Techatrix

Hello, I have the same zls crash using nvim + coc.nvim.

Zig Version

0.11.0-dev.4404+4f6013bf5

Zig Language Server Version

0.11.0-dev.632+4aa4bd7

Steps to Reproduce

Starting from this code source:

const std = @import("std"); path:                                                                                                                                                                                              
                                                                                                                                                                                                                               
test "zls positionToIndex trash" {                                                                                                                                                                                             
    var conf = .{ .header_strategy = .{ .dynamic = 8192 } };                                                                                                                                                                   
    _ = conf;                                                                                                                                                                                                                  
} 

When I add a new line before .dynamic zls crashes in positionToIndex.

const std = @import("std"); path:                                                                                                                                                                                              
                                                                                                                                                                                                                               
test "zls positionToIndex trash" {                                                                                                                                                                                             
    var conf = .{ .header_strategy = .{                                                                                                                                                                                        
        .dynamic = 8192 } };                                                                                                                                                                                                   
    _ = conf;                                                                                                                                                                                                                  
}

Expected Behavior

No crash

Actual Behavior

thread 556744 panic: reached unreachable code                                                                                                                                                                                  
debug: (server): Took 0ms to process notification-$/cancelRequest on Thread 556747                                                                                                                                             
/usr/local/zig/lib/std/debug.zig:343:14: 0x3c8d12 in assert (zls)                                                                                                                                                              
    if (!ok) unreachable; // assertion failure                                                                                                                                                                                 
             ^                                                                                                                                                                                                                 
/home/pierre/prs/zls/src/offsets.zig:49:21: 0x4b5e2d in positionToIndex (zls)                                                                
    std.debug.assert(line == position.line);                                                                                                 
                    ^                                                                                                                        
/home/pierre/prs/zls/src/offsets.zig:274:31: 0x4e0d9e in rangeToLoc (zls)                                                                    
        .end = positionToIndex(text, range.end, encoding),                                                                                   
                              ^                                                                                                              
/home/pierre/prs/zls/src/Server.zig:1193:35: 0x4a03d6 in inlayHintHandler (zls)                                                              
    const loc = offsets.rangeToLoc(handle.text, request.range, server.offset_encoding);                                                      
                                  ^                                                                                                          
/home/pierre/prs/zls/src/Server.zig:1613:66: 0x466381 in sendRequestSync__anon_21797 (zls)                                                   
        .@"textDocument/inlayHint" => try server.inlayHintHandler(arena, params),                                                            
                                                                 ^                                                                           
/home/pierre/prs/zls/src/Server.zig:1692:58: 0x4343db in processMessage (zls)                                                                
                const result = try server.sendRequestSync(arena_allocator.allocator(), method, params);                                      
                                                         ^                                                                                   
/home/pierre/prs/zls/src/Server.zig:1711:33: 0x3f107b in processMessageReportError (zls)                                                     
    return server.processMessage(message) catch |err| switch (message) {                                                                     
                                ^                                                                                                            
/home/pierre/prs/zls/src/Server.zig:1735:62: 0x3d73a9 in processJob (zls)                                                                    
            const response = server.processMessageReportError(parsed_message.value) orelse return;                                           
                                                             ^                                                                               
/usr/local/zig/lib/std/Thread/Pool.zig:94:39: 0x3d65ee in runFn (zls)                                                                        
            @call(.auto, func, closure.arguments);                                                                                           
                                      ^                                                                                                      
/usr/local/zig/lib/std/Thread/Pool.zig:133:18: 0x458774 in worker (zls)                                                                      
            runFn(&run_node.data);                                                                                                           
                 ^                                                                                                                           
/usr/local/zig/lib/std/Thread.zig:412:13: 0x42560d in callFn__anon_19640 (zls)                                                               
            @call(.auto, f, args);                                                                                                           
            ^                                                                                                                                
/usr/local/zig/lib/std/Thread.zig:1210:30: 0x3e6153 in entryFn (zls)                                                                         
                return callFn(f, self.fn_args);                                                                                              
                             ^                                                                                                               
/usr/local/zig/lib/c.zig:239:13: 0x926c60 in clone (c)                                                                                       
            asm volatile (                                                                                                                   
            ^                                                                                                                                
???:?:?: 0x0 in ??? (???)                                                                                                                    
[Error - 10:51:03.617] zls exited with code: null                                                                                            
[Info  - 10:51:03.618] Connection to server got closed. Server will restart.

Here are the debug logs I get from coc.nvim node server when I get the crash. I setup the nvim config to get the log with:

let g:node_client_debug = 1                                                      
let $NODE_CLIENT_LOG_FILE = '/tmp/coc.log'

I hope it can help to reproduce.

coc debug log
09:59:56.224 DEBUG [transport] - receive notification: [
  "nvim_buf_lines_event",
  [
    "[nvim_buf_1]",
    213,
    3,
    4,
    [
      "    var conf = .{ .header_strategy = .{.dynamic = 8192 } };"
    ],
    false
  ]
]
09:59:56.225 DEBUG [transport] - receive notification: [
  "nvim_buf_lines_event",
  [
    "[nvim_buf_1]",
    214,
    3,
    4,
    [
      "    var conf = .{ .header_strategy = .{",
      "    .dynamic = 8192 } };"
    ],
    false
  ]
]
09:59:56.225 DEBUG [transport] - receive notification: [
  "nvim_buf_lines_event",
  [
    "[nvim_buf_1]",
    215,
    4,
    5,
    [
      "        .dynamic = 8192 } };"
    ],
    false
  ]
]
09:59:56.225 DEBUG [transport] - receive notification: [
  "CocAutocmd",
  [
    "CursorMoved",
    1,
    [
      5,
      8
    ]
  ]
]
09:59:56.225 DEBUG [transport] - receive notification: [
  "CocAutocmd",
  [
    "TextChanged",
    1,
    215
  ]
]
09:59:56.325 DEBUG [transport] - request to nvim: 407, nvim_call_function, [
  "coc#window#visible_range",
  [
    1
  ]
]
09:59:56.326 DEBUG [transport] - response of nvim: 407, 1, [
  1,
  7
], null
09:59:56.328 DEBUG [transport] - nvim notification: nvim_call_atomic, [
  [
    [
      "nvim_call_function",
      [
        "setbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          "thread 551709 panic: reached unreachable code"
        ]
      ]
    ],
    [
      "nvim_call_function",
      [
        "appendbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          [
            ""
          ]
        ]
      ]
    ]
  ]
]
09:59:56.413 DEBUG [transport] - nvim notification: nvim_call_atomic, [
  [
    [
      "nvim_call_function",
      [
        "setbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          "/usr/local/zig/lib/std/debug.zig:343:14: 0x34b3b7 in positionToIndex (zls)"
        ]
      ]
    ],
    [
      "nvim_call_function",
      [
        "appendbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          [
            "    if (!ok) unreachable; // assertion failure",
            ""
          ]
        ]
      ]
    ]
  ]
]
09:59:56.413 DEBUG [transport] - nvim notification: nvim_call_atomic, [
  [
    [
      "nvim_call_function",
      [
        "setbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          "             ^"
        ]
      ]
    ],
    [
      "nvim_call_function",
      [
        "appendbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          [
            ""
          ]
        ]
      ]
    ]
  ]
]
09:59:56.415 DEBUG [transport] - nvim notification: nvim_call_atomic, [
  [
    [
      "nvim_call_function",
      [
        "setbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          "/home/pierre/prs/zls/src/offsets.zig:274:31: 0x3211db in sendRequestSync__anon_20436 (zls)"
        ]
      ]
    ],
    [
      "nvim_call_function",
      [
        "appendbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          [
            "        .end = positionToIndex(text, range.end, encoding),",
            "                              ^",
            ""
          ]
        ]
      ]
    ]
  ]
]
09:59:56.416 DEBUG [transport] - nvim notification: nvim_call_atomic, [
  [
    [
      "nvim_call_function",
      [
        "setbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          "/home/pierre/prs/zls/src/Server.zig:1692:58: 0x307449 in processMessage (zls)"
        ]
      ]
    ],
    [
      "nvim_call_function",
      [
        "appendbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          [
            ""
          ]
        ]
      ]
    ]
  ]
]
09:59:56.416 DEBUG [transport] - nvim notification: nvim_call_atomic, [
  [
    [
      "nvim_call_function",
      [
        "setbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          "                const result = try server.sendRequestSync(arena_allocator.allocator(), method, params);"
        ]
      ]
    ],
    [
      "nvim_call_function",
      [
        "appendbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          [
            "                                                         ^",
            ""
          ]
        ]
      ]
    ]
  ]
]
09:59:56.417 DEBUG [transport] - nvim notification: nvim_call_atomic, [
  [
    [
      "nvim_call_function",
      [
        "setbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          "/home/pierre/prs/zls/src/Server.zig:1711:33: 0x2cf02a in processJob (zls)"
        ]
      ]
    ],
    [
      "nvim_call_function",
      [
        "appendbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          [
            ""
          ]
        ]
      ]
    ]
  ]
]
09:59:56.417 DEBUG [transport] - nvim notification: nvim_call_atomic, [
  [
    [
      "nvim_call_function",
      [
        "setbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          "    return server.processMessage(message) catch |err| switch (message) {"
        ]
      ]
    ],
    [
      "nvim_call_function",
      [
        "appendbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          [
            "                                ^",
            ""
          ]
        ]
      ]
    ]
  ]
]
09:59:56.417 DEBUG [transport] - nvim notification: nvim_call_atomic, [
  [
    [
      "nvim_call_function",
      [
        "setbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          "/usr/local/zig/lib/std/Thread/Pool.zig:94:39: 0x2cbaa4 in runFn (zls)"
        ]
      ]
    ],
    [
      "nvim_call_function",
      [
        "appendbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          [
            "            @call(.auto, func, closure.arguments)"
          ]
        ]
      ]
    ]
  ]
]
09:59:56.417 DEBUG [transport] - nvim notification: nvim_call_atomic, [
  [
    [
      "nvim_call_function",
      [
        "setbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          "            @call(.auto, func, closure.arguments);"
        ]
      ]
    ],
    [
      "nvim_call_function",
      [
        "appendbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          [
            "                                      ^",
            ""
          ]
        ]
      ]
    ]
  ]
]
09:59:56.418 DEBUG [transport] - nvim notification: nvim_call_atomic, [
  [
    [
      "nvim_call_function",
      [
        "setbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          "/usr/local/zig/lib/std/Thread/Pool.zig:133:18: 0x2d98bf in entryFn (zls)"
        ]
      ]
    ],
    [
      "nvim_call_function",
      [
        "appendbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          [
            "            runFn(&run_node.data);",
            "                 ^",
            ""
          ]
        ]
      ]
    ]
  ]
]
09:59:56.418 DEBUG [transport] - nvim notification: nvim_call_atomic, [
  [
    [
      "nvim_call_function",
      [
        "setbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          "/usr/local/zig/lib/c.zig:239:13: 0x508450 in clone (c)"
        ]
      ]
    ],
    [
      "nvim_call_function",
      [
        "appendbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          [
            "            asm volatile (",
            "            ^",
            "???:?:?: 0x0 in ??? (???)",
            ""
          ]
        ]
      ]
    ]
  ]
]
09:59:56.420 DEBUG [transport] - nvim notification: nvim_call_atomic, [
  [
    [
      "nvim_call_function",
      [
        "setbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          "[Info  - 09:59:56.420] Connection to server got closed. Server will restart."
        ]
      ]
    ],
    [
      "nvim_call_function",
      [
        "appendbufline",
        [
          "output:///Zig%20Language%20Server",
          "$",
          [
            ""
          ]
        ]
      ]
    ]
  ]
]

krichprollsch avatar Aug 04 '23 08:08 krichprollsch

I tried to debug by modifiing the zls code source:

diff --git a/src/offsets.zig b/src/offsets.zig
index 0c901d0..09626de 100644
--- a/src/offsets.zig
+++ b/src/offsets.zig
@@ -46,6 +46,9 @@ pub fn positionToIndex(text: []const u8, position: types.Position, encoding: Enc
             line_start_index = i + 1;
         }
     }
+    if (line != position.line) {
+        std.debug.print("line: {}, position.line: {}, text: {s}\n", .{ line, position.line, text });
+    }
     std.debug.assert(line == position.line);
 
     const line_text = std.mem.sliceTo(text[line_start_index..], '\n')

I get the log:

line: 6, position.line: 7, text: const std = @import("std");                     
                                                                                 
test "zls positionToIndex trash" {                                               
    var conf = .{ .header_strategy = .{ .dynamic = 8192 } };                     
    _ = conf;                                                                    
}                                                                                

It looks like the text value is not the last one? b/c when zls crashes, my editor contains:

const std = @import("std"); path:                                                
                                                                                 
test "zls positionToIndex trash" {                                               
    var conf = .{ .header_strategy = .{                                          
        .dynamic = 8192 } };                                                     
    _ = conf;                                                                    
} 

krichprollsch avatar Aug 04 '23 08:08 krichprollsch

When I disable the inlayHint in the coc config, zls no longer crashes. It looks like the inlay hint request is sent before the notification change :thinking:

krichprollsch avatar Aug 04 '23 10:08 krichprollsch

I just took a look at coc.nvim. This is where inlay hint request appears to be constructed and send: buffer.ts#L169-L188 The range parameter seems to come from a visible_range function here: window.vim#L191 If I had to guess I would say that that function returns the the first and last line in the current window which may return a last line that is after the last line in the document. I will have to do some more digging to figure out what coc is doing. Even if this is an issue with coc, ZLS should still either reject that request or sanitize its content (maybe "clamp" positions and ranges)

Techatrix avatar Aug 04 '23 10:08 Techatrix

As far as I can see (but not sure at all), go pls returns an error in this case: https://github.com/golang/tools/blob/master/gopls/internal/lsp/protocol/mapper.go#L359-L360

krichprollsch avatar Aug 04 '23 11:08 krichprollsch