Вызов для получения ресурса в PHP 7.3.4 периодически возвращает nullptr
Я исследую сбой, который происходит, когда наша программа на C++ вызывает ts_resource(0) в PHP 7.3.4.
Код был написан разработчиком, который с тех пор покинул компанию, и я очень мало знаю PHP. Первоначальный код был написан для PHP 5.3 и отлично работал в течение многих лет, но когда PHP был обновлен до 7.3.4, наша программа начала периодически падать. Я обнаружил, что сбой вызван вызовом tsrm_get_ls_cache(), который возвращает nullptr. Я добавил проверку для nullptr и остановил сбой, но я хотел бы знать, почему вызов для получения ресурса возвращает nullptr и что я могу сделать, чтобы предотвратить его. Я предполагаю, что проблема связана с памятью, так как она прерывистая.
Я не уверен, какой код показывать, так как вызовы PHP в нашем коде обширны. PHP скомпилирован с поддержкой ZTS, поэтому он многопоточный.
На этапе инициализации диспетчер безопасности потока запускается с:
tsrm_startup(128, 1, 0, NULL);
ts_resource(0);
ZEND_TSRMLS_CACHE_UPDATE();
и наша функция Execute, которая вызывается каждый раз, когда вызывается код PHP, начинается с:
ts_resource(0);
ZEND_TSRMLS_CACHE_UPDATE();
if (tsrm_get_ls_cache() == nullptr)
return false;
ExecuteContext context;
context.pOutputStream = pOutputStream;
SG(server_context) = (void*)&context;
Затем некоторая инициализация класса контекста выполняется перед вызовом php_request_startup(TSRMLS_C);
Когда происходит сбой вызова для получения ресурса, происходит фактический сбой, потому что происходит сбой malloc: вызов ts_resource(0) в начале функции Execute вызывает следующую функцию PHP для выделения нового ресурса:
allocate_new_resource(&thread_resources->next, thread_id);
и этот вызов Malloc не удается выделить
static void allocate_new_resource(tsrm_tls_entry **thread_resources_ptr, THREAD_T thread_id)
{
(*thread_resources_ptr) = (tsrm_tls_entry *) malloc(sizeof(tsrm_tls_entry));
...
Если кто-то может предложить какие-либо причины, почему распределение ресурсов может быть неудачным, я был бы очень благодарен.
0 ответов
Вы пробовали использовать TSRMLS_CACHE_UPDATE вместо ZEND_TSRMLS_CACHE_UPDATE (обратите внимание на префикс ZEND_)?
Итак, как я понял, TSRMLS_CACHE_DEFINE следует устанавливать один раз для каждой единицы компиляции. TSRMLS_CACHE_EXTERN следует включать в другие файлы, и при необходимости следует вызывать TSRMLS_CACHE_UPDATE.