Samsung / netcoredbg

NetCoreDbg is a managed code debugger with MI interface for CoreCLR.
MIT License
780 stars 101 forks source link

Cannot receive request in VSCode mode #71

Open fenixjiang opened 2 years ago

fenixjiang commented 2 years ago
  1. Start netcoredbg with arg: "--interpreter=vscode --server"
  2. My DapClient like this: var endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1", 4711)); var socket = new Socket(AdressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socket.Connent(endPoint); var stream = new NetworkStream(socket); var options = new DebugAdapterClientOptions().WithInput(stream).Withoutput(stream); var client = DebugAdapterClinet.Create(options); await client.Initialize(System.Threading.CancellationToken.None); <----run to here and block !!!
  3. In server side(vscodeprotocol.cpp) at func std::string VSCodeProtocol::ReadData() { ... std::getline(cin, line); if(! cin.good()) { //Always run to here, even if DapClinet is just connected, before sending the initialization command。 } ... }

Is there anything I missed? I am not good at English, I hope my description clears up my problem. Thanks.

alpencolt commented 2 years ago

@fenixjiang as I understand you write your own plugin for VSCode. According to source code you trying to pass null to NetCoreDbg which sets failbit in cin (check). You should pass VSCode protocol commands instead.

@viewizard could share where to look them?

fenixjiang commented 2 years ago

@alpencolt Thank you for your reply!

Here is a Dap implementation include a DebugAdapterClient( https://github.com/OmniSharp/csharp-language-server-protocol).

I think as far as netcoredbg supports vscode mode, then it should be able to receive messages from dap Client. In fact, it did receive/respond the message from/to my DapClient, but it need to set a breakpoint on the socket connect, and wait for the DapClient send the initialize command. Without this breakpoint, the previous situation will occur.

I set a breakpoint on if(! cin.good()) at method std::string VSCodeProtocol::ReadData(), I can see my initialize request in the cin. getline

I don't know what to do next. Any suggestions?

viewizard commented 2 years ago

I set a breakpoint on if(! cin.good()) at method std::string VSCodeProtocol::ReadData(), I can see my initialize request in the cin.

As I see, debugger execute code inside !cin.good() code block after you command received, that mean you work with cin in wrong way and this is not related to command you sent. More you could read here: https://en.cppreference.com/w/cpp/io/basic_ios/good

fenixjiang commented 2 years ago

@viewizard I don't know how to get that command in the cin. I tried call cin.Ignore() cin.clear() before std::getline(). I use cin.seekg() to move the position. I make a endless loop to read buff from cin, but i can't get that command string.

alpencolt commented 2 years ago

Check what you send on plugin side, you send something that makes cin !good, probably it's null or EOF. Also you can print line on debugger side to check what comes

0xfk0 commented 2 years ago

I suggest to record communication between two parties by using tcpdump (wireshark, etc...) or strace. Devil might hide in the details.

0xfk0 commented 2 years ago

Which file type is used for netcoredbg's stdin/stdout in your case? This is socket, named pipe, anonymous (unnamed) pipe, something other?

I suspect, we may have issue with unnamed pipes on windows: "Asynchronous (overlapped) read and write operations are not supported by anonymous pipes". (see https://docs.microsoft.com/en-us/windows/win32/ipc/anonymous-pipe-operations)

Can you switch to using of named pipes or sockets in place of stdin/stderr? See unnamed_pair function (in iosystem_win32.cpp) as an example, how to create pair of named pipes.

Try to set up breakpoints in iosystem_win32.cpp, in async_read function and check, that return {} never executes (this means an error). Also check, that Class::read function never returns error (ReadFile API call might return error).

0xfk0 commented 2 years ago

Please rebuild netcoredbg in Debug mode and enable full logs (as described here: https://github.com/Samsung/netcoredbg). Then reproduce the issue, record the log and attach the log to this bug report. This is the first thing you should do. If some errors occurs within IORedirect and IOSystem, IOSystemTraits<T> classes, these errors must be logged.

fenixjiang commented 2 years ago

@kfrolov I found the problem according to your suggestion. The file type is socket, overlapped I/O. The Class::readmethod in iosystem_win32.cpp returnERROR_IO_PENGDING, and i didn'see where it was processed. Because I don’t know where is the best place to processed with it, so i directly modified Class::Readthe method, call GetOverlappedResult while last error is ERROR_IO_PENDING.

Class::IOResult Class::read(const FileHandle& fh, void *buf, size_t count)
{
    DWORD dwRead = 0;
    OVERLAPPED ov = {};
    if (!ReadFile(fh.handle, buf, (DWORD)count, &dwRead, &ov))
    {
        //return { (GetLastError() == ERROR_IO_PENDING ? IOResult::Pending : IOResult::Error), dwRead };
        DWORD lastError = GetLastError();
        if (lastError == ERROR_IO_PENDING)
        {
            if (!GetOverlappedResult(fh.handle, &ov, &dwRead, TRUE))
                return { IOResult::Error, dwRead };
        }
        else
            return { IOResult::Error, dwRead };
    }
    return { (dwRead == 0 ? IOResult::Eof : IOResult::Success), dwRead };
}

After this modification, netcoredbg can communicate with my Dap client.

Now there is a new problem. After sending and receiving more than 10 messages, the 'ReadFile' inClass::read return ERROR_WORKING_SET_QUOTA . The cout.flush() failed in VSCodeprotocol::EmitEvent(). I debug into flush in ostream:line548, const sentry _Ok(*this) is false.

I guess the default buffer size of StreamBufmay be too small, so I increased the buff to 1M, but the problem is still the same. I am looking for the reason why flush failed.

Is my modification about ERROR_IO_PENDING correct? what is the best practice?

viewizard commented 2 years ago

@fenixjiang you could find working C# example here - https://github.com/Samsung/netcoredbg/tree/master/test-suite Our test suite framework aimed to network and local interaction with debugger by VSCode and MI/GDB protocols. For example, VSCode network part looks like: https://github.com/Samsung/netcoredbg/blob/master/test-suite/NetcoreDbgTest/VSCode/VSCodeTcpDebuggerClient.cs

Hope this helps.

0xfk0 commented 2 years ago

@fenixjiang, IOResult::Pending error is processed here: https://github.com/Samsung/netcoredbg/blob/2de336c9496f6b3e8817ed19c70a9d957b8afc43/src/utils/streams.cpp#L95 As you can see, in case of such error, code just loops until read opeation will be finished. So I not understood, why this error raises through InStreamBuf class up to std::streambuf and cin starts reporting an error.

Look strange, as ERROR_WORKING_SET_QUOTA error, which is caused by multiple calls to ReadFile without calling GetOverlappedResult (which you have added). I suspect, that GetOverlappedResult must be called every time, even if ReadFile returns True.

As I understood, IOSystemTraits<Win32PlatformTag>::read and write function call ReadFile and WriteFile with non NULL OVERLAPPED argument because of sockets: OVERLAPPED not needed for other file types, but for sockets it is needed, otherwise ReadFile or WriteFile will fail. This is why OVERLAPPED have non-null in synchronous read/write functions. I suspect, this is because WinSock2 library open sockets in asynchronous (withFILE_FLAG_OVERLAPPED` mode).

Microsoft's documentation says (https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile), "The lpOverlapped parameter must not be NULL..." if file opened with FILE_FLAG_OVERLAPPED set.

And you a right, that GetOverlappedResult(..., bWait=1) must be called to wait for a result. And I suspect, that it must be called even if ReadFile returns True. Also microsoft documentation says, that lpNumberOfBytesRead must be set to NULL (when calling ReadFile) if you are using overlapped IO.

And I think, same is correct for WriteFile. So you must patch both functions, IOSystemTraits<Win32PlatformTag>::read and write.

I curious, why ERROR_IO_PENDING was never raised in our cases. Looks like you have very different Windows version, WinSock2 library, etc... Which exact windows version are you using? Can you reproduce the bug on regular Windows-10 version?

And last question, how are you running netcoredbg? The sockets for cin/cout was opened by netcoreddbg itself (by call to IOSystem::listen_socket, that happens if you are passing --server option to netcoredbg), or you create sockets by itself and pass opened sockets from your program to child process (which is netcoredbg) ?

0xfk0 commented 2 years ago

flush function calls OutStreamBuf::sync(), which calls IOSystem::write, which in fact is IOSystemTraits<Win32PlatformTag>::write. I think the problem is same, win32 function WriteFile returns an error because you have not called GetOverlappedResult, but OVERLAPPED is not null.

fenixjiang commented 2 years ago

Here is my test program with VSCodeTcpDebuggerClient

        static void Main(string[] args)
    {
        Console.WriteLine("Hello World!");

        var tcpClient = new VSCodeTcpDebuggerClient("127.0.0.1", 4711);
        var debugger = new VSCodeDebugger(tcpClient);

        //init
        InitializeRequest initReq = new InitializeRequest();
        initReq.arguments.clientID = "myTest";
        initReq.arguments.clientName = "My Test";
        initReq.arguments.adapterID = "coreclr";
        //initReq.arguments.pathFormat = "path";
        //initReq.arguments.linesStartAt1 = true;
        //initReq.arguments.columnsStartAt1 = true;
        initReq.arguments.supportsVariableType = true;
        initReq.arguments.supportsVariablePaging = true;
        initReq.arguments.supportsRunInTerminalRequest = true;
        //initReq.arguments.supportsProgressReporting = true;
        //initReq.arguments.supportsMemoryReferences = true;
        //initReq.arguments.locale = "en-us";

        var result = debugger.Request(initReq);

        //breaks;

        var bp = new SetBreakpointsRequest();

        var file = @"D:\Github\Debugger\Test\ConsoleApp16\ConsoleApp2_2\Program.cs";

        bp.arguments.source.path = file;
        bp.arguments.source.name = System.IO.Path.GetFileName(file);
        bp.arguments.breakpoints.Add(new SourceBreakpoint(11));

        var bpRet = debugger.Request(bp);

        //launch
        LaunchRequest launchReq = new LaunchRequest();
        //launchReq.arguments.name = "Test my console";
        //launchReq.arguments.type = "coreclr";
        //launchReq.arguments.preLaunchTask = "build";
        launchReq.arguments.program = @"C:\Program Files\dotnet\dotnet.exe";
        launchReq.arguments.cwd = @"D:\Github\Debugger\Test\ConsoleApp16\ConsoleApp2_2\bin\Debug\netcoreapp2.2";
        launchReq.arguments.args = new System.Collections.Generic.List<string>() { "exec", "D:\\Github\\Debugger\\Test\\ConsoleApp16\\ConsoleApp2_2\\bin\\Debug\\netcoreapp2.2\\ConsoleApp2_2.dll", "AAAA", "BBB" };
        launchReq.arguments.env = new System.Collections.Generic.Dictionary<string, string>();
        //launchReq.arguments.console = "internalConsole";
        //launchReq.arguments.stopAtEntry = true;
        //launchReq.arguments.internalConsoleOptions = "openOnSessionStart";
        //launchReq.arguments.__sessionId = Guid.NewGuid().ToString();

        var r1 = debugger.Request(launchReq);

        //configrationDone 
        var cfgDone = new ConfigurationDoneRequest();
        var cfgRet = debugger.Request(cfgDone);

                //Please ignore those, just to print the messages
                while (true)
        {
            if (!debugger.IsEventReceived(OnEventReceived))
                Task.Delay(500).Wait();
        }

        _ = Console.ReadLine();
    }

And I get the same result. After netcoredbg sends a few messages, in my case it was 8, then vscodeprotocol.cpp/cout.flush fail and cout.eof() return true.

fenixjiang commented 2 years ago

I thought there might be a bug here.

I modified this VSCodeProtocol::EmitEvent method, call cout.clear() after cout.flush(), and communication is normal now.

void VSCodeProtocol::EmitEvent(const std::string &name, const nlohmann::json &body)
{
    std::lock_guard<std::mutex> lock(m_outMutex);
    json response;
    response["type"] = "event";
    response["event"] = name;
    response["body"] = body;
    std::string output = response.dump();
    output = VSCodeSeq(m_seqCounter) + output.substr(1);
    ++m_seqCounter;

    cout << CONTENT_LENGTH << output.size() << TWO_CRLF << output;

    cout.flush();
    cout.clear();     //<-----Add this line!!!

    Log(LOG_EVENT, output);
}

For now I have not found the reason why the eof status is set after cout.flush().

viewizard commented 2 years ago

We definitely will not add some code just because this change behavior in the way you need. I don't see any reason for cout.clear(); line here. The point is - this could be another issue, that you suppress by this line, but not provide real fix. This issue must be investigated first in order to find out why only you have eof here.

0xfk0 commented 2 years ago

@viewizard, I think you need to test netcoredbg running on Windows-7 and may be on Windows-Vista or Windows-XP. I guess, that all issues caused by overlapped IO which works differently on same previous Windows version.

cout.clear() works, because cout.flush() causes an error. In our case flush ends with call to WriteFile with non-NULL overlapped argument.

I think @fenixjiang uses some "non typical" windows version (installed libraries, other environment related things...) And this is why the bug was not meet in our cases.

alpencolt commented 2 years ago

@fenixjiang we cannot call clear() since it removes all flags from stream, but they are useful for case when IDE hangs. we must handle such situation. What Windows version do you use?

Also could you disable all firewalls and antiviruses. If it doesn't help could you check passed data via WireShark or other sniffer.

fenixjiang commented 2 years ago

Sorry for replying so late. My windows version is 10.0.18363.1916, and dotnet sdks version is 5.0.302.

I thought my client may be used incorrectly. I haven't seen other people having the same problem as mine in message transmission. Transmission is a very basic function, and there should not be such a problem. The preconceived ideas have kept me from finding the root of the problem. The changes I made before are probably just to solve the superficial problem.

alpencolt commented 2 years ago

@fenixjiang check latest release we've fixed some issues on windows platform

fenixjiang commented 2 years ago

@alpencolt I had check the latest release, but my problem still exists.

I start netcoredbg with arguments "--interpreter=vscode --server", then connect it with a dap client (https://github.com/OmniSharp/csharp-language-server-protocol).

netcoredbg exit while init request is send. netcoredbg does not process any command.

GetLastError() is ERROR_IO_PENDING after call function ReadFile in Class::read in file iosystem_win32.cpp . ERROR_IO_PENDING is not considered as IOResult::Error. The loop in InStreamBuf::underflow in file streams.cpp can continued to call ReadFile, after a while, GetLastError() after call ReadFile return ERROR_NOT_ENOUGH_QUOTA, this is considered as IOResult::Error that make InStreamBuf:::underflow return eof, then VSCodeprotocol::CommandLoop return.

During my debugging, I find it does not call GetOverlappedResult while the last error is ERROR_IO_PENDING as Microsoft's documentation says (https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile).

viewizard commented 2 years ago

I updated upstream sources, it should support Windows 10 x86 now. Could you please confirm, that you still have this issue with latest sources?

fenixjiang commented 2 years ago

@viewizard I have checked out the lastest sources, and build successfully under Win10 x86. The following problem occurred when experiencing the new features: I started netcoredbg with --interpreter=cli --hot-reload ,then debug a simple console.

we got a assertion failed.

 ncdb> file C:\Users\jz\source\repos\ConsoleApp1\ConsoleApp1\bin\Debug\net5.0\ConsoleApp1.exe
 ncdb> b C:\Users\jz\source\repos\ConsoleApp1\ConsoleApp1\Program.cs:17
 ncdb> run
 Assertion failed: !read_lock, file C:\Work\netcoredbg_v78\src\utils\ioredirect.cpp, line 404

Then i try start netcoredbg directly from VS2019, still have above issue.

I will try this under Win10 x64 , and run netcoredbg in vscode mode later.

viewizard commented 2 years ago

Note, we support Hot Reload feature for Tizen OS only, since it required custom runtime build + you will need generate IL/metadata/PDB deltas somehow, and even for Tizen OS it have WIP status.

viewizard commented 2 years ago

Here is patch that fix issue with Assertion failed: !read_lock, file C:\Work\netcoredbg_v78\src\utils\ioredirect.cpp, line 404

From 28defb5d7130d1f7a6736c46e5f7eb177743c010 Mon Sep 17 00:00:00 2001
From: Mikhail Kurinnoi <m.kurinnoi@samsung.com>
Date: Fri, 10 Jun 2022 18:01:42 +0300
Subject: [PATCH] Fix CLI work on Windows.

---
 src/utils/iosystem_win32.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/utils/iosystem_win32.cpp b/src/utils/iosystem_win32.cpp
index d206c6c..dc2d4e9 100644
--- a/src/utils/iosystem_win32.cpp
+++ b/src/utils/iosystem_win32.cpp
@@ -525,7 +525,7 @@ Class::IOSystem::StdFiles Class::get_std_files()
         std::max_align_t align_field;
         char mem[sizeof(Handles)];
     };
-    mem_align_t mem_align_tmp;
+    static mem_align_t mem_align_tmp;
     char * const mem = mem_align_tmp.mem;

     Handles& handles = *new (mem) Handles {
-- 
2.25.1

will be in upstream at next sync.

fenixjiang commented 2 years ago

@viewizard I tred run netcoredbg under vscode mode, and still has transmission issue. These are netcoredbg received and output:

-> (C)  {"seq":1,"type":"request","command":"initialize","arguments":{"clientID":"netcoredbg ClientId","clientName":"netcoredbg Client","adapterID":"netcoredbg AdapterId","supportsVariableType":true,"supportsVariablePaging":true,"supportsRunInTerminalRequest":true,"supportsMemoryReferences":true,"supportsProgressReporting":true}}
<- (E)  {"body":{"capabilities":{"exceptionBreakpointFilters":[{"filter":"all","label":"all"},{"filter":"user-unhandled","label":"user-unhandled"}],"supportTerminateDebuggee":true,"supportsCancelRequest":true,"supportsConditionalBreakpoints":true,"supportsConfigurationDoneRequest":true,"supportsExceptionFilterOptions":true,"supportsExceptionInfoRequest":true,"supportsExceptionOptions":false,"supportsFunctionBreakpoints":true,"supportsSetExpression":true,"supportsSetVariable":true,"supportsTerminateRequest":true}},"event":"capabilities","seq":"1","type":"event"}
<- (E)  {"body":{},"event":"initialized","seq":"2","type":"event"}
<- (R)  {"body":{"exceptionBreakpointFilters":[{"filter":"all","label":"all"},{"filter":"user-unhandled","label":"user-unhandled"}],"supportTerminateDebuggee":true,"supportsCancelRequest":true,"supportsConditionalBreakpoints":true,"supportsConfigurationDoneRequest":true,"supportsExceptionFilterOptions":true,"supportsExceptionInfoRequest":true,"supportsExceptionOptions":false,"supportsFunctionBreakpoints":true,"supportsSetExpression":true,"supportsSetVariable":true,"supportsTerminateRequest":true},"command":"initialize","request_seq":1,"seq":"3","success":true,"type":"response"}

At this time code runs to vscodeprotocol.cpp

void VSCodeProtocol::CommandLoop()
{
    std::thread commandsWorker{&VSCodeProtocol::CommandsWorker, this};

    m_exit = false;

    while (!m_exit)
    {
        std::string requestText = ReadData(cin);
        if (requestText.empty())
        {
            CommandQueueEntry queueEntry;
            queueEntry.command = "ncdbg_disconnect";
            std::lock_guard<std::mutex> guardCommandsMutex(m_commandsMutex);
            m_commandsQueue.clear();
            m_commandsQueue.emplace_back(std::move(queueEntry));
            m_commandsCV.notify_one(); // notify_one with lock
            break; <------------------------------HERE!!!-----------
        }
....

and in iosystem_win32.cpp Class::IOResult Class::read(const FileHandle& fh, void *buf, size_t count) , the last error of ReadFile is ERROR_WORKING_SET_QUOTA.

Here are packages captured by wireshark

1   0.000000    kubernetes.docker.internal  kubernetes.docker.internal  TCP 56  11312 → trinity-dist(4711) [SYN] Seq=0 Win=65535 Len=0 MSS=65495 WS=256 SACK_PERM=1
2   0.000059    kubernetes.docker.internal  kubernetes.docker.internal  TCP 56  trinity-dist(4711) → 11312 [SYN, ACK] Seq=0 Ack=1 Win=65535 Len=0 MSS=65495 WS=256 SACK_PERM=1
3       0.000113    kubernetes.docker.internal  kubernetes.docker.internal  TCP 44  11312 → trinity-dist(4711) [ACK] Seq=1 Ack=1 Win=2619648 Len=0
4   0.011588    kubernetes.docker.internal  kubernetes.docker.internal  TCP 390 11312 → trinity-dist(4711) [PSH, ACK] Seq=1 Ack=1 Win=2619648 Len=346
5   0.011616    kubernetes.docker.internal  kubernetes.docker.internal  TCP 44  trinity-dist(4711) → 11312 [ACK] Seq=1 Ack=347 Win=2619648 Len=0
6   0.023814    kubernetes.docker.internal  kubernetes.docker.internal  TCP 626 trinity-dist(4711) → 11312 [PSH, ACK] Seq=1 Ack=347 Win=2619648 Len=582
7   0.023838    kubernetes.docker.internal  kubernetes.docker.internal  TCP 44  11312 → trinity-dist(4711) [ACK] Seq=347 Ack=583 Win=2619136 Len=0
8   0.025151    kubernetes.docker.internal  kubernetes.docker.internal  TCP 124 trinity-dist(4711) → 11312 [PSH, ACK] Seq=583 Ack=347 Win=2619648 Len=80
9       0.025171    kubernetes.docker.internal  kubernetes.docker.internal  TCP 44  11312 → trinity-dist(4711) [ACK] Seq=347 Ack=663 Win=2619136 Len=0
10  0.025626    kubernetes.docker.internal  kubernetes.docker.internal  TCP 643 trinity-dist(4711) → 11312 [PSH, ACK] Seq=663 Ack=347 Win=2619648 Len=599
11  0.025649    kubernetes.docker.internal  kubernetes.docker.internal  TCP 44  11312 → trinity-dist(4711) [ACK] Seq=347 Ack=1262 Win=2618368 Len=0
12  0.053768    kubernetes.docker.internal  kubernetes.docker.internal  TCP 400 11312 → trinity-dist(4711) [PSH, ACK] Seq=347 Ack=1262 Win=2618368 Len=356
13  0.053800    kubernetes.docker.internal  kubernetes.docker.internal  TCP 44  trinity-dist(4711) → 11312 [ACK] Seq=1262 Ack=703 Win=2619392 Len=0
14  0.058389    kubernetes.docker.internal  kubernetes.docker.internal  TCP 338 11312 → trinity-dist(4711) [PSH, ACK] Seq=703 Ack=1262 Win=2618368 Len=294
15  0.058415    kubernetes.docker.internal  kubernetes.docker.internal  TCP 44  trinity-dist(4711) → 11312 [ACK] Seq=1262 Ack=997 Win=2619136 Len=0
16  0.062129    kubernetes.docker.internal  kubernetes.docker.internal  TCP 486 11312 → trinity-dist(4711) [PSH, ACK] Seq=997 Ack=1262 Win=2618368 Len=442
17  0.062173    kubernetes.docker.internal  kubernetes.docker.internal  TCP 44  trinity-dist(4711) → 11312 [ACK] Seq=1262 Ack=1439 Win=2618624 Len=0

package No. 10 is the last response send from netcoredbg.

Content-Length: 576 

{"body":{"exceptionBreakpointFilters":[{"filter":"all","label":"all"},{"filter":"user-unhandled","label":"user-unhandled"}],"supportTerminateDebuggee":true,"supportsCancelRequest":true,"supportsConditionalBreakpoints":true,"supportsConfigurationDoneRequest":true,"supportsExceptionFilterOptions":true,"supportsExceptionInfoRequest":true,"supportsExceptionOptions":false,"supportsFunctionBreakpoints":true,"supportsSetExpression":true,"supportsSetVariable":true,"supportsTerminateRequest":true},"command":"initialize","request_seq":1,"seq":"3","success":true,"type":"response"}

packages No.12, 14, 16 is not processed by netcoredbg. package details are below: No.12

Content-Length: 333 

{"seq":2,"type":"request","command":"setBreakpoints","arguments":{"source":{"name":"CollectionTest.cs","path":"C:\\Users\\JiangZhen\\source\\repos\\ConsoleApp49\\ConsoleApp49\\CollectionTest.cs"},"breakpoints":[{"line":62,"column":17},{"line":90,"column":13},{"line":133,"column":9},{"line":155,"column":9},{"line":180,"column":3}]}}

No.14

Content-Length: 271 

{"seq":3,"type":"request","command":"launch","arguments":{"program":"C:\\Users\\JiangZhen\\source\\repos\\ConsoleApp49\\ConsoleApp1\\bin\\Debug\\net6.0\\ConsoleApp1.exe","cwd":"C:\\Users\\JiangZhen\\source\\repos\\ConsoleApp49\\ConsoleApp1\\bin\\Debug\\net6.0","env":{}}}

No.16

Content-Length: 419 

{"seq":4,"type":"request","command":"setExceptionBreakpoints","arguments":{"filters":["user-unhandled"],"filterOptions":[{"filterId":"all","condition":"System.NullReferenceException"},{"filterId":"all","condition":"System.Reflection.MissingMetadataException"},{"filterId":"all","condition":"System.Reflection.MissingRuntimeArtifactException"},{"filterId":"all","condition":"System.Windows.Markup.XamlParseException"}]}}
alpencolt commented 2 years ago

@fenixjiang command look right I've found old discussion https://alt.winsock.programming.narkive.com/dJgOGTYa/iocp-readfile-strange-error-error-working-set-quota Most likely reason of ERROR_WORKING_SET_QUOTA is some limitation on the system.

0xfk0 commented 2 years ago

Please take a look at this question on stackoverflow: https://stackoverflow.com/questions/3442385/calls-to-readfile-return-error-working-set-quota

The problem is clearly described above in my comment from Oct 2021: _"Look strange, as ERROR_WORKING_SETQUOTA error, which is caused by multiple calls to ReadFile without calling GetOverlappedResult (which you have added). I suspect, that GetOverlappedResult must be called every time, even if ReadFile returns True."

fenixjiang commented 2 years ago

From the very beginning, I modified the code according to kfrolov's suggestion to solve the communication problem in VSCode mode, so far it is running well, but I don't know if these modifications are the best practice.

Hereis my modifications:

// Function perform reading from the file: it may read up to `count' bytes to `buf'.
Class::IOResult Class::read(const FileHandle& fh, void *buf, size_t count)
{
    //DWORD dwRead = 0;
    //OVERLAPPED ov = {};
    //if (! ReadFile(fh.handle, buf, (DWORD)count, &dwRead, &ov))
        //return { (GetLastError() == ERROR_IO_PENDING ? IOResult::Pending : IOResult::Error), dwRead };
    //else
        //return { (dwRead == 0 ? IOResult::Eof : IOResult::Success), dwRead };

    DWORD dwRead = 0;
    OVERLAPPED ov = {};
    ov.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

    if (!ReadFile(fh.handle, buf, (DWORD)count, 0, &ov))
    {
    if (GetLastError() == ERROR_IO_PENDING)
    {
        WaitForSingleObject(ov.hEvent, INFINITE);

        CloseHandle(ov.hEvent);

        if (GetOverlappedResult(fh.handle, &ov, &dwRead, TRUE))
        {
            DWORD err = GetLastError();
            if ( err == ERROR_IO_PENDING
                || err == WAIT_TIMEOUT
                || err == ERROR_IO_INCOMPLETE)
            {
                return { dwRead == 0? IOResult::Pending : IOResult::Success, dwRead };
            }
            else
                return { (dwRead == 0 ? IOResult::Eof : IOResult::Success), dwRead };
        }
        else
        {
            DWORD error = GetLastError();

            return { ( error== ERROR_IO_PENDING || error == ERROR_IO_INCOMPLETE || error == WAIT_TIMEOUT ? IOResult::Pending : IOResult::Error), dwRead };
        }
    }
    else
    {
        return { IOResult::Eof, dwRead };
    }
}
else
{
    return { (ov.InternalHigh == 0 ? IOResult::Eof : IOResult::Success), ov.InternalHigh };
}   

}