pkulchenko/MobDebug

IntelliJ IDEA + EmmyLua + mobdebug = very unstable handshake

Opened this issue · 4 comments

Version: 0.8
When initiating debug most of times (but not 100%, maybe in 1% it works fine), it looks like this:

Start mobdebug server at port:8172
Waiting for process connection...
Connected.

And then nothing happens. Execution point is not showed in source code. As if handshake is not passed.

Investigated, discovered with Wireshark that "DELB * 0\n" command is sent by server-side into the app.
But call to server:receive() in debugger_loop never returns.
netstat showed that app read everything from network.

lldb to lua client process shows that somebody calls receive(1) before debugger_loop does that and steals bytes from incoming request.

Search in source code shows that :receive(1) only here:
https://github.com/pkulchenko/MobDebug/blob/0.80/src/mobdebug.lua#L489

If I comment that line out, handshake always passes OK.

I assume that is_pending mechanism

  • should not be invoked at the very beginning, when handshake is not passed;
  • or it is broken completely? I don't get it what good would stealing 1 character from server->client stream could do. But then I could be stupid ;)

Пользуясь случаем, огромное спасибо за замечательную работу, пользуемся каждый день много лет!

Investigated, discovered with Wireshark that "DELB * 0\n" command is sent by server-side into the app.
But call to server:receive() in debugger_loop never returns.
netstat showed that app read everything from network.

lldb to lua client process shows that somebody calls receive(1) before debugger_loop does that and steals bytes from incoming request.

Search in source code shows that :receive(1) only here:
https://github.com/pkulchenko/MobDebug/blob/0.80/src/mobdebug.lua#L489

If I comment that line out, handshake always passes OK.

I assume that is_pending mechanism

  • should not be invoked at the very beginning, when handshake is not passed;
  • or it is broken completely? I don't get it what good would stealing 1 character from server->client stream could do. But then I could be stupid ;)

Thanks for supercool module, we're using it a lot and are very happy!

lldb to lua client process shows that somebody calls receive(1) before debugger_loop does that and steals bytes from incoming request.

Correct, but it should add the read byte back to the line inside handle_breakpoint or in the debugger_loop.

Also, stealing one character shouldn't affect server:receive("*l") in debugger_loop, as it reads everything up to an end-of-line (it may not do anything useful if the command is incorrect, but will still read something). It will block though if there is nothing to read or if it doesn't get EOL.

It looks like it's not working for you in some of the cases, but it's not quite clear what is different about those cases. I can't reproduce this issue, but would be curious to explore it further to see what may be influencing it.

Can you try capturing the exact protocol (request/response messages) when it works and when it doesn't work? Since the sequence of calls (including is_pending) is the same every time, something is different in those cases when things don't work, so it would help to know what exactly.

Thanks, Paul, for your curiosity!
I'm not sure how to help here.
What I see in Wireshark in bad case is that

DELB * 0\n

Was sent by debugger.

In normal cases (rare) we get

200 OK\n

Reply.

In bad cases we see no reply, and app hangs.
lldb in C world shows buffer_meth_receive calling recvraw with size of 1.

I've tried wrapping call to receive("*l) with print statements of "before" and "after".
I see "before", and, when it hangs, there is no "after".

My current understanding is that it can't

return from that receive to "add the read byte back to the line inside "in the debugger loop".

So at some point we have

  • stolen D
  • stolen E
  • L
  • B
  • space
  • *
  • space
  • 0
  • newline

And then control comes to receive("*l")

  • it peacefully awaits for input
  • + While debugger likewise peacefully awaits for "200 OK"
  • = DEADLOCK.

Currently if I just comment out that line, handshake ALWAYS works for me.
But I feel that commenting out might break some other important use-cases.

I'm open for any additional investigation if need be, Pavel