Вызов для получения ресурса в 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.

Другие вопросы по тегам