Call to get resource in PHP 7.3.4 intermittently returns nullptr

Viewed 110

I am investigating a crash which is occurring when our C++ program calls ts_resource(0) in PHP 7.3.4.

The code was written by a developer who has since left the company and I have very little knowledge of PHP. The original code was written for PHP 5.3 and has worked perfectly for years, but when PHP was upgraded to 7.3.4 our program started to crash intermittently. I discovered the crash is caused by a call to tsrm_get_ls_cache() which is returning a nullptr. I have added a check for the nullptr and so stopped the crash but I would like to know why the call to get the resource returns nullptr and what I can do to prevent it. I assume the problem is memory related as it is intermittent.

I am not sure what code to show as the calls to PHP in our code are extensive. The PHP is compiled with ZTS enabled so it multithreaded.

In the initialisation stage the thread safe manager is started with:

tsrm_startup(128, 1, 0, NULL);
ts_resource(0);
ZEND_TSRMLS_CACHE_UPDATE();

and our Execute function which is called each time PHP code is called starts with:

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;

Next some initialisation of the context class is carried out before calling php_request_startup(TSRMLS_C);

When the call to get resource fails, the actual failure occurs because malloc fails: The call to ts_resource(0) at the beginning of the Execute function calls into the following PHP function to allocate new resource:

allocate_new_resource(&thread_resources->next, thread_id);

and this call to malloc fails the allocation

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)); ...

If anyone can suggest any reasons why the resource allocation might be failing I would be very grateful.

1 Answers

Have you tried to use TSRMLS_CACHE_UPDATE instead of ZEND_TSRMLS_CACHE_UPDATE (notice ZEND_ prefix )?

So, as I have understood TSRMLS_CACHE_DEFINE should be set once per compilation unit. TSRMLS_CACHE_EXTERN should be included in other files and TSRMLS_CACHE_UPDATE should be called when appropriate.

Related