Skip to content

tool4d 21R3 crashes (0xC0000005) servicing workspace/diagnostic when the workspace is not a formal 4D project #48

Description

@foregroundDev

tool4d 21R3 crashes (0xC0000005) servicing workspace/diagnostic when the workspace is not a formal 4D project

Summary

With 4D-Analyzer.diagnostics.scope set to Workspace (the default), the tool4d language server crashes with an access violation (0xC0000005, Windows exit code 3221225477) immediately after receiving a workspace/diagnostic request, when the opened folder is a plain folder that contains loose .4dm file(s) but is not a structured 4D project (no Project/, no .4DProject).

Single-file diagnostics (textDocument/diagnostic) work fine; only the workspace-wide scan crashes. The result is a language server that dies on startup and cannot recover ("Client is not running", Cannot call write after a stream was destroyed).

This is a regression: tool4d 21 (build 100422) does not crash under the same conditions; 21R3 (build 100164) does.

Environment

Extension 4D-Analyzer 0.2.9
tool4d 21R3 build 100164 (serverInfo version 2130)
Known-good tool4d 21 build 100422 (no crash)
VS Code 1.127.0
OS Windows 11 Home 10.0.26200 (x64)
Setting 4D-Analyzer.diagnostics.scope = Workspace (default)

Steps to reproduce

  1. Open a folder that is not a 4D project (e.g. any folder containing one loose .4dm file among unrelated files — in my case a Go project).
  2. Ensure 4D-Analyzer.diagnostics.scope = Workspace (default) and tool4d version resolves to 21R3.
  3. Open the .4dm file so the extension activates.

Actual result

The server crashes. From the verbose LSP trace:

Sending request 'initialize - (0)'            -> OK (31ms)
Sending notification 'textDocument/didOpen'
Sending request 'textDocument/diagnostic (1)' -> OK (28ms), no result
Sending request 'workspace/diagnostic (2)'
[Error] Client 4D-LSP: connection to server is erroring. read ECONNRESET
Language server exited with exit code 3221225477   (0xC0000005 access violation)

Expected result

workspace/diagnostic over a non-4D-project folder should return diagnostics (or an empty result), not crash the server.

Minimal reproduction (isolated from VS Code)

The crash is reproducible by driving tool4d directly over the LSP socket. The critical detail is that the client must answer the server's workspace/configuration callback — that is what makes tool4d actually walk the workspace tree, and the walk is what faults. A client that ignores the callback returns too fast and does not crash.

Node harness (node repro.js <path-to-tool4d.exe>):

const net = require('net');
const { spawn } = require('child_process');
const rootUri = "file:///c%3A/path/to/non-4d-project-folder";
const docUri  = rootUri + "/some.4dm";
const cfg = { trace:{server:"off"}, server:{path:"",tool4d:{enable:true,version:"latest",channel:"stable",location:""}},
              diagnostics:{enable:true, scope:"Workspace"}, dependencies:{debug:false} };
function frame(o){const s=JSON.stringify(o);return `Content-Length: ${Buffer.byteLength(s)}\r\n\r\n${s}`;}

net.createServer(sock=>{
  let buf=Buffer.alloc(0);
  const send=o=>sock.write(frame(o));
  sock.on('data',d=>{ buf=Buffer.concat([buf,d]);
    while(true){ const h=buf.indexOf("\r\n\r\n"); if(h<0)break;
      const m=buf.slice(0,h).toString().match(/Content-Length:\s*(\d+)/i); if(!m)break;
      const len=+m[1],s=h+4; if(buf.length<s+len)break;
      const msg=JSON.parse(buf.slice(s,s+len)); buf=buf.slice(s+len);
      if(msg.method==="workspace/configuration") send({jsonrpc:"2.0",id:msg.id,result:(msg.params.items||[{}]).map(()=>cfg)});
      else if(msg.method && msg.id!=null) send({jsonrpc:"2.0",id:msg.id,result:null});
    }});
  send({jsonrpc:"2.0",id:0,method:"initialize",params:{processId:process.pid,rootUri,
    capabilities:{textDocument:{diagnostic:{}},workspace:{configuration:true,workspaceFolders:true}},
    initializationOptions:cfg, workspaceFolders:[{uri:rootUri,name:"repro"}]}});
  setTimeout(()=>{ send({jsonrpc:"2.0",method:"initialized",params:{}});
    send({jsonrpc:"2.0",method:"textDocument/didOpen",params:{textDocument:{uri:docUri,languageId:"4d",version:1,text:"//x\n"}}}); },300);
  setTimeout(()=>{ send({jsonrpc:"2.0",id:2,method:"workspace/diagnostic",params:{previousResultIds:[],partialResultToken:"t"}}); },1200);
}).listen(0,'127.0.0.1',function(){
  const child=spawn(process.argv[2],["--lsp="+this.address().port]);
  child.on('exit',c=>console.log("tool4d exit",c,"0x"+(c>>>0).toString(16)));
});

Observed: with tool4d 21R3tool4d exit 3221225477 0xc0000005. With tool4d 21 → no crash.

Workaround

Set 4D-Analyzer.diagnostics.scope to Document. This suppresses the workspace/diagnostic request; single-file diagnostics and all other language features continue to work, and the server no longer crashes.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions