php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #38273 Incorrect return address after the execution of a signal handler?
Submitted: 2006-07-31 19:40 UTC Modified: 2009-03-20 10:54 UTC
Votes:2
Avg. Score:4.0 ± 1.0
Reproduced:2 of 2 (100.0%)
Same Version:0 (0.0%)
Same OS:0 (0.0%)
From: axelluttgens at swing dot be Assigned:
Status: Not a bug Package: PCNTL related
PHP Version: 5.2.4 OS: Mac OSX 10.4.7
Private report: No CVE-ID: None
 [2006-07-31 19:40 UTC] axelluttgens at swing dot be
Description:
------------
It seems there is a problem with the construction of the return address to be used after an interrupt handler.

Now, I'm not sure whether the problem is a general one, or more precisely located in the socket_xxx() family of functions.
I used the socket_select() function for building the example, as I needed a function whose execution is liable to be suspended until the occurence of an interrupt.

But the "workaround" described hereafter anyway seems to reveal some misbehavior.

Reproduce code:
---------------
Create an executable file, say "sigtest.php", with following contents:

#!/usr/local/bin/php

<?php

declare(ticks = 1);

$gotINT = FALSE;

function SaveINT()
{
	$GLOBALS['gotINT'] = TRUE;
	echo "Received SIGINT\n";
}

function HandleINT()
{
	echo "Handling SIGINT\n";
}

function PollSigs()
{
	if ($GLOBALS['gotINT'])
		HandleINT();
}

pcntl_signal(SIGINT, 'SaveINT');

$endpoint = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($endpoint, '127.0.0.1', 12345);
socket_listen($endpoint, 10);
while (!socket_select($r = array($endpoint), $w = NULL, $e = NULL, NULL))
	if (($err = socket_last_error()) === SOCKET_EINTR)
	{
		# $err = $err;
		PollSigs();
	}
	else
	{
		echo "socket_select() failed with $err\n";
		exit(1);
	}

?>

Expected result:
----------------
During execution of above file on the terminal, a break (^C) should result in:

1. the capture of SIGINT, and thus the execution of SaveINT(),
2. the continuation of execution after socket_select(), and thus the execution of HandleINT() consecutively to the call of PollSigs(). 

Actual result:
--------------
[1] With above code, launching the executable yields:

$ /Volumes/Data/Sources/sigtest.php 

^C
Warning: socket_select() unable to select [4]: Interrupted system call in /Volumes/Data/Sources/sigtest.php on line 31
Received SIGINT
^C
Warning: socket_select() unable to select [4]: Interrupted system call in /Volumes/Data/Sources/sigtest.php on line 31
Handling SIGINT
Received SIGINT

[2] Now, uncomment the
   # $err = $err;
line in the source and launch the executable again:

$ /Volumes/Data/Sources/sigtest.php 

^C
Warning: socket_select() unable to select [4]: Interrupted system call in /Volumes/Data/Sources/sigtest.php on line 31
Received SIGINT
Handling SIGINT
^C
Warning: socket_select() unable to select [4]: Interrupted system call in /Volumes/Data/Sources/sigtest.php on line 31
Received SIGINT
Handling SIGINT

The dummy instruction (ie, $err = $err;) thus allows to restore exepected behavior.

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2006-07-31 20:13 UTC] tony2001@php.net
Please try using this CVS snapshot:

  http://snaps.php.net/php5.2-latest.tar.gz
 
For Windows:
 
  http://snaps.php.net/win32/php5.2-win32-latest.zip


 [2006-08-01 11:59 UTC] axelluttgens at swing dot be
Hello Tony, thanks again for your follow up!

For various reasons, I am currently really stuck with PHP 4 here. In that sense, PHP 5 isn't an alternative for me yet.

But perhaps were you considering a very precise point?
Do you want me to try something else?

TIA,
Axel
 [2006-08-02 11:05 UTC] axelluttgens at swing dot be
As a follow-up: a "switch" statement, instead of reproduce code's "if" statement, does not seem to be affected by the problem.

So, replacing the while loop in reproduce code with this one:

while (!socket_select($r = array($endpoint), $w = NULL, $e = NULL, NULL))
	switch ($err = socket_last_error())
	{
		case SOCKET_EINTR:
			socket_clear_error();
			PollSigs();
			break;
		default:
			echo "socket_select() failed with $err\n";
			break 2;
	}


I get the expected behavior back (without having to resort to the "dummy statement" kludge):

$ /Volumes/Data/Sources/sigtest.php 

^C
Warning: socket_select() unable to select [4]: Interrupted system call in /Volumes/Data/Sources/sigtest.php on line 32
Received SIGINT
Handling SIGINT
^C
Warning: socket_select() unable to select [4]: Interrupted system call in /Volumes/Data/Sources/sigtest.php on line 32
Received SIGINT
Handling SIGINT

Could this be of some help for narrowing the cause?
 [2007-07-11 13:05 UTC] jani@php.net
Please try the 5.2 snapshot as requested before. We are going to discontinue support for PHP 4 this year so it is very unlikely that this bug will ever get fixed in PHP 4. But if the bug does not exist in PHP 5.2 it's possible to backport the fix from it to PHP 4.
 [2007-07-13 07:56 UTC] axelluttgens at swing dot be
Hello Jani,

I'll try to test the case with the php5.2-200707130630 snapshot during this week-end.

Thanks for the follow-up,
Axel
 [2007-07-14 11:03 UTC] axelluttgens at swing dot be
So, as announced, I've compiled the php5.2-200707130630 snapshot.
Here follows the output of a "php -i" command:

	PHP Version => 5.2.4-dev
	
	System => Darwin ALMbp.local 8.10.1 Darwin Kernel Version 8.10.1: Wed May 23 16:33:00 PDT 2007; root:xnu-792.22.5~1/RELEASE_I386 i386
	Build Date => Jul 13 2007 10:13:10
	Configure Command =>  './configure'  '--prefix=/usr/local/php5' '--with-zlib-dir=/usr' '--with-zlib' '--enable-zip' '--enable-mbstring' '--enable-exif' '--enable-sockets' '--enable-ftp' '--enable-pcntl' '--with-iodbc=/usr' '--with-curl=/usr' '--with-curlwrappers' '--with-ldap=/usr' '--with-kerberos=/usr' '--with-apxs=/usr/sbin/apxs
	Server API => Command Line Interface
	Virtual Directory Support => disabled
	Configuration File (php.ini) Path => /usr/local/php5/lib
	Loaded Configuration File => (none)
	PHP API => 20041225
	PHP Extension => 20060613
	Zend Extension => 220060519
	Debug Build => no
	Thread Safety => disabled
	Zend Memory Manager => enabled
	IPv6 Support => enabled
	Registered PHP Streams => zip, php, file, data, ftp, gopher, telnet, dict, ldap, http, https, ftps, compress.zlib  
	Registered Stream Socket Transports => tcp, udp, unix, udg
	Registered Stream Filters => string.rot13, string.toupper, string.tolower, string.strip_tags, convert.*, consumed, convert.iconv.*, zlib.*
	
	
	This program makes use of the Zend Scripting Language Engine:
	Zend Engine v2.2.0, Copyright (c) 1998-2007 Zend Technologies

Of course, things have changed since July 2006, as I am now on an Intel Mac, with OS X 10.4.10.
Anyway, I doubt to be able to exacly reproduce the former environement; but, if needed, I could perhaps try the same on a 10.4.10 PPC.

So, I first tried the original reproduce code, the one dated 2006-07-31 with the "if" statement.
It seems that I still get the unexpected behavior when the dummy statement ($err = $err;) is commented out:

	$ ./sigtest.php 
	
	^C
	Warning: socket_select(): unable to select [4]: Interrupted system call in /Volumes/ALMbpData/sigtest.php on line 32
	Received SIGINT
	^C
	Warning: socket_select(): unable to select [4]: Interrupted system call in /Volumes/ALMbpData/sigtest.php on line 32
	Handling SIGINT
	Received SIGINT
	^C
	Warning: socket_select(): unable to select [4]: Interrupted system call in /Volumes/ALMbpData/sigtest.php on line 32
	Handling SIGINT
	Received SIGINT
	[and so on...]

and that uncommenting the dummy statement still brings the expected behavior back:

	$ ./sigtest.php 
	
	^C
	Warning: socket_select(): unable to select [4]: Interrupted system call in /Volumes/ALMbpData/sigtest.php on line 32
	Received SIGINT
	Handling SIGINT
	^C
	Warning: socket_select(): unable to select [4]: Interrupted system call in /Volumes/ALMbpData/sigtest.php on line 32
	Received SIGINT
	Handling SIGINT
	[and so on...]

In a word, it looks like the same behavior has been carried over from php 4 to php 5.

On the other hand, re-reading my variant dated 2006-08-02, the one with the "switch" statement instead of the "if" statement, I believe I just introduced noise (sorry for that...).
Indeed, one may notice that I introduced a statement between the "case SOCKET_EINTR:" and the PollSigs() call.
Removing that extraneous statement, the socket_clear_error() call, I just get the same unexpected behavior as with he original reproduce code.
In a sense, this is good news, as the basic features of the language thus behave similary!

HTH,
Axel
 [2008-07-18 16:16 UTC] jani@php.net
Ticks are deprecated in PHP 5.3.0 and will be completely removed in PHP
6. We're not going to waste time trying to fix the inherently broken
thing. 
 [2008-07-19 22:25 UTC] axelluttgens at swing dot be
Hello Jani,

Thanks for your follow-up.
But I don't understand the relationship with ticks. Could you explain?

TIA,
Axel
 [2009-03-19 13:26 UTC] lbarnaud@php.net
Looking at this code, we can see that between socket_select() call and HandleInt() call, the code have no "tickable" statements.

So the first time the tick functions (signal handlers) are called after socket_select() is before returning from PollSigs().

This is why the output differs in the first interrupt. This also explains why the two variants (the one with a dummy statement before calling PollSigs() and the one with switch) have a different behavior.

(this is at most counter-intuitive, but not a bug)
 [2009-03-20 10:54 UTC] axelluttgens at swing dot be
Yes, of course. :-)

Thanks a lot,
Axel
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 21 11:01:30 2024 UTC