From: Dmitry Stogov Date: Wed, 9 Jul 2014 07:57:42 +0000 (+0400) Subject: Partial fix that allows internal constructors to set $this to null. X-Git-Tag: POST_PHPNG_MERGE~70^2~2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1dd07d6bf438a6a60f2fefcdd7e5c45045ef88f9;p=php 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(). --- diff --git a/Zend/zend_API.h b/Zend/zend_API.h index b702bd4138..beca63c50b 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -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))) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 8ca7968109..1ac9f63570 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -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(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 797c4e0943..9e06d76d47 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -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(); } diff --git a/ext/date/php_date.c b/ext/date/php_date.c index a87cfa60f9..758d0f9513 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -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); diff --git a/ext/fileinfo/fileinfo.c b/ext/fileinfo/fileinfo.c index 86cd02a613..a612e04280 100644 --- a/ext/fileinfo/fileinfo.c +++ b/ext/fileinfo/fileinfo.c @@ -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) diff --git a/ext/intl/breakiterator/rulebasedbreakiterator_methods.cpp b/ext/intl/breakiterator/rulebasedbreakiterator_methods.cpp index e171cf76ab..50df1a61ab 100644 --- a/ext/intl/breakiterator/rulebasedbreakiterator_methods.cpp +++ b/ext/intl/breakiterator/rulebasedbreakiterator_methods.cpp @@ -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(); } } diff --git a/ext/intl/calendar/gregoriancalendar_methods.cpp b/ext/intl/calendar/gregoriancalendar_methods.cpp index 41e2735485..e62164f7d6 100644 --- a/ext/intl/calendar/gregoriancalendar_methods.cpp +++ b/ext/intl/calendar/gregoriancalendar_methods.cpp @@ -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(); } } diff --git a/ext/intl/collator/collator_create.c b/ext/intl/collator/collator_create.c index 7ed4c53439..5801a68d0d 100644 --- a/ext/intl/collator/collator_create.c +++ b/ext/intl/collator/collator_create.c @@ -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(); + } } /* }}} */ diff --git a/ext/intl/dateformat/dateformat_create.cpp b/ext/intl/dateformat/dateformat_create.cpp index f678f5f54e..856db16b1d 100644 --- a/ext/intl/dateformat/dateformat_create.cpp +++ b/ext/intl/dateformat/dateformat_create.cpp @@ -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(); + } } /* }}} */ diff --git a/ext/intl/formatter/formatter_main.c b/ext/intl/formatter/formatter_main.c index 233e0e285b..26473ebe78 100644 --- a/ext/intl/formatter/formatter_main.c +++ b/ext/intl/formatter/formatter_main.c @@ -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(); + } } /* }}} */ diff --git a/ext/intl/msgformat/msgformat.c b/ext/intl/msgformat/msgformat.c index 62999436c2..b9f6c7a369 100644 --- a/ext/intl/msgformat/msgformat.c +++ b/ext/intl/msgformat/msgformat.c @@ -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(); + } } /* }}} */ diff --git a/ext/intl/resourcebundle/resourcebundle_class.c b/ext/intl/resourcebundle/resourcebundle_class.c index 8d6ce87ac8..77f2e90588 100644 --- a/ext/intl/resourcebundle/resourcebundle_class.c +++ b/ext/intl/resourcebundle/resourcebundle_class.c @@ -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(); + } } /* }}} */ diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index f8f4f79602..b2904118e8 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -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);