php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #77194 php7ts.dll crashing when running embed
Submitted: 2018-11-23 14:08 UTC Modified: 2018-12-09 17:02 UTC
Votes:2
Avg. Score:5.0 ± 0.0
Reproduced:2 of 2 (100.0%)
Same Version:2 (100.0%)
Same OS:0 (0.0%)
From: svbussww at 126 dot com Assigned:
Status: Open Package: Reproducible crash
PHP Version: 7.2.12 OS: Windows 7
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2018-11-23 14:08 UTC] svbussww at 126 dot com
Description:
------------
php - 7.2.12
php - 7.3.0RC5

php.ini
No extensions are turned on

Test script:
---------------
Test script http://jxcraft.net/Test.zip, VC12 Project, php7ts.dll From https://windows.php.net/download/ ,not actually working, because I've cutted some parts from working project. Script works from time to time and crashes very often.

Actual result:
--------------
Can't initialize heap: [0x000001e7] Attempt to access invalid address.

Problem event name: APPCRASH
Application Name: Test.exe
Application version: 0.0.0.0
Application time stamp: 5bf4612b
Fault module name: php7ts.dll
Fault module version: 7.2.12.0
Fault module timestamp: 5be3d4fd
Exception code: c0000005
Abnormal offset: 000000000001f648
Operating system version: 6.1.7601.2.1.0.256.1
Locale ID: 2052
Other information 1: e3c7
Additional information 2: e3c7d0ab13feedaa62f1ab674aea779c
Additional information 3: ffa7
Additional information 4: ffa7101e299bb1a426430e84b351f5c2

Patches

Fix-Multi-Thread-Allocation-Alignment-Memory-Failure (last revision 2018-11-29 16:46 UTC by svbussww at 126 dot com)

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2018-11-23 15:38 UTC] ab@php.net
-Status: Open +Status: Feedback
 [2018-11-23 15:38 UTC] ab@php.net
Thanks for the report. First, vc12 is not suitable, if you use 7.2 binaries from php.net. Please compile your project with vc15 (vs2017) and post a backtrace. Depending on it, but likely, we'll need some reproduce, too.

Thanks.
 [2018-11-23 19:52 UTC] svbussww at 126 dot com
-Status: Feedback +Status: 打开
 [2018-11-23 19:52 UTC] svbussww at 126 dot com
This problem also exists in VC15
And the problem exists in 7.0.32 7.1.24 7.2.12 7.3.0RC5 In the version
After php_module_startup call
Calling ts_resource_ex in a newly started thread has a chance to crash
Will not crash if php_module_startup is not called
 [2018-11-23 20:57 UTC] svbussww at 126 dot com
-Status: ?? +Status: Open
 [2018-11-23 20:57 UTC] svbussww at 126 dot com
Stack

php7ts.dll!_emalloc(unsigned __int64 size) Line 2425
php7ts.dll!cwd_globals_ctor(_virtual_cwd_globals * cwd_g) Line 391
php7ts.dll!allocate_new_resource(_tsrm_tls_entry * * thread_resources_ptr, unsigned long thread_id) 行 315
php7ts.dll!ts_resource_ex(int id, unsigned long * th_id) Line 395

Exception

The first chance exception at 0x000007FEE3C9F648 (php7ts.dll) (in Test.exe): 0xC0000005: An access violation occurred while reading location 0x0000000000000000.
There is an unhandled exception at 0x000007FEE3C9F648 (php7ts.dll) (in Test.exe): 0xC0000005: An access violation occurred while reading location 0x0000000000000000.
 [2018-11-23 22:23 UTC] ab@php.net
-Status: Open +Status: Feedback
 [2018-11-23 22:23 UTC] ab@php.net
Thanks for the further info. The embed SAPI has php_embed_startup(), which calls php_module_startup(). If you call it separately, you might be calling it twice. Otherwise, it's not clear to me, what exactly is NULL that it tries to dereference, in emalloc, in cwd_globals_ctor? It would rock, if you could extract only the relevant piece of your code where embed is integrated (just as one file with the corresponding embed only API calls), that one could review. It's otherwise a bit hard to guess, as embed is something that gets integrated into another app and the failures can be specific to that app.

Thanks.
 [2018-11-23 22:49 UTC] svbussww at 126 dot com
-Status: Feedback +Status: Open
 [2018-11-23 22:49 UTC] svbussww at 126 dot com
Call API Step Accurate

in Main

tsrm_startup
sapi_startup
php_embed_startup(Internal call php_module_startup)

CreateThread(Loop call)
....

-------------

in Thread

ts_resource
...
ts_free_thread

-------------

The php_module_startup function determines that it is only called once in php_embed_startup

Test VC++ Code In http://jxcraft.net/Test.cpp

Suitable for PHP7.2.12,php7ts.dll Use officially compiled DLL

All remaining irrelevant code has been removed
 [2018-11-26 15:39 UTC] ab@php.net
Thanks for the further info. Please realize, that you're not using the embed SAPI, but are developing your own. To use embed SAPI, you should link with php7embed.lib and include sapi/embed/php_embed.h. It is fine to develop a custom SAPI as you do, but in that case no bug report against the embed SAPI should be filed.

The code you've posted looks OK at first glance. If you indeed were intended to use the embed SAPI, please check a worky example here https://gist.github.com/paresy/3cbd4c6a469511ac7479aa0e7c42fea7, linked from bug #74011. Unfortunately I don't come to debug your code in near days, so can't tell yet whether it uncovers a bug in PHP.

Thanks.
 [2018-11-26 21:21 UTC] svbussww at 126 dot com
Since my test code is completely from php_embed.c and checked correctly
So in theory, using php7embed.lib should also have this problem.
I will go through the standard usage test, but I still hope that I can pay attention to it.
If the standard method still exists, I will follow up the feedback.
 [2018-11-26 22:16 UTC] svbussww at 126 dot com
The problem persists after using the standard method
Environment is Windows 7 SP1 + VS2017 Enterprise

Test code

DWORD WINAPI ThreadProc(LPVOID lpParameter) {
	ts_resource(0);
	ts_free_thread();
	return 0;
}

int main(){
	php_embed_init(0, NULL);
	for (;;){
		HANDLE Thread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
		if (Thread != NULL) CloseHandle(Thread);
	}
	php_embed_shutdown();
	return 0;
}


Debug

Problem event name: APPCRASH
Application Name: Test.exe
Application version: 0.0.0.0
Application timestamp: 5bfc6f7c
Fault module name: php7ts.dll
Fault module version: 7.2.12.0
Fault module timestamp: 5be3d4fd
Exception code: c0000005
Abnormal offset: 000000000001f648
OS version: 6.1.7601.2.1.0.256.1
Locale ID: 2052
Other information 1:e3c7
Additional information 2:e3c7d0ab13feedaa62f1ab674aea779c
Other information 3: db03
Other information 4: db03925cc4db17c3dff9789e6103f141

Can't initialize heap: [0x000001e7] Attempt to access invalid address.

Exception thrown at 0x000007FEEAD5F648 (in php7ts.dll) (in Test.exe): 0xC0000005: An access violation occurred while reading location 0x0000000000000000.

Stack

php7ts.dll!_emalloc(unsigned __int64 size) Line 2425
php7ts.dll!cwd_globals_ctor(_virtual_cwd_globals * cwd_g) Line 391
php7ts.dll!allocate_new_resource(_tsrm_tls_entry * * thread_resources_ptr, unsigned long thread_id) Line 315
php7ts.dll!ts_resource_ex(int id, unsigned long * th_id) Line 395
Test.exe!ThreadProc(void * lpParameter) Line 9
 [2018-11-27 12:03 UTC] svbussww at 126 dot com
Can't initialize heap: [0x000001e7] Attempt to access invalid address.

Tracking source code is generated from zend_alloc.c

in zend_mm_mmap_fixed
VirtualAlloc Error return NULL
 [2018-11-27 12:46 UTC] svbussww at 126 dot com
The bug has been found

file Zend/zend_alloc.c
function zend_mm_chunk_alloc_int
zend_mm_mmap After not aligned
zend_mm_mmap_fixed Call failed is return 0

The cause of the bug
zend_mm_mmap The allocated memory address is released. In the case of multithreading, it may be preempted by other threads.
This causes the subsequent zend_mm_mmap_fixed function to allocate memory and cause the program to crash.

Temporary solution

static void *zend_mm_chunk_alloc_int(size_t size, size_t alignment)
{
	LOOP:;
	void *ptr = zend_mm_mmap(size);

	if (ptr == NULL) {
		return NULL;
	} else if (ZEND_MM_ALIGNED_OFFSET(ptr, alignment) == 0) {
#ifdef MADV_HUGEPAGE
	    madvise(ptr, size, MADV_HUGEPAGE);
#endif
		return ptr;
	} else {
		size_t offset;

		/* chunk has to be aligned */
		zend_mm_munmap(ptr, size);
		ptr = zend_mm_mmap(size + alignment - REAL_PAGE_SIZE);
#ifdef _WIN32
		offset = ZEND_MM_ALIGNED_OFFSET(ptr, alignment);
		zend_mm_munmap(ptr, size + alignment - REAL_PAGE_SIZE);
		ptr = zend_mm_mmap_fixed((void*)((char*)ptr + (alignment - offset)), size);
		if(ptr == NULL) goto LOOP;
		offset = ZEND_MM_ALIGNED_OFFSET(ptr, alignment);
		if (offset != 0) {
			zend_mm_munmap(ptr, size);
			return NULL;
		}
		return ptr;
#else
		offset = ZEND_MM_ALIGNED_OFFSET(ptr, alignment);
		if (offset != 0) {
			offset = alignment - offset;
			zend_mm_munmap(ptr, offset);
			ptr = (char*)ptr + offset;
			alignment -= offset;
		}
		if (alignment > REAL_PAGE_SIZE) {
			zend_mm_munmap((char*)ptr + size, alignment - REAL_PAGE_SIZE);
		}
# ifdef MADV_HUGEPAGE
	    madvise(ptr, size, MADV_HUGEPAGE);
# endif
#endif
		return ptr;
	}
}

I hope the development team can solve this bug as soon as possible.
 [2018-11-27 13:41 UTC] svbussww at 126 dot com
Fix the temporary plan

static void *zend_mm_chunk_alloc_int(size_t size, size_t alignment)
{
	void *ptr = zend_mm_mmap(size);

	if (ptr == NULL) {
		return NULL;
	} else if (ZEND_MM_ALIGNED_OFFSET(ptr, alignment) == 0) {
#ifdef MADV_HUGEPAGE
	    madvise(ptr, size, MADV_HUGEPAGE);
#endif
		return ptr;
	} else {
		size_t offset;

		/* chunk has to be aligned */
		zend_mm_munmap(ptr, size);
		LOOP:;
		ptr = zend_mm_mmap(size + alignment - REAL_PAGE_SIZE);
		if (ptr == NULL) return NULL;
#ifdef _WIN32
		offset = ZEND_MM_ALIGNED_OFFSET(ptr, alignment);
		zend_mm_munmap(ptr, size + alignment - REAL_PAGE_SIZE);
		ptr = zend_mm_mmap_fixed((void*)((char*)ptr + (alignment - offset)), size);
		if(ptr == NULL) goto LOOP;
		offset = ZEND_MM_ALIGNED_OFFSET(ptr, alignment);
		if (offset != 0) {
			zend_mm_munmap(ptr, size);
			return NULL;
		}
		return ptr;
#else
		offset = ZEND_MM_ALIGNED_OFFSET(ptr, alignment);
		if (offset != 0) {
			offset = alignment - offset;
			zend_mm_munmap(ptr, offset);
			ptr = (char*)ptr + offset;
			alignment -= offset;
		}
		if (alignment > REAL_PAGE_SIZE) {
			zend_mm_munmap((char*)ptr + size, alignment - REAL_PAGE_SIZE);
		}
# ifdef MADV_HUGEPAGE
	    madvise(ptr, size, MADV_HUGEPAGE);
# endif
#endif
		return ptr;
	}
}
 [2018-11-29 16:49 UTC] svbussww at 126 dot com
I have uploaded a fix.
Use _aligned_malloc and _aligned_free instead of unreliable VirtualAlloc and VirtualFree
 [2018-12-07 11:01 UTC] jr at concept-br dot de
Same Problem here also in 7.2.13 on Windows Server 2012 R2. We restart the apache service every hour to "workaround" until a bugfix is released
 [2018-12-09 17:02 UTC] ab@php.net
@jr at concept-br dot de, please post a backtrace.

Thanks.
 
PHP Copyright © 2001-2018 The PHP Group
All rights reserved.
Last updated: Mon Dec 10 03:01:25 2018 UTC