Bug #71596 [Com]: Segmentation fault on ZTS with date function (setlocale)

From: Date: Tue, 16 Feb 2016 10:15:12 +0000
Subject: Bug #71596 [Com]: Segmentation fault on ZTS with date function (setlocale)
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-199255@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=71596&edit=1 ID: 71596 Comment by: maroszek at gmx dot net Reported by: maroszek at gmx dot net Summary: Segmentation fault on ZTS with date function (setlocale) Status: Feedback Type: Bug Package: Date/time related Operating System: Windows PHP Version: 7.0.3 Block user comment: N Private report: N New Comment: I have another upcoming ZTS bugreport :) and thanks for your time and effort! std::thread seems to properly use beginthread. Nevertheless i updated the example just to be sure. And i linked to threadlocale.obj to ensure that locales for each thread are enabled. I also compiled the PHP7 example with Visual Studio 2015 Update 1. The error remains :) Can you have a look if you can reproduce it aswell? Updated Example: unsigned __stdcall phpThread(void* params) { ts_resource(0); while (true) { zend_file_handle file_handle; file_handle.type = ZEND_HANDLE_FILENAME; file_handle.filename = "date.php"; file_handle.handle.fp = NULL; file_handle.opened_path = NULL; file_handle.free_filename = 0; if (php_request_startup(TSRMLS_C) == FAILURE) { //std::cout << "ERR" << std::endl; php_request_shutdown(NULL); continue; } if (php_execute_script(&file_handle TSRMLS_CC) == FAILURE) break; //std::cout << "RUN" << std::endl; php_request_shutdown(NULL); } std::cout << "DIED" << std::endl; return 0; } int main(int argc, const char * argv[]) { tsrm_startup(128, 1, 0, NULL); sapi_startup(&php_embed_module); php_embed_module.ini_entries = "date.timezone=Europe/Berlin\n\0"; if (php_embed_module.startup(&php_embed_module) == FAILURE) { throw std::runtime_error("Could not start PHP!"); } for (int i = 0; i < 10; i++) { _beginthreadex(NULL, 0, phpThread, NULL, 0, NULL); //std::thread([]{phpThread(NULL);}).detach(); } while (true); return 0; } Previous Comments: ------------------------------------------------------------------------ [2016-02-16 08:20:07] ab@php.net It's great you constantly aim improving the situation with TS builds :) It looks correct to call configtreadlocale only once in the main thread. That's also what is being done in the snippet from the doc page. However, from the doc page: [QUOTE] These functions affect the behavior of setlocale, _tsetlocale, _wsetlocale, _beginthread, and _beginthreadex. If another method is used to create threads, the locale settings have no effect on those threads. [/QUOTE] I'm currently unaware whether std::thread() is using _beginthread(), maybe you could trace it? But if it doesn't, setlocale() will be clearly not thread safe so would require locking. FYI we use vc11 with PHP5 currently, and vc14 with 7.0. vc12 could possibly have build issues with PHP < 7 and in any case there are no dep libs builds for it. Cheers. ------------------------------------------------------------------------ [2016-02-15 10:27:02] maroszek at gmx dot net When adding this code before ts_resource(0); the crash remains but looks a little bit different. _configthreadlocale(_ENABLE_PER_THREAD_LOCALE); MSDN: https://msdn.microsoft.com/de-de/library/26c0tb7x.aspx We a calling this function in SAPI.c in sapi_startup. AFAIK this function is only called for the "main" thread. If i read the MSDN right, we need to call this function in all worker threads aswell. Neither one of the SAPIs does this!? ------------------------------------------------------------------------ [2016-02-15 09:39:55] maroszek at gmx dot net Examples: https://www.dropbox.com/s/c5cs2rz1zcssk3r/CrashTest.zip StackTrace: https://www.dropbox.com/s/saff1d5z5z2vpon/PHPStackTraceSetLocale.png?dl=0 ------------------------------------------------------------------------ [2016-02-15 09:38:26] maroszek at gmx dot net Description: ------------ Description: ------------ PHP 7 is current stable (Also reproducable with 5.6.18) PHP 7 is used as Embed (Also reproducable with 5.6.18) Visual Studio 2013 I build a simple example to demonstrate the threading problem. It crashes nearly instatly. Running only one thread works fine. Expected result: ---------------- No crash. Endless loop doing the work. Actual result: -------------- Crash. I attached a backtrace which shows the concurrent access to setlocale which causes the crash Test script: --------------- #include <stdio.h> #include <iostream> #include <thread> #include <main/php.h> #include <main/SAPI.h> #include <main/php_main.h> #include <main/php_variables.h> #include <main/php_ini.h> #include <zend_ini.h> #ifdef ZTS ZEND_TSRMLS_CACHE_EXTERN(); #endif zend_module_entry ips_module_entry = { STANDARD_MODULE_HEADER, "XYZ", NULL, NULL, NULL, NULL, NULL, NULL, NO_VERSION_YET, STANDARD_MODULE_PROPERTIES }; static size_t php_embed_read_post(char *str, size_t str_length) { return 0; } static char* php_embed_read_cookies() { return NULL; } static size_t php_embed_ub_write(const char *str, size_t str_length) { std::cout << str; return str_length; } static void php_embed_flush(void *server_context) { // } static void php_embed_send_header(sapi_header_struct *sapi_header, void *server_context) { // } static void php_embed_log_message(char *message) { fprintf(stderr, "%s\n", message); } static void php_embed_register_variables(zval *track_vars_array) { // } static int php_embed_startup(sapi_module_struct *sapi_module) { if (php_module_startup(sapi_module, NULL, 0) == FAILURE) { return FAILURE; } return SUCCESS; } sapi_module_struct php_embed_module = { "XYZ", /* name */ "PHP for XYZ", /* pretty name */ php_embed_startup, /* startup */ php_module_shutdown_wrapper, /* shutdown */ NULL, /* activate */ NULL, /* deactivate */ php_embed_ub_write, /* unbuffered write */ php_embed_flush, /* flush */ NULL, /* get uid */ NULL, /* getenv */ php_error, /* error handler */ NULL, /* header handler */ NULL, /* send headers handler */ php_embed_send_header, /* send header handler */ php_embed_read_post, /* read POST data */ php_embed_read_cookies, /* read Cookies */ php_embed_register_variables, /* register server variables */ php_embed_log_message, /* Log message */ NULL, /* Get request time */ NULL, /* Child terminate */ STANDARD_SAPI_MODULE_PROPERTIES }; int main(int argc, const char * argv[]) { tsrm_startup(128, 1, 0, NULL); sapi_startup(&php_embed_module); php_embed_module.ini_entries = "date.timezone=Europe/Berlin\n\0"; if (php_embed_module.startup(&php_embed_module) == FAILURE) { throw std::runtime_error("Could not start PHP!"); } for (int i = 0; i < 10; i++) { std::thread([&argv]{ ts_resource(0); while (true){ zend_file_handle file_handle; file_handle.type = ZEND_HANDLE_FILENAME; file_handle.filename = "date.php"; file_handle.handle.fp = NULL; file_handle.opened_path = NULL; file_handle.free_filename = 0; if (php_request_startup() == FAILURE) { //std::cout << "ERR" << std::endl; php_request_shutdown(NULL); continue; } if (php_execute_script(&file_handle) == FAILURE) break; //std::cout << "RUN" << std::endl; php_request_shutdown(NULL); } std::cout << "DIED" << std::endl; }).detach(); } while (true); return 0; } ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=71596&edit=1

« previous php.bugs (#199255) next »