svaarala / duktape

Duktape - embeddable Javascript engine with a focus on portability and compact footprint
MIT License
5.96k stars 516 forks source link

Column-level breakpoints? #591

Open harold-b opened 8 years ago

harold-b commented 8 years ago

Would it be even close to non-trivial to add column-level breakpoints?

In context, I'm asking because it would be nice to be able to debug transpiled and minified scripts, whilst having the source map on the debug client.

That is, in order to do something like: DebugClient > SetBreakpointAt( line ) > GetOutputPositionFromSourceMap( line ) > SendSetBreakpointToDuktape( file, line, column )

Would this be feasible at all?

Thanks

svaarala commented 8 years ago

Just from a feasibility perspective, it would need:

Another solution to the original problem would be source map support so that the "pc2line" information of a function would actually reflect the source map rather than the literal source. This would also mean tracebacks would point to pre-source-map lines.

harold-b commented 8 years ago

Thanks for the prompt reply and thorough response.

Well, I'm actually surprised that it's much simpler than I thought. I gather from your list that the most complicated task would be having the executor take into account the column when triggering breaks.

I understand your concern over breaking the debug protocol. Perhaps adding the column, or column range, could simply be added as optional parameters after the line dvalue. The target can simply take it to mean as the first column if it's missing, which would keep existing clients working correctly.

My current implementation is working great with the typescript transpiled code + source map, since the typescript output allows is pretty clean, column-wise. But it would be great going forward to have the ability to debug minified source. Especially since I plan on deploying larger amounts of code over the network on devices ( hot-reloading games ), so I wanted to see what your thoughts were on this.

From my perspective I would prefer having sourcemaps being on the client-side since I'd rather keep all debug data on locally. Though I see your point. :)

I'm really enjoying working with duktape and implementing the debugger. Thank you for the awesome library! :+1:

harold-b commented 8 years ago

Oh I wanted to mention a bug I came across while implementing the debugger:

I'm using v1.40, there's a sneaky bug that happens sometimes where duktape get's stuck in an infinite loop trying to read data when the connection has been dropped. This seems to be happening only in cases where the read callback fails for any erroneous reason. That is, when I do a clean detach it it doesn't occur. I've been trying to isolate it to create a repro case but, haven't been able to yet. I'll see if I can trap it.

The other thing is, I noticed that the callstack response message seems to return 0-length strings for prototype functions. Any global object functions return the full name, but any function object assigned to a prototype object returns with a 0-length string. Any functions that are global on top of prototype functions return the name correctly. Any remedy for this?

svaarala commented 8 years ago

To clarify, the read callback returns 0 to indicate a read error, and Duktape will then keep on calling it? That would be a pretty clear bug in Duktape as a zero error return is used to indicate a transport failure and Duktape should then never call the read/write callbacks again.

Re: prototype functions, are you referring to something like this?

MyObject.prototype.foo = function () {
    // ...
};

If so, that function is indeed anonymous: it's a function expression with no name and gets assigned to an object. However, the function expression is unaware of that assignment so doesn't "inherit" the name. The usual fix is to add a name (probably the same as the assigned key) for the function expression:

MyObject.prototype.foo = function foo() {
    // ...
};
svaarala commented 8 years ago

Nice to hear you've enjoyed working with the debugger stuff :) It has been one of the more difficult design issues because it needs to work in very low memory targets, and because it needs to abstract away any physical transport to remain flexible with respect to very different targets. Sometimes that's been frustrating when getting started because the user needs to implement an abstract transport provider etc.

At some point there's going to be a design iteration on the transport and dvalue encoding, I might poll you then for opinions on which way to go if that's OK :-)

harold-b commented 8 years ago

Yes it's returning zero and it keeps calling it. If I recall when I was tracking the bug, it enters a function that flags itself for detachment to prevent re-entry. But somehow it never does the actual detaching, so it never clears the flag and it keeps trying to read from the callback. I'll continue trying to trigger it and see if can get it isolated.

About the prototype functions, I thought that might be the case! Typescript generates them as in your first examples. I had a quick look at tsc compiler options but I don't think it supports emitting a name for them. Bummer, but I'll take what I can get. It's not like can't see the function name on the source at least.

I found your dvalue transport quite elegant! I'll gladly provide any output once you're considering the next iteration.

svaarala commented 8 years ago

The detach processing is actually delayed on purpose to a later point in code - this is to allow the detached callback to immediately reattach without messing up the debugger state. So basically everything is torn down and when the detached callback is finally called, it can process an attach without issues.

The downside of this is that there's a section of code which runs in "detach pending" mode. I'll give it a read through if I can isolate the problem. Any clues to what use case triggers it? :)

harold-b commented 8 years ago

Yes usually seems to do it when stopped on a breakpoint and closing the connection abruptly. I disconnect the debugger abruptly like that, reconnect and repeat, and after a few tries it seems to trigger it.

It then get's stuck attempting to read and attempting to do duk__debug_do_detach1() via DUK__SET_CONN_BROKEN() but heap->dbg_detaching is already set, so it returns immediately, whilst cb's remain uncleared. It then continues on to duk__debug_process_message() and repeats.

svaarala commented 8 years ago

Thanks, that's probably enough to pinpoint the issue.

Looking at the code dbg_detaching = 1 is only done in duk__debug_do_detach1() and when that's done for the first time it should always also clear the read callback: https://github.com/svaarala/duktape/blob/master/src/duk_debugger.c#L46-L59. So I'm not yet sure how this situation could happen.

svaarala commented 8 years ago

Could you try -DDUK_OPT_DEBUG + -DDUK_OPT_DPRINT + -DDUK_OPT_DDPRINT when reproducing the issue? The debug log might give a clue :)

harold-b commented 8 years ago

Hmm I had wrongly assumed there was another place dbg_detaching was being changed, since it was protected from re-entry. That means I'm probably messing it up on my end.

Hold off on looking into this any further lest I waste your time. I'll take a look tomorrow to find out the issue and report back.

harold-b commented 8 years ago

Well I got up eager to find out what the issue was. I couldn't find anything that seemed wrong on my side, I thought maybe I was making some odd call to duktape or something out of place but it all seemed in order.

I managed to get the bug to happen twice again, seemingly arbitrarily when forcefully disconnecting while it's on the paused state. I tried to get it to happen again after adding a stacktrace sump function for the first time it happened, because I wanted to see if it ever returned to my side after the first failed call to the read callback. But I've been trying to trigger it for a while and it's not happening =/. Even when removing the stackdump func, just int case.

In the 2 times that it happened, I never got a call to the detached callback. Here's what I could capture from the log :

[DD] duk_debugger.c:1890 (duk_debug_process_messages): top at loop top: 3
[D] duk_debugger.c:1902 (duk_debug_process_messages): paused, process debug message, blocking if necessary
receive OK
receive OK
receive OK
receive OK     // This logs are on my side, whenever the read callback succeeds.
[DD] duk_hobject_props.c:867 (duk__realloc_props): resized hobject 00AD2438 props (0 -> 42 bytes), from {p=NULL,e_size=0,e_next=0,a_size=0,h_size=0} to {p=00AD1E08,e_size=2,e_next=0,a_size=0,h_size=0}, abandon_array=0, unadjusted new_e_size=2
[DD] duk_hobject_props.c:867 (duk__realloc_props): resized hobject 00AD2438 props (42 -> 84 bytes), from {p=00AD1E08,e_size=2,e_next=2,a_size=0,h_size=0} to {p=00A95378,e_size=4,e_next=2,a_size=0,h_size=0}, abandon_array=0, unadjusted new_e_size=4
[DD] duk_hobject_props.c:1064 (duk_hobject_compact_props): compacting hobject, used e keys 3, used a keys 0, min a size 0, resized array density would be: 0/0 = -nan(ind)
[DD] duk_hobject_props.c:1073 (duk_hobject_compact_props): decided to keep array during compaction
[DD] duk_hobject_props.c:1088 (duk_hobject_compact_props): compacting hobject -> new e_size 3, new a_size=0, new h_size=0, abandon_array=0
[DD] duk_hobject_props.c:867 (duk__realloc_props): resized hobject 00AD2438 props (84 -> 63 bytes), from {p=00A95378,e_size=4,e_next=3,a_size=0,h_size=0} to {p=00AC0F78,e_size=3,e_next=3,a_size=0,h_size=0}, abandon_array=0, unadjusted new_e_size=3
[DD] duk_hobject_props.c:3673 (duk_hobject_putprop): put to existing own plain property, property is writable
[DD] duk_hobject_props.c:3762 (duk_hobject_putprop): put to an existing entry at index 1 -> new value 3
[DD] duk_hobject_props.c:3673 (duk_hobject_putprop): put to existing own plain property, property is writable
[DD] duk_hobject_props.c:3762 (duk_hobject_putprop): put to an existing entry at index 1 -> new value 3
[DD] duk_heap_refcount.c:265 (duk__refzero_free_pending): refzero processing 00AD2438: {game/9:true}
receive OK   // The last valid receive

[DD] duk_debugger.c:1890 (duk_debug_process_messages): top at loop top: 3
[D] duk_debugger.c:1902 (duk_debug_process_messages): paused, process debug message, blocking if necessary
debug read failed, ret == 0 (EOF), closing connection    // First time the call fails

[D] duk_debugger.c:253 (duk_debug_read_bytes): connection error during read, return zero data
[D] duk_debugger.c:1783 (duk__debug_process_message): invalid initial byte, drop connection: 0
[DD] duk_debugger.c:1890 (duk_debug_process_messages): top at loop top: 3
[D] duk_debugger.c:1902 (duk_debug_process_messages): paused, process debug message, blocking if necessary
debug read failed, ret == 0 (EOF), closing connection // Here it attempts to call it again, even though it failed the first time
                                                      //  the detach callback logs when it detaches, and it was never called.

And here's the stack trace at that point. Keep in mind that I'm not sure if it return control over to my side after the first time it failed the read callback. So I don't know if it looped over again, and handled over control to duktape once more, if that's possible.

DuktapeTest.exe!DbgSocketRead(void * udata=0x0015ca3c, char * buffer=0x004bd6ab, unsigned int length=1) Line 487    C++
    DuktapeTest.exe!duk_debug_read_bytes(duk_hthread * thr=0x00aa5ba0, unsigned char * data=0x004bd6ab, unsigned int length=1) Line 250 C
    DuktapeTest.exe!duk_debug_read_byte(duk_hthread * thr=0x00aa5ba0) Line 269  C
    DuktapeTest.exe!duk__debug_process_message(duk_hthread * thr=0x00aa5ba0) Line 1686  C
    DuktapeTest.exe!duk_debug_process_messages(duk_hthread * thr=0x00aa5ba0, int no_block=0) Line 1905  C
    DuktapeTest.exe!duk__interrupt_handle_debugger(duk_hthread * thr=0x00aa5ba0, int * out_immediate=0x004bdb04, unsigned int * out_interrupt_retval=0x004bdaf8) Line 1624  C
    DuktapeTest.exe!duk__executor_interrupt(duk_hthread * thr=0x00aa5ba0) Line 1742 C
    DuktapeTest.exe!duk__js_execute_bytecode_inner(duk_hthread * entry_thread=0x00aa5ba0, unsigned int entry_callstack_top=1) Line 2313 C
    DuktapeTest.exe!duk_js_execute_bytecode(duk_hthread * exec_thr=0x00aa5ba0) Line 2068    C
    DuktapeTest.exe!duk__handle_call_inner(duk_hthread * thr=0x00aa5ba0, int num_stack_args=0, unsigned int call_flags=0, int idx_func=2) Line 1580 C
    DuktapeTest.exe!duk_handle_call_protected(duk_hthread * thr=0x00aa5ba0, int num_stack_args=0, unsigned int call_flags=0) Line 1062  C
    DuktapeTest.exe!duk_pcall(duk_hthread * ctx=0x00aa5ba0, int nargs=0) Line 134   C
    DuktapeTest.exe!MainLoop() Line 325 C++
    DuktapeTest.exe!main(int argc=1, const char * * argv=0x00a9e848) Line 208   C++
    DuktapeTest.exe!invoke_main() Line 74   C++
    DuktapeTest.exe!__scrt_common_main_seh() Line 264   C++
    DuktapeTest.exe!__scrt_common_main() Line 309   C++
    DuktapeTest.exe!mainCRTStartup() Line 17    C++
    kernel32.dll!7694336a() Unknown

I'll keep looking an see what I can find. Still not sure where the issue lies. But please have a look at the log to see if there's anything that jumps out to you. I'll keep looking where I've might have messed up.

svaarala commented 8 years ago

I'll look at this in detail tomorrow. What should happen is that once the error has occurred, we might try to dispatch one more message. When the transport is already "broken" the internal read calls will just keep on returning zero bytes to make error handling easier. This should lead to a harmless second call to the "detach1" handler which should be ignored because we're already detaching.

The debug message should exit on the next loop round because there's an explicit check for read_cb being NULL: https://github.com/svaarala/duktape/blob/master/src/duk_debugger.c#L1893-L1895.

Two just-in-case questions:

harold-b commented 8 years ago

To answer your questions: No on both accounts. This is how the main loop looks, very simple:

void MainLoop()
{
    for(;;)
    {
        // Check for new client
        if( _dbgSocket == 0 )
        {
            // Non-blocking call on the listener socket to check if a new client has connected
            DbgTryAcceptClient();

            // If a new client has in-fact connected, then we attach the debugger
            if( _dbgSocket != 0 )
            {
                duk_debugger_attach( cx,
                    DbgSocketRead      ,
                    DbgSocketWrite     ,
                    DbgSocketPeek      ,
                    DbgSocketReadFlush ,
                    DbgSocketWriteFlush,
                    DbgDetached, (void*)&_dbgData ); 
            }
        }

        if( _dbgSocket != 0 )
            duk_debugger_cooperate( cx );

        // Run Update func on the script
        duk_get_prop_string( cx , -1, "Update" );

        if (duk_pcall(cx, 0) != 0 )
            errorExit( );

        duk_pop( cx );  // pop result/error

        Sleep( 50 );
    }
}

DbgDetached(), the detachment callback simply calls closesocket() and nullifies the descriptor, logs it, and returns.

The read callback is taken from your transport layer code so its basically the same. Only added a call to dump the stack now upon failure( Which I haven't managed to hit yet). No other calls are made.

The other calls to "detach1" are certainly returning upon the re-entry check, but I don't know how it's getting marked before clearing it the first time. This is what has me baffled. I was assuming i had a buffer overrun on my calls somewhere, but I can't seem to find anything. But I'd figure something else must be corrupted if that were the case...

svaarala commented 8 years ago

Ok, I'll give the code paths a thorough read through tomorrow.

One thing that jumps out is that after the first read there's the log message "connection error during read, return zero data", which should be followed by DUK__SET_CONN_BROKEN() which calls into duk__debug_do_detach1().

Assuming heap->dbg_detaching == 0 at this stage, we should see:

DUK_D(DUK_DPRINT("debugger transport detaching, marking transport broken"));

But this is absent from your log which is baffling given that:

$ grep 'detaching =' src/*
src/duk_debugger.c: heap->dbg_detaching = 1;  /* prevent multiple in-progress detaches */
src/duk_debugger.c: heap->dbg_detaching = 0;

In other words, the only way to avoid that log message should be if heap->dbg_detaching != 0 and the only site where that is set is inside duk__debug_do_detach1().

fatcerberus commented 8 years ago

Is it possible one of the callbacks is throwing an error? You brought up in #596 that that's a potential issue.

svaarala commented 8 years ago

Unless the callbacks call into the Duktape API (which is forbidden for the read callback) no errors can be thrown as far as Duktape is concerned.

harold-b commented 8 years ago

In other words, the only way to avoid that log message should be if heap->dbg_detaching != 0 and the only site where that is set is inside duk__debug_do_detach1().

Yes, this is why I think I corrupted something somewhere... Still trying to track though.

I just managed to trigger it again, it never returns control to me once I hand off work to duk_pcall(). As you mention the actual detachment and nullifying of callbacks didn't happen. But no other info other than that. I couldn't tell how it was changed. I set up a data breakpoint on dbg_detaching, but now it won't trigger the bug!

I'm gonna keep trying...

harold-b commented 8 years ago

Well, doesn't seem to wan't to show up once I set the data breakpoint =/.

I honestly don't know where this is happening. This is a mock setup for the debug client so the application is very simple. It's just initialization, the loop I posted and the callbacks. All I'm doing is logging.

And the duk_heap's dbg_detaching is reasonably deep in the structure, so if I were corrupting some data due to an overrun it seems I would have messed up other stuff. Also, the value ofdbg_detaching is always 1 when this happens, no funny values.

There seems to be no easy way to reproduce it either. It just seems to happen when the target is in a paused state and i forcibly drop the connection. But even in those cases, it happens randomly.

I'll continue working normally, I'll report any more findings I come across.

fatcerberus commented 8 years ago

Something is definitely going horribly wrong here:

[D] duk_debugger.c:253 (duk_debug_read_bytes): connection error during read, return zero data
[D] duk_debugger.c:1783 (duk__debug_process_message): invalid initial byte, drop connection: 0

Relevant Duktape code:

            DUK_D(DUK_DPRINT("connection error during read, return zero data"));
            DUK__SET_CONN_BROKEN(thr, 1);

DUK__SET_CONN_BROKEN (and therefore duk__debug_do_detach1()) is called immediately after logging the read error, however the log indicates it's not called and the very next entry is "invalid initial byte: 0". It makes no sense whatsoever.

harold-b commented 8 years ago

Something is definitely going horribly wrong here:

Indeed! But I can't see how it's occurring. duk__debug_do_detach1 doesn't have any preemptive returns before clearing the callbacks, which would cause it to lock itself in. So I don't get it.

Now that I set the hardware breakpoints on dbg_detaching, it won't happen. =/

I swear it must be something stupid I'm doing somewhere...

fatcerberus commented 8 years ago

@svaarala It looks like there's definitely something screwy going on with the detach handling. I did some testing using minisphere and SSJ; I couldn't reproduce @harold-b's infinite loop, but did notice some very bad misbehavior when re-attaching in the detach callback. Annotated log:

[D] duk_debugger.c:2159 (duk_debug_process_messages): processing debug message, peek indicated no data, stop processing
[D] duk_debugger.c:2164 (duk_debug_process_messages): paused, process debug message, blocking if necessary
[D] duk_debugger.c:2164 (duk_debug_process_messages): paused, process debug message, blocking if necessary

# Here I Ctrl+C'd out of SSJ to forcibly drop the connection.

[D] duk_debugger.c:255 (duk_debug_read_bytes): connection error during read, return zero data
[D] duk_debugger.c:44 (duk__debug_do_detach1): debugger transport detaching, marking transport broken
[D] duk_debugger.c:2113 (duk__debug_process_message): invalid initial byte, drop connection: 0
[D] duk_debugger.c:104 (duk__debug_do_detach2): detached during message loop, delayed call to detached_cb

# I then started SSJ again and reattached...

[D] duk_debugger.c:2164 (duk_debug_process_messages): paused, process debug message, blocking if necessary
[D] duk_debugger.c:1427 (duk__debug_handle_eval): debug command Eval
[D] duk_debugger.c:2164 (duk_debug_process_messages): paused, process debug message, blocking if necessary
[D] duk_debugger.c:2164 (duk_debug_process_messages): paused, process debug message, blocking if necessary

# ...and executed `e pig` in SSJ, causing a ReferenceError:

[D] duk_debugger.c:1427 (duk__debug_handle_eval): debug command Eval
[D] duk_error_misc.c:105 (duk_err_setup_heap_ljstate): throw with debugger attached, report to client
[D] duk_error_misc.c:116 (duk_err_setup_heap_ljstate): throw will be fatal, halt before longjmp
[D] duk_debugger.c:2164 (duk_debug_process_messages): paused, process debug message, blocking if necessary
[D] duk_debugger.c:2113 (duk__debug_process_message): invalid initial byte, drop connection: 0
[D] duk_debugger.c:44 (duk__debug_do_detach1): debugger transport detaching, marking transport broken
[D] duk_debugger.c:104 (duk__debug_do_detach2): detached during message loop, delayed call to detached_cb

# For whatever reason, minisphere didn't attempt to reattach and so shut itself down
# as it was started with the --debug switch:

[D] duk_heap_alloc.c:276 (duk_heap_free): free heap: 000001CA154B87F0
[D] duk_debugger.c:44 (duk__debug_do_detach1): debugger transport detaching, marking transport broken

# That last one shouldn't have happened, because it already marked it broken above!
fatcerberus commented 8 years ago

Looking through that log again, I notice another issue: e pig not only triggered a Throw notify, but a nested pause(!). That's not supposed to happen anymore, and indeed normally doesn't--until after I've reattached from inside the detach callback.

fatcerberus commented 8 years ago

@harold-b You mention it happens when execution is paused. Is it perhaps dependent on the way in which Duktape became paused, i.e., via a breakpoint vs. a debugger statement?

harold-b commented 8 years ago

@harold-b You mention it happens when execution is paused. Is it perhaps dependent on the way in which Duktape became paused, i.e., via a breakpoint vs. a debugger statement?

It was with breakpoints. Usually I placed a breakpoint, removed it ( while still paused ), and forcibly closed the connection. And that is how it usually triggered. There may have been occasions where I simply paused the execution, I don't recall, but it certainly happened with the breakpoints.

It happened pretty often 2 days ago. But as for today and yesterday, I'm having a hard time triggering it. No idea whats going on.

fatcerberus commented 8 years ago

No idea either, but I suspect #597 (which I can reproduce on command) is related.

harold-b commented 8 years ago

I've been trying to reproduce this again... And something is definitely happening... I haven' been able to get it properly locked in the read loop as before, but now I got it to detach, set dbg_detaching = 1, clear the callbacks, returns control to me but never clears debug detaching to zero. This is also confirmed by the hardware breakpoint, it was only hit once when it was set to one, but it's never being hit when clearing it to zero. Pausing the execution I can see that dbg_detaching is indeed still set to 1, even though the callbacks are cleared.

I'll post a log in a little bit as I sort some things out.

svaarala commented 8 years ago

I found one issue which happens when (1) Duktape is running (not paused) and (2) the bytecode executor writes a periodic Status notify and (3) that write fails. This causes Duktape to execute "detach1" but never to execute "detach2". I'll verify a possible fix and push in around 10-15 minutes, see #599. It'd be nice if you could then check if that's also the root cause for your issue.

harold-b commented 8 years ago

Sorry I had to step away from the computer for a moment, here I am now. I'll have a look at #599 and report back with the behavior.

As for what I just mentioned a moment ago, here's the log just in case. I haven't followed to closely the conversation on #599 yet so I'm not sure if this is pertinent to it, but here's the log of what happened this time. What triggered it was pausing on a breakpoint, hitting play to resume execution, and removing the breakpoint quickly then forcibly shutting down the connection.

Usually when I close the connection it very quickly hits the data breakpoint for setting dbg_detached, but when this happened, it took a moment spewing a lot of log data before hitting the hardware breakpoint setting dbg_detached to 1 @ https://github.com/svaarala/duktape/blob/master/src/duk_debugger.c#L46.

But https://github.com/svaarala/duktape/blob/master/src/duk_debugger.c#L106 was never hit.

It clears the callbacks, but never clears dbg_detached, it continues executing the main loop over and over without allowing me to reconnect again, since debug detached is never called and the socket is assumed to be "alive". Here's the log:


// Last set of succesful recceive callbacks
receive OK

[DD] duk_debugger.c:1890 (duk_debug_process_messages): top at loop top: 5
[D] duk_debugger.c:1902 (duk_debug_process_messages): paused, process debug message, blocking if necessary

receive OK
receive OK

[D] duk_debugger.c:1157 (duk__debug_handle_del_break): debug command DelBreak

receive OK
receive OK

[DD] duk_debugger.c:1890 (duk_debug_process_messages): top at loop top: 5
[D] duk_debugger.c:1902 (duk_debug_process_messages): paused, process debug message, blocking if necessary

receive OK
receive OK

[D] duk_debugger.c:1084 (duk__debug_handle_resume): debug command Resume

receive OK

[DD] duk_js_call.c:1936 (duk_handle_safe_call): duk_handle_safe_call: thr=008F5BA0, num_stack_args=1, num_stack_rets=1, valstack_top=8, idx_retbase=7, rec_depth=1/1000, entry_valstack_bottom_index=7, entry_callstack_top=2, entry_catchstack_top=0, entry_call_recursion_depth=1, entry_curr_thread=008F5BA0, entry_thread_state=2
[DD] duk_js_call.c:1936 (duk_handle_safe_call): duk_handle_safe_call: thr=008F5BA0, num_stack_args=1, num_stack_rets=1, valstack_top=9, idx_retbase=8, rec_depth=1/1000, entry_valstack_bottom_index=7, entry_callstack_top=2, entry_catchstack_top=0, entry_call_recursion_depth=1, entry_curr_thread=008F5BA0, entry_thread_state=2
[DD] duk_debugger.c:1890 (duk_debug_process_messages): top at loop top: 5

// Peek starts failing by first timing out, then with socket errors.
// we return 0 from the peek callback on both cases, but do not close the socket.
poll timed out
peek FAIL

[D] duk_debugger.c:1897 (duk_debug_process_messages): processing debug message, peek indicated no data, stop processing
[DD] duk_debugger.c:1932 (duk_debug_process_messages): top at exit: 5
[D] duk_js_executor.c:1652 (duk__interrupt_handle_debugger): processed debug messages, restart execution to recheck possibly changed breakpoints
[DD] duk_js_executor.c:1875 (duk__executor_recheck_debugger): ACTIVE BREAKPOINTS: 0
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 1, fun 0091C438,consts 00907E64, funcs 00907EA4, lev 1, regbot 7, regtop 12, catchstack_top=0, preventcount=1
[DD] duk_js_executor.c:2307 (duk__js_execute_bytecode_inner): dbg_force_restart flag forced restart execution
[DD] duk_js_executor.c:1875 (duk__executor_recheck_debugger): ACTIVE BREAKPOINTS: 0
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 1, fun 0091C438,consts 00907E64, funcs 00907EA4, lev 1, regbot 7, regtop 12, catchstack_top=0, preventcount=1
[DD] duk_js_executor.c:1678 (duk__executor_interrupt): execution interrupt, counter=0, init=1, instruction counts: executor=3613, interrupt=818
[DD] duk_hobject_props.c:3673 (duk_hobject_putprop): put to existing own plain property, property is writable
[DD] duk_hobject_props.c:3762 (duk_hobject_putprop): put to an existing entry at index 1 -> new value 118
[DD] duk_js_call.c:2402 (duk_handle_ecma_call_setup): handle_ecma_call_setup: thr=008F5BA0, num_stack_args=1, call_flags=0x00000000 (resume=0, tailcall=0), idx_func=2, idx_args=4, entry_valstack_bottom_index=7
[DD] duk_js_executor.c:1875 (duk__executor_recheck_debugger): ACTIVE BREAKPOINTS: 0
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 2, fun 0091C668,consts 008E468C, funcs 008E46AC, lev 2, regbot 11, regtop 16, catchstack_top=0, preventcount=1
[DD] duk_js_call.c:2402 (duk_handle_ecma_call_setup): handle_ecma_call_setup: thr=008F5BA0, num_stack_args=1, call_flags=0x00000000 (resume=0, tailcall=0), idx_func=2, idx_args=4, entry_valstack_bottom_index=11
[DD] duk_js_executor.c:1875 (duk__executor_recheck_debugger): ACTIVE BREAKPOINTS: 0
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 3, fun 0091C6D8,consts 009064A4, funcs 009064A4, lev 3, regbot 15, regtop 16, catchstack_top=0, preventcount=1
[DD] duk_js_executor.c:1414 (duk__handle_return): -> return not intercepted, restart execution in caller
[DD] duk_js_executor.c:1875 (duk__executor_recheck_debugger): ACTIVE BREAKPOINTS: 0
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 2, fun 0091C668,consts 008E468C, funcs 008E46AC, lev 2, regbot 11, regtop 16, catchstack_top=0, preventcount=1
[DD] duk_js_executor.c:1414 (duk__handle_return): -> return not intercepted, restart execution in caller
[DD] duk_js_executor.c:1875 (duk__executor_recheck_debugger): ACTIVE BREAKPOINTS: 0
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 1, fun 0091C438,consts 00907E64, funcs 00907EA4, lev 1, regbot 7, regtop 12, catchstack_top=0, preventcount=1
[DD] duk_js_executor.c:1414 (duk__handle_return): -> return not intercepted, restart execution in caller
[DD] duk_js_executor.c:1875 (duk__executor_recheck_debugger): ACTIVE BREAKPOINTS: 0
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 0, fun 0091C0B8,consts 00919B4C, funcs 00919B6C, lev 0, regbot 4, regtop 7, catchstack_top=0, preventcount=1
[DD] duk_js_executor.c:1678 (duk__executor_interrupt): execution interrupt, counter=0, init=17, instruction counts: executor=3630, interrupt=835
[DD] duk_heap_misc.c:69 (duk_heap_switch_thread): switch thread, new thread is NULL, no interrupt counter changes
[DD] duk_js_call.c:1723 (duk__handle_call_inner): returning with debugger enabled, force interrupt

Will Call duk_debugger_cooperate()

[DD] duk_debugger.c:1884 (duk_debug_process_messages): top at entry: 2
[DD] duk_debugger.c:1890 (duk_debug_process_messages): top at loop top: 2

poll timed out
peek FAIL

[D] duk_debugger.c:1897 (duk_debug_process_messages): processing debug message, peek indicated no data, stop processing
[DD] duk_debugger.c:1932 (duk_debug_process_messages): top at exit: 2

Will call duk_pcall()

[DD] duk_js_call.c:1047 (duk_handle_call_protected): duk_handle_call_protected: thr=008F5BA0, num_stack_args=0, call_flags=0x00000000 (ignorerec=0, constructor=0), valstack_top=4, idx_func=2, idx_args=4, rec_depth=0/1000, entry_valstack_bottom_index=0, entry_callstack_top=0, entry_catchstack_top=0, entry_call_recursion_depth=0, entry_curr_thread=NULL, entry_thread_state=1
[DD] duk_js_call.c:1201 (duk__handle_call_inner): duk__handle_call_inner: num_stack_args=0, call_flags=0x00000000, top=4
[DD] duk_js_call.c:1247 (duk__handle_call_inner): duk__handle_call_inner: thr=008F5BA0, num_stack_args=0, call_flags=0x00000000 (ignorerec=0, constructor=0), valstack_top=4, idx_func=2, idx_args=4, rec_depth=0/1000, entry_valstack_bottom_index=0, entry_callstack_top=0, entry_catchstack_top=0, entry_call_recursion_depth=0, entry_curr_thread=NULL, entry_thread_state=1
[DD] duk_heap_misc.c:53 (duk_heap_switch_thread): switch thread, initial entry, init default interrupt counter
[DD] duk_js_executor.c:1875 (duk__executor_recheck_debugger): ACTIVE BREAKPOINTS: 0
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 0, fun 0091C0B8,consts 00919B4C, funcs 00919B6C, lev 0, regbot 4, regtop 7, catchstack_top=0, preventcount=1
[DD] duk_js_executor.c:2307 (duk__js_execute_bytecode_inner): dbg_force_restart flag forced restart execution
[DD] duk_js_executor.c:1875 (duk__executor_recheck_debugger): ACTIVE BREAKPOINTS: 0
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 0, fun 0091C0B8,consts 00919B4C, funcs 00919B6C, lev 0, regbot 4, regtop 7, catchstack_top=0, preventcount=1
[DD] duk_js_executor.c:1678 (duk__executor_interrupt): execution interrupt, counter=0, init=0, instruction counts: executor=3631, interrupt=835
[DD] duk_js_call.c:2402 (duk_handle_ecma_call_setup): handle_ecma_call_setup: thr=008F5BA0, num_stack_args=0, call_flags=0x00000000 (resume=0, tailcall=0), idx_func=1, idx_args=3, entry_valstack_bottom_index=4
[DD] duk_js_executor.c:1875 (duk__executor_recheck_debugger): ACTIVE BREAKPOINTS: 0
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 1, fun 0091C438,consts 00907E64, funcs 00907EA4, lev 1, regbot 7, regtop 12, catchstack_top=0, preventcount=1
[DD] duk_hobject_props.c:3673 (duk_hobject_putprop): put to existing own plain property, property is writable
[DD] duk_hobject_props.c:3762 (duk_hobject_putprop): put to an existing entry at index 1 -> new value 119
[DD] duk_js_call.c:2402 (duk_handle_ecma_call_setup): handle_ecma_call_setup: thr=008F5BA0, num_stack_args=1, call_flags=0x00000000 (resume=0, tailcall=0), idx_func=2, idx_args=4, entry_valstack_bottom_index=7
[DD] duk_js_executor.c:1875 (duk__executor_recheck_debugger): ACTIVE BREAKPOINTS: 0
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 2, fun 0091C668,consts 008E468C, funcs 008E46AC, lev 2, regbot 11, regtop 16, catchstack_top=0, preventcount=1
[DD] duk_js_call.c:2402 (duk_handle_ecma_call_setup): handle_ecma_call_setup: thr=008F5BA0, num_stack_args=1, call_flags=0x00000000 (resume=0, tailcall=0), idx_func=2, idx_args=4, entry_valstack_bottom_index=11
[DD] duk_js_executor.c:1875 (duk__executor_recheck_debugger): ACTIVE BREAKPOINTS: 0
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 3, fun 0091C6D8,consts 009064A4, funcs 009064A4, lev 3, regbot 15, regtop 16, catchstack_top=0, preventcount=1
[DD] duk_js_executor.c:1414 (duk__handle_return): -> return not intercepted, restart execution in caller
[DD] duk_js_executor.c:1875 (duk__executor_recheck_debugger): ACTIVE BREAKPOINTS: 0
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 2, fun 0091C668,consts 008E468C, funcs 008E46AC, lev 2, regbot 11, regtop 16, catchstack_top=0, preventcount=1
[DD] duk_js_executor.c:1414 (duk__handle_return): -> return not intercepted, restart execution in caller
[DD] duk_js_executor.c:1875 (duk__executor_recheck_debugger): ACTIVE BREAKPOINTS: 0
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 1, fun 0091C438,consts 00907E64, funcs 00907EA4, lev 1, regbot 7, regtop 12, catchstack_top=0, preventcount=1
[DD] duk_js_executor.c:1414 (duk__handle_return): -> return not intercepted, restart execution in caller
[DD] duk_js_executor.c:1875 (duk__executor_recheck_debugger): ACTIVE BREAKPOINTS: 0
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 0, fun 0091C0B8,consts 00919B4C, funcs 00919B6C, lev 0, regbot 4, regtop 7, catchstack_top=0, preventcount=1
[DD] duk_js_executor.c:1678 (duk__executor_interrupt): execution interrupt, counter=0, init=28, instruction counts: executor=3659, interrupt=863
[DD] duk_heap_misc.c:69 (duk_heap_switch_thread): switch thread, new thread is NULL, no interrupt counter changes
[DD] duk_js_call.c:1723 (duk__handle_call_inner): returning with debugger enabled, force interrupt

Will Call duk_debugger_cooperate()

[DD] duk_debugger.c:1884 (duk_debug_process_messages): top at entry: 2
[DD] duk_debugger.c:1890 (duk_debug_process_messages): top at loop top: 2

poll timed out
peek FAIL

[D] duk_debugger.c:1897 (duk_debug_process_messages): processing debug message, peek indicated no data, stop processing
[DD] duk_debugger.c:1932 (duk_debug_process_messages): top at exit: 2

Will call duk_pcall()

// This output pattern occurrs a lot of times, until finally the next call to duk_pcall() outputs:

[DD] duk_js_call.c:1047 (duk_handle_call_protected): duk_handle_call_protected: thr=008F5BA0, num_stack_args=0, call_flags=0x00000000 (ignorerec=0, constructor=0), valstack_top=4, idx_func=2, idx_args=4, rec_depth=0/1000, entry_valstack_bottom_index=0, entry_callstack_top=0, entry_catchstack_top=0, entry_call_recursion_depth=0, entry_curr_thread=NULL, entry_thread_state=1
[DD] duk_js_call.c:1201 (duk__handle_call_inner): duk__handle_call_inner: num_stack_args=0, call_flags=0x00000000, top=4
[DD] duk_js_call.c:1247 (duk__handle_call_inner): duk__handle_call_inner: thr=008F5BA0, num_stack_args=0, call_flags=0x00000000 (ignorerec=0, constructor=0), valstack_top=4, idx_func=2, idx_args=4, rec_depth=0/1000, entry_valstack_bottom_index=0, entry_callstack_top=0, entry_catchstack_top=0, entry_call_recursion_depth=0, entry_curr_thread=NULL, entry_thread_state=1
[DD] duk_heap_misc.c:53 (duk_heap_switch_thread): switch thread, initial entry, init default interrupt counter
[DD] duk_js_executor.c:1875 (duk__executor_recheck_debugger): ACTIVE BREAKPOINTS: 0
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 0, fun 0091C0B8,consts 00919B4C, funcs 00919B6C, lev 0, regbot 4, regtop 7, catchstack_top=0, preventcount=1
[DD] duk_js_executor.c:2307 (duk__js_execute_bytecode_inner): dbg_force_restart flag forced restart execution
[DD] duk_js_executor.c:1875 (duk__executor_recheck_debugger): ACTIVE BREAKPOINTS: 0
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 0, fun 0091C0B8,consts 00919B4C, funcs 00919B6C, lev 0, regbot 4, regtop 7, catchstack_top=0, preventcount=1
[DD] duk_js_executor.c:1678 (duk__executor_interrupt): execution interrupt, counter=0, init=0, instruction counts: executor=6966, interrupt=4055
[DD] duk_js_call.c:2402 (duk_handle_ecma_call_setup): handle_ecma_call_setup: thr=008F5BA0, num_stack_args=0, call_flags=0x00000000 (resume=0, tailcall=0), idx_func=1, idx_args=3, entry_valstack_bottom_index=4
[DD] duk_js_executor.c:1875 (duk__executor_recheck_debugger): ACTIVE BREAKPOINTS: 0
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 1, fun 0091C438,consts 00907E64, funcs 00907EA4, lev 1, regbot 7, regtop 12, catchstack_top=0, preventcount=1
[DD] duk_hobject_props.c:3673 (duk_hobject_putprop): put to existing own plain property, property is writable
[DD] duk_hobject_props.c:3762 (duk_hobject_putprop): put to an existing entry at index 1 -> new value 234
[DD] duk_js_call.c:2402 (duk_handle_ecma_call_setup): handle_ecma_call_setup: thr=008F5BA0, num_stack_args=1, call_flags=0x00000000 (resume=0, tailcall=0), idx_func=2, idx_args=4, entry_valstack_bottom_index=7
[DD] duk_js_executor.c:1875 (duk__executor_recheck_debugger): ACTIVE BREAKPOINTS: 0
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 2, fun 0091C668,consts 008E468C, funcs 008E46AC, lev 2, regbot 11, regtop 16, catchstack_top=0, preventcount=1
[DD] duk_js_call.c:2402 (duk_handle_ecma_call_setup): handle_ecma_call_setup: thr=008F5BA0, num_stack_args=1, call_flags=0x00000000 (resume=0, tailcall=0), idx_func=2, idx_args=4, entry_valstack_bottom_index=11
[DD] duk_js_executor.c:1875 (duk__executor_recheck_debugger): ACTIVE BREAKPOINTS: 0
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 3, fun 0091C6D8,consts 009064A4, funcs 009064A4, lev 3, regbot 15, regtop 16, catchstack_top=0, preventcount=1
[DD] duk_js_executor.c:1414 (duk__handle_return): -> return not intercepted, restart execution in caller
[DD] duk_js_executor.c:1875 (duk__executor_recheck_debugger): ACTIVE BREAKPOINTS: 0
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 2, fun 0091C668,consts 008E468C, funcs 008E46AC, lev 2, regbot 11, regtop 16, catchstack_top=0, preventcount=1
[DD] duk_js_executor.c:1414 (duk__handle_return): -> return not intercepted, restart execution in caller
[DD] duk_js_executor.c:1875 (duk__executor_recheck_debugger): ACTIVE BREAKPOINTS: 0
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 1, fun 0091C438,consts 00907E64, funcs 00907EA4, lev 1, regbot 7, regtop 12, catchstack_top=0, preventcount=1
[DD] duk_js_executor.c:1414 (duk__handle_return): -> return not intercepted, restart execution in caller
[DD] duk_js_executor.c:1875 (duk__executor_recheck_debugger): ACTIVE BREAKPOINTS: 0
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 0, fun 0091C0B8,consts 00919B4C, funcs 00919B6C, lev 0, regbot 4, regtop 7, catchstack_top=0, preventcount=1
[DD] duk_js_executor.c:1678 (duk__executor_interrupt): execution interrupt, counter=0, init=28, instruction counts: executor=6994, interrupt=4083

// Starts reporting write failures
debug write failed, closing connection: 

[D] duk_debugger.c:572 (duk_debug_write_byte): connection error during write
[D] duk_debugger.c:44 (duk__debug_do_detach1): debugger transport detaching, marking transport broken

debug write failed, closing connection: 

[D] duk_debugger.c:572 (duk_debug_write_byte): connection error during write

debug write failed, closing connection: 

[D] duk_debugger.c:548 (duk_debug_write_bytes): connection error during write
[D] duk_debugger.c:523 (duk_debug_write_bytes): attempt to write 1 bytes in detached state, ignore
[D] duk_debugger.c:565 (duk_debug_write_byte): attempt to write 1 bytes in detached state, ignore
[D] duk_debugger.c:523 (duk_debug_write_bytes): attempt to write 1 bytes in detached state, ignore
[D] duk_debugger.c:523 (duk_debug_write_bytes): attempt to write 1 bytes in detached state, ignore
[DD] duk_js_call.c:1936 (duk_handle_safe_call): duk_handle_safe_call: thr=008F5BA0, num_stack_args=1, num_stack_rets=1, valstack_top=6, idx_retbase=5, rec_depth=1/1000, entry_valstack_bottom_index=4, entry_callstack_top=1, entry_catchstack_top=0, entry_call_recursion_depth=1, entry_curr_thread=008F5BA0, entry_thread_state=2
[D] duk_debugger.c:523 (duk_debug_write_bytes): attempt to write 1 bytes in detached state, ignore
[D] duk_debugger.c:523 (duk_debug_write_bytes): attempt to write 11 bytes in detached state, ignore
[DD] duk_js_call.c:1936 (duk_handle_safe_call): duk_handle_safe_call: thr=008F5BA0, num_stack_args=1, num_stack_rets=1, valstack_top=7, idx_retbase=6, rec_depth=1/1000, entry_valstack_bottom_index=4, entry_callstack_top=1, entry_catchstack_top=0, entry_call_recursion_depth=1, entry_curr_thread=008F5BA0, entry_thread_state=2
[D] duk_debugger.c:523 (duk_debug_write_bytes): attempt to write 1 bytes in detached state, ignore
[D] duk_debugger.c:523 (duk_debug_write_bytes): attempt to write 6 bytes in detached state, ignore
[D] duk_debugger.c:523 (duk_debug_write_bytes): attempt to write 2 bytes in detached state, ignore
[D] duk_debugger.c:523 (duk_debug_write_bytes): attempt to write 1 bytes in detached state, ignore
[D] duk_debugger.c:565 (duk_debug_write_byte): attempt to write 1 bytes in detached state, ignore
[D] duk_debugger.c:164 (duk_debug_write_flush): attempt to write flush in detached state, ignore
[DD] duk_debugger.c:1884 (duk_debug_process_messages): top at entry: 3
[DD] duk_debugger.c:1890 (duk_debug_process_messages): top at loop top: 3
[D] duk_debugger.c:1893 (duk_debug_process_messages): debug connection broken, stop processing messages
[D] duk_debugger.c:145 (duk_debug_read_flush): attempt to read flush in detached state, ignore
[DD] duk_debugger.c:1932 (duk_debug_process_messages): top at exit: 3
[D] duk_js_executor.c:1656 (duk__interrupt_handle_debugger): debugger became detached, resume normal execution
[DD] duk_heap_misc.c:69 (duk_heap_switch_thread): switch thread, new thread is NULL, no interrupt counter changes

// Here it returns back to main loop normally after the write failure, the detach callback was never called
Will Call duk_debugger_cooperate()
Will call duk_pcall()

[DD] duk_js_call.c:1047 (duk_handle_call_protected): duk_handle_call_protected: thr=008F5BA0, num_stack_args=0, call_flags=0x00000000 (ignorerec=0, constructor=0), valstack_top=4, idx_func=2, idx_args=4, rec_depth=0/1000, entry_valstack_bottom_index=0, entry_callstack_top=0, entry_catchstack_top=0, entry_call_recursion_depth=0, entry_curr_thread=NULL, entry_thread_state=1
[DD] duk_js_call.c:1201 (duk__handle_call_inner): duk__handle_call_inner: num_stack_args=0, call_flags=0x00000000, top=4
[DD] duk_js_call.c:1247 (duk__handle_call_inner): duk__handle_call_inner: thr=008F5BA0, num_stack_args=0, call_flags=0x00000000 (ignorerec=0, constructor=0), valstack_top=4, idx_func=2, idx_args=4, rec_depth=0/1000, entry_valstack_bottom_index=0, entry_callstack_top=0, entry_catchstack_top=0, entry_call_recursion_depth=0, entry_curr_thread=NULL, entry_thread_state=1
[DD] duk_heap_misc.c:53 (duk_heap_switch_thread): switch thread, initial entry, init default interrupt counter
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 0, fun 0091C0B8,consts 00919B4C, funcs 00919B6C, lev 0, regbot 4, regtop 7, catchstack_top=0, preventcount=1
[DD] duk_js_executor.c:1678 (duk__executor_interrupt): execution interrupt, counter=0, init=0, instruction counts: executor=6995, interrupt=4083
[DD] duk_js_call.c:2402 (duk_handle_ecma_call_setup): handle_ecma_call_setup: thr=008F5BA0, num_stack_args=0, call_flags=0x00000000 (resume=0, tailcall=0), idx_func=1, idx_args=3, entry_valstack_bottom_index=4
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 1, fun 0091C438,consts 00907E64, funcs 00907EA4, lev 1, regbot 7, regtop 12, catchstack_top=0, preventcount=1
[DD] duk_hobject_props.c:3673 (duk_hobject_putprop): put to existing own plain property, property is writable
[DD] duk_hobject_props.c:3762 (duk_hobject_putprop): put to an existing entry at index 1 -> new value 235
[DD] duk_js_call.c:2402 (duk_handle_ecma_call_setup): handle_ecma_call_setup: thr=008F5BA0, num_stack_args=1, call_flags=0x00000000 (resume=0, tailcall=0), idx_func=2, idx_args=4, entry_valstack_bottom_index=7
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 2, fun 0091C668,consts 008E468C, funcs 008E46AC, lev 2, regbot 11, regtop 16, catchstack_top=0, preventcount=1
[DD] duk_js_call.c:2402 (duk_handle_ecma_call_setup): handle_ecma_call_setup: thr=008F5BA0, num_stack_args=1, call_flags=0x00000000 (resume=0, tailcall=0), idx_func=2, idx_args=4, entry_valstack_bottom_index=11
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 3, fun 0091C6D8,consts 009064A4, funcs 009064A4, lev 3, regbot 15, regtop 16, catchstack_top=0, preventcount=1
[DD] duk_js_executor.c:1414 (duk__handle_return): -> return not intercepted, restart execution in caller
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 2, fun 0091C668,consts 008E468C, funcs 008E46AC, lev 2, regbot 11, regtop 16, catchstack_top=0, preventcount=1
[DD] duk_js_executor.c:1414 (duk__handle_return): -> return not intercepted, restart execution in caller
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 1, fun 0091C438,consts 00907E64, funcs 00907EA4, lev 1, regbot 7, regtop 12, catchstack_top=0, preventcount=1
[DD] duk_js_executor.c:1414 (duk__handle_return): -> return not intercepted, restart execution in caller
[DD] duk_js_executor.c:2269 (duk__js_execute_bytecode_inner): restarting execution, thr 008F5BA0, act idx 0, fun 0091C0B8,consts 00919B4C, funcs 00919B6C, lev 0, regbot 4, regtop 7, catchstack_top=0, preventcount=1
[DD] duk_heap_misc.c:69 (duk_heap_switch_thread): switch thread, new thread is NULL, no interrupt counter changes

// Repeats normally... duk_detaching is still 1
Will Call duk_debugger_cooperate()
Will call duk_pcall()
harold-b commented 8 years ago

Just to make sure, could it be because of any improperly configured build settings I have? I'm working with VS2015.

svaarala commented 8 years ago

The symptoms sound a lot like what I think I've managed to fix in #599. The root cause is that a debug transport write error occuring outside the message loop (= not paused state) will trigger detach1() handling (clearing of callbacks but won't call the detached callback yet). Duktape then never manages to call detach2() because it won't make it it to the message loop with read_cb NULLed. The changes in #599 try to fix that by allowing Duktape to enter the message loop and handle detach2() when read_cb is NULL but dbg_detaching is set.

harold-b commented 8 years ago

Got it, I'm checking out the branch now and setting up to test it. Gotta get python 2 on my machine since I'm using 3.3.