View Issue Details

IDProjectCategoryView StatusLast Update
0002335XdebugStep Debuggingpublic2025-04-14 23:33
ReporterZobo Assigned To 
PrioritynormalSeverityminorReproducibilityalways
Status confirmedResolutionopen 
Product Version3.4.2 
Target Version3.4dev 
Summary0002335: Failed dbgp connection is not marked as not active
Description

If a DBGP client disconnects from Xdebug - without sending the detach command - the connection will never be marked as not active. This causes Xdebug to never reconnect to the dbgp client, either as the consequence of xdebug_connect_to_client or xdebug_break or ctrl socker "pause",

The problem is that the return of xdebug_dbgp_cmdloop() is never checked. Return value of 0 indicates that the connection is dropped.

Proposed fix is to update the connection state with xdebug_mark_debug_connection_not_active() inside xdebug_dbgp_cmdloop()

https://github.com/xdebug/xdebug/pull/1002

Steps To Reproduce

XDEBUG_MODE=debug
<?php

while (true) {
sleep(1);
xdebug_connect_to_client();
xdebug_break();
}

Start dbgpClient, when Xdebug connects, Ctrl-C out. Start dbgpClient again, Xdebug will not connect to it again.

Additional Information

The fix caused an interesting problem with tests. Attaching the comment from the PR here. https://github.com/xdebug/xdebug/pull/1002#issuecomment-2752219515

So I just want to write this down as it took me way to long to understand what's going on and why it can't be fixed elegantly. Had to refresh my knowledge about POSIX sockets.

Word of the day: Socket inheritance with child process fork/clone.

So what's happening is that the change (probably correctly) causes Xdebug to reconnect to the dbcp client for every xdebug_break() call. Now the test is written so, that it expect the code to break one time, does some dbgp commands and disconnects and lets PHP run.
What happens is that this was just loop one. two and three are still going to be executed. And when they hit xdebug_break() Xdebug now tries to re-establish a connection to the client.

But hey, you say, when we send all command we actually stop listening to dbgp port!
Oh, ye naïve child... We close the listen socket in the parent (bug01931-003.phpt) process, but when we fork/clone/proc_open the child process (bug01931-003.inc) the listen socket actually gets inherited. And because of that Xdebug connects back to the listen socket (ironically) that exists in the same process and there is nobody to call ever accept(), so Xdebug waits forever...
There would be a nice way to fix this, had PHP exposed O_CLOEXEC/SOCK_CLOEXEC in stream_socket_server (through context or whatnot).
Sidenote: This is possible with fopen mode e.

So the way I see it, there's two options for fixes:

modify dbgpClient.php to keep accepting and dropping DBGP connections until the child process exits...
modify this specific test to not trigger multiple DBGP sessions...
I'll propose the test fix for now...

TagsNo tags attached.
Operating System
PHP Version8.2.0-8.2.9

Activities

There are no notes attached to this issue.

Issue History

Date Modified Username Field Change
2025-04-11 19:31 Zobo New Issue
2025-04-14 23:33 derick Status new => confirmed
2025-04-14 23:33 derick Target Version => 3.4dev