php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #79696 Child exited Segmentation fault, __strchr_sse2, putenv
Submitted: 2020-06-12 16:30 UTC Modified: 2021-05-21 17:46 UTC
Votes:2
Avg. Score:5.0 ± 0.0
Reproduced:2 of 2 (100.0%)
Same Version:1 (50.0%)
Same OS:1 (50.0%)
From: andrixnet at yahoo dot com Assigned:
Status: Wont fix Package: Apache2 related
PHP Version: 7.3.19 OS: Linux Slackware-14.2
Private report: No CVE-ID: None
View Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
If you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: andrixnet at yahoo dot com
New email:
PHP Version: OS:

 

 [2020-06-12 16:30 UTC] andrixnet at yahoo dot com
Description:
------------
I have several Slackware-14.2 servers upgraded to latest security patches and with PHP-7.3 built from source. (distro comes with 5.6).
Building PHP following instructions from this post: https://www.linuxquestions.org/questions/slackware-14/building-php-7-3-and-php-7-4-on-slackware-14-2-a-4175671161/ and references.

I run several WordPress sites with WooCommerce. They all run under HTTPS. mod_ssl according to distro.
The same problem happened on PHP-7.1.x and persisted after upgrade to PHP-7.3.x.

I am getting intermittent errors in Apache error_log (the main server log, not the virtualhost). 

AH00051: child pid 5584 exit signal Segmentation fault (11)

In order to better analyze the situation I rebuilt Apache and PHP with debug symbols, I enabled core dumps in Apache and opened the core dump with gdb, resulting in the trace below.

Tested with 7.3.17 and 7.3.19.

Apache runs with mpm_event module.
If I run Apache with mpm_prefork, the issue does not happen (at least during tests for several hours). (workaround tried after reading last answer here: https://stackoverflow.com/questions/52224388/segmentation-fault-with-symfony-4-1-php-7-1-2x )




Test script:
---------------
I cannot provide explicit test script, it happens using WordPress with WooCommerce. 
I can say that at least happens while editing products (in this app) and while visiting some other components/pages. I am not sure how much it depends on the theme or other plugins installed in WP, but I can reproduce this fairly certain as described.

End-user result is either a blank page (rare) or incomplete/erroneous page load (error occured during an AJAX call)

Various other WP sites also yield this behaviour, including (but less frequent) errors in error_log such as:
Out of memory (no timesptamp)
zend_mm_heap_corrupted (no timestamp)
and frequent 
AH00051: child pid 5584 exit signal Segmentation fault (11)

This happens on multiple servers based on Slackware-14.2 with equivalent configuration.

It started to happen roughly after WP version got to 5.4.
I do host WP sites (http only) that don't seem to yield these errors, reason unknown.
I do host custom built PHP sites that do not yield these errors, reason unknown.


Further backtraces and details of my investigation have been posted on the Slackware support forum: https://www.linuxquestions.org/questions/slackware-14/apache-and-php-errors-mostly-when-hosting-wordpress-4175676899/




Actual result:
--------------
PHP configure:

EXTENSION_DIR=/usr/lib${LIBDIRSUFFIX}/php/extensions \
CFLAGS="$SLKCFLAGS" \
CXXFLAGS="$SLKCFLAGS -DU_USING_ICU_NAMESPACE=1" \
./configure \
  --prefix=/usr \
  --libdir=/usr/lib${LIBDIRSUFFIX} \
  --with-libdir=lib${LIBDIRSUFFIX} \
  --localstatedir=/var \
  --sysconfdir=/etc \
  --datarootdir=/usr/share \
  --datadir=/usr/share \
  --infodir=/usr/info \
  --mandir=/usr/man \
  --with-apxs2=/usr/bin/apxs \
  --enable-fpm \
  --with-fpm-user=apache \
  --with-fpm-group=apache \
  --enable-maintainer-zts \
  --enable-pcntl \
  --enable-mbregex \
  --enable-tokenizer=shared \
  --with-config-file-scan-dir=/etc/php.d \
  --with-config-file-path=/etc \
  --with-layout=PHP \
  --disable-sigchild \
  --enable-xml \
  --with-libxml-dir=/usr \
  --with-xmlrpc=shared \
  --enable-simplexml \
  --enable-xmlreader=shared \
  --enable-dom=shared \
  --enable-filter \
  --disable-debug \
  --with-openssl=shared \
  --with-pcre-regex=/usr \
  --with-zlib=shared,/usr \
  --enable-bcmath=shared \
  --with-bz2=shared,/usr \
  --enable-calendar=shared \
  --enable-ctype=shared \
  --with-curl=shared \
  --enable-dba=shared \
  --with-gdbm=/usr \
  --with-db4=/usr \
  --enable-exif=shared \
  --enable-ftp=shared \
  --with-gd=shared \
  --with-jpeg-dir=/usr \
  --with-png-dir=/usr \
  --with-zlib-dir=/usr \
  --with-xpm-dir=/usr \
  --with-freetype-dir=/usr \
  --with-gettext=shared,/usr \
  --with-gmp=shared,/usr \
  --with-iconv=shared \
  --with-imap-ssl=/usr \
  --with-imap=$IMAPLIBDIR \
  --with-ldap=shared \
  --enable-mbstring=shared \
  --enable-hash \
  --enable-mysqlnd=shared \
  --with-mysqli=shared,mysqlnd \
  --with-mysql-sock=/var/run/mysql/mysql.sock \
  --with-iodbc=shared,/usr \
  --enable-pdo=shared \
  --with-pdo-mysql=shared,mysqlnd \
  --with-pdo-sqlite=shared,/usr \
  --with-pdo-odbc=shared,iODBC,/usr \
  --with-pspell=shared,/usr \
  --with-enchant=shared,/usr \
  --enable-shmop=shared \
  --with-snmp=shared,/usr \
  --enable-soap=shared \
  --enable-sockets \
  --with-sqlite3=shared \
  --enable-sysvmsg \
  --enable-sysvsem \
  --enable-sysvshm \
  --enable-wddx=shared \
  --with-xsl=shared,/usr \
  --enable-zip=shared \
  --with-tsrm-pthreads \
  --enable-intl=shared \
  --enable-opcache \
  --enable-shared=yes \
  --enable-static=no \
  --with-gnu-ld \
  --with-pic \
  --enable-phpdbg \
  --with-sodium \
  --without-readline \
  --with-libedit \
  --with-password-argon2 \
  --build=$ARCH-slackware-linux || exit 1


The following PHP components are enabled (according to my distro): 
+extension=bcmath
+extension=bz2
+extension=calendar
+extension=ctype
+extension=curl
+extension=dba
+extension=dom
+extension=enchant
+extension=exif
+extension=ftp
+extension=gd
+extension=gettext
+extension=gmp
+extension=iconv
+extension=intl
+extension=ldap
+extension=mbstring
+extension=mysqlnd
+extension=mysqli
+extension=odbc
+extension=openssl
+zend_extension=opcache
+extension=pdo
+extension=pdo_mysql
+extension=pdo_sqlite
+extension=pdo_odbc
+extension=pspell
+extension=shmop
+extension=snmp
+extension=soap
+extension=sqlite3
+extension=tokenizer
+extension=wddx
+extension=xmlreader
+extension=xmlrpc
+extension=xsl
+extension=zip
+extension=zlib

============== Analysis of core dump =================================
Thread 1 (Thread 0x7faea5430700 (LWP 5591)):
#0  0x00007faed1b56363 in __strchr_sse2 () at /lib64/libc.so.6
#1  0x00007faed1b06848 in putenv () at /lib64/libc.so.6
#2  0x00007faec54024d6 in php_putenv_destructor (zv=0x7fae64982f80) at /tmp/php-7.3.19/ext/standard/basic_functions.c:3483
        pe = 0x7fae64956360
#3  0x00007faec5638489 in zend_hash_destroy (ht=0x7fae8c07fba8) at /tmp/php-7.3.19/Zend/zend_hash.c:1429
        p = 0x7fae64982f80
        end = 0x7fae64982fa0
#4  0x00007faec5404056 in zm_deactivate_basic (type=1, module_number=18) at /tmp/php-7.3.19/ext/standard/basic_functions.c:3844
#5  0x00007faec56244c0 in zend_deactivate_modules () at /tmp/php-7.3.19/Zend/zend_API.c:2648
        module = 0x55d1cccff530
        p = 0x55d1ccfe1338
        __orig_bailout = 0x0
        __bailout =
---Type <return> to continue, or q <return> to quit---
                {{__jmpbuf = {140387650275024, -5732632193025448223, 0, 140388115631583, 140388073670400, 0, -5732632193054808351, -5732702830982076703}, __mask_was_saved = 0, __saved_mask = {__val = {12714041233733445345, 140385301037056, 140388842331298, 140388073664552, 0, 6, 4294967295, 100, 140387649847328, 36, 140387649899096, 0, 0, 140388073664304, 140388612397665, 0}}}}
#6  0x00007faec553066c in php_request_shutdown (dummy=0x0) at /tmp/php-7.3.19/main/main.c:1902
        report_memleaks = 1 '\001'
#7  0x00007faec57bef0d in php_apache_request_dtor (r=0x7fae8800e3e0) at /tmp/php-7.3.19/sapi/apache2handler/sapi_apache2.c:539
#8  0x00007faec57bfa3f in php_handler (r=0x7fae8800e3e0) at /tmp/php-7.3.19/sapi/apache2handler/sapi_apache2.c:711
        ctx = 0x7fae8800c048
        conf = 0x7fae88009620
        brigade = 0x7fae880186e8
        bucket = 0x0
        rv = 0
        parent_req = 0x0
#9  0x000055d1cada7b9e in ap_run_handler (r=0x7fae8800e3e0) at config.c:170
        pHook = 0x55d1ccaed130
        n = 16
        rv = -1
#10 0x000055d1cada86db in ap_invoke_handler (r=0x7fae8800e3e0) at config.c:444
        handler = 0x0
        p = 0x7fae8800e3e0 "\bÃ\025\210®\177"
        result = 0
        old_handler = 0x7fae88016c08 "application/x-httpd-php"
        ignore = 0x55d1cad9c46e <ap_process_request_internal+2297> "\211Eü\203}ü"
#11 0x000055d1cadc6fdb in ap_internal_redirect (new_uri=0x7fae8800e338 "/index.php?message_path=wp%3Aproduct%3Aadmin_notices&query=post%253D323%252Caction%253Dedit%252Cclassic-editor%253D&full_jp_logo_exists=false&_wpnonce=c9341fc148", r=0x7fae8815c380)
    at http_request.c:790
        access_status = 0
        new = 0x7fae8800e3e0
#12 0x00007faec644efed in handler_redirect (r=0x7fae8815c380) at mod_rewrite.c:5259
#13 0x000055d1cada7b9e in ap_run_handler (r=0x7fae8815c380) at config.c:170
        pHook = 0x55d1ccaed130
        n = 14
        rv = -1
#14 0x000055d1cada86db in ap_invoke_handler (r=0x7fae8815c380) at config.c:444
        handler = 0x0
        p = 0x7fae8815c380 "\bÃ\025\210®\177"
        result = 0
        old_handler = 0x7faec6451260 "redirect-handler"
        ignore = 0x55d1cad9c46e <ap_process_request_internal+2297> "\211Eü\203}ü"
#15 0x000055d1cadc60d1 in ap_process_async_request (r=0x7fae8815c380) at http_request.c:452
        c = 0x7faea0031298
        access_status = 0
#16 0x000055d1cadc2168 in ap_process_http_async_connection (c=0x7faea0031298) at http_core.c:158
        r = 0x7fae8815c380
        cs = 0x7faea0031260
#17 0x000055d1cadc2373 in ap_process_http_connection (c=0x7faea0031298) at http_core.c:252
#18 0x000055d1cadb5b3c in ap_run_process_connection (c=0x7faea0031298) at connection.c:42
        pHook = 0x55d1ccaedcb0
        n = 3
        rv = -1
#19 0x00007faed1025d43 in process_socket (thd=0x55d1ccb33448, p=0x7faea0030f68, sock=0x7faea0030ff0, cs=0x7faea00311f0, my_child_nu---Type <return> to continue, or q <return> to quit---
m=0, my_thread_num=4) at event.c:1050
        c = 0x7faea0031298
        conn_id = 4
        clogging = 0
        rv = -1522336112
        rc = 0
#20 0x00007faed1027ee5 in worker_thread (thd=0x55d1ccb33448, dummy=0x7faea0001340) at event.c:2083
        csd = 0x7faea0030ff0
        cs = 0x7faea00311f0
        te = 0x0
        ptrans = 0x7faea0030f68
        ti = 0x7faea0001340
        process_slot = 0
        thread_slot = 4
        rv = 0
        is_idle = 0
#21 0x00007faed20a1684 in start_thread () at /lib64/libpthread.so.0
#22 0x00007faed1bd3eed in clone () at /lib64/libc.so.6



Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2020-06-12 16:56 UTC] nikic@php.net
Given the trace, this is likely running into the fact that putenv() is not thread-safe. This has been mostly mitigated in PHP 7.4 with https://github.com/php/php-src/commit/072eb6dd77b079a6f90ca5b155f9b0add1b5f2d4.
 [2020-06-12 17:02 UTC] andrixnet at yahoo dot com
Any chance of the fix being backported to 7.3 in a future revision?
Besides WP, we are hosting sites which still need work to be 7.4 compatible.

Also, what makes this be strongly related to WP?
 [2020-06-12 20:24 UTC] andrixnet at yahoo dot com
Further crashes with backtrace: 

Thread 1 (Thread 0x7f97857fa700 (LWP 16428)):
#0  0x00007f97b8d3a028 in __strncmp_sse2 () at /lib64/libc.so.6
#1  0x00007f97ac5e7d0a in zif_putenv (execute_data=0x7f9746c26700, return_value=0x7f97857f5060)
    at /tmp/php-7.3.19/ext/standard/basic_functions.c:4231
 [2020-06-12 20:58 UTC] andrixnet at yahoo dot com
I am trying to backport myself that code to 7.3.
Yet one of the blocks that now has tsrm_env_lock yield this: 

Thread 1 (Thread 0x7f97857fa700 (LWP 16428)):
#0  0x00007f97b8d3a028 in __strncmp_sse2 () at /lib64/libc.so.6
#1  0x00007f97ac5e7d0a in zif_putenv (execute_data=0x7f9746c26700, return_value=0x7f97857f5060)
    at /tmp/php-7.3.19/ext/standard/basic_functions.c:4231
        setting = 0x7f978f486b78 "MAGICK_THREAD_LIMIT=1"
        setting_len = 21
        p = 0x7f97767f5eb3 ""
        env = 0x7f97781bb448
        pe =
          {putenv_string = 0x7f97767f5eb8 "MAGICK_THREAD_LIMIT=1", previous_value = 0x0, key = 0x7f97767f5ea0 "MAGICK_THREAD_LIMIT", key_len = 19}
#2  0x00007f97ac982ebd in execute_ex () at /tmp/php-7.3.19/Zend/zend_vm_execute.h:649
        call = 0x7f9746c26700
        fbc = 0x7f975c0f3840
        ret = 0x7f97857f5060
        retval =
            {value = {lval = 140288916162632, dval = 6.931193396825927e-310, counted = 0x7f978f038848, str = 0x7f978f038848, arr = 0x7f978f038848, obj = 0x7f978f038848, res = 0x7f978f038848, ref = 0x7f978f038848, ast = 0x7f978f038848, zv = 0x7f978f038848, ptr = 0x7f978f038848, ce = 0x7f978f038848, func = 0x7f978f038848, ww = {w1 = 2399373384, w2 = 32663}}, u1 = {v = {type = 1 '\001', type_flags = 0 '\000', u = {call_info = 0, extra = 0}}, type_info = 1}, u2 = {next = 0, cache_slot = 0, opline_num = 0, lineno = 0, num_args = 0, fe_pos = 0, fe_iter_idx = 0, access_flags = 0, property_guard = 0, constant_flags = 0, extra = 0}}
        orig_opline = 0x0
        orig_execute_data = 0x7f97857fa700
#3  0x00007f97ac982ebd in execute_ex (ex=0x7f9746c26030) at /tmp/php-7.3.19/Zend/zend_vm_execute.h:55503

the zif_putenv call leads to PHP_FUNCTION(putenv) in basic_functions.c: 

        tsrm_env_lock();
        zend_hash_str_del(&BG(putenv_ht), pe.key, pe.key_len);

        /* find previous value */
        pe.previous_value = NULL;
        for (env = environ; env != NULL && *env != NULL; env++) {
            if (!strncmp(*env, pe.key, pe.key_len) && (*env)[pe.key_len] == '=') {  /* found it */
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this is the line refered to in the core dump.
#if defined(PHP_WIN32)
                        /* must copy previous value because MSVCRT's putenv can free the string without notice */
                        pe.previous_value = estrdup(*env);
#else
                        pe.previous_value = *env;
#endif
                        break;
                }
        }

#if HAVE_UNSETENV
        if (!p) { /* no '=' means we want to unset it */
                unsetenv(pe.putenv_string);
        }
        if (!p || putenv(pe.putenv_string) == 0) { /* success */
#else
# ifndef PHP_WIN32
        if (putenv(pe.putenv_string) == 0) { /* success */
# else
                wchar_t *keyw, *valw = NULL;

                keyw = php_win32_cp_any_to_w(pe.key);
                if (value) {
                        valw = php_win32_cp_any_to_w(value);
                }
                /* valw may be NULL, but the failed conversion still needs to be checked. */
                if (!keyw || !valw && value) {
                        efree(pe.putenv_string);
                        efree(pe.key);
                        free(keyw);
                        free(valw);
                        RETURN_FALSE;
                }

        error_code = SetEnvironmentVariableW(keyw, valw);

        if (error_code != 0
# ifndef ZTS
        /* We need both SetEnvironmentVariable and _putenv here as some
                dependency lib could use either way to read the environment.
                Obviously the CRT version will be useful more often. But
                generally, doing both brings us on the safe track at least
                in NTS build. */
        && _wputenv_s(keyw, valw ? valw : L"") == 0
# endif
        ) { /* success */
# endif
#endif
                zend_hash_str_add_mem(&BG(putenv_ht), pe.key, pe.key_len, &pe, sizeof(putenv_entry));
#ifdef HAVE_TZSET
                if (!strncmp(pe.key, "TZ", pe.key_len)) {
                        tzset();
                }
#endif
                tsrm_env_unlock();

They correspond to the 3rd and 4th changes in basic_functions.c here https://github.com/php/php-src/commit/072eb6dd77b079a6f90ca5b155f9b0add1b5f2d4
 [2020-06-12 21:25 UTC] andrixnet at yahoo dot com
In my backporting I tried this, without success. 
It behaves like it's not there, like the locking mechanism has no effect. 

PHP is compiled with --enable-maintainer-zts and thus all TSRM functionality should be available.

At this point my C knowledge gets overwhelmed. Please help.

=============================================================================
diff -urb php-7.3.19.orig/TSRM/TSRM.c php-7.3.19/TSRM/TSRM.c
--- php-7.3.19.orig/TSRM/TSRM.c	2020-06-09 11:06:31.000000000 +0300
+++ php-7.3.19/TSRM/TSRM.c	2020-06-12 21:21:06.233248609 +0300
@@ -53,6 +53,7 @@
 
 
 static MUTEX_T tsmm_mutex;	/* thread-safe memory manager mutex */
+static MUTEX_T tsrm_env_mutex; /* tsrm environ mutex */
 
 /* New thread handlers */
 static tsrm_thread_begin_func_t tsrm_new_thread_begin_handler = NULL;
@@ -164,6 +165,9 @@
 	tsmm_mutex = tsrm_mutex_alloc();
 
 	TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Started up TSRM, %d expected threads, %d expected resources", expected_threads, expected_resources));
+
+	tsrm_env_mutex = tsrm_mutex_alloc();
+
 	return 1;
 }/*}}}*/
 
@@ -208,6 +212,8 @@
 	}
 	tsrm_mutex_free(tsmm_mutex);
 	tsmm_mutex = NULL;
+	tsrm_mutex_free(tsrm_env_mutex);
+	tsrm_env_mutex = NULL;
 	TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Shutdown TSRM"));
 	if (tsrm_error_file!=stderr) {
 		fclose(tsrm_error_file);
@@ -228,6 +234,15 @@
 	tsrm_shutdown_handler = NULL;
 }/*}}}*/
 
+/* {{{ */
+/* environ lock api */
+TSRM_API int tsrm_env_lock() {
+    return tsrm_mutex_lock(tsrm_env_mutex);
+}
+
+TSRM_API int tsrm_env_unlock() {
+    return tsrm_mutex_unlock(tsrm_env_mutex);
+} /* }}} */
 
 /* allocates a new thread-safe-resource id */
 TSRM_API ts_rsrc_id ts_allocate_id(ts_rsrc_id *rsrc_id, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor)
diff -urb php-7.3.19.orig/TSRM/TSRM.h php-7.3.19/TSRM/TSRM.h
--- php-7.3.19.orig/TSRM/TSRM.h	2020-06-09 11:06:31.000000000 +0300
+++ php-7.3.19/TSRM/TSRM.h	2020-06-12 21:04:02.716411401 +0300
@@ -91,6 +91,10 @@
 TSRM_API int tsrm_startup(int expected_threads, int expected_resources, int debug_level, char *debug_filename);
 TSRM_API void tsrm_shutdown(void);
 
+/* environ lock API */
+TSRM_API int tsrm_env_lock();
+TSRM_API int tsrm_env_unlock();
+
 /* allocates a new thread-safe-resource id */
 TSRM_API ts_rsrc_id ts_allocate_id(ts_rsrc_id *rsrc_id, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor);
 
@@ -183,6 +187,9 @@
 
 #else /* non ZTS */
 
+#define tsrm_env_lock()    0
+#define tsrm_env_unlock()  0
+
 #define TSRMLS_FETCH()
 #define TSRMLS_FETCH_FROM_CTX(ctx)
 #define TSRMLS_SET_CTX(ctx)
diff -urb php-7.3.19.orig/UPGRADING.INTERNALS php-7.3.19/UPGRADING.INTERNALS
--- php-7.3.19.orig/UPGRADING.INTERNALS	2020-06-09 11:06:31.000000000 +0300
+++ php-7.3.19/UPGRADING.INTERNALS	2020-06-12 21:10:30.352344136 +0300
@@ -29,6 +29,7 @@
   z. HAVE_ST_BLKSIZE and HAVE_ST_RDEV
   aa. RETSIGTYPE
   bb. php_setcookie
+  cc. TSRM environment locking
 
 2. Build system changes
   a. Unix build system changes
@@ -181,6 +182,19 @@
                       zend_string *path, zend_string *domain, int secure,
                       int httponly, zend_string *samesite, int url_encode);
 
+ cc. TSRM adds tsrm_env_lock() and tsrm_env_unlock() for ZTS:
+     code that may change environ and may run concurrently with user code in ZTS
+     is expected to use this exclusion API to maintain as much safety as reasonable.
+     This results in "thread safe" getenv/putenv in Windows and Unix, however
+     functions that may read the environment without exclusion still exist,
+     for example:
+       - setlocale
+       - mktime
+       - tzset
+     The above is not an exhaustive list of such functions, while getenv/putenv will
+     behave as if they are safe, care should still be taken in multi-threaded
+     environments.
+
 ========================
 2. Build system changes
 ========================
diff -urb php-7.3.19.orig/ext/standard/basic_functions.c php-7.3.19/ext/standard/basic_functions.c
--- php-7.3.19.orig/ext/standard/basic_functions.c	2020-06-09 11:06:36.000000000 +0300
+++ php-7.3.19/ext/standard/basic_functions.c	2020-06-12 23:08:03.612663536 +0300
@@ -3472,6 +3472,7 @@
 {
 	putenv_entry *pe = Z_PTR_P(zv);
 
+
 	if (pe->previous_value) {
 # if defined(PHP_WIN32)
 		/* MSVCRT has a bug in putenv() when setting a variable that
@@ -3511,6 +3512,7 @@
 	}
 #endif
 
+
 	efree(pe->putenv_string);
 	efree(pe->key);
 	efree(pe);
@@ -3811,7 +3813,9 @@
 	BG(page_inode) = -1;
 	BG(page_mtime) = -1;
 #ifdef HAVE_PUTENV
+	tsrm_env_lock();
 	zend_hash_init(&BG(putenv_ht), 1, NULL, php_putenv_destructor, 0);
+	tsrm_env_unlock();
 #endif
 	BG(user_shutdown_function_names) = NULL;
 
@@ -3841,7 +3845,9 @@
 	ZVAL_UNDEF(&BG(strtok_zval));
 	BG(strtok_string) = NULL;
 #ifdef HAVE_PUTENV
+	tsrm_env_lock();
 	zend_hash_destroy(&BG(putenv_ht));
+	tsrm_env_unlock();
 #endif
 
 	BG(mt_rand_is_seeded) = 0;
@@ -4150,11 +4156,22 @@
 		}
 	}
 #else
+
+	tsrm_env_lock();
+
 	/* system method returns a const */
 	ptr = getenv(str);
+
+	if (ptr) {
+		RETVAL_STRING(ptr);
+	}
+
+	tsrm_env_unlock();
+
 	if (ptr) {
-		RETURN_STRING(ptr);
+	    return;
 	}
+
 #endif
 	RETURN_FALSE;
 }
@@ -4205,6 +4222,7 @@
 	}
 #endif
 
+	tsrm_env_lock();
 	zend_hash_str_del(&BG(putenv_ht), pe.key, pe.key_len);
 
 	/* find previous value */
@@ -4265,6 +4283,7 @@
 			tzset();
 		}
 #endif
+		tsrm_env_unlock();
 #if defined(PHP_WIN32)
 		free(keyw);
 		free(valw);
diff -urb php-7.3.19.orig/ext/standard/info.c php-7.3.19/ext/standard/info.c
--- php-7.3.19.orig/ext/standard/info.c	2020-06-09 11:06:36.000000000 +0300
+++ php-7.3.19/ext/standard/info.c	2020-06-12 21:16:19.887288448 +0300
@@ -965,6 +965,7 @@
 		SECTION("Environment");
 		php_info_print_table_start();
 		php_info_print_table_header(2, "Variable", "Value");
+		tsrm_env_lock();
 		for (env=environ; env!=NULL && *env !=NULL; env++) {
 			tmp1 = estrdup(*env);
 			if (!(tmp2=strchr(tmp1,'='))) { /* malformed entry? */
@@ -976,6 +977,7 @@
 			php_info_print_table_row(2, tmp1, tmp2);
 			efree(tmp1);
 		}
+		tsrm_env_unlock();
 		php_info_print_table_end();
 	}
 
diff -urb php-7.3.19.orig/main/php_variables.c php-7.3.19/main/php_variables.c
--- php-7.3.19.orig/main/php_variables.c	2020-06-09 11:06:31.000000000 +0300
+++ php-7.3.19/main/php_variables.c	2020-06-12 21:18:31.840268566 +0300
@@ -580,6 +580,8 @@
 	char *environment, *env;
 #endif
 
+	tsrm_env_lock();
+
 #ifndef PHP_WIN32
 	for (env = environ; env != NULL && *env != NULL; env++) {
 		import_environment_variable(Z_ARRVAL_P(array_ptr), *env);
@@ -591,6 +593,8 @@
 	}
 	FreeEnvironmentStringsA(environment);
 #endif
+
+	tsrm_env_unlock();
 }
 
 zend_bool php_std_auto_global_callback(char *name, uint32_t name_len)
diff -urb php-7.3.19.orig/sapi/litespeed/lsapi_main.c php-7.3.19/sapi/litespeed/lsapi_main.c
--- php-7.3.19.orig/sapi/litespeed/lsapi_main.c	2020-06-09 11:06:31.000000000 +0300
+++ php-7.3.19/sapi/litespeed/lsapi_main.c	2020-06-12 21:04:02.720411400 +0300
@@ -249,6 +249,7 @@
         return;
     }
 
+    tsrm_env_lock();
     for (env = environ; env != NULL && *env != NULL; env++) {
         p = strchr(*env, '=');
         if (!p) {               /* malformed entry? */
@@ -263,6 +264,7 @@
         t[nlen] = '\0';
         add_variable(t, nlen, p + 1, strlen( p + 1 ), array_ptr);
     }
+    tsrm_env_unlock();
     if (t != buf && t != NULL) {
         efree(t);
     }
 [2021-05-15 10:04 UTC] php at linocomm dot net
I am running into the same problem with PHP 7.4.19 which would indicate that the problem is not fully fixed with https://github.com/php/php-src/commit/072eb6dd77b079a6f90ca5b155f9b0add1b5f2d4.

Environment is Centos 7 with the only site running on the server a WooCommerce site, latest version.

The problem doesn't happen with the same site on another server running Centos 8 with Apache version 7.2.24. This leads me to think that it is either a problem specific to PHP 7.3/7.4, or that some incompatible modules are causing it.

In all cases, the mpm_event module is used. I cannot reproduce the problem with mpm_prefork, which is reason to think it is a thread-safe problem.
 [2021-05-21 11:46 UTC] krakjoe@php.net
-Status: Open +Status: Wont fix
 [2021-05-21 11:46 UTC] krakjoe@php.net
The environment is inherently not thread safe. The only fix we can provide, and did, is very narrow in scope - it can only ensure that core uses the environment safely, but obviously all the other code you are loading is not obliged to use our lock on the environment and has no way too, they are still going to manipulate it in a non-thread safe way.

There is nothing more we can do about this, sorry.
 [2021-05-21 17:46 UTC] andrixnet at yahoo dot com
I know there are many components and many dependencies. 
However I can't but wander: same webapp on same PHP version, yet built on another  distro doesn't seem to have this problem. 
And I am talking from personal experience and related experience of colegues involved in similar projects.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 21 14:01:32 2024 UTC