summaryrefslogtreecommitdiff
path: root/ext/opcache
diff options
context:
space:
mode:
Diffstat (limited to 'ext/opcache')
-rw-r--r--ext/opcache/Optimizer/optimize_func_calls.c2
-rw-r--r--ext/opcache/Optimizer/pass1_5.c209
-rw-r--r--ext/opcache/Optimizer/zend_optimizer.c8
-rw-r--r--ext/opcache/ZendAccelerator.c17
-rw-r--r--ext/opcache/ZendAccelerator.h1
-rw-r--r--ext/opcache/tests/bug68104.phpt19
-rw-r--r--ext/opcache/tests/bug68252.phpt20
-rw-r--r--ext/opcache/zend_accelerator_module.c2
8 files changed, 193 insertions, 85 deletions
diff --git a/ext/opcache/Optimizer/optimize_func_calls.c b/ext/opcache/Optimizer/optimize_func_calls.c
index aa62a4542d..9031a38f56 100644
--- a/ext/opcache/Optimizer/optimize_func_calls.c
+++ b/ext/opcache/Optimizer/optimize_func_calls.c
@@ -143,8 +143,6 @@ void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx TSRMLS
if (!(opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) && call_stack[call - 1].func) {
if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) {
opline->extended_value |= ZEND_ARG_COMPILE_TIME_BOUND | ZEND_ARG_SEND_BY_REF;
- } else if (opline->extended_value) {
- opline->extended_value |= ZEND_ARG_COMPILE_TIME_BOUND;
} else {
opline->opcode = ZEND_SEND_VAR;
opline->extended_value = 0;
diff --git a/ext/opcache/Optimizer/pass1_5.c b/ext/opcache/Optimizer/pass1_5.c
index b91ac5b50f..15bca2adf8 100644
--- a/ext/opcache/Optimizer/pass1_5.c
+++ b/ext/opcache/Optimizer/pass1_5.c
@@ -341,28 +341,75 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx TSRML
}
break;
- case ZEND_INIT_FCALL:
+ case ZEND_DO_FCALL: {
+ zend_op *send1_opline = opline - 1;
+ zend_op *send2_opline = NULL;
+ zend_op *init_opline = NULL;
+
+ while (send1_opline->opcode == ZEND_NOP) {
+ send1_opline--;
+ }
+ if (send1_opline->opcode != ZEND_SEND_VAL ||
+ ZEND_OP1_TYPE(send1_opline) != IS_CONST) {
+ /* don't colllect constants after unknown function call */
+ collect_constants = 0;
+ break;
+ }
+ if (send1_opline->op2.num == 2) {
+ send2_opline = send1_opline;
+ send1_opline--;
+ while (send1_opline->opcode == ZEND_NOP) {
+ send1_opline--;
+ }
+ if (send1_opline->opcode != ZEND_SEND_VAL ||
+ ZEND_OP1_TYPE(send1_opline) != IS_CONST) {
+ /* don't colllect constants after unknown function call */
+ collect_constants = 0;
+ break;
+ }
+ }
+ init_opline = send1_opline - 1;
+ while (init_opline->opcode == ZEND_NOP) {
+ init_opline--;
+ }
+ if (init_opline->opcode != ZEND_INIT_FCALL ||
+ ZEND_OP2_TYPE(init_opline) != IS_CONST ||
+ Z_TYPE(ZEND_OP2_LITERAL(init_opline)) != IS_STRING) {
+ /* don't colllect constants after unknown function call */
+ collect_constants = 0;
+ break;
+ }
+
/* define("name", scalar); */
- if (collect_constants &&
- ZEND_OP2_TYPE(opline) == IS_CONST &&
- Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING &&
- Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("define")-1 &&
- zend_binary_strcasecmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), "define", sizeof("define")-1) == 0) {
+ if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("define")-1 &&
+ zend_binary_strcasecmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), Z_STRLEN(ZEND_OP2_LITERAL(init_opline)), "define", sizeof("define")-1) == 0) {
- if ((opline+1)->opcode == ZEND_SEND_VAL &&
- ZEND_OP1_TYPE(opline+1) == IS_CONST &&
- Z_TYPE(ZEND_OP1_LITERAL(opline+1)) == IS_STRING &&
- (opline+2)->opcode == ZEND_SEND_VAL &&
- ZEND_OP1_TYPE(opline+2) == IS_CONST &&
- Z_TYPE(ZEND_OP1_LITERAL(opline+2)) <= IS_STRING &&
- (opline+3)->opcode == ZEND_DO_FCALL) {
-
- zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(opline+1), &ZEND_OP1_LITERAL(opline+2));
+ if (Z_TYPE(ZEND_OP1_LITERAL(send1_opline)) == IS_STRING &&
+ send2_opline &&
+ Z_TYPE(ZEND_OP1_LITERAL(send2_opline)) <= IS_STRING) {
+
+ if (collect_constants) {
+ zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(send1_opline), &ZEND_OP1_LITERAL(send2_opline));
+ }
+
+ if (RESULT_UNUSED(opline) &&
+ !zend_memnstr(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), "::", sizeof("::") - 1, Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)) + Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)))) {
+
+ opline->opcode = ZEND_DECLARE_CONST;
+ opline->op1_type = IS_CONST;
+ opline->op2_type = IS_CONST;
+ opline->result_type = IS_UNUSED;
+ opline->op1.constant = send1_opline->op1.constant;
+ opline->op2.constant = send2_opline->op1.constant;
+ opline->result.zv = NULL;
+
+ literal_dtor(&ZEND_OP2_LITERAL(init_opline));
+ MAKE_NOP(init_opline);
+ MAKE_NOP(send1_opline);
+ MAKE_NOP(send2_opline);
+ }
break;
}
- } else {
- /* don't colllect constants after any other function call */
- collect_constants = 0;
}
/* pre-evaluate constant functions:
@@ -372,42 +419,42 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx TSRML
is_callable(x)
extension_loaded(x)
*/
- if ((opline + 1)->opcode == ZEND_SEND_VAL &&
- (opline + 2)->opcode == ZEND_DO_FCALL &&
- ZEND_OP1_TYPE(opline + 1) == IS_CONST && Z_TYPE(ZEND_OP1_LITERAL(opline + 1)) == IS_STRING &&
- ZEND_OP2_TYPE(opline) == IS_CONST && Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
- if ((Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("function_exists")-1 &&
- !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)),
+ if (!send2_opline &&
+ Z_TYPE(ZEND_OP1_LITERAL(send1_opline)) == IS_STRING) {
+ if ((Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("function_exists")-1 &&
+ !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
"function_exists", sizeof("function_exists")-1)) ||
- (Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("is_callable")-1 &&
- !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)),
+ (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("is_callable")-1 &&
+ !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
"is_callable", sizeof("is_callable")))) {
zend_internal_function *func;
char *lc_name = zend_str_tolower_dup(
- Z_STRVAL(ZEND_OP1_LITERAL(opline + 1)), Z_STRLEN(ZEND_OP1_LITERAL(opline + 1)));
+ Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)));
- if ((func = zend_hash_str_find_ptr(EG(function_table), lc_name, Z_STRLEN(ZEND_OP1_LITERAL(opline + 1)))) != NULL &&
+ if ((func = zend_hash_str_find_ptr(EG(function_table), lc_name, Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)))) != NULL &&
func->type == ZEND_INTERNAL_FUNCTION &&
func->module->type == MODULE_PERSISTENT) {
zval t;
ZVAL_BOOL(&t, 1);
- if (zend_optimizer_replace_by_const(op_array, opline + 3, IS_VAR, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) {
- literal_dtor(&ZEND_OP2_LITERAL(opline));
+ if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t TSRMLS_CC)) {
+ literal_dtor(&ZEND_OP2_LITERAL(init_opline));
+ MAKE_NOP(init_opline);
+ literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
+ MAKE_NOP(send1_opline);
MAKE_NOP(opline);
- literal_dtor(&ZEND_OP1_LITERAL(opline + 1));
- MAKE_NOP(opline + 1);
- MAKE_NOP(opline + 2);
+ efree(lc_name);
+ break;
}
}
efree(lc_name);
- } else if (Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("extension_loaded")-1 &&
- !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)),
+ } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("extension_loaded")-1 &&
+ !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
"extension_loaded", sizeof("extension_loaded")-1)) {
zval t;
char *lc_name = zend_str_tolower_dup(
- Z_STRVAL(ZEND_OP1_LITERAL(opline + 1)), Z_STRLEN(ZEND_OP1_LITERAL(opline + 1)));
+ Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)));
zend_module_entry *m = zend_hash_str_find_ptr(&module_registry,
- lc_name, Z_STRLEN(ZEND_OP1_LITERAL(opline + 1)));
+ lc_name, Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)));
efree(lc_name);
if (!m) {
@@ -424,60 +471,89 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx TSRML
}
}
- if (zend_optimizer_replace_by_const(op_array, opline + 3, IS_VAR, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) {
- literal_dtor(&ZEND_OP2_LITERAL(opline));
+ if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t TSRMLS_CC)) {
+ literal_dtor(&ZEND_OP2_LITERAL(init_opline));
+ MAKE_NOP(init_opline);
+ literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
+ MAKE_NOP(send1_opline);
MAKE_NOP(opline);
- literal_dtor(&ZEND_OP1_LITERAL(opline + 1));
- MAKE_NOP(opline + 1);
- MAKE_NOP(opline + 2);
+ break;
}
- } else if (Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("defined")-1 &&
- !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)),
+ } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("defined")-1 &&
+ !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
"defined", sizeof("defined")-1)) {
zval t;
- if (zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline + 1)), &t, 0 TSRMLS_CC)) {
+ if (zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(send1_opline)), &t, 0 TSRMLS_CC)) {
ZVAL_BOOL(&t, 1);
- if (zend_optimizer_replace_by_const(op_array, opline + 3, IS_VAR, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) {
- literal_dtor(&ZEND_OP2_LITERAL(opline));
+ if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t TSRMLS_CC)) {
+ literal_dtor(&ZEND_OP2_LITERAL(init_opline));
+ MAKE_NOP(init_opline);
+ literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
+ MAKE_NOP(send1_opline);
MAKE_NOP(opline);
- literal_dtor(&ZEND_OP1_LITERAL(opline + 1));
- MAKE_NOP(opline + 1);
- MAKE_NOP(opline + 2);
+ break;
}
}
- } else if (Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("constant")-1 &&
- !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)),
+ } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("constant")-1 &&
+ !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
"constant", sizeof("constant")-1)) {
zval t;
- if (zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline + 1)), &t, 1 TSRMLS_CC)) {
- if (zend_optimizer_replace_by_const(op_array, opline + 3, IS_VAR, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) {
- literal_dtor(&ZEND_OP2_LITERAL(opline));
+ if (zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(send1_opline)), &t, 1 TSRMLS_CC)) {
+ if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t TSRMLS_CC)) {
+ literal_dtor(&ZEND_OP2_LITERAL(init_opline));
+ MAKE_NOP(init_opline);
+ literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
+ MAKE_NOP(send1_opline);
MAKE_NOP(opline);
- literal_dtor(&ZEND_OP1_LITERAL(opline + 1));
- MAKE_NOP(opline + 1);
- MAKE_NOP(opline + 2);
+ break;
}
}
} else if ((CG(compiler_options) & ZEND_COMPILE_NO_BUILTIN_STRLEN) == 0 &&
- Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("strlen")-1 &&
- !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)),
+ Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("strlen")-1 &&
+ !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
"strlen", sizeof("strlen")-1)) {
zval t;
- ZVAL_LONG(&t, Z_STRLEN(ZEND_OP1_LITERAL(opline + 1)));
- if (zend_optimizer_replace_by_const(op_array, opline + 3, IS_VAR, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) {
- literal_dtor(&ZEND_OP2_LITERAL(opline));
+ ZVAL_LONG(&t, Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)));
+ if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t TSRMLS_CC)) {
+ literal_dtor(&ZEND_OP2_LITERAL(init_opline));
+ MAKE_NOP(init_opline);
+ literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
+ MAKE_NOP(send1_opline);
MAKE_NOP(opline);
- literal_dtor(&ZEND_OP1_LITERAL(opline + 1));
- MAKE_NOP(opline + 1);
- MAKE_NOP(opline + 2);
+ break;
+ }
+ /* dirname(IS_CONST/IS_STRING) -> IS_CONST/IS_STRING */
+ } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("dirname")-1 &&
+ !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
+ "dirname", sizeof("dirname")-1) &&
+ IS_ABSOLUTE_PATH(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)))) {
+ zend_string *dirname = zend_string_init(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)), 0);
+ dirname->len = zend_dirname(dirname->val, dirname->len);
+ if (IS_ABSOLUTE_PATH(dirname->val, dirname->len)) {
+ zval t;
+
+ ZVAL_STR(&t, dirname);
+ if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t TSRMLS_CC)) {
+ literal_dtor(&ZEND_OP2_LITERAL(init_opline));
+ MAKE_NOP(init_opline);
+ literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
+ MAKE_NOP(send1_opline);
+ MAKE_NOP(opline);
+ break;
+ }
+ } else {
+ zend_string_release(dirname);
}
}
}
+ /* don't colllect constants after any other function call */
+ collect_constants = 0;
break;
+ }
case ZEND_STRLEN:
if (ZEND_OP1_TYPE(opline) == IS_CONST &&
Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) {
@@ -530,7 +606,6 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx TSRML
case ZEND_FE_RESET:
case ZEND_FE_FETCH:
case ZEND_NEW:
- case ZEND_DO_FCALL:
case ZEND_JMP_SET:
case ZEND_COALESCE:
collect_constants = 0;
diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c
index 1a6d0b675a..589028368f 100644
--- a/ext/opcache/Optimizer/zend_optimizer.c
+++ b/ext/opcache/Optimizer/zend_optimizer.c
@@ -283,6 +283,14 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array,
case ZEND_ASSIGN_DIM:
case ZEND_SEPARATE:
return 0;
+ case ZEND_SEND_VAR:
+ opline->extended_value = 0;
+ opline->opcode = ZEND_SEND_VAL;
+ break;
+ case ZEND_SEND_VAR_EX:
+ opline->extended_value = 0;
+ opline->opcode = ZEND_SEND_VAL_EX;
+ break;
case ZEND_SEND_VAR_NO_REF:
if (opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) {
if (opline->extended_value & ZEND_ARG_SEND_BY_REF) {
diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c
index 6f37146a91..42117ae1b7 100644
--- a/ext/opcache/ZendAccelerator.c
+++ b/ext/opcache/ZendAccelerator.c
@@ -878,12 +878,12 @@ static inline int do_validate_timestamps(zend_persistent_script *persistent_scri
int validate_timestamp_and_record(zend_persistent_script *persistent_script, zend_file_handle *file_handle TSRMLS_DC)
{
if (ZCG(accel_directives).revalidate_freq &&
- (persistent_script->dynamic_members.revalidate >= ZCSG(revalidate_at))) {
+ persistent_script->dynamic_members.revalidate >= ZCG(request_time)) {
return SUCCESS;
} else if (do_validate_timestamps(persistent_script, file_handle TSRMLS_CC) == FAILURE) {
return FAILURE;
} else {
- persistent_script->dynamic_members.revalidate = ZCSG(revalidate_at);
+ persistent_script->dynamic_members.revalidate = ZCG(request_time) + ZCG(accel_directives).revalidate_freq;
return SUCCESS;
}
}
@@ -1424,7 +1424,7 @@ static zend_persistent_script *compile_and_cache_file(zend_file_handle *file_han
* otherwise we have a race-condition.
*/
new_persistent_script->timestamp = timestamp;
- new_persistent_script->dynamic_members.revalidate = ZCSG(revalidate_at);
+ new_persistent_script->dynamic_members.revalidate = ZCG(request_time) + ZCG(accel_directives).revalidate_freq;
}
if (file_handle->opened_path) {
@@ -1894,13 +1894,6 @@ static void accel_activate(void)
zend_accel_error(ACCEL_LOG_WARNING, "Internal functions count changed - was %d, now %d", ZCG(internal_functions_count), zend_hash_num_elements(&ZCG(function_table)));
}
- if (ZCG(accel_directives).validate_timestamps) {
- time_t now = ZCG(request_time);
- if (now > ZCSG(revalidate_at) + (time_t)ZCG(accel_directives).revalidate_freq) {
- ZCSG(revalidate_at) = now;
- }
- }
-
ZCG(cwd) = NULL;
SHM_PROTECT();
@@ -2353,10 +2346,6 @@ static int accel_startup(zend_extension *extension)
accelerator_orig_zend_resolve_path = zend_resolve_path;
zend_resolve_path = persistent_zend_resolve_path;
- if (ZCG(accel_directives).validate_timestamps) {
- ZCSG(revalidate_at) = zend_accel_get_time() + ZCG(accel_directives).revalidate_freq;
- }
-
/* Override chdir() function */
if ((func = zend_hash_str_find_ptr(CG(function_table), "chdir", sizeof("chdir")-1)) != NULL &&
func->type == ZEND_INTERNAL_FUNCTION) {
diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h
index 066c957e9f..119148aa27 100644
--- a/ext/opcache/ZendAccelerator.h
+++ b/ext/opcache/ZendAccelerator.h
@@ -270,7 +270,6 @@ typedef struct _zend_accel_shared_globals {
LONGLONG restart_in;
#endif
zend_bool restart_in_progress;
- time_t revalidate_at;
/* Interned Strings Support */
char *interned_strings_start;
char *interned_strings_top;
diff --git a/ext/opcache/tests/bug68104.phpt b/ext/opcache/tests/bug68104.phpt
new file mode 100644
index 0000000000..8d3bf70a4d
--- /dev/null
+++ b/ext/opcache/tests/bug68104.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Bug #68104 (Segfault while pre-evaluating a disabled function)
+--CREDITS--
+manuel <manuel@mausz.at>
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+disable_functions=dl
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+var_dump(is_callable("dl"));
+dl("a.so");
+?>
+--EXPECTF--
+bool(true)
+
+Warning: dl() has been disabled for security reasons in %sbug68104.php on line %d
diff --git a/ext/opcache/tests/bug68252.phpt b/ext/opcache/tests/bug68252.phpt
new file mode 100644
index 0000000000..e05467a244
--- /dev/null
+++ b/ext/opcache/tests/bug68252.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Bug #68252 (segfault in Zend/zend_hash.c in function _zend_hash_del_el)
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.fast_shutdown=1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+/* run this test script with valgrind */
+function a() {
+ echo "okey";
+}
+
+create_function('', 'var_dump("22");');
+
+a();
+--EXPECT--
+okey
diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c
index 001c3ee9ed..fcaf96408c 100644
--- a/ext/opcache/zend_accelerator_module.c
+++ b/ext/opcache/zend_accelerator_module.c
@@ -499,7 +499,7 @@ static int accelerator_get_scripts(zval *return_value TSRMLS_DC)
timerclear(&exec_time);
timerclear(&fetch_time);
- zend_hash_str_update(Z_ARRVAL_P(return_value), cache_entry->key, cache_entry->key_length-1, &persistent_script_report);
+ zend_hash_str_update(Z_ARRVAL_P(return_value), cache_entry->key, cache_entry->key_length, &persistent_script_report);
}
}
accelerator_shm_read_unlock(TSRMLS_C);