Partial fix that allows internal constructors to set $this to null.

The address of $this passed to drectly called internal constructor in execute_data->return_value.
Internal constructors should use ZEND_CTOR_MAKE_NULL() macro (insted of previous ZEND_NULL(EG(This))) to do the work.

This patch doesn't fix the problem for indirectly called constructors. e.g. parant::__construct().
This commit is contained in:
Dmitry Stogov 2014-07-09 11:57:42 +04:00
parent ca414c6904
commit 1dd07d6bf4
13 changed files with 124 additions and 8 deletions

View File

@ -637,6 +637,27 @@ END_EXTERN_C()
} \
} while (0)
/* May be used in internal constructors to make them return NULL */
#if 1 // support for directly called constructors only ???
#define ZEND_CTOR_MAKE_NULL() do { \
if (EG(current_execute_data)->return_value) { \
zval_ptr_dtor(EG(current_execute_data)->return_value); \
ZVAL_NULL(EG(current_execute_data)->return_value); \
} \
} while (0)
#else // attempt to support calls to parent::__construct() ???
#define ZEND_CTOR_MAKE_NULL() do { \
if (EG(current_execute_data)->return_value) { \
zval_ptr_dtor(EG(current_execute_data)->return_value); \
ZVAL_NULL(EG(current_execute_data)->return_value); \
} else if (EG(current_execute_data)->prev_execute_data && \
EG(current_execute_data)->prev_execute_data->object == \
EG(current_execute_data)->object) { \
EG(current_execute_data)->prev_execute_data->object = NULL; \
} \
} while (0)
#endif
#define RETURN_ZVAL_FAST(z) { RETVAL_ZVAL_FAST(z); return; }
#define HASH_OF(p) (Z_TYPE_P(p)==IS_ARRAY ? Z_ARRVAL_P(p) : ((Z_TYPE_P(p)==IS_OBJECT ? Z_OBJ_HT_P(p)->get_properties((p) TSRMLS_CC) : NULL)))

View File

@ -2363,6 +2363,10 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS
EX(call) = zend_vm_stack_push_call_frame(
fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC);
if (OP2_TYPE == IS_UNUSED) {
EX(call)->return_value = NULL;
}
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
@ -3490,6 +3494,9 @@ ZEND_VM_HANDLER(68, ZEND_NEW, ANY, ANY)
if (RETURN_VALUE_USED(opline)) {
ZVAL_COPY(EX_VAR(opline->result.var), &object_zval);
EX(call)->return_value = EX_VAR(opline->result.var);
} else {
EX(call)->return_value = NULL;
}
CHECK_EXCEPTION();

View File

@ -982,6 +982,9 @@ static int ZEND_FASTCALL ZEND_NEW_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
if (RETURN_VALUE_USED(opline)) {
ZVAL_COPY(EX_VAR(opline->result.var), &object_zval);
EX(call)->return_value = EX_VAR(opline->result.var);
} else {
EX(call)->return_value = NULL;
}
CHECK_EXCEPTION();
@ -3808,6 +3811,10 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER(
EX(call) = zend_vm_stack_push_call_frame(
fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC);
if (IS_CONST == IS_UNUSED) {
EX(call)->return_value = NULL;
}
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}
@ -4774,6 +4781,10 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZE
EX(call) = zend_vm_stack_push_call_frame(
fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC);
if (IS_TMP_VAR == IS_UNUSED) {
EX(call)->return_value = NULL;
}
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}
@ -5608,6 +5619,10 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZE
EX(call) = zend_vm_stack_push_call_frame(
fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC);
if (IS_VAR == IS_UNUSED) {
EX(call)->return_value = NULL;
}
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}
@ -6301,6 +6316,10 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER
EX(call) = zend_vm_stack_push_call_frame(
fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC);
if (IS_UNUSED == IS_UNUSED) {
EX(call)->return_value = NULL;
}
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}
@ -7130,6 +7149,10 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEN
EX(call) = zend_vm_stack_push_call_frame(
fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC);
if (IS_CV == IS_UNUSED) {
EX(call)->return_value = NULL;
}
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}
@ -15438,6 +15461,10 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZE
EX(call) = zend_vm_stack_push_call_frame(
fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC);
if (IS_CONST == IS_UNUSED) {
EX(call)->return_value = NULL;
}
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}
@ -17666,6 +17693,10 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND
EX(call) = zend_vm_stack_push_call_frame(
fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC);
if (IS_TMP_VAR == IS_UNUSED) {
EX(call)->return_value = NULL;
}
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}
@ -19861,6 +19892,10 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND
EX(call) = zend_vm_stack_push_call_frame(
fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC);
if (IS_VAR == IS_UNUSED) {
EX(call)->return_value = NULL;
}
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}
@ -21325,6 +21360,10 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(Z
EX(call) = zend_vm_stack_push_call_frame(
fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC);
if (IS_UNUSED == IS_UNUSED) {
EX(call)->return_value = NULL;
}
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}
@ -23228,6 +23267,10 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_
EX(call) = zend_vm_stack_push_call_frame(
fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC);
if (IS_CV == IS_UNUSED) {
EX(call)->return_value = NULL;
}
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}

View File

@ -2683,7 +2683,7 @@ PHP_METHOD(DateTime, __construct)
zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sO!", &time_str, &time_str_len, &timezone_object, date_ce_timezone)) {
if (!php_date_initialize(Z_PHPDATE_P(getThis()), time_str, time_str_len, NULL, timezone_object, 1 TSRMLS_CC)) {
//??? ZVAL_NULL(getThis());
ZEND_CTOR_MAKE_NULL();
}
}
zend_restore_error_handling(&error_handling TSRMLS_CC);

View File

@ -287,6 +287,7 @@ PHP_MINFO_FUNCTION(fileinfo)
if (object) { \
zend_object_store_ctor_failed(Z_OBJ_P(object) TSRMLS_CC); \
Z_OBJ_P(object) = NULL; \
ZEND_CTOR_MAKE_NULL(); \
} \
} while (0)

View File

@ -105,6 +105,7 @@ U_CFUNC PHP_METHOD(IntlRuleBasedBreakIterator, __construct)
if (Z_TYPE_P(return_value) == IS_OBJECT && Z_OBJ_P(return_value) == NULL) {
zend_object_store_ctor_failed(Z_OBJ(orig_this) TSRMLS_CC);
zval_dtor(&orig_this);
ZEND_CTOR_MAKE_NULL();
}
}

View File

@ -198,6 +198,8 @@ U_CFUNC PHP_METHOD(IntlGregorianCalendar, __construct)
if (Z_TYPE_P(return_value) == IS_OBJECT && Z_OBJ_P(return_value) == NULL) {
zend_object_store_ctor_failed(Z_OBJ(orig_this) TSRMLS_CC);
zval_dtor(&orig_this);
ZEND_CTOR_MAKE_NULL();
}
}

View File

@ -72,8 +72,16 @@ PHP_FUNCTION( collator_create )
*/
PHP_METHOD( Collator, __construct )
{
zval orig_this = *getThis();
return_value = getThis();
collator_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (Z_TYPE_P(return_value) == IS_OBJECT && Z_OBJ_P(return_value) == NULL) {
zend_object_store_ctor_failed(Z_OBJ(orig_this) TSRMLS_CC);
zval_dtor(&orig_this);
ZEND_CTOR_MAKE_NULL();
}
}
/* }}} */

View File

@ -187,9 +187,17 @@ U_CFUNC PHP_FUNCTION( datefmt_create )
*/
U_CFUNC PHP_METHOD( IntlDateFormatter, __construct )
{
zval orig_this = *getThis();
/* return_value param is being changed, therefore we will always return
* NULL here */
return_value = getThis();
datefmt_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (Z_TYPE_P(return_value) == IS_OBJECT && Z_OBJ_P(return_value) == NULL) {
zend_object_store_ctor_failed(Z_OBJ(orig_this) TSRMLS_CC);
zval_dtor(&orig_this);
ZEND_CTOR_MAKE_NULL();
}
}
/* }}} */

View File

@ -90,8 +90,16 @@ PHP_FUNCTION( numfmt_create )
*/
PHP_METHOD( NumberFormatter, __construct )
{
zval orig_this = *getThis();
return_value = getThis();
numfmt_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (Z_TYPE_P(return_value) == IS_OBJECT && Z_OBJ_P(return_value) == NULL) {
zend_object_store_ctor_failed(Z_OBJ(orig_this) TSRMLS_CC);
zval_dtor(&orig_this);
ZEND_CTOR_MAKE_NULL();
}
}
/* }}} */

View File

@ -108,8 +108,16 @@ PHP_FUNCTION( msgfmt_create )
*/
PHP_METHOD( MessageFormatter, __construct )
{
zval orig_this = *getThis();
return_value = getThis();
msgfmt_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (Z_TYPE_P(return_value) == IS_OBJECT && Z_OBJ_P(return_value) == NULL) {
zend_object_store_ctor_failed(Z_OBJ(orig_this) TSRMLS_CC);
zval_dtor(&orig_this);
ZEND_CTOR_MAKE_NULL();
}
}
/* }}} */

View File

@ -139,8 +139,16 @@ ZEND_END_ARG_INFO()
*/
PHP_METHOD( ResourceBundle, __construct )
{
zval orig_this = *getThis();
return_value = getThis();
resourcebundle_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (Z_TYPE_P(return_value) == IS_OBJECT && Z_OBJ_P(return_value) == NULL) {
zend_object_store_ctor_failed(Z_OBJ(orig_this) TSRMLS_CC);
zval_dtor(&orig_this);
ZEND_CTOR_MAKE_NULL();
}
}
/* }}} */

View File

@ -211,7 +211,7 @@ static PHP_METHOD(PDO, dbh_constructor)
if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!s!a!", &data_source, &data_source_len,
&username, &usernamelen, &password, &passwordlen, &options)) {
Z_OBJ_P(object) = NULL;
ZEND_CTOR_MAKE_NULL();
return;
}
@ -225,7 +225,7 @@ static PHP_METHOD(PDO, dbh_constructor)
snprintf(alt_dsn, sizeof(alt_dsn), "pdo.dsn.%s", data_source);
if (FAILURE == cfg_get_string(alt_dsn, &ini_dsn)) {
zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "invalid data source name");
Z_OBJ_P(object) = NULL;
ZEND_CTOR_MAKE_NULL();
return;
}
@ -234,7 +234,7 @@ static PHP_METHOD(PDO, dbh_constructor)
if (!colon) {
zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "invalid data source name (via INI: %s)", alt_dsn);
Z_OBJ_P(object) = NULL;
ZEND_CTOR_MAKE_NULL();
return;
}
}
@ -244,13 +244,13 @@ static PHP_METHOD(PDO, dbh_constructor)
data_source = dsn_from_uri(data_source + sizeof("uri:")-1, alt_dsn, sizeof(alt_dsn) TSRMLS_CC);
if (!data_source) {
zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "invalid data source URI");
Z_OBJ_P(object) = NULL;
ZEND_CTOR_MAKE_NULL();
return;
}
colon = strchr(data_source, ':');
if (!colon) {
zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "invalid data source name (via URI)");
Z_OBJ_P(object) = NULL;
ZEND_CTOR_MAKE_NULL();
return;
}
}
@ -261,7 +261,7 @@ static PHP_METHOD(PDO, dbh_constructor)
/* NB: don't want to include the data_source in the error message as
* it might contain a password */
zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "could not find driver");
Z_OBJ_P(object) = NULL;
ZEND_CTOR_MAKE_NULL();
return;
}
@ -401,7 +401,7 @@ options:
/* the connection failed; things will tidy up in free_storage */
/* XXX raise exception */
Z_OBJ_P(object) = NULL;
ZEND_CTOR_MAKE_NULL();
}
/* }}} */
@ -461,6 +461,7 @@ static void pdo_stmt_construct(pdo_stmt_t *stmt, zval *object, zend_class_entry
if (zend_call_function(&fci, &fcc TSRMLS_CC) == FAILURE) {
Z_OBJ_P(object) = NULL;
ZEND_CTOR_MAKE_NULL();
object = NULL; /* marks failure */
} else if (!Z_ISUNDEF(retval)) {
zval_ptr_dtor(&retval);