php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #35612 [PATCH] iis6 Access Violation crash
Submitted: 2005-12-09 12:29 UTC Modified: 2005-12-22 17:51 UTC
Votes:8
Avg. Score:5.0 ± 0.0
Reproduced:8 of 8 (100.0%)
Same Version:8 (100.0%)
Same OS:6 (75.0%)
From: alacn dot uhahaa at gmail dot com Assigned: dmitry
Status: Closed Package: IIS related
PHP Version: 5CVS-2005-12-20 (snap) OS: Windows Server 2003
Private report: No CVE-ID:
 [2005-12-09 12:29 UTC] alacn dot uhahaa at gmail dot com
Description:
------------
PHP5 and PHP4 on iis6 (windows server 2003) sometimes crash with access violation

Reproduce code:
---------------
(code at zend_execute_API.c)

before iis shutdown or recycle the pool, it will call "zend_shutdown_timeout_thread()", that will post a quit message on "timeout_thread_id" and return


Expected result:
----------------
"zend_shutdown_timeout_thread()" should wait "timeout_thread" finish before return


Actual result:
--------------
sometimes "zend_shutdown_timeout_thread()" return before the "tiumeout_thread" finish, and the iis release the library, than the iis crash at "timeout_thread_proc()" because the library was released.

the fix for PHP5 and PHP4 at "zend_execute_API.c"

"[...]" means hidden code...

#ifdef ZEND_WIN32
#include <process.h>
/* true global */
[...]
// add next line
static HANDLE timeout_thread_finish_event;
#endif

[...]

static unsigned __stdcall timeout_thread_proc(void *pArgs)
{
[...]
DestroyWindow(timeout_window);
UnregisterClass(wc.lpszClassName, NULL);
// add next line
SetEvent(timeout_thread_finish_event);
return 0;
}

void zend_init_timeout_thread()
{
timeout_thread_event = CreateEvent([..]);
// add next line
timeout_thread_finish_event = CreateEvent(0, 0, 0, 0);
[...]
}

void zend_shutdown_timeout_thread()
{
[...]
PostThreadMessage(timeout_thread_id, WM_QUIT, 0, 0);
// add next line
WaitForSingleObject(timeout_thread_finish_event, 30000);
}


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2005-12-09 19:11 UTC] dmitry@php.net
Fixed in CVS HEAD, PHP_5_1 and PHP_5_0.
 [2005-12-19 08:51 UTC] sniper@php.net
Please try using this CVS snapshot:

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

And this time, really make sure you have the right PHP installed. Only way to be sure is to delete ALL old dlls related to PHP. Especially from C:\windows\ directory.
Also, make any patches against the latest CVS sources. PHP 4 is too old.
 [2005-12-20 12:38 UTC] alacn dot uhahaa at gmail dot com
ok.. here is udiff for latest cvs (php5.1)

what is happenning is that since the thread that created the timeout thread have different access levels than the one that will wait it finish, waitforsingleobject on timeout thread handle wont work right, it will always timeout, and access violation will occur

expected: it should return before the timeout, that way wont occur access violation

the fix: it should wait at least 30 secs, waitforsingleobject will never elapse all the 30 secs, unless in a bad error,
- it will always return before the 30 secs, as it should -


btw ...cant php4 be fixed too? :(


--- php5.1-200512200930_zend_execute_API.c	Fri Dec 16 21:30:06 2005
+++ php5.1-200512200930_fixed_zend_execute_API.c	Tue Dec 20 08:44:24 2005
@@ -46,7 +46,7 @@
 static WNDCLASS wc;
 static HWND timeout_window;
 static HANDLE timeout_thread_event;
-static HANDLE timeout_thread_handle;
+static HANDLE timeout_thread_finish;
 static DWORD timeout_thread_id;
 static int timeout_thread_initialized=0;
 #endif
@@ -1282,6 +1282,7 @@
 	}
 	DestroyWindow(timeout_window);
 	UnregisterClass(wc.lpszClassName, NULL);
+	SetEvent(timeout_thread_finish);
 	return 0;
 }
 
@@ -1289,7 +1290,8 @@
 void zend_init_timeout_thread()
 {
 	timeout_thread_event = CreateEvent(NULL, FALSE, FALSE, NULL);
-	timeout_thread_handle = _beginthreadex(NULL, 0, timeout_thread_proc, NULL, 0, &timeout_thread_id);
+	timeout_thread_finish = CreateEvent(0, 0, 0, 0);
+	_beginthreadex(NULL, 0, timeout_thread_proc, NULL, 0, &timeout_thread_id);
 	WaitForSingleObject(timeout_thread_event, INFINITE);
 }
 
@@ -1302,8 +1304,7 @@
 	PostThreadMessage(timeout_thread_id, WM_QUIT, 0, 0);
 
 	/* Wait for thread termination */
-	WaitForSingleObject(timeout_thread_handle, 5000);
-	CloseHandle(timeout_thread_handle);
+	WaitForSingleObject(timeout_thread_finish, 30000);
 }
 
 #endif
 [2005-12-21 08:11 UTC] vaguener at hotmail dot com
thats right,

when i set the wait time to INFINITE in the current code
"WaitForSingleObject(timeout_thread_handle, INFINITE);"
it never close the worker process.

but on alacn's code it do.
"WaitForSingleObject(timeout_thread_finish, INFINITE);"
 [2005-12-21 11:09 UTC] dmitry@php.net
alacn, could you please explain why WaitForSingleObject() may not work on thread handle? (it works fine for me).
Is it IIS6 specific behavior?

Also I didn't understand, why you need 30 sec timeout?
The tmeout thread is event based and it never locks. It should quit right after it gets WM_QUIT.

 [2005-12-21 19:08 UTC] alacn dot uhahaa at gmail dot com
ok, i have tested it on iis5 (windows xp) and iis6 (windows 2003), both is configured to use the extension php5isapi.dll.

we use WaitForSingleObject to wait the thread finish:
- it will return WAIT_OBJECT_0 when the thread finish,
- or return WAIT_TIMEOUT if the thread didnt finish before the time elapse

the thing is, it should result WAIT_OBJECT_0 meaning that the thread was ended fine.

lets debug it, set WITH_ALACN_PATCH to 0 to use current code; or set it to 1 to use fixed code

"everyone" user need have full access on the "c:\temp\" otherwise it can fail create the file.


on the file c:\temp\php_debug.log:

-- means its fine
WaitForSingleObject:
it returned WAIT_OBJECT_0! thread was ended.

-- means that we didnt wait the thread finish
WaitForSingleObject:
it returned WAIT_TIMEOUT! thread may still running!.

-- deadlocked after WaitForSingleObject, process killed!
WaitForSingleObject:




--- php5.1-200512211530_zend_execute_API.c	Tue Dec 20 09:30:10 2005
+++ php5.1-200512211530_debug_zend_execute_API.c	Wed Dec 21 15:52:46 2005
@@ -1256,6 +1256,26 @@
 }
 
 
+void save_debug_msg(char *sz)
+{
+	HANDLE h;
+	int i;
+	DWORD dwRW;
+
+	h = CreateFile("c:\\temp\\php_debug.log", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+	if(h == INVALID_HANDLE_VALUE) return;
+
+	SetFilePointer(h, 0, 0, 2);
+
+	i = strlen(sz);
+	WriteFile(h, sz, i, &dwRW, 0);
+
+	CloseHandle(h);
+}
+
+// change this!!
+#define WITH_ALACN_PATCH	1
+
 
 static unsigned __stdcall timeout_thread_proc(void *pArgs)
 {
@@ -1284,6 +1304,9 @@
 	}
 	DestroyWindow(timeout_window);
 	UnregisterClass(wc.lpszClassName, NULL);
+#if WITH_ALACN_PATCH
+	SetEvent(timeout_thread_handle);
+#endif
 	return 0;
 }
 
@@ -1291,20 +1314,42 @@
 void zend_init_timeout_thread()
 {
 	timeout_thread_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+#if WITH_ALACN_PATCH
+	timeout_thread_handle = CreateEvent(0, 0, 0, 0);
+	_beginthreadex(NULL, 0, timeout_thread_proc, NULL, 0, &timeout_thread_id);
+#else
 	timeout_thread_handle = _beginthreadex(NULL, 0, timeout_thread_proc, NULL, 0, &timeout_thread_id);
+#endif
 	WaitForSingleObject(timeout_thread_event, INFINITE);
 }
 
 
 void zend_shutdown_timeout_thread()
 {
+	DWORD dw;
+
 	if (!timeout_thread_initialized) {
 		return;
 	}
 	PostThreadMessage(timeout_thread_id, WM_QUIT, 0, 0);
 
+	save_debug_msg("WaitForSingleObject:\r\n");
+
 	/* Wait for thread termination */
-	WaitForSingleObject(timeout_thread_handle, 5000);
+	dw = WaitForSingleObject(timeout_thread_handle, INFINITE);
+	switch(dw)
+	{
+	case WAIT_OBJECT_0:
+		save_debug_msg("it returned WAIT_OBJECT_0! thread was ended.\r\n");
+		break;
+	case WAIT_TIMEOUT:
+		save_debug_msg("it returned WAIT_TIMEOUT! thread may still running!.\r\n");
+		break;
+	default:
+		save_debug_msg("unknow return.\n");
+		break;
+	}
+
 	CloseHandle(timeout_thread_handle);
 }
 [2005-12-22 17:51 UTC] dmitry@php.net
I still didn't undestand why WaitForSingleObject() doesn't work for thread inside IIS? It works fine in CLI, CGI, FastCGI, ...

I applied your solution into HEAD, PHP_5_1 and PHP_5_0, but not with 30 sec timeout (5 sec).
 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Wed Apr 23 14:02:33 2014 UTC