Skip to content

Commit 5c32624

Browse files
ndosschecmb69
andcommitted
Use ZendMM in ext-gmp
While libgmp uses true globals to track the allocator, and is therefore not safe to use in a threaded environment, we can make use of a thread-local variable that indicates whether the current thread is currently performing a PHP request. We set this TLS global to true if it is in RINIT, and set it to false in post-RSHUTDOWN. This ensures that any (de)allocation during the request will go through ZendMM while keeping it possible for this thread to be reused or for other threads using libgmp. Co-authored-by: "Christoph M. Becker" <[email protected]>
1 parent bfca4c7 commit 5c32624

File tree

2 files changed

+57
-2
lines changed

2 files changed

+57
-2
lines changed

ext/gmp/gmp.c

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,14 @@ zend_module_entry gmp_module_entry = {
5959
ext_functions,
6060
ZEND_MODULE_STARTUP_N(gmp),
6161
NULL,
62-
NULL,
62+
ZEND_MODULE_ACTIVATE_N(gmp),
6363
ZEND_MODULE_DEACTIVATE_N(gmp),
6464
ZEND_MODULE_INFO_N(gmp),
6565
PHP_GMP_VERSION,
6666
ZEND_MODULE_GLOBALS(gmp),
6767
ZEND_GINIT(gmp),
6868
NULL,
69-
NULL,
69+
ZEND_MODULE_POST_ZEND_DEACTIVATE_N(gmp),
7070
STANDARD_MODULE_PROPERTIES_EX
7171
};
7272
/* }}} */
@@ -81,6 +81,16 @@ ZEND_GET_MODULE(gmp)
8181
static zend_class_entry *gmp_ce;
8282
static zend_object_handlers gmp_object_handlers;
8383

84+
/* Allocator state: `gmp_request_allocator` is a true TLS global
85+
* to indicate whether this thread is currently working on a PHP request.
86+
* Just checking EG() is not enough because other modules may be loaded in the webserver. */
87+
static TSRM_TLS bool gmp_request_allocator = false;
88+
/* True globals for the old allocator, as these are global state in gmplib,
89+
* this doesn't need to be TLS. */
90+
static void *(*gmp_old_alloc)(size_t);
91+
static void *(*gmp_old_realloc)(void *, size_t, size_t);
92+
static void (*gmp_old_free)(void *, size_t);
93+
8494
PHP_GMP_API zend_class_entry *php_gmp_class_entry(void) {
8595
return gmp_ce;
8696
}
@@ -521,6 +531,33 @@ static int gmp_unserialize(zval *object, zend_class_entry *ce, const unsigned ch
521531
}
522532
/* }}} */
523533

534+
static void *gmp_alloc(size_t size)
535+
{
536+
if (gmp_request_allocator) {
537+
return emalloc(size);
538+
} else {
539+
return gmp_old_alloc(size);
540+
}
541+
}
542+
543+
static void *gmp_realloc(void *ptr, size_t old_size, size_t new_size)
544+
{
545+
if (gmp_request_allocator) {
546+
return erealloc(ptr, new_size);
547+
} else {
548+
return gmp_old_realloc(ptr, old_size, new_size);
549+
}
550+
}
551+
552+
static void gmp_free(void *ptr, size_t size)
553+
{
554+
if (gmp_request_allocator) {
555+
efree_size(ptr, size);
556+
} else {
557+
return gmp_old_free(ptr, size);
558+
}
559+
}
560+
524561
/* {{{ ZEND_GINIT_FUNCTION */
525562
static ZEND_GINIT_FUNCTION(gmp)
526563
{
@@ -551,10 +588,19 @@ ZEND_MINIT_FUNCTION(gmp)
551588

552589
register_gmp_symbols(module_number);
553590

591+
mp_get_memory_functions(&gmp_old_alloc, &gmp_old_realloc, &gmp_old_free);
592+
mp_set_memory_functions(gmp_alloc, gmp_realloc, gmp_free);
593+
554594
return SUCCESS;
555595
}
556596
/* }}} */
557597

598+
ZEND_MODULE_ACTIVATE_D(gmp)
599+
{
600+
gmp_request_allocator = true;
601+
return SUCCESS;
602+
}
603+
558604
/* {{{ ZEND_RSHUTDOWN_FUNCTION */
559605
ZEND_MODULE_DEACTIVATE_D(gmp)
560606
{
@@ -567,6 +613,13 @@ ZEND_MODULE_DEACTIVATE_D(gmp)
567613
}
568614
/* }}} */
569615

616+
ZEND_MODULE_POST_ZEND_DEACTIVATE_D(gmp)
617+
{
618+
/* We have to deactivate it after all request state has been freed. */
619+
gmp_request_allocator = false;
620+
return SUCCESS;
621+
}
622+
570623
/* {{{ ZEND_MINFO_FUNCTION */
571624
ZEND_MODULE_INFO_D(gmp)
572625
{

ext/gmp/php_gmp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ extern zend_module_entry gmp_module_entry;
2626
#define PHP_GMP_VERSION PHP_VERSION
2727

2828
ZEND_MODULE_STARTUP_D(gmp);
29+
ZEND_MODULE_ACTIVATE_D(gmp);
2930
ZEND_MODULE_DEACTIVATE_D(gmp);
31+
ZEND_MODULE_POST_ZEND_DEACTIVATE_D(gmp);
3032
ZEND_MODULE_INFO_D(gmp);
3133

3234
ZEND_BEGIN_MODULE_GLOBALS(gmp)

0 commit comments

Comments
 (0)