Skip to content

Commit

Permalink
Fix "double free" bug against override function caused by function de…
Browse files Browse the repository at this point in the history
…structor on PHP 7.2.0+
  • Loading branch information
hnw committed Nov 19, 2017
1 parent 22442e5 commit a7584f4
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 3 deletions.
18 changes: 18 additions & 0 deletions php_timecop.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,24 @@ ZEND_END_MODULE_GLOBALS(timecop)
#define TIMECOP_OCE(cname, mname) \
{cname, mname, OVRD_CLASS_PREFIX cname, SAVE_FUNC_PREFIX mname}

/*
* Trick for guarding the multi-referenced internal function from function destructor on PHP 7.2.0+
* See: https://github.com/hnw/php-timecop/issues/29#issuecomment-332171527
*/
#define GUARD_FUNCTION_ARG_INFO_BEGIN(zend_func) { \
zend_arg_info *orig_arg_info; \
zend_function *zf = zend_func; \
if (zf->type == ZEND_INTERNAL_FUNCTION) { \
orig_arg_info = zf->common.arg_info; \
zf->common.arg_info = NULL; \
}

#define GUARD_FUNCTION_ARG_INFO_END() \
if (zf->type == ZEND_INTERNAL_FUNCTION) { \
zf->common.arg_info = orig_arg_info; \
} \
}

struct timecop_override_func_entry {
char *orig_func;
char *ovrd_func;
Expand Down
14 changes: 11 additions & 3 deletions timecop_php7.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_timecop_date_create_from_format, 0, 0, 2)
ZEND_ARG_INFO(0, format)
ZEND_ARG_INFO(0, time)
#if PHP_VERSION_ID >= 70200
ZEND_ARG_OBJ_INFO(0, object, DateTimeZone, 1)
ZEND_ARG_OBJ_INFO(0, object, DateTimeZone, 1)
#else
ZEND_ARG_INFO(0, object)
#endif
Expand Down Expand Up @@ -527,8 +527,10 @@ static int timecop_func_override()
zf_orig, sizeof(zend_internal_function));
function_add_ref(zf_orig);

GUARD_FUNCTION_ARG_INFO_BEGIN(zf_orig);
zend_hash_str_update_mem(EG(function_table), p->orig_func, strlen(p->orig_func),
zf_ovrd, sizeof(zend_internal_function));
GUARD_FUNCTION_ARG_INFO_END();
function_add_ref(zf_ovrd);

p++;
Expand Down Expand Up @@ -620,22 +622,28 @@ static int timecop_class_override()
static int timecop_func_override_clear()
{
const struct timecop_override_func_entry *p;
zend_function *zf_orig;
zend_function *zf_orig, *zf_ovld;

p = &(timecop_override_func_table[0]);
while (p->orig_func != NULL) {
zf_orig = zend_hash_str_find_ptr(EG(function_table),
p->save_func, strlen(p->save_func));
if (zf_orig == NULL) {
zf_ovld = zend_hash_str_find_ptr(EG(function_table),
p->orig_func, strlen(p->orig_func));
if (zf_orig == NULL || zf_ovld == NULL) {
p++;
continue;
}

GUARD_FUNCTION_ARG_INFO_BEGIN(zf_ovld);
zend_hash_str_update_mem(EG(function_table), p->orig_func, strlen(p->orig_func),
zf_orig, sizeof(zend_internal_function));
GUARD_FUNCTION_ARG_INFO_END();
function_add_ref(zf_orig);

GUARD_FUNCTION_ARG_INFO_BEGIN(zf_orig);
zend_hash_str_del(EG(function_table), p->save_func, strlen(p->save_func));
GUARD_FUNCTION_ARG_INFO_END();

p++;
}
Expand Down

0 comments on commit a7584f4

Please sign in to comment.