diff options
Diffstat (limited to 'ext')
127 files changed, 2776 insertions, 642 deletions
diff --git a/ext/bcmath/bcmath.c b/ext/bcmath/bcmath.c index fd14050f05..10450f1968 100644 --- a/ext/bcmath/bcmath.c +++ b/ext/bcmath/bcmath.c @@ -207,6 +207,21 @@ static void php_str2num(bc_num *num, char *str) } /* }}} */ +/* {{{ split_bc_num + Convert to bc_num detecting scale */ +static bc_num split_bc_num(bc_num num) { + bc_num newnum; + if (num->n_refs >= 1) { + return num; + } + newnum = _bc_new_num_ex(0, 0, 0); + *newnum = *num; + newnum->n_refs = 1; + num->n_refs--; + return newnum; +} +/* }}} */ + /* {{{ proto string bcadd(string left_operand, string right_operand [, int scale]) Returns the sum of two arbitrary precision numbers */ PHP_FUNCTION(bcadd) @@ -233,6 +248,7 @@ PHP_FUNCTION(bcadd) bc_add (first, second, &result, scale); if (result->n_scale > scale) { + result = split_bc_num(result); result->n_scale = scale; } @@ -270,6 +286,7 @@ PHP_FUNCTION(bcsub) bc_sub (first, second, &result, scale); if (result->n_scale > scale) { + result = split_bc_num(result); result->n_scale = scale; } @@ -307,6 +324,7 @@ PHP_FUNCTION(bcmul) bc_multiply (first, second, &result, scale); if (result->n_scale > scale) { + result = split_bc_num(result); result->n_scale = scale; } @@ -345,6 +363,7 @@ PHP_FUNCTION(bcdiv) switch (bc_divide(first, second, &result, scale)) { case 0: /* OK */ if (result->n_scale > scale) { + result = split_bc_num(result); result->n_scale = scale; } RETVAL_STR(bc_num2str(result)); @@ -420,8 +439,9 @@ PHP_FUNCTION(bcpowmod) scale_int = (int) ((int)scale < 0 ? 0 : scale); if (bc_raisemod(first, second, mod, &result, scale_int) != -1) { - if (result->n_scale > scale) { - result->n_scale = (int)scale; + if (result->n_scale > scale_int) { + result = split_bc_num(result); + result->n_scale = scale_int; } RETVAL_STR(bc_num2str(result)); } else { @@ -462,6 +482,7 @@ PHP_FUNCTION(bcpow) bc_raise (first, second, &result, scale); if (result->n_scale > scale) { + result = split_bc_num(result); result->n_scale = scale; } @@ -496,6 +517,7 @@ PHP_FUNCTION(bcsqrt) if (bc_sqrt (&result, scale) != 0) { if (result->n_scale > scale) { + result = split_bc_num(result); result->n_scale = scale; } RETVAL_STR(bc_num2str(result)); diff --git a/ext/bcmath/tests/bug72093-win32.phpt b/ext/bcmath/tests/bug72093-win32.phpt new file mode 100644 index 0000000000..a9b2077823 --- /dev/null +++ b/ext/bcmath/tests/bug72093-win32.phpt @@ -0,0 +1,18 @@ +--TEST-- +Bug 72093: bcpowmod accepts negative scale and corrupts _one_ definition +--SKIPIF-- +<?php +if(!extension_loaded("bcmath")) print "skip"; +if (substr(PHP_OS, 0, 3) != 'WIN') { + die('skip valid only for windows'); +} +?> +--FILE-- +<?php +var_dump(bcpowmod(1, "A", 128, -200)); +var_dump(bcpowmod(1, 1.2, 1, 1)); +?> +--EXPECTF-- +string(1) "1" +string(3) "0.0" +bc math warning: non-zero scale in exponent diff --git a/ext/bcmath/tests/bug72093.phpt b/ext/bcmath/tests/bug72093.phpt new file mode 100644 index 0000000000..911af5698f --- /dev/null +++ b/ext/bcmath/tests/bug72093.phpt @@ -0,0 +1,18 @@ +--TEST-- +Bug 72093: bcpowmod accepts negative scale and corrupts _one_ definition +--SKIPIF-- +<?php +if(!extension_loaded("bcmath")) print "skip"; +if (substr(PHP_OS, 0, 3) == 'WIN') { + die('skip Not valid for windows'); +} +?> +--FILE-- +<?php +var_dump(bcpowmod(1, "A", 128, -200)); +var_dump(bcpowmod(1, 1.2, 1, 1)); +?> +--EXPECTF-- +string(1) "1" +bc math warning: non-zero scale in exponent +string(3) "0.0" diff --git a/ext/curl/interface.c b/ext/curl/interface.c index ca899af843..90e2e30987 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -568,6 +568,13 @@ PHP_MINFO_FUNCTION(curl) #if LIBCURL_VERSION_NUM >= 0x072600 /* 7.38.0 */ {"GSSAPI", CURL_VERSION_GSSAPI}, #endif +#if LIBCURL_VERSION_NUM >= 0x072800 /* 7.40.0 */ + {"KERBEROS5", CURL_VERSION_KERBEROS5}, + {"UNIX_SOCKETS", CURL_VERSION_UNIX_SOCKETS}, +#endif +#if LIBCURL_VERSION_NUM >= 0x072f00 /* 7.47.0 */ + {"PSL", CURL_VERSION_PSL}, +#endif {NULL, 0} }; @@ -847,11 +854,6 @@ PHP_MINIT_FUNCTION(curl) REGISTER_CURL_CONSTANT(CURLPROXY_SOCKS4); REGISTER_CURL_CONSTANT(CURLPROXY_SOCKS5); -#if LIBCURL_VERSION_NUM >= 0x071200 /* Available since 7.18.0 */ - REGISTER_CURL_CONSTANT(CURLPROXY_SOCKS4A); - REGISTER_CURL_CONSTANT(CURLPROXY_SOCKS5_HOSTNAME); -#endif - /* Curl Share constants */ REGISTER_CURL_CONSTANT(CURLSHOPT_NONE); REGISTER_CURL_CONSTANT(CURLSHOPT_SHARE); @@ -860,9 +862,6 @@ PHP_MINIT_FUNCTION(curl) /* Curl Http Version constants (CURLOPT_HTTP_VERSION) */ REGISTER_CURL_CONSTANT(CURL_HTTP_VERSION_1_0); REGISTER_CURL_CONSTANT(CURL_HTTP_VERSION_1_1); -#if LIBCURL_VERSION_NUM >= 0x072100 /* 7.33.0 */ - REGISTER_CURL_CONSTANT(CURL_HTTP_VERSION_2_0); -#endif REGISTER_CURL_CONSTANT(CURL_HTTP_VERSION_NONE); /* Curl Lock constants */ @@ -892,9 +891,6 @@ PHP_MINIT_FUNCTION(curl) REGISTER_CURL_CONSTANT(CURL_VERSION_KERBEROS4); REGISTER_CURL_CONSTANT(CURL_VERSION_LIBZ); REGISTER_CURL_CONSTANT(CURL_VERSION_SSL); -#if LIBCURL_VERSION_NUM >= 0x072100 /* 7.33.0 */ - REGISTER_CURL_CONSTANT(CURL_VERSION_HTTP2); -#endif #if LIBCURL_VERSION_NUM >= 0x070a06 /* Available since 7.10.6 */ REGISTER_CURL_CONSTANT(CURLOPT_HTTPAUTH); @@ -999,6 +995,7 @@ PHP_MINIT_FUNCTION(curl) #endif #if LIBCURL_VERSION_NUM >= 0x071000 /* Available since 7.16.0 */ + REGISTER_CURL_CONSTANT(CURLE_SSL_CACERT_BADFILE); REGISTER_CURL_CONSTANT(CURLOPT_SSL_SESSIONID_CACHE); REGISTER_CURL_CONSTANT(CURLMOPT_PIPELINING); #endif @@ -1056,6 +1053,9 @@ PHP_MINIT_FUNCTION(curl) REGISTER_CURL_CONSTANT(CURLPAUSE_SEND_CONT); REGISTER_CURL_CONSTANT(CURL_READFUNC_PAUSE); REGISTER_CURL_CONSTANT(CURL_WRITEFUNC_PAUSE); + + REGISTER_CURL_CONSTANT(CURLPROXY_SOCKS4A); + REGISTER_CURL_CONSTANT(CURLPROXY_SOCKS5_HOSTNAME); #endif #if LIBCURL_VERSION_NUM >= 0x071202 /* Available since 7.18.2 */ @@ -1088,6 +1088,9 @@ PHP_MINIT_FUNCTION(curl) REGISTER_CURL_CONSTANT(CURLOPT_PROXYPASSWORD); REGISTER_CURL_CONSTANT(CURLOPT_PROXYUSERNAME); REGISTER_CURL_CONSTANT(CURLOPT_USERNAME); + REGISTER_CURL_CONSTANT(CURL_REDIR_POST_301); + REGISTER_CURL_CONSTANT(CURL_REDIR_POST_302); + REGISTER_CURL_CONSTANT(CURL_REDIR_POST_ALL); #endif #if LIBCURL_VERSION_NUM >= 0x071303 /* Available since 7.19.3 */ @@ -1117,6 +1120,12 @@ PHP_MINIT_FUNCTION(curl) REGISTER_CURL_CONSTANT(CURLPROTO_SFTP); REGISTER_CURL_CONSTANT(CURLPROTO_TELNET); REGISTER_CURL_CONSTANT(CURLPROTO_TFTP); + + REGISTER_CURL_CONSTANT(CURLPROXY_HTTP_1_0); + + REGISTER_CURL_CONSTANT(CURLFTP_CREATE_DIR); + REGISTER_CURL_CONSTANT(CURLFTP_CREATE_DIR_NONE); + REGISTER_CURL_CONSTANT(CURLFTP_CREATE_DIR_RETRY); #endif #if LIBCURL_VERSION_NUM >= 0x071306 /* Available since 7.19.6 */ @@ -1152,8 +1161,8 @@ PHP_MINIT_FUNCTION(curl) REGISTER_CURL_CONSTANT(CURL_RTSPREQ_PLAY); REGISTER_CURL_CONSTANT(CURL_RTSPREQ_RECEIVE); REGISTER_CURL_CONSTANT(CURL_RTSPREQ_RECORD); - REGISTER_CURL_CONSTANT(CURL_RTSPREQ_SETUP); REGISTER_CURL_CONSTANT(CURL_RTSPREQ_SET_PARAMETER); + REGISTER_CURL_CONSTANT(CURL_RTSPREQ_SETUP); REGISTER_CURL_CONSTANT(CURL_RTSPREQ_TEARDOWN); #endif @@ -1196,6 +1205,7 @@ PHP_MINIT_FUNCTION(curl) #endif #if LIBCURL_VERSION_NUM >= 0x071600 /* Available since 7.22.0 */ + REGISTER_CURL_CONSTANT(CURLAUTH_NTLM_WB); REGISTER_CURL_CONSTANT(CURLGSSAPI_DELEGATION_FLAG); REGISTER_CURL_CONSTANT(CURLGSSAPI_DELEGATION_POLICY_FLAG); REGISTER_CURL_CONSTANT(CURLOPT_GSSAPI_DELEGATION); @@ -1215,18 +1225,119 @@ PHP_MINIT_FUNCTION(curl) REGISTER_CURL_CONSTANT(CURLSSLOPT_ALLOW_BEAST); #endif +#if LIBCURL_VERSION_NUM >= 0x071901 /* Available since 7.25.1 */ + REGISTER_CURL_CONSTANT(CURL_REDIR_POST_303); +#endif + +#if LIBCURL_VERSION_NUM >= 0x071c00 /* Available since 7.28.0 */ + REGISTER_CURL_CONSTANT(CURLSSH_AUTH_AGENT); +#endif + +#if LIBCURL_VERSION_NUM >= 0x071e00 /* Available since 7.30.0 */ + REGISTER_CURL_CONSTANT(CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE); + REGISTER_CURL_CONSTANT(CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE); + REGISTER_CURL_CONSTANT(CURLMOPT_MAX_HOST_CONNECTIONS); + REGISTER_CURL_CONSTANT(CURLMOPT_MAX_PIPELINE_LENGTH); + REGISTER_CURL_CONSTANT(CURLMOPT_MAX_TOTAL_CONNECTIONS); +#endif + +#if LIBCURL_VERSION_NUM >= 0x071f00 /* Available since 7.31.0 */ + REGISTER_CURL_CONSTANT(CURLOPT_SASL_IR); +#endif + +#if LIBCURL_VERSION_NUM >= 0x072100 /* Available since 7.33.0 */ + REGISTER_CURL_CONSTANT(CURLOPT_DNS_INTERFACE); + REGISTER_CURL_CONSTANT(CURLOPT_DNS_LOCAL_IP4); + REGISTER_CURL_CONSTANT(CURLOPT_DNS_LOCAL_IP6); + REGISTER_CURL_CONSTANT(CURLOPT_XOAUTH2_BEARER); + + REGISTER_CURL_CONSTANT(CURL_HTTP_VERSION_2_0); + REGISTER_CURL_CONSTANT(CURL_VERSION_HTTP2); +#endif + #if LIBCURL_VERSION_NUM >= 0x072200 /* Available since 7.34.0 */ + REGISTER_CURL_CONSTANT(CURLOPT_LOGIN_OPTIONS); + REGISTER_CURL_CONSTANT(CURL_SSLVERSION_TLSv1_0); REGISTER_CURL_CONSTANT(CURL_SSLVERSION_TLSv1_1); REGISTER_CURL_CONSTANT(CURL_SSLVERSION_TLSv1_2); #endif -#if LIBCURL_VERSION_NUM >= 0x072B00 /* Available since 7.43.0 */ +#if LIBCURL_VERSION_NUM >= 0x072400 /* Available since 7.36.0 */ + REGISTER_CURL_CONSTANT(CURLOPT_EXPECT_100_TIMEOUT_MS); + REGISTER_CURL_CONSTANT(CURLOPT_SSL_ENABLE_ALPN); + REGISTER_CURL_CONSTANT(CURLOPT_SSL_ENABLE_NPN); +#endif + +#if LIBCURL_VERSION_NUM >= 0x072500 /* Available since 7.37.0 */ + REGISTER_CURL_CONSTANT(CURLHEADER_SEPARATE); + REGISTER_CURL_CONSTANT(CURLHEADER_UNIFIED); + REGISTER_CURL_CONSTANT(CURLOPT_HEADEROPT); + REGISTER_CURL_CONSTANT(CURLOPT_PROXYHEADER); +#endif + +#if LIBCURL_VERSION_NUM >= 0x072600 /* Available since 7.38.0 */ + REGISTER_CURL_CONSTANT(CURLAUTH_NEGOTIATE); +#endif + +#if LIBCURL_VERSION_NUM >= 0x072700 /* Available since 7.39.0 */ + REGISTER_CURL_CONSTANT(CURLOPT_PINNEDPUBLICKEY); +#endif + +#if LIBCURL_VERSION_NUM >= 0x072800 /* Available since 7.40.0 */ + REGISTER_CURL_CONSTANT(CURLOPT_UNIX_SOCKET_PATH); + + REGISTER_CURL_CONSTANT(CURLPROTO_SMB); + REGISTER_CURL_CONSTANT(CURLPROTO_SMBS); +#endif + +#if LIBCURL_VERSION_NUM >= 0x072900 /* Available since 7.41.0 */ + REGISTER_CURL_CONSTANT(CURLOPT_SSL_VERIFYSTATUS); +#endif + +#if LIBCURL_VERSION_NUM >= 0x072a00 /* Available since 7.42.0 */ + REGISTER_CURL_CONSTANT(CURLOPT_PATH_AS_IS); + REGISTER_CURL_CONSTANT(CURLOPT_SSL_FALSESTART); +#endif + +#if LIBCURL_VERSION_NUM >= 0x072b00 /* Available since 7.43.0 */ + REGISTER_CURL_CONSTANT(CURL_HTTP_VERSION_2); + + REGISTER_CURL_CONSTANT(CURLOPT_PIPEWAIT); + REGISTER_CURL_CONSTANT(CURLOPT_PROXY_SERVICE_NAME); + REGISTER_CURL_CONSTANT(CURLOPT_SERVICE_NAME); + REGISTER_CURL_CONSTANT(CURLPIPE_NOTHING); REGISTER_CURL_CONSTANT(CURLPIPE_HTTP1); REGISTER_CURL_CONSTANT(CURLPIPE_MULTIPLEX); #endif +#if LIBCURL_VERSION_NUM >= 0x072c00 /* Available since 7.44.0 */ + REGISTER_CURL_CONSTANT(CURLSSLOPT_NO_REVOKE); +#endif + +#if LIBCURL_VERSION_NUM >= 0x072d00 /* Available since 7.45.0 */ + REGISTER_CURL_CONSTANT(CURLOPT_DEFAULT_PROTOCOL); +#endif + +#if LIBCURL_VERSION_NUM >= 0x072e00 /* Available since 7.46.0 */ + REGISTER_CURL_CONSTANT(CURLOPT_STREAM_WEIGHT); +#endif + +#if LIBCURL_VERSION_NUM >= 0x072f00 /* Available since 7.47.0 */ + REGISTER_CURL_CONSTANT(CURL_HTTP_VERSION_2TLS); +#endif + +#if LIBCURL_VERSION_NUM >= 0x073000 /* Available since 7.48.0 */ + REGISTER_CURL_CONSTANT(CURLOPT_TFTP_NO_OPTIONS); +#endif + +#if LIBCURL_VERSION_NUM >= 0x073100 /* Available since 7.49.0 */ + REGISTER_CURL_CONSTANT(CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE); + REGISTER_CURL_CONSTANT(CURLOPT_CONNECT_TO); + REGISTER_CURL_CONSTANT(CURLOPT_TCP_FASTOPEN); +#endif + #if CURLOPT_FTPASCII != 0 REGISTER_CURL_CONSTANT(CURLOPT_FTPASCII); #endif @@ -1338,7 +1449,6 @@ static size_t curl_write(char *data, size_t size, size_t nmemb, void *ctx) ZVAL_STRINGL(&argv[1], data, length); fci.size = sizeof(fci); - fci.function_table = EG(function_table); fci.object = NULL; ZVAL_COPY_VALUE(&fci.function_name, &t->func_name); fci.retval = &retval; @@ -1388,7 +1498,6 @@ static int curl_fnmatch(void *ctx, const char *pattern, const char *string) ZVAL_STRING(&argv[2], string); fci.size = sizeof(fci); - fci.function_table = EG(function_table); ZVAL_COPY_VALUE(&fci.function_name, &t->func_name); fci.object = NULL; fci.retval = &retval; @@ -1444,7 +1553,6 @@ static size_t curl_progress(void *clientp, double dltotal, double dlnow, double ZVAL_LONG(&argv[4], (zend_long)ulnow); fci.size = sizeof(fci); - fci.function_table = EG(function_table); ZVAL_COPY_VALUE(&fci.function_name, &t->func_name); fci.object = NULL; fci.retval = &retval; @@ -1506,7 +1614,6 @@ static size_t curl_read(char *data, size_t size, size_t nmemb, void *ctx) ZVAL_LONG(&argv[2], (int)size * nmemb); fci.size = sizeof(fci); - fci.function_table = EG(function_table); ZVAL_COPY_VALUE(&fci.function_name, &t->func_name); fci.object = NULL; fci.retval = &retval; @@ -1573,7 +1680,6 @@ static size_t curl_write_header(char *data, size_t size, size_t nmemb, void *ctx ZVAL_STRINGL(&argv[1], data, length); fci.size = sizeof(fci); - fci.function_table = EG(function_table); ZVAL_COPY_VALUE(&fci.function_name, &t->func_name); fci.object = NULL; fci.retval = &retval; @@ -2173,6 +2279,36 @@ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue) /* {{{ case CURLOPT_TCP_KEEPIDLE: case CURLOPT_TCP_KEEPINTVL: #endif +#if LIBCURL_VERSION_NUM >= 0x071f00 /* Available since 7.31.0 */ + case CURLOPT_SASL_IR: +#endif +#if LIBCURL_VERSION_NUM >= 0x072400 /* Available since 7.36.0 */ + case CURLOPT_EXPECT_100_TIMEOUT_MS: + case CURLOPT_SSL_ENABLE_ALPN: + case CURLOPT_SSL_ENABLE_NPN: +#endif +#if LIBCURL_VERSION_NUM >= 0x072500 /* Available since 7.37.0 */ + case CURLOPT_HEADEROPT: +#endif +#if LIBCURL_VERSION_NUM >= 0x072900 /* Available since 7.41.0 */ + case CURLOPT_SSL_VERIFYSTATUS: +#endif +#if LIBCURL_VERSION_NUM >= 0x072a00 /* Available since 7.42.0 */ + case CURLOPT_PATH_AS_IS: + case CURLOPT_SSL_FALSESTART: +#endif +#if LIBCURL_VERSION_NUM >= 0x072b00 /* Available since 7.43.0 */ + case CURLOPT_PIPEWAIT: +#endif +#if LIBCURL_VERSION_NUM >= 0x072e00 /* Available since 7.46.0 */ + case CURLOPT_STREAM_WEIGHT: +#endif +#if LIBCURL_VERSION_NUM >= 0x073000 /* Available since 7.48.0 */ + case CURLOPT_TFTP_NO_OPTIONS: +#endif +#if LIBCURL_VERSION_NUM >= 0x073100 /* Available since 7.49.0 */ + case CURLOPT_TCP_FASTOPEN: +#endif #if CURLOPT_MUTE != 0 case CURLOPT_MUTE: #endif @@ -2258,6 +2394,19 @@ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue) /* {{{ #if LIBCURL_VERSION_NUM >= 0x071900 /* Available since 7.25.0 */ case CURLOPT_MAIL_AUTH: #endif +#if LIBCURL_VERSION_NUM >= 0x072200 /* Available since 7.34.0 */ + case CURLOPT_LOGIN_OPTIONS: +#endif +#if LIBCURL_VERSION_NUM >= 0x072700 /* Available since 7.39.0 */ + case CURLOPT_PINNEDPUBLICKEY: +#endif +#if LIBCURL_VERSION_NUM >= 0x072b00 /* Available since 7.43.0 */ + case CURLOPT_PROXY_SERVICE_NAME: + case CURLOPT_SERVICE_NAME: +#endif +#if LIBCURL_VERSION_NUM >= 0x072d00 /* Available since 7.45.0 */ + case CURLOPT_DEFAULT_PROTOCOL: +#endif { zend_string *str = zval_get_string(zvalue); int ret = php_curl_option_str(ch, option, ZSTR_VAL(str), ZSTR_LEN(str), 0); @@ -2275,6 +2424,15 @@ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue) /* {{{ #if LIBCURL_VERSION_NUM >= 0x071400 /* Available since 7.20.0 */ case CURLOPT_RTSP_SESSION_ID: #endif +#if LIBCURL_VERSION_NUM >= 0x072100 /* Available since 7.33.0 */ + case CURLOPT_DNS_INTERFACE: + case CURLOPT_DNS_LOCAL_IP4: + case CURLOPT_DNS_LOCAL_IP6: + case CURLOPT_XOAUTH2_BEARER: +#endif +#if LIBCURL_VERSION_NUM >= 0x072800 /* Available since 7.40.0 */ + case CURLOPT_UNIX_SOCKET_PATH: +#endif #if LIBCURL_VERSION_NUM >= 0x071004 /* Available since 7.16.4 */ case CURLOPT_KRBLEVEL: #else @@ -2420,6 +2578,12 @@ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue) /* {{{ #if LIBCURL_VERSION_NUM >= 0x071503 /* Available since 7.21.3 */ case CURLOPT_RESOLVE: #endif +#if LIBCURL_VERSION_NUM >= 0x072500 /* Available since 7.37.0 */ + case CURLOPT_PROXYHEADER: +#endif +#if LIBCURL_VERSION_NUM >= 0x073100 /* Available since 7.49.0 */ + case CURLOPT_CONNECT_TO: +#endif { zval *current; HashTable *ph; @@ -2458,6 +2622,16 @@ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue) /* {{{ name = "CURLOPT_RESOLVE"; break; #endif +#if LIBCURL_VERSION_NUM >= 0x072500 /* Available since 7.37.0 */ + case CURLOPT_PROXYHEADER: + name = "CURLOPT_PROXYHEADER"; + break; +#endif +#if LIBCURL_VERSION_NUM >= 0x073100 /* Available since 7.49.0 */ + case CURLOPT_CONNECT_TO: + name = "CURLOPT_CONNECT_TO"; + break; +#endif } php_error_docref(NULL, E_WARNING, "You must pass either an object or an array with the %s argument", name); return FAILURE; diff --git a/ext/curl/multi.c b/ext/curl/multi.c index 641d20f903..ab6d56c438 100644 --- a/ext/curl/multi.c +++ b/ext/curl/multi.c @@ -417,6 +417,13 @@ static int _php_curl_multi_setopt(php_curlm *mh, zend_long option, zval *zvalue, #if LIBCURL_VERSION_NUM >= 0x071003 /* 7.16.3 */ case CURLMOPT_MAXCONNECTS: #endif +#if LIBCURL_VERSION_NUM >= 0x071e00 /* 7.30.0 */ + case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE: + case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE: + case CURLMOPT_MAX_HOST_CONNECTIONS: + case CURLMOPT_MAX_PIPELINE_LENGTH: + case CURLMOPT_MAX_TOTAL_CONNECTIONS: +#endif error = curl_multi_setopt(mh->multi, option, zval_get_long(zvalue)); break; diff --git a/ext/curl/tests/bug68937.phpt b/ext/curl/tests/bug68937.phpt index 139cc17abd..0f346cf3fa 100644 --- a/ext/curl/tests/bug68937.phpt +++ b/ext/curl/tests/bug68937.phpt @@ -8,13 +8,19 @@ include 'skipif.inc'; --FILE-- <?php -$ch = curl_init('http://www.google.com/'); +include 'server.inc'; +$host = curl_cli_server_start(); + +$url = "{$host}/get.php"; + +$ch = curl_init($url); curl_setopt_array($ch, array( CURLOPT_HEADER => false, CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_INFILESIZE => 1, CURLOPT_HTTPHEADER => array( + 'Expect:', 'Content-Length: 1', ), CURLOPT_READFUNCTION => 'curl_read', diff --git a/ext/curl/tests/bug68937_2.phpt b/ext/curl/tests/bug68937_2.phpt index 29851ec6e1..c25da3fd71 100644 --- a/ext/curl/tests/bug68937_2.phpt +++ b/ext/curl/tests/bug68937_2.phpt @@ -7,8 +7,12 @@ include 'skipif.inc'; ?> --FILE-- <?php +include 'server.inc'; +$host = curl_cli_server_start(); -$ch = curl_init('http://www.google.com/'); +$url = "{$host}/get.php"; + +$ch = curl_init($url); curl_setopt_array($ch, array( CURLOPT_HEADER => false, CURLOPT_RETURNTRANSFER => true, @@ -16,6 +20,7 @@ curl_setopt_array($ch, array( CURLOPT_INFILESIZE => filesize(__FILE__), CURLOPT_INFILE => fopen(__FILE__, 'r'), CURLOPT_HTTPHEADER => array( + 'Expect:', 'Content-Length: 1', ), CURLOPT_READFUNCTION => 'curl_read', diff --git a/ext/curl/tests/check_win_config.phpt b/ext/curl/tests/check_win_config.phpt index 3d13638f90..fc1c66609a 100644 --- a/ext/curl/tests/check_win_config.phpt +++ b/ext/curl/tests/check_win_config.phpt @@ -42,6 +42,9 @@ SSPI => Yes TLS-SRP => No
HTTP2 => No
GSSAPI => No
+KERBEROS5 => Yes
+UNIX_SOCKETS => No
+PSL => No
Protocols => dict, file, ftp, ftps, gopher, http, https, imap, imaps, ldap, pop3, pop3s, rtsp, scp, sftp, smtp, smtps, telnet, tftp
Host => %s-pc-win32
SSL Version => OpenSSL/%s
diff --git a/ext/dom/xpath.c b/ext/dom/xpath.c index 3cc9abaa3c..e31dcefb78 100644 --- a/ext/dom/xpath.c +++ b/ext/dom/xpath.c @@ -171,7 +171,6 @@ static void dom_xpath_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, } fci.size = sizeof(fci); - fci.function_table = EG(function_table); obj = valuePop(ctxt); if (obj->stringval == NULL) { diff --git a/ext/exif/exif.c b/ext/exif/exif.c index 0f3c889b21..44b9fee0b1 100644 --- a/ext/exif/exif.c +++ b/ext/exif/exif.c @@ -2946,7 +2946,7 @@ static int exif_process_IFD_TAG(image_info_type *ImageInfo, char *dir_entry, cha /* When there are any characters after the first NUL */ ImageInfo->CopyrightPhotographer = estrdup(value_ptr); ImageInfo->CopyrightEditor = estrndup(value_ptr+length+1, byte_count-length-1); - spprintf(&ImageInfo->Copyright, 0, "%s, %s", value_ptr, value_ptr+length+1); + spprintf(&ImageInfo->Copyright, 0, "%s, %s", ImageInfo->CopyrightPhotographer, ImageInfo->CopyrightEditor); /* format = TAG_FMT_UNDEFINED; this musn't be ASCII */ /* but we are not supposed to change this */ /* keep in mind that image_info does not store editor value */ @@ -3115,6 +3115,11 @@ static int exif_process_IFD_in_JPEG(image_info_type *ImageInfo, char *dir_start, ImageInfo->sections_found |= FOUND_IFD0; + if ((dir_start + 2) >= (offset_base+IFDlength)) { + exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "Illegal IFD size"); + return FALSE; + } + NumDirEntries = php_ifd_get16u(dir_start, ImageInfo->motorola_intel); if ((dir_start+2+NumDirEntries*12) > (offset_base+IFDlength)) { @@ -3138,6 +3143,10 @@ static int exif_process_IFD_in_JPEG(image_info_type *ImageInfo, char *dir_start, * Hack to make it process IDF1 I hope * There are 2 IDFs, the second one holds the keys (0x0201 and 0x0202) to the thumbnail */ + if ((dir_start+2+12*de + 4) >= (offset_base+IFDlength)) { + exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "Illegal IFD size"); + return FALSE; + } NextDirOffset = php_ifd_get32u(dir_start+2+12*de, ImageInfo->motorola_intel); if (NextDirOffset) { /* the next line seems false but here IFDlength means length of all IFDs */ @@ -3187,9 +3196,13 @@ static void exif_process_TIFF_in_JPEG(image_info_type *ImageInfo, char *CharBuf, } /* Check the next two values for correctness. */ + if (length < 8) { + exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Invalid TIFF start (1)"); + return; + } exif_value_2a = php_ifd_get16u(CharBuf+2, ImageInfo->motorola_intel); offset_of_ifd = php_ifd_get32u(CharBuf+4, ImageInfo->motorola_intel); - if ( exif_value_2a != 0x2a || offset_of_ifd < 0x08) { + if (exif_value_2a != 0x2a || offset_of_ifd < 0x08) { exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Invalid TIFF start (1)"); return; } diff --git a/ext/exif/tests/bug72094.phpt b/ext/exif/tests/bug72094.phpt new file mode 100644 index 0000000000..611faf9152 --- /dev/null +++ b/ext/exif/tests/bug72094.phpt @@ -0,0 +1,61 @@ +--TEST-- +Bug #72094: Out of bounds heap read access in exif header processing +--SKIPIF-- +<?php if (!extension_loaded('exif')) print 'skip exif extension not available';?> +--FILE-- +<?php +print_r(exif_read_data(__DIR__ . '/bug72094_1.jpg')); +print_r(exif_read_data(__DIR__ . '/bug72094_2.jpg')); +print_r(exif_read_data(__DIR__ . '/bug72094_3.jpg')); +print_r(exif_read_data(__DIR__ . '/bug72094_4.jpg')); +?> +DONE +--EXPECTF-- +Warning: exif_read_data(bug72094_1.jpg): Process tag(x3030=UndefinedTa): Illegal format code 0x3030, suppose BYTE in %s%ebug72094.php on line %d + +Warning: exif_read_data(bug72094_1.jpg): Process tag(x3030=UndefinedTa): Illegal format code 0x3030, suppose BYTE in %s%ebug72094.php on line %d + +Warning: exif_read_data(bug72094_1.jpg): Process tag(x3030=UndefinedTa): Illegal format code 0x3030, suppose BYTE in %s%ebug72094.php on line %d + +Warning: exif_read_data(bug72094_1.jpg): Process tag(x3030=UndefinedTa): Illegal format code 0x3030, suppose BYTE in %s%ebug72094.php on line %d + +Warning: exif_read_data(bug72094_1.jpg): Process tag(x3030=UndefinedTa): Illegal format code 0x3030, suppose BYTE in %s%ebug72094.php on line %d + +Warning: exif_read_data(bug72094_1.jpg): Process tag(x8298=Copyright ): Illegal format code 0x3030, suppose BYTE in %s%ebug72094.php on line %d + +Warning: exif_read_data(bug72094_1.jpg): Illegal IFD offset in %s%ebug72094.php on line %d + +Warning: exif_read_data(bug72094_1.jpg): File structure corrupted in %s%ebug72094.php on line %d + +Warning: exif_read_data(bug72094_1.jpg): Invalid JPEG file in %s%ebug72094.php on line %d + +Warning: exif_read_data(bug72094_2.jpg): Illegal IFD size in %s%ebug72094.php on line %d + +Warning: exif_read_data(bug72094_2.jpg): File structure corrupted in %s%ebug72094.php on line %d + +Warning: exif_read_data(bug72094_2.jpg): Invalid JPEG file in %s%ebug72094.php on line %d + +Warning: exif_read_data(bug72094_3.jpg): Process tag(x3030=UndefinedTa): Illegal format code 0x3030, suppose BYTE in %s%ebug72094.php on line %d + +Warning: exif_read_data(bug72094_3.jpg): Process tag(x3030=UndefinedTa): Illegal format code 0x3030, suppose BYTE in %s%ebug72094.php on line %d + +Warning: exif_read_data(bug72094_3.jpg): Process tag(x3030=UndefinedTa): Illegal format code 0x3030, suppose BYTE in %s%ebug72094.php on line %d + +Warning: exif_read_data(bug72094_3.jpg): Process tag(x3030=UndefinedTa): Illegal format code 0x3030, suppose BYTE in %s%ebug72094.php on line %d + +Warning: exif_read_data(bug72094_3.jpg): Process tag(x3030=UndefinedTa): Illegal format code 0x3030, suppose BYTE in %s%ebug72094.php on line %d + +Warning: exif_read_data(bug72094_3.jpg): Process tag(x3030=UndefinedTa): Illegal format code 0x3030, suppose BYTE in %s%ebug72094.php on line %d + +Warning: exif_read_data(bug72094_3.jpg): Illegal IFD size in %s%ebug72094.php on line %d + +Warning: exif_read_data(bug72094_3.jpg): File structure corrupted in %s%ebug72094.php on line %d + +Warning: exif_read_data(bug72094_3.jpg): Invalid JPEG file in %s%ebug72094.php on line %d + +Warning: exif_read_data(bug72094_4.jpg): Invalid TIFF start (1) in %s%ebug72094.php on line %d + +Warning: exif_read_data(bug72094_4.jpg): File structure corrupted in %s%ebug72094.php on line %d + +Warning: exif_read_data(bug72094_4.jpg): Invalid JPEG file in %s%ebug72094.php on line %d +DONE diff --git a/ext/exif/tests/bug72094_1.jpg b/ext/exif/tests/bug72094_1.jpg Binary files differnew file mode 100644 index 0000000000..d21382b44b --- /dev/null +++ b/ext/exif/tests/bug72094_1.jpg diff --git a/ext/exif/tests/bug72094_2.jpg b/ext/exif/tests/bug72094_2.jpg Binary files differnew file mode 100644 index 0000000000..ec414ce02b --- /dev/null +++ b/ext/exif/tests/bug72094_2.jpg diff --git a/ext/exif/tests/bug72094_3.jpg b/ext/exif/tests/bug72094_3.jpg Binary files differnew file mode 100644 index 0000000000..8b05314b67 --- /dev/null +++ b/ext/exif/tests/bug72094_3.jpg diff --git a/ext/exif/tests/bug72094_4.jpg b/ext/exif/tests/bug72094_4.jpg Binary files differnew file mode 100644 index 0000000000..ca6d453c2c --- /dev/null +++ b/ext/exif/tests/bug72094_4.jpg diff --git a/ext/gd/libgd/gd_gd2.c b/ext/gd/libgd/gd_gd2.c index efc6ef47af..6726fee826 100644 --- a/ext/gd/libgd/gd_gd2.c +++ b/ext/gd/libgd/gd_gd2.c @@ -145,9 +145,15 @@ static int _gd2GetHeader(gdIOCtxPtr in, int *sx, int *sy, int *cs, int *vers, in cidx = gdCalloc(sidx, 1); for (i = 0; i < nc; i++) { if (gdGetInt(&cidx[i].offset, in) != 1) { + gdFree(cidx); goto fail1; } if (gdGetInt(&cidx[i].size, in) != 1) { + gdFree(cidx); + goto fail1; + } + if (cidx[i].offset < 0 || cidx[i].size < 0) { + gdFree(cidx); goto fail1; } } diff --git a/ext/gd/tests/bug71912.phpt b/ext/gd/tests/bug71912.phpt new file mode 100644 index 0000000000..c86188b0f2 --- /dev/null +++ b/ext/gd/tests/bug71912.phpt @@ -0,0 +1,16 @@ +--TEST-- +Bug #71912 (libgd: signedness vulnerability) +--SKIPIF-- +<?php + if(!extension_loaded('gd')){ die('skip gd extension not available'); } + if(!function_exists('imagecreatefromgd2')) die('skip imagecreatefromgd2() not available'); +?> +--FILE-- +<?php +imagecreatefromgd2(__DIR__ . DIRECTORY_SEPARATOR . "invalid_neg_size.gd2"); +?> +OK +--EXPECTF-- + +Warning: imagecreatefromgd2(): '%s%einvalid_neg_size.gd2' is not a valid GD2 file in %s%ebug71912.php on line %d +OK diff --git a/ext/gd/tests/bug71952.phpt b/ext/gd/tests/bug71952.phpt new file mode 100644 index 0000000000..f1f66bf26d --- /dev/null +++ b/ext/gd/tests/bug71952.phpt @@ -0,0 +1,14 @@ +--TEST-- +Bug #71952 (Corruption inside imageaffinematrixget) +--SKIPIF-- +<?php + if(!extension_loaded('gd')){ die('skip gd extension not available'); } +?> +--FILE-- +<?php +$vals=[str_repeat("A","200"),0,1,2,3,4,5,6,7,8,9]; +imageaffinematrixget(4,$vals[0]); +var_dump($vals[0]); +?> +--EXPECTF-- +string(200) "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
\ No newline at end of file diff --git a/ext/gd/tests/invalid_neg_size.gd2 b/ext/gd/tests/invalid_neg_size.gd2 Binary files differnew file mode 100644 index 0000000000..3075f15a81 --- /dev/null +++ b/ext/gd/tests/invalid_neg_size.gd2 diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index 56235e0c68..a1e15899c9 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -1144,11 +1144,10 @@ ZEND_FUNCTION(gmp_export) } else { size_t bits_per_word = size * 8; size_t count = (mpz_sizeinbase(gmpnumber, 2) + bits_per_word - 1) / bits_per_word; - size_t out_len = count * size; - zend_string *out_string = zend_string_alloc(out_len, 0); + zend_string *out_string = zend_string_safe_alloc(count, size, 0, 0); mpz_export(ZSTR_VAL(out_string), NULL, order, size, endian, 0, gmpnumber); - ZSTR_VAL(out_string)[out_len] = '\0'; + ZSTR_VAL(out_string)[ZSTR_LEN(out_string)] = '\0'; RETURN_NEW_STR(out_string); } diff --git a/ext/interbase/ibase_blobs.c b/ext/interbase/ibase_blobs.c index 70640236c3..3cd649dbf9 100644 --- a/ext/interbase/ibase_blobs.c +++ b/ext/interbase/ibase_blobs.c @@ -99,7 +99,7 @@ int _php_ibase_blob_get(zval *return_value, ibase_blob *ib_blob, zend_ulong max_ zend_ulong cur_len; unsigned short seg_len; - bl_data = zend_string_alloc(max_len, 0); + bl_data = zend_string_safe_alloc(1, max_len, 0, 0); for (cur_len = stat = 0; (stat == 0 || stat == isc_segment) && cur_len < max_len; cur_len += seg_len) { diff --git a/ext/intl/calendar/calendar_class.cpp b/ext/intl/calendar/calendar_class.cpp index 1f3a68b802..574f9a0fc3 100644 --- a/ext/intl/calendar/calendar_class.cpp +++ b/ext/intl/calendar/calendar_class.cpp @@ -177,7 +177,7 @@ static HashTable *Calendar_get_debug_info(zval *object, int *is_temp) HashTable *debug_info_tz; timezone_object_construct(&cal->getTimeZone(), &ztz , 0); - debug_info = Z_OBJ_HANDLER(ztz, get_debug_info)(&ztz, &is_tmp); + debug_info_tz = Z_OBJ_HANDLER(ztz, get_debug_info)(&ztz, &is_tmp); assert(is_tmp == 1); array_init(&ztz_debug); diff --git a/ext/intl/dateformat/dateformat_create.cpp b/ext/intl/dateformat/dateformat_create.cpp index 51ec063270..00a5cc593c 100644 --- a/ext/intl/dateformat/dateformat_create.cpp +++ b/ext/intl/dateformat/dateformat_create.cpp @@ -36,7 +36,7 @@ extern "C" { #include "dateformat_helpers.h" #include "zend_exceptions.h" -#if U_ICU_VERSION_MINOR_NUM < 50 +#if U_ICU_VERSION_MAJOR_NUM < 50 #define UDAT_PATTERN 0 #endif diff --git a/ext/intl/grapheme/grapheme_string.c b/ext/intl/grapheme/grapheme_string.c index 9fb4e35405..0735a7e822 100644 --- a/ext/intl/grapheme/grapheme_string.c +++ b/ext/intl/grapheme/grapheme_string.c @@ -110,7 +110,7 @@ PHP_FUNCTION(grapheme_strpos) size_t haystack_len, needle_len; const char *found; zend_long loffset = 0; - int32_t offset = 0; + int32_t offset = 0, noffset = 0; zend_long ret_pos; if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|l", &haystack, &haystack_len, &needle, &needle_len, &loffset) == FAILURE) { @@ -126,6 +126,7 @@ PHP_FUNCTION(grapheme_strpos) /* we checked that it will fit: */ offset = (int32_t) loffset; + noffset = offset >= 0 ? offset : haystack_len + offset; /* the offset is 'grapheme count offset' so it still might be invalid - we'll check it later */ @@ -138,7 +139,7 @@ PHP_FUNCTION(grapheme_strpos) /* quick check to see if the string might be there * I realize that 'offset' is 'grapheme count offset' but will work in spite of that */ - found = php_memnstr(haystack + offset, needle, needle_len, haystack + haystack_len); + found = php_memnstr(haystack + noffset, needle, needle_len, haystack + haystack_len); /* if it isn't there the we are done */ if (!found) { @@ -199,13 +200,13 @@ PHP_FUNCTION(grapheme_stripos) is_ascii = ( grapheme_ascii_check((unsigned char*)haystack, haystack_len) >= 0 ); if ( is_ascii ) { + int32_t noffset = offset >= 0 ? offset : haystack_len + offset; needle_dup = estrndup(needle, needle_len); php_strtolower(needle_dup, needle_len); haystack_dup = estrndup(haystack, haystack_len); php_strtolower(haystack_dup, haystack_len); - found = php_memnstr(haystack_dup + offset + ((offset < 0) ? haystack_len : 0) - , needle_dup, needle_len, haystack_dup + haystack_len); + found = php_memnstr(haystack_dup + noffset, needle_dup, needle_len, haystack_dup + haystack_len); efree(haystack_dup); efree(needle_dup); diff --git a/ext/intl/msgformat/msgformat_helpers.cpp b/ext/intl/msgformat/msgformat_helpers.cpp index ed63105fa7..ce7899edd9 100644 --- a/ext/intl/msgformat/msgformat_helpers.cpp +++ b/ext/intl/msgformat/msgformat_helpers.cpp @@ -264,6 +264,10 @@ static HashTable *umsg_parse_format(MessageFormatter_object *mfo, type = Formattable::kDouble; } else if (argType == UMSGPAT_ARG_TYPE_SELECT) { type = Formattable::kString; +#if U_ICU_VERSION_MAJOR_NUM >= 50 + } else if (argType == UMSGPAT_ARG_TYPE_SELECTORDINAL) { + type = Formattable::kDouble; +#endif } else { type = Formattable::kString; } diff --git a/ext/intl/tests/bug72061.phpt b/ext/intl/tests/bug72061.phpt new file mode 100644 index 0000000000..782c32c11c --- /dev/null +++ b/ext/intl/tests/bug72061.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #72061: Out-of-bounds reads in zif_grapheme_stripos with negative offset +--SKIPIF-- +<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?> +--FILE-- +<?php + +var_dump(grapheme_stripos(str_repeat("ABCD", 16384), "A", -201)); +var_dump(grapheme_strpos(str_repeat("ABCD", 16384), "A", -201)); +?> +DONE +--EXPECT-- +int(65336) +int(65336) +DONE
\ No newline at end of file diff --git a/ext/intl/tests/msgfmt_bug70484.phpt b/ext/intl/tests/msgfmt_bug70484.phpt new file mode 100644 index 0000000000..9d0bdc4ee8 --- /dev/null +++ b/ext/intl/tests/msgfmt_bug70484.phpt @@ -0,0 +1,97 @@ +--TEST-- +Bug #70484 selectordinal doesn't work with named parameters +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '5.0') < 0) + die('skip for ICU 5.0+'); +--FILE-- +<?php + +$locale = array("de", "fr", "en", "ru",); + +$data = array(42, 42.42, 2147483643, 2147483643.12345, 5); + +foreach ($locale as $lc) { + echo "$lc string key\n"; + $m = new MessageFormatter($lc, "{n, selectordinal, =5 {five} zero {#-zero} one {#-one} two {#-two} few {#-few} many {#-many} other {#-other}}"); + foreach ($data as $i) { + var_dump($m->format(array("n" => $i))); + if ($m->getErrorCode()) { + echo "$lc $i ", $m->getErrorMessage(); + } + } + echo "\n"; + + echo "$lc numeric key\n"; + $m = new MessageFormatter($lc, "{0, selectordinal, =5 {five} zero {#-zero} one {#-one} two {#-two} few {#-few} many {#-many} other {#-other}}"); + foreach ($data as $i) { + var_dump($m->format(array($i))); + if ($m->getErrorCode()) { + echo "$lc $i ", $m->getErrorMessage(); + } + } + echo "\n"; +} + +?> +==DONE== +--EXPECT-- +de string key +string(8) "42-other" +string(11) "42,42-other" +string(19) "2.147.483.643-other" +string(23) "2.147.483.643,123-other" +string(4) "five" + +de numeric key +string(8) "42-other" +string(11) "42,42-other" +string(19) "2.147.483.643-other" +string(23) "2.147.483.643,123-other" +string(4) "five" + +fr string key +string(8) "42-other" +string(11) "42,42-other" +string(22) "2 147 483 643-other" +string(26) "2 147 483 643,123-other" +string(4) "five" + +fr numeric key +string(8) "42-other" +string(11) "42,42-other" +string(22) "2 147 483 643-other" +string(26) "2 147 483 643,123-other" +string(4) "five" + +en string key +string(6) "42-two" +string(11) "42.42-other" +string(17) "2,147,483,643-few" +string(23) "2,147,483,643.123-other" +string(4) "five" + +en numeric key +string(6) "42-two" +string(11) "42.42-other" +string(17) "2,147,483,643-few" +string(23) "2,147,483,643.123-other" +string(4) "five" + +ru string key +string(8) "42-other" +string(11) "42,42-other" +string(22) "2 147 483 643-other" +string(26) "2 147 483 643,123-other" +string(4) "five" + +ru numeric key +string(8) "42-other" +string(11) "42,42-other" +string(22) "2 147 483 643-other" +string(26) "2 147 483 643,123-other" +string(4) "five" + +==DONE== diff --git a/ext/intl/tests/timezone_IDforWindowsID_basic.phpt b/ext/intl/tests/timezone_IDforWindowsID_basic.phpt new file mode 100644 index 0000000000..4127d8e31c --- /dev/null +++ b/ext/intl/tests/timezone_IDforWindowsID_basic.phpt @@ -0,0 +1,46 @@ +--TEST-- +IntlTimeZone::getIDForWindowsID basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '52') < 0) + die('skip for ICU >= 52'); +--FILE-- +<?php + +$tzs = array( + 'Gnomeregan' => array(NULL), + 'India Standard Time' => array(NULL), + 'Pacific Standard Time' => array('001', 'CA', 'MX', 'US', 'ZZ'), + 'Romance Standard Time' => array('001', 'BE', 'DK', 'ES', 'FR'), +); + +foreach ($tzs as $tz => $regions) { + echo "** $tz\n"; + foreach ($regions as $region) { + var_dump(IntlTimeZone::getIDForWindowsID($tz, $region)); + if (intl_get_error_code() != U_ZERO_ERROR) { + echo "Error: ", intl_get_error_message(), "\n"; + } + } +} + +--EXPECT-- +** Gnomeregan +bool(false) +Error: intltz_get_windows_id: Unknown windows timezone: U_ILLEGAL_ARGUMENT_ERROR +** India Standard Time +string(13) "Asia/Calcutta" +** Pacific Standard Time +string(19) "America/Los_Angeles" +string(17) "America/Vancouver" +string(15) "America/Tijuana" +string(19) "America/Los_Angeles" +string(7) "PST8PDT" +** Romance Standard Time +string(12) "Europe/Paris" +string(15) "Europe/Brussels" +string(17) "Europe/Copenhagen" +string(13) "Europe/Madrid" +string(12) "Europe/Paris" diff --git a/ext/intl/tests/timezone_windowsID_basic.phpt b/ext/intl/tests/timezone_windowsID_basic.phpt new file mode 100644 index 0000000000..dd48f016e2 --- /dev/null +++ b/ext/intl/tests/timezone_windowsID_basic.phpt @@ -0,0 +1,43 @@ +--TEST-- +IntlTimeZone::getWindowsID basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '52') < 0) + die('skip for ICU >= 52'); +--FILE-- +<?php + +$tzs = array( + 'America/Bogota', + 'America/Havana', + 'America/Indiana/Knox', + 'America/Los_Angeles', + 'Azeroth/Kalimdor/Durotar', + 'Africa/Casablanca', + 'Asia/Singapore', + 'Australia/Perth', + 'Europe/London', + 'Europe/Istanbul', +); + +foreach ($tzs as $tz) { + var_dump(IntlTimeZone::getWindowsID($tz)); + if (intl_get_error_code() != U_ZERO_ERROR) { + echo "Error: ", intl_get_error_message(), "\n"; + } +} + +--EXPECT-- +string(24) "SA Pacific Standard Time" +string(21) "Eastern Standard Time" +string(21) "Central Standard Time" +string(21) "Pacific Standard Time" +bool(false) +Error: intltz_get_windows_id: Unknown system timezone: U_ILLEGAL_ARGUMENT_ERROR +string(21) "Morocco Standard Time" +string(23) "Singapore Standard Time" +string(26) "W. Australia Standard Time" +string(17) "GMT Standard Time" +string(20) "Turkey Standard Time" diff --git a/ext/intl/timezone/timezone_class.cpp b/ext/intl/timezone/timezone_class.cpp index d1e8e2e0a6..f67e55ae4e 100644 --- a/ext/intl/timezone/timezone_class.cpp +++ b/ext/intl/timezone/timezone_class.cpp @@ -439,6 +439,17 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_void, 0, 0, 0) ZEND_END_ARG_INFO() +#if U_ICU_VERSION_MAJOR_NUM >= 52 +ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_getWindowsID, 0, ZEND_RETURN_VALUE, 1) + ZEND_ARG_INFO(0, timezone) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_getIDForWindowsID, 0, ZEND_RETURN_VALUE, 1) + ZEND_ARG_INFO(0, timezone) + ZEND_ARG_INFO(0, region) +ZEND_END_ARG_INFO() +#endif + /* }}} */ /* {{{ TimeZone_class_functions @@ -475,6 +486,10 @@ static zend_function_entry TimeZone_class_functions[] = { PHP_ME_MAPPING(toDateTimeZone, intltz_to_date_time_zone, ainfo_tz_void, ZEND_ACC_PUBLIC) PHP_ME_MAPPING(getErrorCode, intltz_get_error_code, ainfo_tz_void, ZEND_ACC_PUBLIC) PHP_ME_MAPPING(getErrorMessage, intltz_get_error_message, ainfo_tz_void, ZEND_ACC_PUBLIC) +#if U_ICU_VERSION_MAJOR_NUM >= 52 + PHP_ME_MAPPING(getWindowsID, intltz_get_windows_id, ainfo_tz_getWindowsID, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + PHP_ME_MAPPING(getIDForWindowsID, intltz_get_id_for_windows_id, ainfo_tz_getIDForWindowsID, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) +#endif PHP_FE_END }; /* }}} */ diff --git a/ext/intl/timezone/timezone_methods.cpp b/ext/intl/timezone/timezone_methods.cpp index a35174d3da..20c0e02480 100644 --- a/ext/intl/timezone/timezone_methods.cpp +++ b/ext/intl/timezone/timezone_methods.cpp @@ -647,3 +647,81 @@ U_CFUNC PHP_FUNCTION(intltz_get_error_message) message = intl_error_get_message(TIMEZONE_ERROR_P(to)); RETURN_STR(message); } + +#if U_ICU_VERSION_MAJOR_NUM >= 52 +/* {{{ proto string IntlTimeZone::getWindowsID(string $timezone) + proto string intltz_get_windows_id(string $timezone) +Translate a system timezone (e.g. "America/Los_Angeles" into a +Windows Timezone (e.g. "Pacific Standard Time") + */ +U_CFUNC PHP_FUNCTION(intltz_get_windows_id) +{ + zend_string *id, *winID; + UnicodeString uID, uWinID; + UErrorCode error; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &id) == FAILURE) { + return; + } + + error = U_ZERO_ERROR; + if (intl_stringFromChar(uID, id->val, id->len, &error) == FAILURE) { + intl_error_set(NULL, error, + "intltz_get_windows_id: could not convert time zone id to UTF-16", 0); + RETURN_FALSE; + } + + error = U_ZERO_ERROR; + TimeZone::getWindowsID(uID, uWinID, error); + INTL_CHECK_STATUS(error, "intltz_get_windows_id: Unable to get timezone from windows ID"); + if (uWinID.length() == 0) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_get_windows_id: Unknown system timezone", 0); + RETURN_FALSE; + } + + error = U_ZERO_ERROR; + winID = intl_convert_utf16_to_utf8(uWinID.getBuffer(), uWinID.length(), &error); + INTL_CHECK_STATUS(error, "intltz_get_windows_id: could not convert time zone id to UTF-8"); + RETURN_STR(winID); +} +/* }}} */ + +/* {{{ proto string IntlTimeZone::getIDForWindowsID(string $timezone[, string $region = NULL]) + proto string intltz_get_id_for_windows_id(string $timezone[, string $region = NULL]) +Translate a windows timezone (e.g. "Pacific Time Zone" into a +System Timezone (e.g. "America/Los_Angeles") + */ +U_CFUNC PHP_FUNCTION(intltz_get_id_for_windows_id) +{ + zend_string *winID, *region = NULL, *id; + UnicodeString uWinID, uID; + UErrorCode error; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|S", &winID, ®ion) == FAILURE) { + return; + } + + error = U_ZERO_ERROR; + if (intl_stringFromChar(uWinID, winID->val, winID->len, &error) == FAILURE) { + intl_error_set(NULL, error, + "intltz_get_id_for_windows_id: could not convert time zone id to UTF-16", 0); + RETURN_FALSE; + } + + error = U_ZERO_ERROR; + TimeZone::getIDForWindowsID(uWinID, region ? region->val : NULL, uID, error); + INTL_CHECK_STATUS(error, "intltz_get_id_for_windows_id: Unable to get windows ID for timezone"); + if (uID.length() == 0) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_get_windows_id: Unknown windows timezone", 0); + RETURN_FALSE; + } + + error = U_ZERO_ERROR; + id = intl_convert_utf16_to_utf8(uID.getBuffer(), uID.length(), &error); + INTL_CHECK_STATUS(error, "intltz_get_id_for_windows_id: could not convert time zone id to UTF-8"); + RETURN_STR(id); +} +/* }}} */ +#endif diff --git a/ext/intl/timezone/timezone_methods.h b/ext/intl/timezone/timezone_methods.h index 29d72913fd..6e6fa3f472 100644 --- a/ext/intl/timezone/timezone_methods.h +++ b/ext/intl/timezone/timezone_methods.h @@ -65,4 +65,9 @@ PHP_FUNCTION(intltz_get_error_code); PHP_FUNCTION(intltz_get_error_message); +#if U_ICU_VERSION_MAJOR_NUM >= 52 +PHP_FUNCTION(intltz_get_windows_id); +PHP_FUNCTION(intltz_get_id_for_windows_id); +#endif + #endif /* #ifndef TIMEZONE_METHODS_H */ diff --git a/ext/intl/transliterator/transliterator_class.c b/ext/intl/transliterator/transliterator_class.c index ce8c7e6291..5c80b25af8 100644 --- a/ext/intl/transliterator/transliterator_class.c +++ b/ext/intl/transliterator/transliterator_class.c @@ -269,9 +269,15 @@ static zval *Transliterator_read_property( zval *object, zval *member, int type, static void Transliterator_write_property( zval *object, zval *member, zval *value, void **cache_slot ) { + zend_class_entry *scope; TRANSLITERATOR_PROPERTY_HANDLER_PROLOG; - if( ( EG( scope ) != Transliterator_ce_ptr ) && + if (EG(fake_scope)) { + scope = EG(fake_scope); + } else { + scope = zend_get_executed_scope(); + } + if( ( scope != Transliterator_ce_ptr ) && ( zend_binary_strcmp( "id", sizeof( "id" ) - 1, Z_STRVAL_P( member ), Z_STRLEN_P( member ) ) == 0 ) ) { diff --git a/ext/json/json.c b/ext/json/json.c index bd7c0b0c1b..d3c6111d4d 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -254,7 +254,7 @@ static PHP_FUNCTION(json_decode) return; } - JSON_G(error_code) = 0; + JSON_G(error_code) = PHP_JSON_ERROR_NONE; if (!str_len) { JSON_G(error_code) = PHP_JSON_ERROR_SYNTAX; diff --git a/ext/json/json_encoder.c b/ext/json/json_encoder.c index 8da5abd088..62df102847 100644 --- a/ext/json/json_encoder.c +++ b/ext/json/json_encoder.c @@ -457,6 +457,7 @@ static void php_json_encode_serializable_object(smart_str *buf, zval *val, int o zend_class_entry *ce = Z_OBJCE_P(val); zval retval, fname; HashTable* myht; + int origin_error_code; if (Z_TYPE_P(val) == IS_ARRAY) { myht = Z_ARRVAL_P(val); @@ -470,8 +471,10 @@ static void php_json_encode_serializable_object(smart_str *buf, zval *val, int o return; } + ZVAL_STRING(&fname, "jsonSerialize"); + origin_error_code = JSON_G(error_code); if (FAILURE == call_user_function_ex(EG(function_table), val, &fname, &retval, 0, NULL, 1, NULL) || Z_TYPE(retval) == IS_UNDEF) { zend_throw_exception_ex(NULL, 0, "Failed calling %s::jsonSerialize()", ZSTR_VAL(ce->name)); smart_str_appendl(buf, "null", sizeof("null") - 1); @@ -479,6 +482,7 @@ static void php_json_encode_serializable_object(smart_str *buf, zval *val, int o return; } + JSON_G(error_code) = origin_error_code; if (EG(exception)) { /* Error already raised */ zval_ptr_dtor(&retval); diff --git a/ext/json/tests/bug72069.phpt b/ext/json/tests/bug72069.phpt new file mode 100644 index 0000000000..0ff8c98621 --- /dev/null +++ b/ext/json/tests/bug72069.phpt @@ -0,0 +1,29 @@ +--TEST-- +Bug #72069 (Behavior \JsonSerializable different from json_encode) +--SKIPIF-- +<?php if (!extension_loaded("json")) print "skip"; ?> +--FILE-- +<?php + +$result = json_encode(['end' => json_decode(null, true)]); +var_dump($result); + +class A implements \JsonSerializable +{ + function jsonSerialize() + { + return ['end' => json_decode(null, true)]; + } +} +$a = new A(); +$toJsonData = $a->jsonSerialize(); +$result = json_encode($a); +var_dump($result); + +$result = json_encode($toJsonData); +var_dump($result); +?> +--EXPECT-- +string(12) "{"end":null}" +string(12) "{"end":null}" +string(12) "{"end":null}" diff --git a/ext/mysqli/mysqli.c b/ext/mysqli/mysqli.c index 7d971c1b99..a907eed42f 100644 --- a/ext/mysqli/mysqli.c +++ b/ext/mysqli/mysqli.c @@ -1282,7 +1282,6 @@ void php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAMETERS, int override_flags if (ce->constructor) { fci.size = sizeof(fci); - fci.function_table = &ce->function_table; ZVAL_UNDEF(&fci.function_name); fci.object = Z_OBJ_P(return_value); fci.retval = &retval; @@ -1308,7 +1307,7 @@ void php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAMETERS, int override_flags fcc.initialized = 1; fcc.function_handler = ce->constructor; - fcc.calling_scope = EG(scope); + fcc.calling_scope = zend_get_executed_scope(); fcc.called_scope = Z_OBJCE_P(return_value); fcc.object = Z_OBJ_P(return_value); diff --git a/ext/oci8/oci8_dtrace.d b/ext/oci8/oci8_dtrace.d index 30c98de912..c8b5dfcfc3 100644 --- a/ext/oci8/oci8_dtrace.d +++ b/ext/oci8/oci8_dtrace.d @@ -4,11 +4,11 @@ +----------------------------------------------------------------------+ | Copyright (c) 2013 Zend Technologies Ltd. (http://www.zend.com) | +----------------------------------------------------------------------+ - | This source file is subject to version 3.01 of the Zend license, | + | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | - | http://www.zend.com/license/3_01.txt. | - | If you did not receive a copy of the Zend license and are unable to | + | http://www.php.net/license/3_01.txt. | + | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@zend.com so we can mail you a copy immediately. | +----------------------------------------------------------------------+ diff --git a/ext/oci8/oci8_interface.c b/ext/oci8/oci8_interface.c index e3bd509216..bb8828b746 100644 --- a/ext/oci8/oci8_interface.c +++ b/ext/oci8/oci8_interface.c @@ -1380,15 +1380,17 @@ PHP_FUNCTION(oci_fetch_all) PHP_OCI_ZVAL_TO_STATEMENT(z_statement, statement); zval_dtor(array); - array_init(array); while (skip--) { if (php_oci_statement_fetch(statement, nrows)) { + array_init(array); RETURN_LONG(0); } } if (flags & PHP_OCI_FETCHSTATEMENT_BY_ROW) { + /* Fetch by Row: array will contain one sub-array per query row */ + array_init(array); columns = safe_emalloc(statement->ncolumns, sizeof(php_oci_out_column *), 0); for (i = 0; i < statement->ncolumns; i++) { @@ -1398,7 +1400,7 @@ PHP_FUNCTION(oci_fetch_all) while (!php_oci_statement_fetch(statement, nrows)) { zval row; - array_init(&row); + array_init_size(&row, statement->ncolumns); for (i = 0; i < statement->ncolumns; i++) { php_oci_column_to_zval(columns[ i ], &element, PHP_OCI_RETURN_LOBS); @@ -1409,7 +1411,7 @@ PHP_FUNCTION(oci_fetch_all) zend_string *zvtmp; zvtmp = zend_string_init(columns[ i ]->name, columns[ i ]->name_len, 0); zend_symtable_update(Z_ARRVAL(row), zvtmp, &element); - zend_string_release(zvtmp); + zend_string_release(zvtmp); } } @@ -1424,6 +1426,8 @@ PHP_FUNCTION(oci_fetch_all) efree(columns); } else { /* default to BY_COLUMN */ + /* Fetch by columns: array will contain one sub-array per query column */ + array_init_size(array, statement->ncolumns); columns = safe_emalloc(statement->ncolumns, sizeof(php_oci_out_column *), 0); outarrs = safe_emalloc(statement->ncolumns, sizeof(zval*), 0); @@ -1440,9 +1444,9 @@ PHP_FUNCTION(oci_fetch_all) columns[ i ] = php_oci_statement_get_column(statement, i + 1, NULL, 0); array_init(&tmp); - zvtmp = zend_string_init(columns[ i ]->name, columns[ i ]->name_len, 0); + zvtmp = zend_string_init(columns[ i ]->name, columns[ i ]->name_len, 0); outarrs[ i ] = zend_symtable_update(Z_ARRVAL_P(array), zvtmp, &tmp); - zend_string_release(zvtmp); + zend_string_release(zvtmp); } } diff --git a/ext/oci8/oci8_statement.c b/ext/oci8/oci8_statement.c index 5fc21c2fbd..55983d3e9f 100644 --- a/ext/oci8/oci8_statement.c +++ b/ext/oci8/oci8_statement.c @@ -1149,7 +1149,8 @@ int php_oci_bind_by_name(php_oci_statement *statement, char *name, size_t name_l return 1; } convert_to_long(var); -#if defined(OCI_MAJOR_VERSION) && OCI_MAJOR_VERSION > 10 +#if defined(OCI_MAJOR_VERSION) && (OCI_MAJOR_VERSION > 10) && \ + (defined(__x86_64__) || defined(__LP64__) || defined(_LP64) || defined(_WIN64)) bind_data = (ub8 *)&Z_LVAL_P(var); value_sz = sizeof(ub8); #else diff --git a/ext/oci8/package.xml b/ext/oci8/package.xml index a672e29671..88462415cb 100644 --- a/ext/oci8/package.xml +++ b/ext/oci8/package.xml @@ -9,7 +9,7 @@ http://pear.php.net/dtd/package-2.0.xsd"> <description> Use the OCI8 extension to access Oracle Database. PHP OCI8 2.1 builds -with PHP 7. Use 'pecl install oci8-2.0.10' to install OCI8 for PHP +with PHP 7. Use 'pecl install oci8-2.0.11' to install OCI8 for PHP 5.2 - PHP 5.6. Use 'pecl install oci8-1.4.10' to install PHP OCI8 1.4 for PHP 4.3.9 - PHP 5.1. The OCI8 extension can be linked with Oracle client libraries from Oracle Database 12.1, 11, or 10.2. These @@ -46,12 +46,12 @@ Interoperability Support" (ID 207303.1) for details. <active>no</active> </lead> - <date>2015-12-12</date> + <date>2016-04-15</date> <time>12:00:00</time> <version> - <release>2.1.0</release> - <api>2.1.0</api> + <release>2.1.1</release> + <api>2.1.1</api> </version> <stability> <release>stable</release> @@ -60,7 +60,7 @@ Interoperability Support" (ID 207303.1) for details. <license uri="http://www.php.net/license">PHP</license> <notes> This version is for PHP 7 only. -Updated driver name format. +Fixed bug #71600 (oci_fetch_all segfaults when selecting more than 8 columns) </notes> <contents> <dir name="/"> @@ -161,6 +161,8 @@ Updated driver name format. <file name="bug51291_1.phpt" role="test" /> <file name="bug51291_2.phpt" role="test" /> <file name="bug68298.phpt" role="test" /> + <file name="bug71422.phpt" role="test" /> + <file name="bug71600.phpt" role="test" /> <file name="clientversion.phpt" role="test" /> <file name="close.phpt" role="test" /> <file name="coll_001.phpt" role="test" /> @@ -467,6 +469,37 @@ Updated driver name format. <release> <version> + <release>2.1.0</release> + <api>2.1.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license uri="http://www.php.net/license">PHP</license> + <notes> +This version is for PHP 7 only. +Updated driver name format. + </notes> +</release> + +<release> + <version> + <release>2.0.10</release> + <api>2.0.10</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license uri="http://www.php.net/license">PHP</license> + <notes> +Fixed bug #68298 (OCI int overflow) + </notes> +</release> + +<release> + <version> <release>2.0.9</release> <api>2.0.9</api> </version> diff --git a/ext/oci8/php_oci8.h b/ext/oci8/php_oci8.h index 7f1fba0353..da62aabac6 100644 --- a/ext/oci8/php_oci8.h +++ b/ext/oci8/php_oci8.h @@ -45,7 +45,7 @@ */ #undef PHP_OCI8_VERSION #endif -#define PHP_OCI8_VERSION "2.1.0" +#define PHP_OCI8_VERSION "2.1.1" extern zend_module_entry oci8_module_entry; #define phpext_oci8_ptr &oci8_module_entry diff --git a/ext/oci8/tests/bug71422.phpt b/ext/oci8/tests/bug71422.phpt new file mode 100644 index 0000000000..5978e04ece --- /dev/null +++ b/ext/oci8/tests/bug71422.phpt @@ -0,0 +1,65 @@ +--TEST-- +Bug #71422 (Fix ORA-01438: value larger than specified precision allowed for this column) +--SKIPIF-- +<?php +if (!extension_loaded('oci8')) die ("skip no oci8 extension"); +?> +--FILE-- +<?php + +require(dirname(__FILE__).'/connect.inc'); + +$stmtarray = array( + "DROP TABLE BUG71422_TEST", + "CREATE TABLE BUG71422_TEST (TEST_ID NUMBER(*,0) NOT NULL, LABEL VARCHAR2(50 CHAR), CONSTRAINT BUG71422_TEST_PK PRIMARY KEY (TEST_ID))", + "INSERT INTO BUG71422_TEST (TEST_ID, LABEL) VALUES (1, 'Foo')" +); + +oci8_test_sql_execute($c, $stmtarray); + +$stmt = oci_parse($c, 'SELECT LABEL AS RAW_QUERY FROM BUG71422_TEST WHERE TEST_ID=1'); +oci_execute($stmt); +while ($row = oci_fetch_array($stmt, OCI_ASSOC+OCI_RETURN_NULLS)) { + var_dump($row); +} + +$stmt = oci_parse($c, 'SELECT LABEL AS NUMERIC_BIND_PARAMETER FROM BUG71422_TEST WHERE TEST_ID=:test_id'); +$value = 1; +oci_bind_by_name($stmt, ':test_id', $value, -1, SQLT_INT); +oci_execute($stmt); +while ($row = oci_fetch_array($stmt, OCI_ASSOC+OCI_RETURN_NULLS)) { + var_dump($row); +} + +$stmt = oci_parse($c, 'SELECT LABEL AS STRING_BIND_PARAMETER FROM BUG71422_TEST WHERE TEST_ID=:test_id'); +$value = 1; +oci_bind_by_name($stmt, ':test_id', $value, -1, SQLT_CHR); +oci_execute($stmt); +while ($row = oci_fetch_array($stmt, OCI_ASSOC+OCI_RETURN_NULLS)) { + var_dump($row); +} + +// Cleanup + +$stmtarray = array( + "DROP TABLE BUG71422_TEST" +); +oci8_test_sql_execute($c, $stmtarray); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +array(1) { + ["RAW_QUERY"]=> + string(3) "Foo" +} +array(1) { + ["NUMERIC_BIND_PARAMETER"]=> + string(3) "Foo" +} +array(1) { + ["STRING_BIND_PARAMETER"]=> + string(3) "Foo" +} +===DONE=== diff --git a/ext/oci8/tests/bug71600.phpt b/ext/oci8/tests/bug71600.phpt new file mode 100644 index 0000000000..102c59f81a --- /dev/null +++ b/ext/oci8/tests/bug71600.phpt @@ -0,0 +1,96 @@ +--TEST-- +Bug #71600 (oci_fetch_all result in segfault when select more than 8 columns) +--SKIPIF-- +<?php +$target_dbs = array('oracledb' => true, 'timesten' => true); // test runs on these DBs +require(dirname(__FILE__).'/skipif.inc'); +?> +--FILE-- +<?php + +require(dirname(__FILE__).'/connect.inc'); + +// Initialize + +$stmtarray = array( + "create table bug71600_tab (col1 number, col2 number, col3 number, + col4 number, col5 number, col6 number, + col7 number, col8 number, col9 number)", + "insert into bug71600_tab values(1, 2, 3, 4, 5, 6, 7, 8, 9)", + "insert into bug71600_tab values(11, 12, 13, 14, 15, 16, 17, 18, 19)" +); + +oci8_test_sql_execute($c, $stmtarray); + +// Run test + +$sql = "select col1,col2,col3,col4,col5,col6,col7,col8,col9 from bug71600_tab"; + +echo "Test 1\n"; +$stmt = oci_parse($c, $sql); + +echo "Executing SELECT statament...\n"; +oci_execute($stmt,OCI_DEFAULT); + +echo "Fetching data by columns...\n"; +oci_fetch_all($stmt, $result); +oci_free_statement($stmt); + +$rsRows=(count($result,1)/($rows = count($result,0)))-1; +echo "$rsRows Records Found\n"; +$rsCount=0; +while($rsCount < $rsRows) +{ + $col1 =$result['COL1'][$rsCount]; + $col9 =$result['COL9'][$rsCount]; + echo "$rsCount|$col1|$col9\n"; + $rsCount++; +} + +echo "Test 2\n"; +$stmt = oci_parse($c, $sql); + +echo "Re-executing SELECT statament...\n"; +oci_execute($stmt,OCI_DEFAULT); + +echo "Fetching data by rows...\n"; +oci_fetch_all($stmt, $result, 0, -1, OCI_FETCHSTATEMENT_BY_ROW); +oci_free_statement($stmt); + +$rsRows=count($result,0); +echo "$rsRows Records Found\n"; +$rsCount=0; +while($rsCount < $rsRows) +{ + $col1 = $result[$rsCount]['COL1']; + $col9 = $result[$rsCount]['COL9']; + echo "$rsCount|$col1|$col9\n"; + $rsCount++; +} + + +// Cleanup + +$stmtarray = array( + "drop table bug71600_tab" +); + +oci8_test_sql_execute($c, $stmtarray); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +Test 1 +Executing SELECT statament... +Fetching data by columns... +2 Records Found +0|1|9 +1|11|19 +Test 2 +Re-executing SELECT statament... +Fetching data by rows... +2 Records Found +0|1|9 +1|11|19 +===DONE=== diff --git a/ext/oci8/tests/driver_name.phpt b/ext/oci8/tests/driver_name.phpt index 758e3979a7..0ff9bc485f 100644 --- a/ext/oci8/tests/driver_name.phpt +++ b/ext/oci8/tests/driver_name.phpt @@ -57,11 +57,11 @@ function get_attr($conn) ?> --EXPECT-- **Test 1.1 - Default values for the attribute ************** -The value of DRIVER_NAME is PHP OCI8 : 2.1.0 +The value of DRIVER_NAME is PHP OCI8 : 2.1.1 ***Test 1.2 - Get the values from different connections ************** Testing with oci_pconnect() -The value of DRIVER_NAME is PHP OCI8 : 2.1.0 +The value of DRIVER_NAME is PHP OCI8 : 2.1.1 Testing with oci_new_connect() -The value of DRIVER_NAME is PHP OCI8 : 2.1.0 +The value of DRIVER_NAME is PHP OCI8 : 2.1.1 Done diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index 0ecb57e2b9..8599d9ba19 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -690,7 +690,6 @@ optimize_constant_binary_op: opline++; continue; } - printf("%d\n", opline->opcode); er = EG(error_reporting); EG(error_reporting) = 0; if (binary_op(&result, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)) == SUCCESS) { diff --git a/ext/opcache/Optimizer/optimize_func_calls.c b/ext/opcache/Optimizer/optimize_func_calls.c index 8af82e4137..b37e0fee57 100644 --- a/ext/opcache/Optimizer/optimize_func_calls.c +++ b/ext/opcache/Optimizer/optimize_func_calls.c @@ -59,37 +59,13 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx) switch (opline->opcode) { case ZEND_INIT_FCALL_BY_NAME: case ZEND_INIT_NS_FCALL_BY_NAME: - if (ZEND_OP2_IS_CONST_STRING(opline)) { - zend_function *func; - zval *function_name = &ZEND_OP2_LITERAL(opline) + 1; - if ((func = zend_hash_find_ptr(&ctx->script->function_table, - Z_STR_P(function_name))) != NULL) { - call_stack[call].func = func; - } - } - call_stack[call].opline = opline; - call++; - break; case ZEND_INIT_STATIC_METHOD_CALL: - if (ZEND_OP2_IS_CONST_STRING(opline)) { - zend_class_entry *ce = NULL; - if (ZEND_OP1_IS_CONST_STRING(opline)) { - zend_string *class_name = Z_STR_P(&ZEND_OP1_LITERAL(opline) + 1); - ce = zend_hash_find_ptr(&ctx->script->class_table, class_name); - } else if (opline->op1_type == IS_UNUSED && op_array->scope - && !(op_array->scope->ce_flags & ZEND_ACC_TRAIT) - && (opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF) { - ce = op_array->scope; - } - if (ce) { - zend_string *func_name = Z_STR_P(&ZEND_OP2_LITERAL(opline) + 1); - call_stack[call].func = zend_hash_find_ptr(&ce->function_table, func_name); - } - } + case ZEND_INIT_METHOD_CALL: + call_stack[call].func = zend_optimizer_get_called_func( + ctx->script, op_array, opline, 0); /* break missing intentionally */ case ZEND_NEW: case ZEND_INIT_DYNAMIC_CALL: - case ZEND_INIT_METHOD_CALL: case ZEND_INIT_FCALL: case ZEND_INIT_USER_CALL: call_stack[call].opline = opline; @@ -109,7 +85,7 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx) Z_CACHE_SLOT(op_array->literals[fcall->op2.constant + 1]) = Z_CACHE_SLOT(op_array->literals[fcall->op2.constant]); literal_dtor(&ZEND_OP2_LITERAL(fcall)); fcall->op2.constant = fcall->op2.constant + 1; - opline->opcode = zend_get_call_op(ZEND_INIT_FCALL, call_stack[call].func); + opline->opcode = zend_get_call_op(fcall, call_stack[call].func); } else if (fcall->opcode == ZEND_INIT_NS_FCALL_BY_NAME) { fcall->opcode = ZEND_INIT_FCALL; fcall->op1.num = zend_vm_calc_used_stack(fcall->extended_value, call_stack[call].func); @@ -117,8 +93,9 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx) literal_dtor(&op_array->literals[fcall->op2.constant]); literal_dtor(&op_array->literals[fcall->op2.constant + 2]); fcall->op2.constant = fcall->op2.constant + 1; - opline->opcode = zend_get_call_op(ZEND_INIT_FCALL, call_stack[call].func); - } else if (fcall->opcode == ZEND_INIT_STATIC_METHOD_CALL) { + opline->opcode = zend_get_call_op(fcall, call_stack[call].func); + } else if (fcall->opcode == ZEND_INIT_STATIC_METHOD_CALL + || fcall->opcode == ZEND_INIT_METHOD_CALL) { /* We don't have specialized opcodes for this, do nothing */ } else { ZEND_ASSERT(0); diff --git a/ext/opcache/Optimizer/zend_call_graph.c b/ext/opcache/Optimizer/zend_call_graph.c index ef586e12a7..f245d14eaa 100644 --- a/ext/opcache/Optimizer/zend_call_graph.c +++ b/ext/opcache/Optimizer/zend_call_graph.c @@ -21,6 +21,8 @@ #include "php.h" #include "zend_compile.h" #include "zend_extensions.h" +#include "Optimizer/zend_optimizer.h" +#include "zend_optimizer_internal.h" #include "zend_inference.h" #include "zend_call_graph.h" #include "zend_func_info.h" @@ -150,39 +152,32 @@ static int zend_analyze_calls(zend_arena **arena, zend_script *script, uint32_t call_info = NULL; switch (opline->opcode) { case ZEND_INIT_FCALL: - if ((func = zend_hash_find_ptr(&script->function_table, Z_STR_P(CRT_CONSTANT(opline->op2)))) != NULL) { - zend_func_info *callee_func_info = ZEND_FUNC_INFO(&func->op_array); - if (callee_func_info) { - call_info = zend_arena_calloc(arena, 1, sizeof(zend_call_info) + (sizeof(zend_send_arg_info) * ((int)opline->extended_value - 1))); - call_info->caller_op_array = op_array; - call_info->caller_init_opline = opline; - call_info->caller_call_opline = NULL; - call_info->callee_func = func; - call_info->num_args = opline->extended_value; - call_info->next_caller = callee_func_info->caller_info; - callee_func_info->caller_info = call_info; - call_info->next_callee = func_info->callee_info; - func_info->callee_info = call_info; - } - } else if ((func = zend_hash_find_ptr(EG(function_table), Z_STR_P(CRT_CONSTANT(opline->op2)))) != NULL && - func->type == ZEND_INTERNAL_FUNCTION) { + case ZEND_INIT_METHOD_CALL: + case ZEND_INIT_STATIC_METHOD_CALL: + func = zend_optimizer_get_called_func( + script, op_array, opline, (build_flags & ZEND_RT_CONSTANTS) != 0); + if (func) { call_info = zend_arena_calloc(arena, 1, sizeof(zend_call_info) + (sizeof(zend_send_arg_info) * ((int)opline->extended_value - 1))); call_info->caller_op_array = op_array; call_info->caller_init_opline = opline; call_info->caller_call_opline = NULL; call_info->callee_func = func; call_info->num_args = opline->extended_value; - call_info->next_caller = NULL; call_info->next_callee = func_info->callee_info; func_info->callee_info = call_info; + + if (func->type == ZEND_INTERNAL_FUNCTION) { + call_info->next_caller = NULL; + } else { + zend_func_info *callee_func_info = ZEND_FUNC_INFO(&func->op_array); + call_info->next_caller = callee_func_info->caller_info; + } } /* break missing intentionally */ case ZEND_INIT_FCALL_BY_NAME: case ZEND_INIT_NS_FCALL_BY_NAME: case ZEND_INIT_DYNAMIC_CALL: case ZEND_NEW: - case ZEND_INIT_METHOD_CALL: - case ZEND_INIT_STATIC_METHOD_CALL: case ZEND_INIT_USER_CALL: call_stack[call] = call_info; call++; diff --git a/ext/opcache/Optimizer/zend_dfg.c b/ext/opcache/Optimizer/zend_dfg.c index b45aac41fb..c1972128d5 100644 --- a/ext/opcache/Optimizer/zend_dfg.c +++ b/ext/opcache/Optimizer/zend_dfg.c @@ -25,21 +25,19 @@ int zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg int set_size; zend_basic_block *blocks = cfg->blocks; int blocks_count = cfg->blocks_count; - zend_bitset tmp, gen, def, use, in, out; + zend_bitset tmp, def, use, in, out; zend_op *opline; uint32_t k, var_num; int j; - /* FIXME: can we use "gen" instead of "def" for flow analyzing? */ set_size = dfg->size; tmp = dfg->tmp; - gen = dfg->gen; def = dfg->def; use = dfg->use; in = dfg->in; out = dfg->out; - /* Collect "gen", "def" and "use" sets */ + /* Collect "def" and "use" sets */ for (j = 0; j < blocks_count; j++) { if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0) { continue; @@ -84,6 +82,9 @@ int zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg goto op1_def; } goto op1_use; + case ZEND_UNSET_VAR: + ZEND_ASSERT(opline->extended_value & ZEND_QUICK_SET); + /* break missing intentionally */ case ZEND_ASSIGN: case ZEND_ASSIGN_REF: case ZEND_BIND_GLOBAL: @@ -92,17 +93,6 @@ int zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg case ZEND_SEND_REF: case ZEND_SEND_VAR_NO_REF: case ZEND_FE_RESET_RW: -op1_def: - if (!DFG_ISSET(use, set_size, j, var_num)) { - // FIXME: include into "use" to ...? - DFG_SET(use, set_size, j, var_num); - DFG_SET(def, set_size, j, var_num); - } - DFG_SET(gen, set_size, j, var_num); - break; - case ZEND_UNSET_VAR: - ZEND_ASSERT(opline->extended_value & ZEND_QUICK_SET); - /* break missing intentionally */ case ZEND_ASSIGN_ADD: case ZEND_ASSIGN_SUB: case ZEND_ASSIGN_MUL: @@ -132,7 +122,11 @@ op1_def: case ZEND_FETCH_OBJ_FUNC_ARG: case ZEND_FETCH_OBJ_UNSET: case ZEND_VERIFY_RETURN_TYPE: - DFG_SET(gen, set_size, j, var_num); +op1_def: + // FIXME: include into "use" too ...? + DFG_SET(use, set_size, j, var_num); + DFG_SET(def, set_size, j, var_num); + break; default: op1_use: if (!DFG_ISSET(def, set_size, j, var_num)) { @@ -142,9 +136,9 @@ op1_use: } else if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) { var_num = EX_VAR_TO_NUM(opline->op1.var); if (opline->opcode == ZEND_VERIFY_RETURN_TYPE) { - DFG_SET(gen, set_size, j, var_num); - } - if (!DFG_ISSET(def, set_size, j, var_num)) { + DFG_SET(use, set_size, j, var_num); + DFG_SET(def, set_size, j, var_num); + } else if (!DFG_ISSET(def, set_size, j, var_num)) { DFG_SET(use, set_size, j, var_num); } } @@ -165,12 +159,9 @@ op1_use: case ZEND_FE_FETCH_R: case ZEND_FE_FETCH_RW: op2_def: - if (!DFG_ISSET(use, set_size, j, var_num)) { - // FIXME: include into "use" to ...? - DFG_SET(use, set_size, j, var_num); - DFG_SET(def, set_size, j, var_num); - } - DFG_SET(gen, set_size, j, var_num); + // FIXME: include into "use" too ...? + DFG_SET(use, set_size, j, var_num); + DFG_SET(def, set_size, j, var_num); break; default: op2_use: @@ -182,10 +173,7 @@ op2_use: } else if (opline->op2_type & (IS_VAR|IS_TMP_VAR)) { var_num = EX_VAR_TO_NUM(opline->op2.var); if (opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW) { - if (!DFG_ISSET(use, set_size, j, var_num)) { - DFG_SET(def, set_size, j, var_num); - } - DFG_SET(gen, set_size, j, var_num); + DFG_SET(def, set_size, j, var_num); } else { if (!DFG_ISSET(def, set_size, j, var_num)) { DFG_SET(use, set_size, j, var_num); @@ -194,10 +182,7 @@ op2_use: } if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) { var_num = EX_VAR_TO_NUM(opline->result.var); - if (!DFG_ISSET(use, set_size, j, var_num)) { - DFG_SET(def, set_size, j, var_num); - } - DFG_SET(gen, set_size, j, var_num); + DFG_SET(def, set_size, j, var_num); } } } diff --git a/ext/opcache/Optimizer/zend_dfg.h b/ext/opcache/Optimizer/zend_dfg.h index 9d864992ca..5ed8cfc5d0 100644 --- a/ext/opcache/Optimizer/zend_dfg.h +++ b/ext/opcache/Optimizer/zend_dfg.h @@ -26,7 +26,6 @@ typedef struct _zend_dfg { int vars; uint32_t size; zend_bitset tmp; - zend_bitset gen; zend_bitset def; zend_bitset use; zend_bitset in; diff --git a/ext/opcache/Optimizer/zend_dump.c b/ext/opcache/Optimizer/zend_dump.c index ba5fb8a0ce..986e470345 100644 --- a/ext/opcache/Optimizer/zend_dump.c +++ b/ext/opcache/Optimizer/zend_dump.c @@ -1143,7 +1143,6 @@ void zend_dump_dfg(const zend_op_array *op_array, const zend_cfg *cfg, const zen for (j = 0; j < cfg->blocks_count; j++) { fprintf(stderr, " BB%d:\n", j); - zend_dump_var_set(op_array, "gen", DFG_BITSET(dfg->gen, dfg->size, j)); zend_dump_var_set(op_array, "def", DFG_BITSET(dfg->def, dfg->size, j)); zend_dump_var_set(op_array, "use", DFG_BITSET(dfg->use, dfg->size, j)); zend_dump_var_set(op_array, "in ", DFG_BITSET(dfg->in, dfg->size, j)); diff --git a/ext/opcache/Optimizer/zend_func_info.c b/ext/opcache/Optimizer/zend_func_info.c index 2aa3ecb928..a684a16e73 100644 --- a/ext/opcache/Optimizer/zend_func_info.c +++ b/ext/opcache/Optimizer/zend_func_info.c @@ -529,7 +529,7 @@ static const func_info_t func_infos[] = { F1("forward_static_call", UNKNOWN_INFO), F1("forward_static_call_array", UNKNOWN_INFO), F1("serialize", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING), - FX("unserialize", UNKNOWN_INFO), + FN("unserialize", UNKNOWN_INFO), F1("var_dump", MAY_BE_NULL), F1("var_export", MAY_BE_NULL | MAY_BE_STRING), F1("debug_zval_dump", MAY_BE_NULL), diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index 38a278d85d..b853a2e55c 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -2888,7 +2888,7 @@ static void zend_update_type_info(const zend_op_array *op_array, case ZEND_POST_INC: case ZEND_POST_DEC: if (ssa_ops[i].result_def >= 0) { - tmp = (MAY_BE_RC1 | t1) & ~(MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_RCN); + tmp = (MAY_BE_RC1 | t1) & ~(MAY_BE_UNDEF|MAY_BE_ERROR|MAY_BE_REF|MAY_BE_RCN); if (t1 & MAY_BE_UNDEF) { tmp |= MAY_BE_NULL; } @@ -3076,7 +3076,7 @@ static void zend_update_type_info(const zend_op_array *op_array, } } if (ssa_ops[i].result_def >= 0) { - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(tmp & ~MAY_BE_REF, ssa_ops[i].result_def); if ((t2 & MAY_BE_OBJECT) && ssa_ops[i].op2_use >= 0 && ssa_var_info[ssa_ops[i].op2_use].ce) { UPDATE_SSA_OBJ_TYPE(ssa_var_info[ssa_ops[i].op2_use].ce, ssa_var_info[ssa_ops[i].op2_use].is_instanceof, ssa_ops[i].result_def); } else { @@ -3096,7 +3096,7 @@ static void zend_update_type_info(const zend_op_array *op_array, if (opline->op2_type == IS_VAR && opline->extended_value == ZEND_RETURNS_FUNCTION) { tmp = (MAY_BE_REF | MAY_BE_RCN | MAY_BE_RC1 | t2) & ~MAY_BE_UNDEF; } else { - tmp = (MAY_BE_REF | t2) & ~(MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN); + tmp = (MAY_BE_REF | t2) & ~(MAY_BE_UNDEF|MAY_BE_ERROR|MAY_BE_RC1|MAY_BE_RCN); } if (t2 & MAY_BE_UNDEF) { tmp |= MAY_BE_NULL; @@ -3164,6 +3164,16 @@ static void zend_update_type_info(const zend_op_array *op_array, UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); } break; + case ZEND_SEND_UNPACK: + if (ssa_ops[i].op1_def >= 0) { + tmp = t1 | MAY_BE_RC1|MAY_BE_RCN; + if (t1 & MAY_BE_ARRAY) { + /* SEND_UNPACK may acquire references into the array */ + tmp |= MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF; + } + UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + } + break; case ZEND_FAST_CONCAT: case ZEND_ROPE_INIT: case ZEND_ROPE_ADD: @@ -3605,7 +3615,10 @@ static void zend_update_type_info(const zend_op_array *op_array, } } if (ssa_ops[i].result_def >= 0) { - tmp = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ERROR; + tmp = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF; + if (opline->opcode != ZEND_FETCH_OBJ_R && opline->opcode != ZEND_FETCH_OBJ_IS) { + tmp |= MAY_BE_ERROR; + } if (opline->result_type == IS_TMP_VAR) { tmp |= MAY_BE_RC1; } else { @@ -4139,6 +4152,19 @@ static int zend_infer_types(const zend_op_array *op_array, const zend_script *sc /* Narrowing integer initialization to doubles */ zend_type_narrowing(op_array, script, ssa); + for (j = 0; j < op_array->last_var; j++) { + if (zend_string_equals_literal(op_array->vars[j], "php_errormsg")) { + /* Mark all SSA vars for $php_errormsg as references, + * to make sure we don't optimize it. */ + int i; + for (i = 0; i < ssa_vars_count; i++) { + if (ssa->vars[i].var == j) { + ssa_var_info[i].type |= MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF; + } + } + } + } + if (ZEND_FUNC_INFO(op_array)) { zend_func_return_info(op_array, script, 1, 0, &ZEND_FUNC_INFO(op_array)->return_info); } diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index a18f79a843..1e4e092512 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -527,6 +527,70 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array, return 1; } +zend_function *zend_optimizer_get_called_func( + zend_script *script, zend_op_array *op_array, zend_op *opline, zend_bool rt_constants) +{ +#define GET_OP(op) CRT_CONSTANT_EX(op_array, opline->op, rt_constants) + switch (opline->opcode) { + case ZEND_INIT_FCALL: + { + zend_string *function_name = Z_STR_P(GET_OP(op2)); + zend_function *func; + if ((func = zend_hash_find_ptr(&script->function_table, function_name)) != NULL) { + return func; + } else if ((func = zend_hash_find_ptr(EG(function_table), function_name)) != NULL) { + ZEND_ASSERT(func->type == ZEND_INTERNAL_FUNCTION); + return func; + } + break; + } + case ZEND_INIT_FCALL_BY_NAME: + case ZEND_INIT_NS_FCALL_BY_NAME: + if (opline->op2_type == IS_CONST && Z_TYPE_P(GET_OP(op2)) == IS_STRING) { + zval *function_name = GET_OP(op2) + 1; + return zend_hash_find_ptr(&script->function_table, Z_STR_P(function_name)); + } + break; + case ZEND_INIT_STATIC_METHOD_CALL: + if (opline->op2_type == IS_CONST && Z_TYPE_P(GET_OP(op2)) == IS_STRING) { + zend_class_entry *ce = NULL; + if (opline->op1_type == IS_CONST && Z_TYPE_P(GET_OP(op1)) == IS_STRING) { + zend_string *class_name = Z_STR_P(GET_OP(op1) + 1); + ce = zend_hash_find_ptr(&script->class_table, class_name); + } else if (opline->op1_type == IS_UNUSED && op_array->scope + && !(op_array->scope->ce_flags & ZEND_ACC_TRAIT) + && (opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF) { + ce = op_array->scope; + } + if (ce) { + zend_string *func_name = Z_STR_P(GET_OP(op2) + 1); + return zend_hash_find_ptr(&ce->function_table, func_name); + } + } + break; + case ZEND_INIT_METHOD_CALL: + if (opline->op1_type == IS_UNUSED + && opline->op2_type == IS_CONST && Z_TYPE_P(GET_OP(op2)) == IS_STRING + && op_array->scope && !(op_array->scope->ce_flags & ZEND_ACC_TRAIT)) { + zend_string *method_name = Z_STR_P(GET_OP(op2) + 1); + zend_function *fbc = zend_hash_find_ptr( + &op_array->scope->function_table, method_name); + if (fbc) { + zend_bool is_private = (fbc->common.fn_flags & ZEND_ACC_PRIVATE) != 0; + zend_bool is_final = (fbc->common.fn_flags & ZEND_ACC_FINAL) != 0; + zend_bool same_scope = fbc->common.scope == op_array->scope; + if ((is_private && same_scope) + || (is_final && (!is_private || same_scope))) { + return fbc; + } + } + } + break; + } + return NULL; +#undef GET_OP +} + static void zend_optimize(zend_op_array *op_array, zend_optimizer_ctx *ctx) { @@ -751,8 +815,7 @@ static void zend_adjust_fcall_stack_size_graph(zend_op_array *op_array) while (call_info) { zend_op *opline = call_info->caller_init_opline; - if (opline && call_info->callee_func) { - ZEND_ASSERT(opline->opcode == ZEND_INIT_FCALL); + if (opline && call_info->callee_func && opline->opcode == ZEND_INIT_FCALL) { opline->op1.num = zend_vm_calc_used_stack(opline->extended_value, call_info->callee_func); } call_info = call_info->next_callee; diff --git a/ext/opcache/Optimizer/zend_optimizer_internal.h b/ext/opcache/Optimizer/zend_optimizer_internal.h index 220a00d6c4..1d51b57634 100644 --- a/ext/opcache/Optimizer/zend_optimizer_internal.h +++ b/ext/opcache/Optimizer/zend_optimizer_internal.h @@ -106,5 +106,7 @@ void zend_optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_c void zend_optimizer_nop_removal(zend_op_array *op_array); void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx *ctx); int zend_optimizer_is_disabled_func(const char *name, size_t len); +zend_function *zend_optimizer_get_called_func( + zend_script *script, zend_op_array *op_array, zend_op *opline, zend_bool rt_constants); #endif diff --git a/ext/opcache/Optimizer/zend_ssa.c b/ext/opcache/Optimizer/zend_ssa.c index a55ccc915a..201317f207 100644 --- a/ext/opcache/Optimizer/zend_ssa.c +++ b/ext/opcache/Optimizer/zend_ssa.c @@ -23,19 +23,47 @@ #include "zend_dump.h" #include "zend_inference.h" -static int needs_pi(const zend_op_array *op_array, zend_dfg *dfg, zend_ssa *ssa, int from, int to, int var) /* {{{ */ -{ - if (from == to || ssa->cfg.blocks[to].predecessors_count != 1) { - zend_ssa_phi *p = ssa->blocks[to].phis; - while (p) { - if (p->pi < 0 && p->var == var) { - return 1; - } - p = p->next; +static zend_bool dominates(const zend_basic_block *blocks, int a, int b) { + while (blocks[b].level > blocks[a].level) { + b = blocks[b].idom; + } + return a == b; +} + +static zend_bool dominates_other_predecessors( + const zend_cfg *cfg, const zend_basic_block *block, int check, int exclude) { + int i; + for (i = 0; i < block->predecessors_count; i++) { + int predecessor = cfg->predecessors[block->predecessor_offset + i]; + if (predecessor != exclude && !dominates(cfg->blocks, check, predecessor)) { + return 0; } + } + return 1; +} + +static zend_bool needs_pi(const zend_op_array *op_array, zend_dfg *dfg, zend_ssa *ssa, int from, int to, int var) /* {{{ */ +{ + zend_basic_block *from_block, *to_block; + int other_successor; + + if (!DFG_ISSET(dfg->in, dfg->size, to, var)) { + /* Variable is not live, certainly won't benefit from pi */ return 0; } - return DFG_ISSET(dfg->in, dfg->size, to, var); + + to_block = &ssa->cfg.blocks[to]; + if (to_block->predecessors_count == 1) { + /* Always place pi if one predecessor (an if branch) */ + return 1; + } + + /* Check that the other successor of the from block does not dominate all other predecessors. + * If it does, we'd probably end up annihilating a positive+negative pi assertion. */ + from_block = &ssa->cfg.blocks[from]; + other_successor = from_block->successors[0] == to + ? from_block->successors[1] : from_block->successors[0]; + return !dominates_other_predecessors(&ssa->cfg, to_block, other_successor, from); } /* }}} */ @@ -62,6 +90,11 @@ static zend_ssa_phi *add_pi( phi->next = ssa->blocks[to].phis; ssa->blocks[to].phis = phi; + /* Block "to" now defines "var" via the pi statement, so add it to the "def" set. Note that + * this is not entirely accurate, because the pi is actually placed along the edge from->to. + * If there is a back-edge to "to" this may result in non-minimal SSA form. */ + DFG_SET(dfg->def, dfg->size, to, var); + return phi; } /* }}} */ @@ -585,6 +618,7 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags, case ZEND_SEND_VAR_NO_REF: case ZEND_SEND_VAR_EX: case ZEND_SEND_REF: + case ZEND_SEND_UNPACK: case ZEND_FE_RESET_RW: //TODO: ??? if (opline->op1_type == IS_CV) { @@ -764,7 +798,7 @@ int zend_build_ssa(zend_arena **arena, const zend_op_array *op_array, uint32_t b zend_ssa_block *ssa_blocks; int blocks_count = ssa->cfg.blocks_count; uint32_t set_size; - zend_bitset tmp, gen, in; + zend_bitset tmp, def, in; int *var = NULL; int i, j, k, changed; zend_dfg dfg; @@ -781,10 +815,9 @@ int zend_build_ssa(zend_arena **arena, const zend_op_array *op_array, uint32_t b /* Compute Variable Liveness */ dfg.vars = op_array->last_var + op_array->T; dfg.size = set_size = zend_bitset_len(dfg.vars); - dfg.tmp = do_alloca((set_size * sizeof(zend_ulong)) * (blocks_count * 5 + 1), dfg_use_heap); - memset(dfg.tmp, 0, (set_size * sizeof(zend_ulong)) * (blocks_count * 5 + 1)); - dfg.gen = dfg.tmp + set_size; - dfg.def = dfg.gen + set_size * blocks_count; + dfg.tmp = do_alloca((set_size * sizeof(zend_ulong)) * (blocks_count * 4 + 1), dfg_use_heap); + memset(dfg.tmp, 0, (set_size * sizeof(zend_ulong)) * (blocks_count * 4 + 1)); + dfg.def = dfg.tmp + set_size; dfg.use = dfg.def + set_size * blocks_count; dfg.in = dfg.use + set_size * blocks_count; dfg.out = dfg.in + set_size * blocks_count; @@ -799,27 +832,31 @@ int zend_build_ssa(zend_arena **arena, const zend_op_array *op_array, uint32_t b } tmp = dfg.tmp; - gen = dfg.gen; + def = dfg.def; in = dfg.in; - /* SSA construction, Step 1: Propagate "gen" sets in merge points */ + /* Place e-SSA pis. This will add additional "def" points, so it must + * happen before def propagation. */ + place_essa_pis(arena, op_array, build_flags, ssa, &dfg); + + /* SSA construction, Step 1: Propagate "def" sets in merge points */ do { changed = 0; for (j = 0; j < blocks_count; j++) { if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0) { continue; } - if (j >= 0 && (blocks[j].predecessors_count > 1 || j == 0)) { - zend_bitset_copy(tmp, gen + (j * set_size), set_size); + if (blocks[j].predecessors_count > 1 || j == 0) { + zend_bitset_copy(tmp, def + (j * set_size), set_size); for (k = 0; k < blocks[j].predecessors_count; k++) { i = ssa->cfg.predecessors[blocks[j].predecessor_offset + k]; while (i != -1 && i != blocks[j].idom) { - zend_bitset_union_with_intersection(tmp, tmp, gen + (i * set_size), in + (j * set_size), set_size); + zend_bitset_union_with_intersection(tmp, tmp, def + (i * set_size), in + (j * set_size), set_size); i = blocks[i].idom; } } - if (!zend_bitset_equal(gen + (j * set_size), tmp, set_size)) { - zend_bitset_copy(gen + (j * set_size), tmp, set_size); + if (!zend_bitset_equal(def + (j * set_size), tmp, set_size)) { + zend_bitset_copy(def + (j * set_size), tmp, set_size); changed = 1; } } @@ -849,110 +886,40 @@ int zend_build_ssa(zend_arena **arena, const zend_op_array *op_array, uint32_t b for (k = 0; k < blocks[j].predecessors_count; k++) { i = ssa->cfg.predecessors[blocks[j].predecessor_offset + k]; while (i != -1 && i != blocks[j].idom) { - zend_bitset_union_with_intersection(tmp, tmp, gen + (i * set_size), in + (j * set_size), set_size); + zend_bitset_union_with_intersection(tmp, tmp, def + (i * set_size), in + (j * set_size), set_size); i = blocks[i].idom; } } } if (!zend_bitset_empty(tmp, set_size)) { - i = op_array->last_var + op_array->T; - while (i > 0) { - i--; - if (zend_bitset_in(tmp, i)) { - zend_ssa_phi *phi = zend_arena_calloc(arena, 1, - sizeof(zend_ssa_phi) + - sizeof(int) * blocks[j].predecessors_count + - sizeof(void*) * blocks[j].predecessors_count); - - if (!phi) { - goto failure; - } - phi->sources = (int*)(((char*)phi) + sizeof(zend_ssa_phi)); - memset(phi->sources, 0xff, sizeof(int) * blocks[j].predecessors_count); - phi->use_chains = (zend_ssa_phi**)(((char*)phi->sources) + sizeof(int) * ssa->cfg.blocks[j].predecessors_count); - - phi->pi = -1; - phi->var = i; - phi->ssa_var = -1; - phi->next = ssa_blocks[j].phis; - ssa_blocks[j].phis = phi; - } - } - } - } - } + ZEND_BITSET_REVERSE_FOREACH(tmp, set_size, i) { + zend_ssa_phi *phi = zend_arena_calloc(arena, 1, + sizeof(zend_ssa_phi) + + sizeof(int) * blocks[j].predecessors_count + + sizeof(void*) * blocks[j].predecessors_count); - place_essa_pis(arena, op_array, build_flags, ssa, &dfg); + phi->sources = (int*)(((char*)phi) + sizeof(zend_ssa_phi)); + memset(phi->sources, 0xff, sizeof(int) * blocks[j].predecessors_count); + phi->use_chains = (zend_ssa_phi**)(((char*)phi->sources) + sizeof(int) * ssa->cfg.blocks[j].predecessors_count); - /* SSA construction, Step ?: Phi after Pi placement based on Dominance Frontiers */ - for (j = 0; j < blocks_count; j++) { - if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0) { - continue; - } - if (blocks[j].predecessors_count > 1) { - zend_bitset_clear(tmp, set_size); - if (blocks[j].flags & ZEND_BB_IRREDUCIBLE_LOOP) { - /* Prevent any values from flowing into irreducible loops by - replacing all incoming values with explicit phis. The - register allocator depends on this property. */ - zend_bitset_copy(tmp, in + (j * set_size), set_size); - } else { - for (k = 0; k < blocks[j].predecessors_count; k++) { - i = ssa->cfg.predecessors[blocks[j].predecessor_offset + k]; - while (i != -1 && i != blocks[j].idom) { - zend_ssa_phi *p = ssa_blocks[i].phis; - while (p) { - if (p) { - if (p->pi >= 0) { - if (zend_bitset_in(in + (j * set_size), p->var) && - !zend_bitset_in(gen + (i * set_size), p->var)) { - zend_bitset_incl(tmp, p->var); - } - } else { - zend_bitset_excl(tmp, p->var); - } - } - p = p->next; - } - i = blocks[i].idom; - } - } - } + phi->pi = -1; + phi->var = i; + phi->ssa_var = -1; - if (!zend_bitset_empty(tmp, set_size)) { - i = op_array->last_var + op_array->T; - while (i > 0) { - i--; - if (zend_bitset_in(tmp, i)) { + /* Place phis after pis */ + { zend_ssa_phi **pp = &ssa_blocks[j].phis; while (*pp) { - if ((*pp)->pi <= 0 && (*pp)->var == i) { + if ((*pp)->pi < 0) { break; } pp = &(*pp)->next; } - if (*pp == NULL) { - zend_ssa_phi *phi = zend_arena_calloc(arena, 1, - sizeof(zend_ssa_phi) + - sizeof(int) * blocks[j].predecessors_count + - sizeof(void*) * blocks[j].predecessors_count); - - if (!phi) { - goto failure; - } - phi->sources = (int*)(((char*)phi) + sizeof(zend_ssa_phi)); - memset(phi->sources, 0xff, sizeof(int) * blocks[j].predecessors_count); - phi->use_chains = (zend_ssa_phi**)(((char*)phi->sources) + sizeof(int) * ssa->cfg.blocks[j].predecessors_count); - - phi->pi = -1; - phi->var = i; - phi->ssa_var = -1; - phi->next = NULL; - *pp = phi; - } + phi->next = *pp; + *pp = phi; } - } + } ZEND_BITSET_FOREACH_END(); } } } @@ -971,7 +938,6 @@ int zend_build_ssa(zend_arena **arena, const zend_op_array *op_array, uint32_t b } ssa->vars_count = op_array->last_var; if (zend_ssa_rename(op_array, build_flags, ssa, var, 0) != SUCCESS) { -failure: free_alloca(var, var_use_heap); free_alloca(dfg.tmp, dfg_use_heap); return FAILURE; diff --git a/ext/opcache/README b/ext/opcache/README index 11c9c2748b..e4d36ba51a 100644 --- a/ext/opcache/README +++ b/ext/opcache/README @@ -215,4 +215,4 @@ opcache.mmap_base errors. opcache.lockfile_path (default "/tmp") - Absolute path used to store shared lockfiles. + Absolute path used to store shared lockfiles (for *nix only) diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h index b4119bcd45..ffcb1b6eb6 100644 --- a/ext/opcache/ZendAccelerator.h +++ b/ext/opcache/ZendAccelerator.h @@ -195,7 +195,9 @@ typedef struct _zend_accel_directives { zend_long max_file_size; zend_long interned_strings_buffer; char *restrict_api; +#ifndef ZEND_WIN32 char *lockfile_path; +#endif #ifdef HAVE_OPCACHE_FILE_CACHE char *file_cache; zend_bool file_cache_only; diff --git a/ext/opcache/tests/bug72014.phpt b/ext/opcache/tests/bug72014.phpt new file mode 100644 index 0000000000..d2ad96c0f1 --- /dev/null +++ b/ext/opcache/tests/bug72014.phpt @@ -0,0 +1,29 @@ +--TEST-- +Bug #72014 (Including a file with anonymous classes multiple times leads to fatal error) +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +--SKIPIF-- +<?php require_once('skipif.inc'); ?> +--FILE-- +<?php +file_put_contents(__DIR__ . "/bug72014.annon.php", <<<PHP +<?php +\$a = new class() { public \$testvar = "Foo\n"; }; +echo \$a->testvar; +PHP +); + +include(__DIR__ . "/bug72014.annon.php"); +include(__DIR__ . "/bug72014.annon.php"); +include(__DIR__ . "/bug72014.annon.php"); +?> +--CLEAN-- +<?php +@unlink(__DIR__ . "/bug72014.annon.php") +?> +--EXPECT-- +Foo +Foo +Foo diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c index 92f496c359..aa01073c97 100644 --- a/ext/opcache/zend_accelerator_module.c +++ b/ext/opcache/zend_accelerator_module.c @@ -299,9 +299,10 @@ ZEND_INI_BEGIN() STD_PHP_INI_BOOLEAN("opcache.enable_cli" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.enable_cli, zend_accel_globals, accel_globals) STD_PHP_INI_ENTRY("opcache.error_log" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.error_log, zend_accel_globals, accel_globals) STD_PHP_INI_ENTRY("opcache.restrict_api" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.restrict_api, zend_accel_globals, accel_globals) - STD_PHP_INI_ENTRY("opcache.lockfile_path" , "/tmp" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.lockfile_path, zend_accel_globals, accel_globals) -#ifdef ZEND_WIN32 +#ifndef ZEND_WIN32 + STD_PHP_INI_ENTRY("opcache.lockfile_path" , "/tmp" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.lockfile_path, zend_accel_globals, accel_globals) +#else STD_PHP_INI_ENTRY("opcache.mmap_base", NULL, PHP_INI_SYSTEM, OnUpdateString, accel_directives.mmap_base, zend_accel_globals, accel_globals) #endif @@ -712,7 +713,10 @@ static ZEND_FUNCTION(opcache_get_configuration) add_assoc_bool(&directives, "opcache.fast_shutdown", ZCG(accel_directives).fast_shutdown); add_assoc_bool(&directives, "opcache.enable_file_override", ZCG(accel_directives).file_override_enabled); add_assoc_long(&directives, "opcache.optimization_level", ZCG(accel_directives).optimization_level); + +#ifndef ZEND_WIN32 add_assoc_string(&directives, "opcache.lockfile_path", STRING_NOT_NULL(ZCG(accel_directives).lockfile_path)); +#endif #ifdef HAVE_OPCACHE_FILE_CACHE add_assoc_string(&directives, "opcache.file_cache", ZCG(accel_directives).file_cache ? ZCG(accel_directives).file_cache : ""); diff --git a/ext/opcache/zend_accelerator_util_funcs.c b/ext/opcache/zend_accelerator_util_funcs.c index 27731dd624..61c9c15d2b 100644 --- a/ext/opcache/zend_accelerator_util_funcs.c +++ b/ext/opcache/zend_accelerator_util_funcs.c @@ -40,8 +40,6 @@ typedef int (*id_function_t)(void *, void *); typedef void (*unique_copy_ctor_func_t)(void *pElement); -static zend_ast *zend_ast_clone(zend_ast *ast); - static void zend_accel_destroy_zend_function(zval *zv) { zend_function *function = Z_PTR_P(zv); @@ -169,61 +167,6 @@ static inline void zend_clone_zval(zval *src) src = Z_REFVAL_P(src); } } - if (Z_TYPE_P(src) == IS_CONSTANT_AST) { - if (Z_REFCOUNT_P(src) > 1 && (ptr = accel_xlat_get(Z_AST_P(src))) != NULL) { - Z_AST_P(src) = ptr; - } else { - zend_ast_ref *old = Z_AST_P(src); - - ZVAL_NEW_AST(src, old->ast); - Z_AST_P(src)->gc = old->gc; - if (Z_REFCOUNT_P(src) > 1) { - accel_xlat_set(old, Z_AST_P(src)); - } - Z_ASTVAL_P(src) = zend_ast_clone(Z_ASTVAL_P(src)); - } - } -} - -static zend_ast *zend_ast_clone(zend_ast *ast) -{ - uint32_t i; - - if (ast->kind == ZEND_AST_ZVAL) { - zend_ast_zval *copy = emalloc(sizeof(zend_ast_zval)); - copy->kind = ZEND_AST_ZVAL; - copy->attr = ast->attr; - ZVAL_COPY_VALUE(©->val, zend_ast_get_zval(ast)); - return (zend_ast *) copy; - } else if (zend_ast_is_list(ast)) { - zend_ast_list *list = zend_ast_get_list(ast); - zend_ast_list *copy = emalloc( - sizeof(zend_ast_list) - sizeof(zend_ast *) + sizeof(zend_ast *) * list->children); - copy->kind = list->kind; - copy->attr = list->attr; - copy->children = list->children; - for (i = 0; i < list->children; i++) { - if (list->child[i]) { - copy->child[i] = zend_ast_clone(list->child[i]); - } else { - copy->child[i] = NULL; - } - } - return (zend_ast *) copy; - } else { - uint32_t children = zend_ast_get_num_children(ast); - zend_ast *copy = emalloc(sizeof(zend_ast) - sizeof(zend_ast *) + sizeof(zend_ast *) * children); - copy->kind = ast->kind; - copy->attr = ast->attr; - for (i = 0; i < children; i++) { - if (ast->child[i]) { - copy->child[i] = zend_ast_clone(ast->child[i]); - } else { - copy->child[i] = NULL; - } - } - return copy; - } } static void zend_hash_clone_constants(HashTable *ht, HashTable *source) @@ -617,7 +560,6 @@ failure: static void zend_accel_class_hash_copy(HashTable *target, HashTable *source, unique_copy_ctor_func_t pCopyConstructor) { - zend_class_entry *ce1; Bucket *p, *end; zval *t; @@ -633,7 +575,17 @@ static void zend_accel_class_hash_copy(HashTable *target, HashTable *source, uni /* Mangled key - ignore and wait for runtime */ continue; } else if (UNEXPECTED(!ZCG(accel_directives).ignore_dups)) { - goto failure; + zend_class_entry *ce1 = Z_PTR(p->val); + if (!(ce1->ce_flags & ZEND_ACC_ANON_CLASS)) { + CG(in_compilation) = 1; + zend_set_compiled_filename(ce1->info.user.filename); + CG(zend_lineno) = ce1->info.user.line_start; + zend_error(E_ERROR, + "Cannot declare %s %s, because the name is already in use", + zend_get_object_type(ce1), ZSTR_VAL(ce1->name)); + return; + } + continue; } } else { t = _zend_hash_append_ptr(target, p->key, Z_PTR(p->val)); @@ -644,13 +596,6 @@ static void zend_accel_class_hash_copy(HashTable *target, HashTable *source, uni } target->nInternalPointer = target->nNumOfElements ? 0 : HT_INVALID_IDX; return; - -failure: - ce1 = Z_PTR(p->val); - CG(in_compilation) = 1; - zend_set_compiled_filename(ce1->info.user.filename); - CG(zend_lineno) = ce1->info.user.line_start; - zend_error(E_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce1), ZSTR_VAL(ce1->name)); } #ifdef __SSE2__ diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index aa3b8e82f3..25a504575d 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -65,7 +65,6 @@ typedef void (*zend_persist_func_t)(zval*); static void zend_persist_zval(zval *z); -static void zend_persist_zval_const(zval *z); static const uint32_t uninitialized_bucket[-HT_MIN_MASK] = {HT_INVALID_IDX, HT_INVALID_IDX}; @@ -204,7 +203,7 @@ static void zend_hash_persist_immutable(HashTable *ht) } /* persist the data itself */ - zend_persist_zval_const(&p->val); + zend_persist_zval(&p->val); nIndex = p->h | ht->nTableMask; Z_NEXT(p->val) = HT_HASH(ht, nIndex); @@ -229,7 +228,7 @@ static void zend_hash_persist_immutable(HashTable *ht) } /* persist the data itself */ - zend_persist_zval_const(&p->val); + zend_persist_zval(&p->val); } } @@ -278,63 +277,10 @@ static void zend_persist_zval(zval *z) zend_accel_store_interned_string(Z_STR_P(z)); Z_GC_FLAGS_P(z) |= flags; Z_TYPE_FLAGS_P(z) &= ~(IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE); - break; - case IS_ARRAY: - new_ptr = zend_shared_alloc_get_xlat_entry(Z_ARR_P(z)); - if (new_ptr) { - Z_ARR_P(z) = new_ptr; - Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE; - } else { - if (Z_IMMUTABLE_P(z)) { - Z_ARR_P(z) = zend_accel_memdup(Z_ARR_P(z), sizeof(zend_array)); - zend_hash_persist_immutable(Z_ARRVAL_P(z)); - } else { - GC_REMOVE_FROM_BUFFER(Z_ARR_P(z)); - zend_accel_store(Z_ARR_P(z), sizeof(zend_array)); - zend_hash_persist(Z_ARRVAL_P(z), zend_persist_zval); - /* make immutable array */ - Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE; - GC_REFCOUNT(Z_COUNTED_P(z)) = 2; - GC_FLAGS(Z_COUNTED_P(z)) |= IS_ARRAY_IMMUTABLE; - Z_ARRVAL_P(z)->u.flags |= HASH_FLAG_STATIC_KEYS; - Z_ARRVAL_P(z)->u.flags &= ~HASH_FLAG_APPLY_PROTECTION; - } - } - break; - case IS_REFERENCE: - new_ptr = zend_shared_alloc_get_xlat_entry(Z_REF_P(z)); - if (new_ptr) { - Z_REF_P(z) = new_ptr; - } else { - zend_accel_store(Z_REF_P(z), sizeof(zend_reference)); - zend_persist_zval(Z_REFVAL_P(z)); - } - break; - case IS_CONSTANT_AST: - new_ptr = zend_shared_alloc_get_xlat_entry(Z_AST_P(z)); - if (new_ptr) { - Z_AST_P(z) = new_ptr; - } else { - zend_accel_store(Z_AST_P(z), sizeof(zend_ast_ref)); - Z_ASTVAL_P(z) = zend_persist_ast(Z_ASTVAL_P(z)); + if (Z_TYPE_P(z) == IS_CONSTANT) { + Z_TYPE_FLAGS_P(z) |= IS_TYPE_IMMUTABLE; } break; - } -} - -static void zend_persist_zval_static(zval *z) -{ - zend_uchar flags; - void *new_ptr; - - switch (Z_TYPE_P(z)) { - case IS_STRING: - case IS_CONSTANT: - flags = Z_GC_FLAGS_P(z) & ~ (IS_STR_PERSISTENT | IS_STR_INTERNED | IS_STR_PERMANENT); - zend_accel_store_interned_string(Z_STR_P(z)); - Z_GC_FLAGS_P(z) |= flags; - Z_TYPE_FLAGS_P(z) &= ~(IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE); - break; case IS_ARRAY: new_ptr = zend_shared_alloc_get_xlat_entry(Z_ARR_P(z)); if (new_ptr) { @@ -381,62 +327,6 @@ static void zend_persist_zval_static(zval *z) } } -static void zend_persist_zval_const(zval *z) -{ - zend_uchar flags; - void *new_ptr; - - switch (Z_TYPE_P(z)) { - case IS_STRING: - case IS_CONSTANT: - flags = Z_GC_FLAGS_P(z) & ~ (IS_STR_PERSISTENT | IS_STR_INTERNED | IS_STR_PERMANENT); - zend_accel_memdup_interned_string(Z_STR_P(z)); - Z_GC_FLAGS_P(z) |= flags; - Z_TYPE_FLAGS_P(z) &= ~(IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE); - break; - case IS_ARRAY: - new_ptr = zend_shared_alloc_get_xlat_entry(Z_ARR_P(z)); - if (new_ptr) { - Z_ARR_P(z) = new_ptr; - Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE; - } else { - if (Z_IMMUTABLE_P(z)) { - Z_ARR_P(z) = zend_accel_memdup(Z_ARR_P(z), sizeof(zend_array)); - zend_hash_persist_immutable(Z_ARRVAL_P(z)); - } else { - GC_REMOVE_FROM_BUFFER(Z_ARR_P(z)); - zend_accel_store(Z_ARR_P(z), sizeof(zend_array)); - zend_hash_persist(Z_ARRVAL_P(z), zend_persist_zval); - /* make immutable array */ - Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE; - GC_REFCOUNT(Z_COUNTED_P(z)) = 2; - GC_FLAGS(Z_COUNTED_P(z)) |= IS_ARRAY_IMMUTABLE; - Z_ARRVAL_P(z)->u.flags |= HASH_FLAG_STATIC_KEYS; - Z_ARRVAL_P(z)->u.flags &= ~HASH_FLAG_APPLY_PROTECTION; - } - } - break; - case IS_REFERENCE: - new_ptr = zend_shared_alloc_get_xlat_entry(Z_REF_P(z)); - if (new_ptr) { - Z_REF_P(z) = new_ptr; - } else { - zend_accel_store(Z_REF_P(z), sizeof(zend_reference)); - zend_persist_zval(Z_REFVAL_P(z)); - } - break; - case IS_CONSTANT_AST: - new_ptr = zend_shared_alloc_get_xlat_entry(Z_AST_P(z)); - if (new_ptr) { - Z_AST_P(z) = new_ptr; - } else { - zend_accel_store(Z_AST_P(z), sizeof(zend_ast_ref)); - Z_ASTVAL_P(z) = zend_persist_ast(Z_ASTVAL_P(z)); - } - break; - } -} - static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_script* main_persistent_script) { int already_stored = 0; @@ -472,7 +362,7 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc if (stored) { op_array->static_variables = stored; } else { - zend_hash_persist(op_array->static_variables, zend_persist_zval_static); + zend_hash_persist(op_array->static_variables, zend_persist_zval); zend_accel_store(op_array->static_variables, sizeof(HashTable)); /* make immutable array */ GC_REFCOUNT(op_array->static_variables) = 2; diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index 53536a1a77..6f542323d2 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -2199,39 +2199,39 @@ static inline int php_openssl_tcp_sockop_accept(php_stream *stream, php_openssl_ php_stream_xport_param *xparam STREAMS_DC) { int clisock; - + zend_bool nodelay = 0; + zval *tmpzval = NULL; + xparam->outputs.client = NULL; + if ((tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_nodelay")) != NULL && + zend_is_true(tmpzval)) { + nodelay = 1; + } + clisock = php_network_accept_incoming(sock->s.socket, - xparam->want_textaddr ? &xparam->outputs.textaddr : NULL, - xparam->want_addr ? &xparam->outputs.addr : NULL, - xparam->want_addr ? &xparam->outputs.addrlen : NULL, - xparam->inputs.timeout, - xparam->want_errortext ? &xparam->outputs.error_text : NULL, - &xparam->outputs.error_code - ); + xparam->want_textaddr ? &xparam->outputs.textaddr : NULL, + xparam->want_addr ? &xparam->outputs.addr : NULL, + xparam->want_addr ? &xparam->outputs.addrlen : NULL, + xparam->inputs.timeout, + xparam->want_errortext ? &xparam->outputs.error_text : NULL, + &xparam->outputs.error_code, + nodelay); if (clisock >= 0) { - php_openssl_netstream_data_t *clisockdata; + php_openssl_netstream_data_t *clisockdata = (php_openssl_netstream_data_t*) emalloc(sizeof(*clisockdata)); - clisockdata = emalloc(sizeof(*clisockdata)); + /* copy underlying tcp fields */ + memset(clisockdata, 0, sizeof(*clisockdata)); + memcpy(clisockdata, sock, sizeof(clisockdata->s)); - if (clisockdata == NULL) { - closesocket(clisock); - /* technically a fatal error */ - } else { - /* copy underlying tcp fields */ - memset(clisockdata, 0, sizeof(*clisockdata)); - memcpy(clisockdata, sock, sizeof(clisockdata->s)); - - clisockdata->s.socket = clisock; + clisockdata->s.socket = clisock; - xparam->outputs.client = php_stream_alloc_rel(stream->ops, clisockdata, NULL, "r+"); - if (xparam->outputs.client) { - xparam->outputs.client->ctx = stream->ctx; - if (stream->ctx) { - GC_REFCOUNT(stream->ctx)++; - } + xparam->outputs.client = php_stream_alloc_rel(stream->ops, clisockdata, NULL, "r+"); + if (xparam->outputs.client) { + xparam->outputs.client->ctx = stream->ctx; + if (stream->ctx) { + GC_REFCOUNT(stream->ctx)++; } } diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index f6f86304e5..35ba1a06f1 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -1030,7 +1030,7 @@ static int preg_get_backref(char **str, int *backref) } if (in_brace) { - if (*walk == 0 || *walk != '}') + if (*walk != '}') return 0; else walk++; diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 1d77f3e0eb..624281c18b 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -436,7 +436,6 @@ static void pdo_stmt_construct(zend_execute_data *execute_data, pdo_stmt_t *stmt zval retval; fci.size = sizeof(zend_fcall_info); - fci.function_table = &dbstmt_ce->function_table; ZVAL_UNDEF(&fci.function_name); fci.object = Z_OBJ_P(object); fci.retval = &retval; @@ -448,7 +447,7 @@ static void pdo_stmt_construct(zend_execute_data *execute_data, pdo_stmt_t *stmt fcc.initialized = 1; fcc.function_handler = dbstmt_ce->constructor; - fcc.calling_scope = EG(scope); + fcc.calling_scope = zend_get_executed_scope(); fcc.called_scope = Z_OBJCE_P(object); fcc.object = Z_OBJ_P(object); diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index da557b8597..c2f3c13399 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -740,7 +740,6 @@ static int do_fetch_class_prepare(pdo_stmt_t *stmt) /* {{{ */ } if (ce->constructor) { - fci->function_table = &ce->function_table; ZVAL_UNDEF(&fci->function_name); fci->retval = &stmt->fetch.cls.retval; fci->param_count = 0; @@ -751,7 +750,7 @@ static int do_fetch_class_prepare(pdo_stmt_t *stmt) /* {{{ */ fcc->initialized = 1; fcc->function_handler = ce->constructor; - fcc->calling_scope = EG(scope); + fcc->calling_scope = zend_get_executed_scope(); fcc->called_scope = ce; return 1; } else if (!Z_ISUNDEF(stmt->fetch.cls.ctor_args)) { diff --git a/ext/pdo_oci/tests/pdo_oci_stream_2a.phpt b/ext/pdo_oci/tests/pdo_oci_stream_2a.phpt index a7f22d5c41..72d2ed93b1 100644 --- a/ext/pdo_oci/tests/pdo_oci_stream_2a.phpt +++ b/ext/pdo_oci/tests/pdo_oci_stream_2a.phpt @@ -53,16 +53,16 @@ $a10 = str_repeat('j', 4095); printf("Inserting 10000 Records ... "); for($i=0; $i<1000; $i++) { - do_insert($db, 1, $a1, $a10); - do_insert($db, 1, $a2, $a9); - do_insert($db, 1, $a3, $a8); - do_insert($db, 1, $a4, $a7); - do_insert($db, 1, $a5, $a6); - do_insert($db, 1, $a6, $a5); - do_insert($db, 1, $a7, $a4); - do_insert($db, 1, $a8, $a3); - do_insert($db, 1, $a9, $a2); - do_insert($db, 1, $a10, $a1); + do_insert($db, $i * 10 + 1, $a1, $a10); + do_insert($db, $i * 10 + 2, $a2, $a9); + do_insert($db, $i * 10 + 3, $a3, $a8); + do_insert($db, $i * 10 + 4, $a4, $a7); + do_insert($db, $i * 10 + 5, $a5, $a6); + do_insert($db, $i * 10 + 6, $a6, $a5); + do_insert($db, $i * 10 + 7, $a7, $a4); + do_insert($db, $i * 10 + 8, $a8, $a3); + do_insert($db, $i * 10 + 9, $a9, $a2); + do_insert($db, $i * 10 + 10, $a10, $a1); } printf("Done\n"); diff --git a/ext/pdo_sqlite/sqlite_driver.c b/ext/pdo_sqlite/sqlite_driver.c index 8c732b9dbe..4e729aab0e 100644 --- a/ext/pdo_sqlite/sqlite_driver.c +++ b/ext/pdo_sqlite/sqlite_driver.c @@ -325,7 +325,6 @@ static int do_callback(struct pdo_sqlite_fci *fc, zval *cb, fake_argc = argc + is_agg; fc->fci.size = sizeof(fc->fci); - fc->fci.function_table = EG(function_table); ZVAL_COPY_VALUE(&fc->fci.function_name, cb); fc->fci.object = NULL; fc->fci.retval = &retval; @@ -475,7 +474,6 @@ static int php_sqlite3_collation_callback(void *context, struct pdo_sqlite_collation *collation = (struct pdo_sqlite_collation*) context; collation->fc.fci.size = sizeof(collation->fc.fci); - collation->fc.fci.function_table = EG(function_table); ZVAL_COPY_VALUE(&collation->fc.fci.function_name, &collation->callback); collation->fc.fci.object = NULL; collation->fc.fci.retval = &retval; diff --git a/ext/pdo_sqlite/tests/bug70221.phpt b/ext/pdo_sqlite/tests/bug70221.phpt index 1ee2378bc6..2d1aea0e8b 100644 --- a/ext/pdo_sqlite/tests/bug70221.phpt +++ b/ext/pdo_sqlite/tests/bug70221.phpt @@ -6,10 +6,13 @@ if (!extension_loaded('pdo_sqlite')) print 'skip not loaded'; ?> --FILE-- <?php -$db = new PDO('sqlite:test.sqlite', null, null, array(PDO::ATTR_PERSISTENT => true)); +$dbfile = __DIR__ . '/test.sqlite'; +$db = new PDO('sqlite:'.$dbfile, null, null, array(PDO::ATTR_PERSISTENT => true)); function _test() { return 42; } $db->sqliteCreateFunction('test', '_test', 0); print("Everything is fine, no exceptions here\n"); +unset($db); +@unlink($dbfile); ?> --EXPECT-- Everything is fine, no exceptions here diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c index af6db069b6..408802cfbf 100644 --- a/ext/pgsql/pgsql.c +++ b/ext/pgsql/pgsql.c @@ -1974,7 +1974,7 @@ PHP_FUNCTION(pg_query_params) params = (char **)safe_emalloc(sizeof(char *), num_params, 0); ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pv_param_arr), tmp) { - + ZVAL_DEREF(tmp); if (Z_TYPE_P(tmp) == IS_NULL) { params[i] = NULL; } else { @@ -2823,7 +2823,6 @@ static void php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, zend_long result_ if (ce->constructor) { fci.size = sizeof(fci); - fci.function_table = &ce->function_table; ZVAL_UNDEF(&fci.function_name); fci.object = Z_OBJ_P(return_value); fci.retval = &retval; @@ -2849,7 +2848,7 @@ static void php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, zend_long result_ fcc.initialized = 1; fcc.function_handler = ce->constructor; - fcc.calling_scope = EG(scope); + fcc.calling_scope = zend_get_executed_scope(); fcc.called_scope = Z_OBJCE_P(return_value); fcc.object = Z_OBJ_P(return_value); @@ -6185,8 +6184,11 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1); } else { - /* better regex? IPV6 and IPV4 */ - if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$", 0) == FAILURE) { + /* The inet type holds an IPv4 or IPv6 host address, and optionally its subnet, all in one field. See more in the doc. + The regex might still be not perfect, but catches the most of IP variants. We might decide to remove the regex + at all though and let the server side to handle it.*/ + if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), "^((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])(\\/[0-9]{1,3})?$", 0) == FAILURE + && php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))(\\/[0-9]{1,3})?$", 0) == FAILURE) { err = 1; } else { @@ -6205,7 +6207,7 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con } PGSQL_CONV_CHECK_IGNORE(); if (err) { - php_error_docref(NULL, E_NOTICE, "Expects NULL or string for '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field)); + php_error_docref(NULL, E_NOTICE, "Expects NULL or IPv4 or IPv6 address string for '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field)); } break; @@ -6220,7 +6222,7 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con ZVAL_STRINGL(&new_val, "NOW()", sizeof("NOW()")-1); } else { /* better regex? */ - if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), "^([0-9]{4}[/-][0-9]{1,2}[/-][0-9]{1,2})([ \\t]+(([0-9]{1,2}:[0-9]{1,2}){1}(:[0-9]{1,2}){0,1}(\\.[0-9]+){0,1}([ \\t]*([+-][0-9]{1,4}(:[0-9]{1,2}){0,1}|[-a-zA-Z_/+]{1,50})){0,1})){0,1}$", 1) == FAILURE) { + if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), "^([0-9]{4}[/-][0-9]{1,2}[/-][0-9]{1,2})(([ \\t]+|T)(([0-9]{1,2}:[0-9]{1,2}){1}(:[0-9]{1,2}){0,1}(\\.[0-9]+){0,1}([ \\t]*([+-][0-9]{1,4}(:[0-9]{1,2}){0,1}|[-a-zA-Z_/+]{1,50})){0,1})){0,1}$", 1) == FAILURE) { err = 1; } else { ZVAL_STRING(&new_val, Z_STRVAL_P(val)); diff --git a/ext/pgsql/tests/bug71062.phpt b/ext/pgsql/tests/bug71062.phpt new file mode 100644 index 0000000000..56e350daad --- /dev/null +++ b/ext/pgsql/tests/bug71062.phpt @@ -0,0 +1,39 @@ +--TEST-- +Bug #71062 pg_convert() doesn't accept ISO 8601 for datatype timestamp +--SKIPIF-- +<?php include("skipif.inc"); ?> +--FILE-- +<?php + +include('config.inc'); + +$db = pg_connect($conn_str); + +$table = "public.test_table_bug71062_bug71062"; + +pg_query($db, "CREATE TABLE $table ( test_field TIMESTAMPTZ )"); + +// ISO 8601 (with 'T' between date and time) +$date_string_php_iso8601 = date_create('8 Dec 2015 5:38')->format(DateTime::ISO8601); + +// ISO 8601 with the 'T' removed +$modified_format = 'Y-m-d H:i:sO'; +$date_string_modified_iso8601 = date_create('8 Dec 2015 5:38')->format($modified_format); + +printf("trying format %s \n", DateTime::ISO8601); +pg_convert($db, $table, ['test_field' => $date_string_php_iso8601]); + +printf("trying format %s \n", $modified_format); +pg_convert($db, $table, ['test_field' => $date_string_modified_iso8601]); + +print "done\n"; + +pg_query($db, "DROP TABLE $table"); + +?> +==OK== +--EXPECT-- +trying format Y-m-d\TH:i:sO +trying format Y-m-d H:i:sO +done +==OK== diff --git a/ext/pgsql/tests/bug71998.phpt b/ext/pgsql/tests/bug71998.phpt new file mode 100644 index 0000000000..b9924166f9 --- /dev/null +++ b/ext/pgsql/tests/bug71998.phpt @@ -0,0 +1,196 @@ +--TEST-- +Bug #71998 Function pg_insert does not insert when column type = inet +--SKIPIF-- +<?php include("skipif.inc"); ?> +--FILE-- +<?php +// Kudos for the IP regex to +// http://stackoverflow.com/a/17871737/3358424 + +include('config.inc'); + +$db = pg_connect($conn_str); + +pg_query("CREATE TABLE tmp_statistics (id integer NOT NULL, remote_addr inet);"); + +$ips = array( + /* IPv4*/ + "127.0.0.1", + "10.0.0.1", + "192.168.1.1", + "0.0.0.0", + "255.255.255.255", + "192.168.1.35/24", + + /* IPv6 */ + "::1", + "::10.2.3.4", + "::ffff:10.4.3.2", + "1:2:3:4:5:6:7:8", + "::ffff:10.0.0.1", + "::ffff:1.2.3.4", + "::ffff:0.0.0.0", + "1:2:3:4:5:6:77:88", + "::ffff:255.255.255.255", + "fe08::7:8", + "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "::5:aef1:ffff/128", + "2001:4f8:3:ba::/112", + +); + +$bad = array( + /* bad */ + "256.257.258.259", + "fe08::7:8interface", + "schnitzel", + "10002.3.4", + "1.2.3.4.5", + "256.0.0.0", + "260.0.0.0", +); + +$ips = array_merge($ips, $bad); +$i = 0; +$errors = 0; +foreach ($ips as $ip) { + $data = array("id" => ++$i, "remote_addr" => $ip); + $r = @pg_insert($db, 'tmp_statistics', $data); + + if (!$r && in_array($ip, $bad)) { + $errors++; + //echo pg_last_error($db); + } + + //pg_query($db, "INSERT INTO tmp_statistics (id, remote_addr) VALUES (2, '127.0.0.1')"); // OK, record inserted +} + + +$r = pg_query($db, "SELECT * FROM tmp_statistics"); +while (false != ($row = pg_fetch_row($r))) { + var_dump($row); +} +echo $errors, " errors catched\n"; + +pg_query($db, "DROP TABLE tmp_statistics"); +pg_close($db); + +?> +==DONE== +--EXPECT-- +array(2) { + [0]=> + string(1) "1" + [1]=> + string(9) "127.0.0.1" +} +array(2) { + [0]=> + string(1) "2" + [1]=> + string(8) "10.0.0.1" +} +array(2) { + [0]=> + string(1) "3" + [1]=> + string(11) "192.168.1.1" +} +array(2) { + [0]=> + string(1) "4" + [1]=> + string(7) "0.0.0.0" +} +array(2) { + [0]=> + string(1) "5" + [1]=> + string(15) "255.255.255.255" +} +array(2) { + [0]=> + string(1) "6" + [1]=> + string(15) "192.168.1.35/24" +} +array(2) { + [0]=> + string(1) "7" + [1]=> + string(3) "::1" +} +array(2) { + [0]=> + string(1) "8" + [1]=> + string(10) "::10.2.3.4" +} +array(2) { + [0]=> + string(1) "9" + [1]=> + string(15) "::ffff:10.4.3.2" +} +array(2) { + [0]=> + string(2) "10" + [1]=> + string(15) "1:2:3:4:5:6:7:8" +} +array(2) { + [0]=> + string(2) "11" + [1]=> + string(15) "::ffff:10.0.0.1" +} +array(2) { + [0]=> + string(2) "12" + [1]=> + string(14) "::ffff:1.2.3.4" +} +array(2) { + [0]=> + string(2) "13" + [1]=> + string(14) "::ffff:0.0.0.0" +} +array(2) { + [0]=> + string(2) "14" + [1]=> + string(17) "1:2:3:4:5:6:77:88" +} +array(2) { + [0]=> + string(2) "15" + [1]=> + string(22) "::ffff:255.255.255.255" +} +array(2) { + [0]=> + string(2) "16" + [1]=> + string(9) "fe08::7:8" +} +array(2) { + [0]=> + string(2) "17" + [1]=> + string(39) "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" +} +array(2) { + [0]=> + string(2) "18" + [1]=> + string(13) "::5:aef1:ffff" +} +array(2) { + [0]=> + string(2) "19" + [1]=> + string(19) "2001:4f8:3:ba::/112" +} +7 errors catched +==DONE== diff --git a/ext/pgsql/tests/bug72028.phpt b/ext/pgsql/tests/bug72028.phpt new file mode 100644 index 0000000000..217a03abc7 --- /dev/null +++ b/ext/pgsql/tests/bug72028.phpt @@ -0,0 +1,52 @@ +--TEST-- +Bug #72028 pg_query_params(): NULL converts to empty string +--SKIPIF-- +<?php include("skipif.inc"); ?> +--FILE-- +<?php +// create test table + +include('config.inc'); + +$conn = pg_connect($conn_str); + +$table = "bug72028_" . md5(uniqid(time())); + +pg_query("CREATE TABLE $table (value TEXT, details TEXT);"); + +$sql = "INSERT INTO $table (value, details) VALUES ($1, $2)"; + +$params = array(null, "insert before looping with a reference"); +$result = pg_query_params($conn, $sql, $params); + +$params2 = array(null, "insert after looping with a reference"); +foreach ($params2 as &$p) { + // doing nothing +} +unset($p); + +$result = pg_query_params($conn, $sql, $params2); + +$r = pg_query("SELECT * FROM $table"); +while (false !== ($i = pg_fetch_assoc($r))) { + var_dump($i); +} + +pg_query("DROP TABLE $table"); + +?> +==DONE== +--EXPECT-- +array(2) { + ["value"]=> + NULL + ["details"]=> + string(38) "insert before looping with a reference" +} +array(2) { + ["value"]=> + NULL + ["details"]=> + string(37) "insert after looping with a reference" +} +==DONE== diff --git a/ext/posix/posix.c b/ext/posix/posix.c index e1f4ef6262..771e316325 100644 --- a/ext/posix/posix.c +++ b/ext/posix/posix.c @@ -987,8 +987,12 @@ int php_posix_group_to_array(struct group *g, zval *array_group) /* {{{ */ array_init(&array_members); add_assoc_string(array_group, "name", g->gr_name); - add_assoc_string(array_group, "passwd", g->gr_passwd); - for (count=0; g->gr_mem[count] != NULL; count++) { + if (g->gr_passwd) { + add_assoc_string(array_group, "passwd", g->gr_passwd); + } else { + add_assoc_null(array_group, "passwd"); + } + for (count = 0; g->gr_mem[count] != NULL; count++) { add_next_index_string(&array_members, g->gr_mem[count]); } zend_hash_str_update(Z_ARRVAL_P(array_group), "members", sizeof("members")-1, &array_members); diff --git a/ext/readline/readline_cli.c b/ext/readline/readline_cli.c index 6f4e47d42b..2cce2292f4 100644 --- a/ext/readline/readline_cli.c +++ b/ext/readline/readline_cli.c @@ -106,7 +106,8 @@ static size_t readline_shell_ub_write(const char *str, size_t str_length) /* {{{ caller (sapi_cli_single_write in sapi/cli) which will actually write due to -1 return code */ php_last_char = str[str_length-1]; - return -1; + + return (size_t) -1; } /* }}} */ diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index dd3bd6e94d..2a7ff61957 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -456,8 +456,8 @@ static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *in zend_class_constant *c; ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, key, c) { - zval_update_constant_ex(&c->value, 1, NULL); - _class_const_string(str, ZSTR_VAL(key), c, indent); + zval_update_constant_ex(&c->value, c->ce); + _class_const_string(str, ZSTR_VAL(key), c, ZSTR_VAL(sub_indent.buf)); } ZEND_HASH_FOREACH_END(); } string_printf(str, "%s }\n", indent); @@ -633,11 +633,15 @@ static void _const_string(string *str, char *name, zval *value, char *indent) /* {{{ _class_const_string */ static void _class_const_string(string *str, char *name, zend_class_constant *c, char *indent) { - char *type = zend_zval_type_name(&c->value); char *visibility = zend_visibility_string(Z_ACCESS_FLAGS(c->value)); - zend_string *value_str = zval_get_string(&c->value); + zend_string *value_str; + char *type; - string_printf(str, "%s Constant [ %s %s %s ] { %s }\n", + zval_update_constant_ex(&c->value, c->ce); + value_str = zval_get_string(&c->value); + type = zend_zval_type_name(&c->value); + + string_printf(str, "%sConstant [ %s %s %s ] { %s }\n", indent, visibility, type, name, ZSTR_VAL(value_str)); zend_string_release(value_str); @@ -706,14 +710,10 @@ static void _parameter_string(string *str, zend_function *fptr, struct _zend_arg zend_op *precv = _get_recv_op((zend_op_array*)fptr, offset); if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) { zval zv; - zend_class_entry *old_scope; string_write(str, " = ", sizeof(" = ")-1); ZVAL_DUP(&zv, RT_CONSTANT(&fptr->op_array, precv->op2)); - old_scope = EG(scope); - EG(scope) = fptr->common.scope; - zval_update_constant_ex(&zv, 1, NULL); - EG(scope) = old_scope; + zval_update_constant_ex(&zv, fptr->common.scope); if (Z_TYPE(zv) == IS_TRUE) { string_write(str, "true", sizeof("true")-1); } else if (Z_TYPE(zv) == IS_FALSE) { @@ -1428,7 +1428,6 @@ static void _reflection_export(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *c /* Call __construct() */ fci.size = sizeof(fci); - fci.function_table = NULL; ZVAL_UNDEF(&fci.function_name); fci.object = Z_OBJ(reflector); fci.retval = &retval; @@ -1461,7 +1460,6 @@ static void _reflection_export(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *c ZVAL_COPY_VALUE(¶ms[1], output_ptr); ZVAL_STRINGL(&fci.function_name, "reflection::export", sizeof("reflection::export") - 1); - fci.function_table = &reflection_ptr->function_table; fci.object = NULL; fci.retval = &retval; fci.param_count = 2; @@ -1933,7 +1931,7 @@ ZEND_METHOD(reflection_function, getStaticVariables) fptr->op_array.static_variables = zend_array_dup(fptr->op_array.static_variables); } ZEND_HASH_FOREACH_VAL(fptr->op_array.static_variables, val) { - if (UNEXPECTED(zval_update_constant_ex(val, 1, fptr->common.scope) != SUCCESS)) { + if (UNEXPECTED(zval_update_constant_ex(val, fptr->common.scope) != SUCCESS)) { return; } } ZEND_HASH_FOREACH_END(); @@ -1962,7 +1960,6 @@ ZEND_METHOD(reflection_function, invoke) } fci.size = sizeof(fci); - fci.function_table = NULL; ZVAL_UNDEF(&fci.function_name); fci.object = NULL; fci.retval = &retval; @@ -1972,7 +1969,7 @@ ZEND_METHOD(reflection_function, invoke) fcc.initialized = 1; fcc.function_handler = fptr; - fcc.calling_scope = EG(scope); + fcc.calling_scope = zend_get_executed_scope(); fcc.called_scope = NULL; fcc.object = NULL; @@ -2021,7 +2018,6 @@ ZEND_METHOD(reflection_function, invokeArgs) } ZEND_HASH_FOREACH_END(); fci.size = sizeof(fci); - fci.function_table = NULL; ZVAL_UNDEF(&fci.function_name); fci.object = NULL; fci.retval = &retval; @@ -2031,7 +2027,7 @@ ZEND_METHOD(reflection_function, invokeArgs) fcc.initialized = 1; fcc.function_handler = fptr; - fcc.calling_scope = EG(scope); + fcc.calling_scope = zend_get_executed_scope(); fcc.called_scope = NULL; fcc.object = NULL; @@ -2892,15 +2888,9 @@ ZEND_METHOD(reflection_parameter, getDefaultValue) return; } - ZVAL_COPY_VALUE(return_value, RT_CONSTANT(¶m->fptr->op_array, precv->op2)); + ZVAL_DUP(return_value, RT_CONSTANT(¶m->fptr->op_array, precv->op2)); if (Z_CONSTANT_P(return_value)) { - zend_class_entry *old_scope = EG(scope); - - EG(scope) = param->fptr->common.scope; - zval_update_constant_ex(return_value, 0, NULL); - EG(scope) = old_scope; - } else { - zval_copy_ctor(return_value); + zval_update_constant_ex(return_value, param->fptr->common.scope); } } /* }}} */ @@ -3252,7 +3242,6 @@ ZEND_METHOD(reflection_method, invoke) } fci.size = sizeof(fci); - fci.function_table = NULL; ZVAL_UNDEF(&fci.function_name); fci.object = object; fci.retval = &retval; @@ -3358,7 +3347,6 @@ ZEND_METHOD(reflection_method, invokeArgs) } fci.size = sizeof(fci); - fci.function_table = NULL; ZVAL_UNDEF(&fci.function_name); fci.object = object ? Z_OBJ_P(object) : NULL; fci.retval = &retval; @@ -3837,6 +3825,9 @@ ZEND_METHOD(reflection_class_constant, getValue) GET_REFLECTION_OBJECT_PTR(ref); ZVAL_DUP(return_value, &ref->value); + if (Z_CONSTANT_P(return_value)) { + zval_update_constant_ex(return_value, ref->ce); + } } /* }}} */ @@ -3971,7 +3962,7 @@ static void add_class_vars(zend_class_entry *ce, int statics, zval *return_value /* this is necessary to make it able to work with default array * properties, returned to user */ if (Z_CONSTANT(prop_copy)) { - if (UNEXPECTED(zval_update_constant_ex(&prop_copy, 1, NULL) != SUCCESS)) { + if (UNEXPECTED(zval_update_constant_ex(&prop_copy, NULL) != SUCCESS)) { return; } } @@ -4627,7 +4618,7 @@ ZEND_METHOD(reflection_class, getConstants) GET_REFLECTION_OBJECT_PTR(ce); array_init(return_value); ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, key, c) { - if (UNEXPECTED(zval_update_constant_ex(&c->value, 1, ce) != SUCCESS)) { + if (UNEXPECTED(zval_update_constant_ex(&c->value, ce) != SUCCESS)) { zend_array_destroy(Z_ARRVAL_P(return_value)); return; } @@ -4675,7 +4666,7 @@ ZEND_METHOD(reflection_class, getConstant) GET_REFLECTION_OBJECT_PTR(ce); ZEND_HASH_FOREACH_PTR(&ce->constants_table, c) { - if (UNEXPECTED(zval_update_constant_ex(&c->value, 1, ce) != SUCCESS)) { + if (UNEXPECTED(zval_update_constant_ex(&c->value, ce) != SUCCESS)) { return; } } ZEND_HASH_FOREACH_END(); @@ -4862,10 +4853,10 @@ ZEND_METHOD(reflection_class, newInstance) return; } - old_scope = EG(scope); - EG(scope) = ce; + old_scope = EG(fake_scope); + EG(fake_scope) = ce; constructor = Z_OBJ_HT_P(return_value)->get_constructor(Z_OBJ_P(return_value)); - EG(scope) = old_scope; + EG(fake_scope) = old_scope; /* Run the constructor if there is one */ if (constructor) { @@ -4890,7 +4881,6 @@ ZEND_METHOD(reflection_class, newInstance) } fci.size = sizeof(fci); - fci.function_table = EG(function_table); ZVAL_UNDEF(&fci.function_name); fci.object = Z_OBJ_P(return_value); fci.retval = &retval; @@ -4900,7 +4890,7 @@ ZEND_METHOD(reflection_class, newInstance) fcc.initialized = 1; fcc.function_handler = constructor; - fcc.calling_scope = EG(scope); + fcc.calling_scope = zend_get_executed_scope();; fcc.called_scope = Z_OBJCE_P(return_value); fcc.object = Z_OBJ_P(return_value); @@ -4966,10 +4956,10 @@ ZEND_METHOD(reflection_class, newInstanceArgs) return; } - old_scope = EG(scope); - EG(scope) = ce; + old_scope = EG(fake_scope); + EG(fake_scope) = ce; constructor = Z_OBJ_HT_P(return_value)->get_constructor(Z_OBJ_P(return_value)); - EG(scope) = old_scope; + EG(fake_scope) = old_scope; /* Run the constructor if there is one */ if (constructor) { @@ -4993,7 +4983,6 @@ ZEND_METHOD(reflection_class, newInstanceArgs) } fci.size = sizeof(fci); - fci.function_table = EG(function_table); ZVAL_UNDEF(&fci.function_name); fci.object = Z_OBJ_P(return_value); fci.retval = &retval; @@ -5003,7 +4992,7 @@ ZEND_METHOD(reflection_class, newInstanceArgs) fcc.initialized = 1; fcc.function_handler = constructor; - fcc.calling_scope = EG(scope); + fcc.calling_scope = zend_get_executed_scope(); fcc.called_scope = Z_OBJCE_P(return_value); fcc.object = Z_OBJ_P(return_value); @@ -5647,7 +5636,9 @@ ZEND_METHOD(reflection_property, getValue) php_error_docref(NULL, E_ERROR, "Internal error: Could not find the property %s::%s", ZSTR_VAL(intern->ce->name), ZSTR_VAL(ref->prop.name)); /* Bails out */ } - ZVAL_DUP(return_value, &CE_STATIC_MEMBERS(intern->ce)[ref->prop.offset]); + member_p = &CE_STATIC_MEMBERS(intern->ce)[ref->prop.offset]; + ZVAL_DEREF(member_p); + ZVAL_COPY(return_value, member_p); } else { const char *class_name, *prop_name; size_t prop_name_len; @@ -5659,7 +5650,8 @@ ZEND_METHOD(reflection_property, getValue) zend_unmangle_property_name_ex(ref->prop.name, &class_name, &prop_name, &prop_name_len); member_p = zend_read_property(ref->ce, object, prop_name, prop_name_len, 1, &rv); - ZVAL_DUP(return_value, member_p); + ZVAL_DEREF(member_p); + ZVAL_COPY(return_value, member_p); } } /* }}} */ diff --git a/ext/reflection/tests/ReflectionClassConstant_basic1.phpt b/ext/reflection/tests/ReflectionClassConstant_basic1.phpt index 3d4f49f144..fd8118650f 100644 --- a/ext/reflection/tests/ReflectionClassConstant_basic1.phpt +++ b/ext/reflection/tests/ReflectionClassConstant_basic1.phpt @@ -53,13 +53,13 @@ reflectClassConstant($instance, "BAD_CONST"); Reflecting on class constant TestClass::PUB __toString(): -string(42) " Constant [ public boolean PUB ] { 1 } +string(38) "Constant [ public boolean PUB ] { 1 } " export(): -string(42) " Constant [ public boolean PUB ] { 1 } +string(38) "Constant [ public boolean PUB ] { 1 } " export(): - Constant [ public boolean PUB ] { 1 } +Constant [ public boolean PUB ] { 1 } NULL getName(): @@ -87,13 +87,13 @@ string(21) "/** My Doc comment */" Reflecting on class constant TestClass::PROT __toString(): -string(46) " Constant [ protected integer PROT ] { 4 } +string(42) "Constant [ protected integer PROT ] { 4 } " export(): -string(46) " Constant [ protected integer PROT ] { 4 } +string(42) "Constant [ protected integer PROT ] { 4 } " export(): - Constant [ protected integer PROT ] { 4 } +Constant [ protected integer PROT ] { 4 } NULL getName(): @@ -121,13 +121,13 @@ string(26) "/** Another doc comment */" Reflecting on class constant TestClass::PRIV __toString(): -string(49) " Constant [ private string PRIV ] { keepOut } +string(45) "Constant [ private string PRIV ] { keepOut } " export(): -string(49) " Constant [ private string PRIV ] { keepOut } +string(45) "Constant [ private string PRIV ] { keepOut } " export(): - Constant [ private string PRIV ] { keepOut } +Constant [ private string PRIV ] { keepOut } NULL getName(): @@ -155,13 +155,13 @@ bool(false) Reflecting on class constant TestClass::PRIV __toString(): -string(49) " Constant [ private string PRIV ] { keepOut } +string(45) "Constant [ private string PRIV ] { keepOut } " export(): -string(49) " Constant [ private string PRIV ] { keepOut } +string(45) "Constant [ private string PRIV ] { keepOut } " export(): - Constant [ private string PRIV ] { keepOut } +Constant [ private string PRIV ] { keepOut } NULL getName(): diff --git a/ext/reflection/tests/ReflectionClassConstant_getValue.phpt b/ext/reflection/tests/ReflectionClassConstant_getValue.phpt new file mode 100644 index 0000000000..e447d15357 --- /dev/null +++ b/ext/reflection/tests/ReflectionClassConstant_getValue.phpt @@ -0,0 +1,47 @@ +--TEST-- +Test variations of getting constant values +--FILE-- +<?php + +/* Use separate classes to make sure that in-place constant updates don't interfere */ +class A { + const X = self::Y * 2; + const Y = 1; +} +class B { + const X = self::Y * 2; + const Y = 1; +} +class C { + const X = self::Y * 2; + const Y = 1; +} + +var_dump((new ReflectionClassConstant('A', 'X'))->getValue()); +echo new ReflectionClassConstant('B', 'X'); +echo new ReflectionClass('C'); + +?> +--EXPECTF-- +int(2) +Constant [ public integer X ] { 2 } +Class [ <user> class C ] { + @@ %s 12-15 + + - Constants [2] { + Constant [ public integer X ] { 2 } + Constant [ public integer Y ] { 1 } + } + + - Static properties [0] { + } + + - Static methods [0] { + } + + - Properties [0] { + } + + - Methods [0] { + } +} diff --git a/ext/session/session.c b/ext/session/session.c index 79d5dd2831..6fd0ee2f37 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -500,7 +500,6 @@ static void php_session_gc(void) /* {{{ */ } } /* }}} */ - static void php_session_initialize(void) /* {{{ */ { zend_string *val = NULL; @@ -627,6 +626,22 @@ static void php_session_save_current_state(int write) /* {{{ */ } /* }}} */ +static void php_session_normalize_vars() /* {{{ */ +{ + PS_ENCODE_VARS; + + IF_SESSION_VARS() { + PS_ENCODE_LOOP( + if (Z_TYPE_P(struc) == IS_PTR) { + zval *zv = (zval *)Z_PTR_P(struc); + ZVAL_COPY_VALUE(struc, zv); + ZVAL_UNDEF(zv); + } + ); + } +} +/* }}} */ + /* ************************* * INI Settings/Handlers * ************************* */ @@ -958,7 +973,6 @@ PS_SERIALIZER_DECODE_FUNC(php_binary) /* {{{ */ { const char *p; const char *endptr = val + vallen; - zval current; int has_value; int namelen; zend_string *name; @@ -981,28 +995,32 @@ PS_SERIALIZER_DECODE_FUNC(php_binary) /* {{{ */ p += namelen + 1; if ((tmp = zend_hash_find(&EG(symbol_table), name))) { - if ((Z_TYPE_P(tmp) == IS_ARRAY && Z_ARRVAL_P(tmp) == &EG(symbol_table)) || tmp == &PS(http_session_vars)) { + if ((Z_TYPE_P(tmp) == IS_ARRAY && + Z_ARRVAL_P(tmp) == &EG(symbol_table)) || tmp == &PS(http_session_vars)) { zend_string_release(name); continue; } } if (has_value) { - ZVAL_UNDEF(¤t); - if (php_var_unserialize(¤t, (const unsigned char **) &p, (const unsigned char *) endptr, &var_hash)) { - zval *zv = php_set_session_var(name, ¤t, &var_hash ); - var_replace(&var_hash, ¤t, zv); + zval *current, rv; + current = var_tmp_var(&var_hash); + if (php_var_unserialize(current, (const unsigned char **) &p, (const unsigned char *) endptr, &var_hash)) { + ZVAL_PTR(&rv, current); + php_set_session_var(name, &rv, &var_hash ); } else { - zval_ptr_dtor(¤t); zend_string_release(name); + php_session_normalize_vars(); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return FAILURE; } + } else { + PS_ADD_VARL(name); } - PS_ADD_VARL(name); zend_string_release(name); } + php_session_normalize_vars(); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return SUCCESS; @@ -1047,10 +1065,9 @@ PS_SERIALIZER_DECODE_FUNC(php) /* {{{ */ { const char *p, *q; const char *endptr = val + vallen; - zval current; - int has_value; ptrdiff_t namelen; zend_string *name; + int has_value, retval = SUCCESS; php_unserialize_data_t var_hash; PHP_VAR_UNSERIALIZE_INIT(var_hash); @@ -1075,34 +1092,37 @@ PS_SERIALIZER_DECODE_FUNC(php) /* {{{ */ q++; if ((tmp = zend_hash_find(&EG(symbol_table), name))) { - if ((Z_TYPE_P(tmp) == IS_ARRAY && Z_ARRVAL_P(tmp) == &EG(symbol_table)) || tmp == &PS(http_session_vars)) { + if ((Z_TYPE_P(tmp) == IS_ARRAY && + Z_ARRVAL_P(tmp) == &EG(symbol_table)) || tmp == &PS(http_session_vars)) { goto skip; } } if (has_value) { - ZVAL_UNDEF(¤t); - if (php_var_unserialize(¤t, (const unsigned char **) &q, (const unsigned char *) endptr, &var_hash)) { - zval *zv = php_set_session_var(name, ¤t, &var_hash); - var_replace(&var_hash, ¤t, zv); + zval *current, rv; + current = var_tmp_var(&var_hash); + if (php_var_unserialize(current, (const unsigned char **)&q, (const unsigned char *)endptr, &var_hash)) { + ZVAL_PTR(&rv, current); + php_set_session_var(name, &rv, &var_hash); } else { - zval_ptr_dtor(¤t); - PHP_VAR_UNSERIALIZE_DESTROY(var_hash); zend_string_release(name); - return FAILURE; + retval = FAILURE; + goto break_outer_loop; } + } else { + PS_ADD_VARL(name); } - PS_ADD_VARL(name); skip: zend_string_release(name); p = q; } break_outer_loop: + php_session_normalize_vars(); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); - return SUCCESS; + return retval; } /* }}} */ diff --git a/ext/session/tests/bug71972.phpt b/ext/session/tests/bug71972.phpt new file mode 100644 index 0000000000..e4c5c6b6d3 --- /dev/null +++ b/ext/session/tests/bug71972.phpt @@ -0,0 +1,28 @@ +--TEST-- +Bug #71972 (Cyclic references causing session_start(): Failed to decode session object) +--SKIPIF-- +<?php include('skipif.inc'); ?> +--INI-- +session.save_handler=files +--FILE-- +<?php +ob_start(); +session_start(); + +$_SESSION['boogie'] = 1; + +$_SESSION['obj1'] = new stdClass(); +for ( $x=2; $x < 20; $x++) { + cyclic_ref($x); +} + +function cyclic_ref($num) { + $_SESSION['obj'.$num] = new stdClass(); + $_SESSION['obj'.$num]->test = new stdClass();//NOTE: No bug if try commenting out this too. + $_SESSION['obj'.$num]->obj1 = $_SESSION['obj1']; +} + +var_dump(session_decode(session_encode()) == $_SESSION); +?> +--EXPECT-- +bool(true) diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c index fc389f2365..803a5cd596 100644 --- a/ext/soap/php_encoding.c +++ b/ext/soap/php_encoding.c @@ -1164,13 +1164,8 @@ static xmlNodePtr to_xml_null(encodeTypePtr type, zval *data, int style, xmlNode static void set_zval_property(zval* object, char* name, zval* val) { - zend_class_entry *old_scope; - - old_scope = EG(scope); - EG(scope) = Z_OBJCE_P(object); - add_property_zval(object, name, val); + zend_update_property(Z_OBJCE_P(object), object, name, strlen(name), val); if (Z_REFCOUNTED_P(val)) Z_DELREF_P(val); - EG(scope) = old_scope; } static zval* get_zval_property(zval* object, char* name, zval *rv) @@ -1181,15 +1176,15 @@ static zval* get_zval_property(zval* object, char* name, zval *rv) zend_class_entry *old_scope; ZVAL_STRING(&member, name); - old_scope = EG(scope); - EG(scope) = Z_OBJCE_P(object); + old_scope = EG(fake_scope); + EG(fake_scope) = Z_OBJCE_P(object); data = Z_OBJ_HT_P(object)->read_property(object, &member, BP_VAR_IS, NULL, rv); if (data == &EG(uninitialized_zval)) { /* Hack for bug #32455 */ zend_property_info *property_info; property_info = zend_get_property_info(Z_OBJCE_P(object), Z_STR(member), 1); - EG(scope) = old_scope; + EG(fake_scope) = old_scope; if (property_info != ZEND_WRONG_PROPERTY_INFO && property_info && zend_hash_exists(Z_OBJPROP_P(object), property_info->name)) { zval_ptr_dtor(&member); @@ -1199,7 +1194,7 @@ static zval* get_zval_property(zval* object, char* name, zval *rv) return NULL; } zval_ptr_dtor(&member); - EG(scope) = old_scope; + EG(fake_scope) = old_scope; return data; } else if (Z_TYPE_P(object) == IS_ARRAY) { zval *data_ptr; @@ -1218,10 +1213,10 @@ static void unset_zval_property(zval* object, char* name) zend_class_entry *old_scope; ZVAL_STRING(&member, name); - old_scope = EG(scope); - EG(scope) = Z_OBJCE_P(object); + old_scope = EG(fake_scope); + EG(fake_scope) = Z_OBJCE_P(object); Z_OBJ_HT_P(object)->unset_property(object, &member, NULL); - EG(scope) = old_scope; + EG(fake_scope) = old_scope; zval_ptr_dtor(&member); } else if (Z_TYPE_P(object) == IS_ARRAY) { zend_hash_str_del(Z_ARRVAL_P(object), name, strlen(name)); diff --git a/ext/soap/soap.c b/ext/soap/soap.c index fcfa2511eb..c842ce5119 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -953,7 +953,6 @@ PHP_METHOD(SoapFault, __toString) line = zend_read_property(soap_fault_class_entry, this_ptr, "line", sizeof("line")-1, 1, &rv4); fci.size = sizeof(fci); - fci.function_table = &Z_OBJCE_P(getThis())->function_table; ZVAL_STRINGL(&fci.function_name, "gettraceasstring", sizeof("gettraceasstring")-1); fci.object = Z_OBJ(EX(This)); fci.retval = &trace; diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c index 6039ac65ba..63674c50d7 100644 --- a/ext/sockets/sockets.c +++ b/ext/sockets/sockets.c @@ -251,6 +251,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_import_stream, 0, 0, 1) ZEND_ARG_INFO(0, stream) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_export_stream, 0, 0, 1) + ZEND_ARG_INFO(0, socket) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_sendmsg, 0, 0, 3) ZEND_ARG_INFO(0, socket) ZEND_ARG_INFO(0, msghdr) @@ -305,6 +309,7 @@ PHP_FUNCTION(socket_shutdown); PHP_FUNCTION(socket_last_error); PHP_FUNCTION(socket_clear_error); PHP_FUNCTION(socket_import_stream); +PHP_FUNCTION(socket_export_stream); /* {{{ sockets_functions[] */ @@ -339,6 +344,7 @@ const zend_function_entry sockets_functions[] = { PHP_FE(socket_last_error, arginfo_socket_last_error) PHP_FE(socket_clear_error, arginfo_socket_clear_error) PHP_FE(socket_import_stream, arginfo_socket_import_stream) + PHP_FE(socket_export_stream, arginfo_socket_export_stream) PHP_FE(socket_sendmsg, arginfo_socket_sendmsg) PHP_FE(socket_recvmsg, arginfo_socket_recvmsg) PHP_FE(socket_cmsg_space, arginfo_socket_cmsg_space) @@ -2307,7 +2313,7 @@ error: return NULL; } -/* {{{ proto void socket_import_stream(resource stream) +/* {{{ proto resource socket_import_stream(resource stream) Imports a stream that encapsulates a socket into a socket extension resource. */ PHP_FUNCTION(socket_import_stream) { @@ -2343,8 +2349,7 @@ PHP_FUNCTION(socket_import_stream) #endif /* hold a zval reference to the stream (holding a php_stream* directly could - * also be done, but this might be slightly better if in the future we want - * to provide a socket_export_stream) */ + * also be done, but this makes socket_export_stream a bit simpler) */ ZVAL_COPY(&retsock->zstream, zstream); php_stream_set_option(stream, PHP_STREAM_OPTION_READ_BUFFER, @@ -2354,6 +2359,103 @@ PHP_FUNCTION(socket_import_stream) } /* }}} */ +/* {{{ proto resource socket_export_stream(resource socket) + Exports a socket extension resource into a stream that encapsulates a socket. */ +PHP_FUNCTION(socket_export_stream) +{ + zval *zsocket; + php_socket *socket; + php_stream *stream = NULL; + php_netstream_data_t *stream_data; + char *protocol = NULL; + size_t protocollen = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zsocket) == FAILURE) { + return; + } + if ((socket = (php_socket *) zend_fetch_resource(Z_RES_P(zsocket), le_socket_name, le_socket)) == NULL) { + RETURN_FALSE; + } + + /* Either we already exported a stream or the socket came from an import, + * just return the existing stream */ + if (!Z_ISUNDEF(socket->zstream)) { + RETURN_ZVAL(&socket->zstream, 1, 0); + } + + /* Determine if socket is using a protocol with one of the default registered + * socket stream wrappers */ + if (socket->type == PF_INET +#if HAVE_IPV6 + || socket->type == PF_INET6 +#endif + ) { + int protoid; + socklen_t protoidlen = sizeof(protoid); + + getsockopt(socket->bsd_socket, SOL_SOCKET, SO_TYPE, (char *) &protoid, &protoidlen); + + if (protoid == SOCK_STREAM) { + /* SO_PROTOCOL is not (yet?) supported on OS X, so lets assume it's TCP there */ +#ifdef SO_PROTOCOL + protoidlen = sizeof(protoid); + getsockopt(socket->bsd_socket, SOL_SOCKET, SO_PROTOCOL, (char *) &protoid, &protoidlen); + if (protoid == IPPROTO_TCP) +#endif + { + protocol = "tcp"; + protocollen = 3; + } + } else if (protoid == SOCK_DGRAM) { + protocol = "udp"; + protocollen = 3; + } +#ifdef PF_UNIX + } else if (socket->type == PF_UNIX) { + int type; + socklen_t typelen = sizeof(type); + + getsockopt(socket->bsd_socket, SOL_SOCKET, SO_TYPE, (char *) &type, &typelen); + + if (type == SOCK_STREAM) { + protocol = "unix"; + protocollen = 4; + } else if (type == SOCK_DGRAM) { + protocol = "udg"; + protocollen = 3; + } +#endif + } + + /* Try to get a stream with the registered sockops for the protocol in use + * We don't want streams to actually *do* anything though, so don't give it + * anything apart from the protocol */ + if (protocol != NULL) { + stream = php_stream_xport_create(protocol, protocollen, 0, 0, NULL, NULL, NULL, NULL, NULL); + } + + /* Fall back to creating a generic socket stream */ + if (stream == NULL) { + stream = php_stream_sock_open_from_socket(socket->bsd_socket, 0); + + if (stream == NULL) { + php_error_docref(NULL, E_WARNING, "failed to create stream"); + RETURN_FALSE; + } + } + + stream_data = (php_netstream_data_t *) stream->abstract; + stream_data->socket = socket->bsd_socket; + stream_data->is_blocked = socket->blocking; + stream_data->timeout.tv_sec = FG(default_socket_timeout); + stream_data->timeout.tv_usec = 0; + + php_stream_to_zval(stream, &socket->zstream); + + RETURN_ZVAL(&socket->zstream, 1, 0); +} +/* }}} */ + /* * Local variables: * tab-width: 4 diff --git a/ext/sockets/tests/socket_export_stream-1.phpt b/ext/sockets/tests/socket_export_stream-1.phpt new file mode 100644 index 0000000000..498e0a277c --- /dev/null +++ b/ext/sockets/tests/socket_export_stream-1.phpt @@ -0,0 +1,27 @@ +--TEST-- +socket_export_stream: Basic test +--SKIPIF-- +<?php +if (!extension_loaded('sockets')) { + die('SKIP sockets extension not available.'); +} + +--FILE-- +<?php + +$domain = (strtoupper(substr(PHP_OS, 0, 3) == 'WIN') ? AF_INET : AF_UNIX); +socket_create_pair($domain, SOCK_STREAM, 0, $s); + +$s0 = reset($s); +$s1 = next($s); + +$stream = socket_export_stream($s0); +var_dump($stream); + +socket_write($s1, "test message"); +socket_close($s1); + +var_dump(stream_get_contents($stream)); +--EXPECTF-- +resource(%d) of type (stream) +string(12) "test message" diff --git a/ext/sockets/tests/socket_export_stream-2.phpt b/ext/sockets/tests/socket_export_stream-2.phpt new file mode 100644 index 0000000000..98528420fa --- /dev/null +++ b/ext/sockets/tests/socket_export_stream-2.phpt @@ -0,0 +1,48 @@ +--TEST-- +socket_export_stream: Bad arguments +--SKIPIF-- +<?php +if (!extension_loaded('sockets')) { + die('SKIP sockets extension not available.'); +} + +--FILE-- +<?php + +var_dump(socket_export_stream()); +var_dump(socket_export_stream(1, 2)); +var_dump(socket_export_stream(1)); +var_dump(socket_export_stream(new stdclass)); +var_dump(socket_export_stream(fopen(__FILE__, "rb"))); +var_dump(socket_export_stream(stream_socket_server("udp://127.0.0.1:58392", $errno, $errstr, STREAM_SERVER_BIND))); +$s = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +var_dump($s); +socket_close($s); +var_dump(socket_export_stream($s)); + + +echo "Done."; +--EXPECTF-- +Warning: socket_export_stream() expects exactly 1 parameter, 0 given in %s on line %d +NULL + +Warning: socket_export_stream() expects exactly 1 parameter, 2 given in %s on line %d +NULL + +Warning: socket_export_stream() expects parameter 1 to be resource, integer given in %s on line %d +NULL + +Warning: socket_export_stream() expects parameter 1 to be resource, object given in %s on line %d +NULL + +Warning: socket_export_stream(): supplied resource is not a valid Socket resource in %s on line %d +bool(false) + +Warning: socket_export_stream(): supplied resource is not a valid Socket resource in %s on line %d +bool(false) +resource(%d) of type (Socket) + +Warning: socket_export_stream(): supplied resource is not a valid Socket resource in %s on line %d +bool(false) +Done. + diff --git a/ext/sockets/tests/socket_export_stream-3.phpt b/ext/sockets/tests/socket_export_stream-3.phpt new file mode 100644 index 0000000000..b13bb34739 --- /dev/null +++ b/ext/sockets/tests/socket_export_stream-3.phpt @@ -0,0 +1,47 @@ +--TEST-- +socket_export_stream: Test with multicasting +--SKIPIF-- +<?php +if (!extension_loaded('sockets')) { + die('SKIP sockets extension not available.'); +} +$s = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +$br = socket_bind($s, '0.0.0.0', 58381); +if ($br === false) + die("SKIP IPv4/port 58381 not available"); +$so = socket_set_option($s, IPPROTO_IP, MCAST_JOIN_GROUP, array( + "group" => '224.0.0.23', + "interface" => "lo", +)); +if ($so === false) + die("SKIP joining group 224.0.0.23 on interface lo failed"); +--FILE-- +<?php + +$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock, '0.0.0.0', 58381); +$stream = socket_export_stream($sock); +var_dump($stream); +$so = socket_set_option($sock, IPPROTO_IP, MCAST_JOIN_GROUP, array( + "group" => '224.0.0.23', + "interface" => "lo", +)); +var_dump($so); + +$sendsock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +var_dump($sendsock); +$br = socket_bind($sendsock, '127.0.0.1'); +$so = socket_sendto($sendsock, $m = "my message", strlen($m), 0, "224.0.0.23", 58381); +var_dump($so); + +stream_set_blocking($stream, 0); +var_dump(fread($stream, strlen($m))); +echo "Done.\n"; +--EXPECTF-- +resource(%d) of type (stream) +bool(true) +resource(%d) of type (Socket) +int(10) +string(10) "my message" +Done. + diff --git a/ext/sockets/tests/socket_export_stream-4-win.phpt b/ext/sockets/tests/socket_export_stream-4-win.phpt new file mode 100644 index 0000000000..e38db7bd08 --- /dev/null +++ b/ext/sockets/tests/socket_export_stream-4-win.phpt @@ -0,0 +1,108 @@ +--TEST-- +socket_export_stream: effects of closing +--SKIPIF-- +<?php +if (!extension_loaded('sockets')) { + die('SKIP sockets extension not available.'); +} +if(substr(PHP_OS, 0, 3) != 'WIN' ) { + die("skip Not Valid for Linux"); +} + +--FILE-- +<?php + +function test($stream, $sock) { + if ($stream !== null) { + echo "stream_set_blocking "; + print_r(stream_set_blocking($stream, 0)); + echo "\n"; + } + if ($sock !== null) { + echo "socket_set_block "; + print_r(socket_set_block($sock)); + echo "\n"; + echo "socket_get_option "; + print_r(socket_get_option($sock, SOL_SOCKET, SO_TYPE)); + echo "\n"; + } + echo "\n"; +} + +echo "normal\n"; +$sock0 = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock0, '0.0.0.0', 58380); +$stream0 = socket_export_stream($sock0); +test($stream0, $sock0); + +echo "\nunset stream\n"; +$sock1 = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock1, '0.0.0.0', 58381); +$stream1 = socket_export_stream($sock1); +unset($stream1); +test(null, $sock1); + +echo "\nunset socket\n"; +$sock2 = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock2, '0.0.0.0', 58382); +$stream2 = socket_export_stream($sock2); +unset($sock2); +test($stream2, null); + +echo "\nclose stream\n"; +$sock3 = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock3, '0.0.0.0', 58383); +$stream3 = socket_export_stream($sock3); +fclose($stream3); +test($stream3, $sock3); + +echo "\nclose socket\n"; +$sock4 = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock4, '0.0.0.0', 58484); +$stream4 = socket_export_stream($sock4); +socket_close($sock4); +test($stream4, $sock4); + +echo "Done.\n"; +--EXPECTF-- +normal +stream_set_blocking 1 +socket_set_block 1 +socket_get_option 2 + + +unset stream +socket_set_block 1 +socket_get_option 2 + + +unset socket +stream_set_blocking 1 + + +close stream +stream_set_blocking +Warning: stream_set_blocking(): supplied resource is not a valid stream resource in %s on line %d + +socket_set_block +Warning: socket_set_block(): unable to set blocking mode [%d]: An operation was attempted on something that is not a socket. + in %s on line %d + +socket_get_option +Warning: socket_get_option(): unable to retrieve socket option [%d]: An operation was attempted on something that is not a socket. + in %s on line %d + + + +close socket +stream_set_blocking +Warning: stream_set_blocking(): supplied resource is not a valid stream resource in %s on line %d + +socket_set_block +Warning: socket_set_block(): supplied resource is not a valid Socket resource in %s on line %d + +socket_get_option +Warning: socket_get_option(): supplied resource is not a valid Socket resource in %s on line %d + + +Done. diff --git a/ext/sockets/tests/socket_export_stream-4.phpt b/ext/sockets/tests/socket_export_stream-4.phpt new file mode 100644 index 0000000000..ff329ec795 --- /dev/null +++ b/ext/sockets/tests/socket_export_stream-4.phpt @@ -0,0 +1,105 @@ +--TEST-- +socket_export_stream: effects of closing +--SKIPIF-- +<?php +if (!extension_loaded('sockets')) { + die('SKIP sockets extension not available.'); +} +if(substr(PHP_OS, 0, 3) == 'WIN' ) { + die("skip Not Valid for Windows"); +} +--FILE-- +<?php + +function test($stream, $sock) { + if ($stream !== null) { + echo "stream_set_blocking "; + print_r(stream_set_blocking($stream, 0)); + echo "\n"; + } + if ($sock !== null) { + echo "socket_set_block "; + print_r(socket_set_block($sock)); + echo "\n"; + echo "socket_get_option "; + print_r(socket_get_option($sock, SOL_SOCKET, SO_TYPE)); + echo "\n"; + } + echo "\n"; +} + +echo "normal\n"; +$sock0 = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock0, '0.0.0.0', 58380); +$stream0 = socket_export_stream($sock0); +test($stream0, $sock0); + +echo "\nunset stream\n"; +$sock1 = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock1, '0.0.0.0', 58381); +$stream1 = socket_export_stream($sock1); +unset($stream1); +test(null, $sock1); + +echo "\nunset socket\n"; +$sock2 = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock2, '0.0.0.0', 58382); +$stream2 = socket_export_stream($sock2); +unset($sock2); +test($stream2, null); + +echo "\nclose stream\n"; +$sock3 = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock3, '0.0.0.0', 58383); +$stream3 = socket_export_stream($sock3); +fclose($stream3); +test($stream3, $sock3); + +echo "\nclose socket\n"; +$sock4 = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock4, '0.0.0.0', 58484); +$stream4 = socket_export_stream($sock4); +socket_close($sock4); +test($stream4, $sock4); + +echo "Done.\n"; +--EXPECTF-- +normal +stream_set_blocking 1 +socket_set_block 1 +socket_get_option 2 + + +unset stream +socket_set_block 1 +socket_get_option 2 + + +unset socket +stream_set_blocking 1 + + +close stream +stream_set_blocking +Warning: stream_set_blocking(): supplied resource is not a valid stream resource in %s on line %d + +socket_set_block +Warning: socket_set_block(): unable to set blocking mode [%d]: %s in %s on line %d + +socket_get_option +Warning: socket_get_option(): unable to retrieve socket option [%d]: %s in %s on line %d + + + +close socket +stream_set_blocking +Warning: stream_set_blocking(): supplied resource is not a valid stream resource in %s on line %d + +socket_set_block +Warning: socket_set_block(): supplied resource is not a valid Socket resource in %s on line %d + +socket_get_option +Warning: socket_get_option(): supplied resource is not a valid Socket resource in %s on line %d + + +Done. diff --git a/ext/sockets/tests/socket_export_stream-5.phpt b/ext/sockets/tests/socket_export_stream-5.phpt new file mode 100644 index 0000000000..732b2072d0 --- /dev/null +++ b/ext/sockets/tests/socket_export_stream-5.phpt @@ -0,0 +1,25 @@ +--TEST-- +socket_export_stream: effects of leaked handles +--SKIPIF-- +<?php +if (!extension_loaded('sockets')) { + die('SKIP sockets extension not available.'); +} +if (!function_exists('leak_variable')) + die('SKIP only for debug builds'); +--FILE-- +<?php + +$sock0 = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock0, '0.0.0.0', 58380); +$stream0 = socket_export_stream($sock0); +leak_variable($stream0, true); + +$sock1 = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock1, '0.0.0.0', 58381); +$stream1 = socket_export_stream($sock1); +leak_variable($sock1, true); + +echo "Done.\n"; +--EXPECT-- +Done. diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index 2a1df40fbb..fdae966023 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -2075,7 +2075,6 @@ static int spl_filesystem_file_call(spl_filesystem_object *intern, zend_function ZVAL_UNDEF(&retval); fci.size = sizeof(fci); - fci.function_table = EG(function_table); fci.object = NULL; fci.retval = &retval; fci.param_count = num_args; @@ -2883,7 +2882,7 @@ SPL_METHOD(SplFileObject, fwrite) if (ZEND_NUM_ARGS() > 1) { if (length >= 0) { - str_len = MAX(0, MIN((size_t)length, str_len)); + str_len = MIN((size_t)length, str_len); } else { /* Negative length given, nothing to write */ str_len = 0; diff --git a/ext/spl/spl_engine.h b/ext/spl/spl_engine.h index 0ee23cac1c..b683c16d94 100644 --- a/ext/spl/spl_engine.h +++ b/ext/spl/spl_engine.h @@ -62,7 +62,6 @@ static inline void spl_instantiate_arg_n(zend_class_entry *pce, zval *retval, in spl_instantiate(pce, retval); fci.size = sizeof(zend_fcall_info); - fci.function_table = &pce->function_table; ZVAL_STR(&fci.function_name, func->common.function_name); fci.object = Z_OBJ_P(retval); fci.retval = &dummy; @@ -72,7 +71,7 @@ static inline void spl_instantiate_arg_n(zend_class_entry *pce, zval *retval, in fcc.initialized = 1; fcc.function_handler = func; - fcc.calling_scope = EG(scope); + fcc.calling_scope = zend_get_executed_scope(); fcc.called_scope = pce; fcc.object = Z_OBJ_P(retval); diff --git a/ext/spl/spl_fixedarray.c b/ext/spl/spl_fixedarray.c index 9bbda05829..e04abf77ea 100644 --- a/ext/spl/spl_fixedarray.c +++ b/ext/spl/spl_fixedarray.c @@ -410,11 +410,11 @@ static inline void spl_fixedarray_object_write_dimension_helper(spl_fixedarray_o static void spl_fixedarray_object_write_dimension(zval *object, zval *offset, zval *value) /* {{{ */ { spl_fixedarray_object *intern; + zval tmp; intern = Z_SPLFIXEDARRAY_P(object); if (intern->fptr_offset_set) { - zval tmp; if (!offset) { ZVAL_NULL(&tmp); offset = &tmp; diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c index 8ff3427011..6a0049733f 100644 --- a/ext/spl/spl_iterators.c +++ b/ext/spl/spl_iterators.c @@ -1998,7 +1998,6 @@ SPL_METHOD(CallbackFilterIterator, accept) zend_fcall_info *fci = &intern->u.cbfilter->fci; zend_fcall_info_cache *fcc = &intern->u.cbfilter->fcc; zval params[3]; - zval result; if (zend_parse_parameters_none() == FAILURE) { return; @@ -2012,19 +2011,22 @@ SPL_METHOD(CallbackFilterIterator, accept) ZVAL_COPY_VALUE(¶ms[1], &intern->current.key); ZVAL_COPY_VALUE(¶ms[2], &intern->inner.zobject); - fci->retval = &result; + fci->retval = return_value; fci->param_count = 3; fci->params = params; fci->no_separation = 0; - if (zend_call_function(fci, fcc) != SUCCESS || Z_TYPE(result) == IS_UNDEF) { + if (zend_call_function(fci, fcc) != SUCCESS || Z_ISUNDEF_P(return_value)) { RETURN_FALSE; } + if (EG(exception)) { - return; + RETURN_NULL(); } - RETURN_ZVAL(&result, 1, 1); + /* zend_call_function may change args to IS_REF */ + ZVAL_COPY_VALUE(&intern->current.data, ¶ms[0]); + ZVAL_COPY_VALUE(&intern->current.key, ¶ms[1]); } /* }}} */ diff --git a/ext/spl/tests/bug72051.phpt b/ext/spl/tests/bug72051.phpt new file mode 100644 index 0000000000..1dfc056d7e --- /dev/null +++ b/ext/spl/tests/bug72051.phpt @@ -0,0 +1,26 @@ +--TEST-- +Bug #72051 (The reference in CallbackFilterIterator doesn't work as expected) +--FILE-- +<?php + +$data = [ + [1,2] +]; + +$callbackTest = new CallbackFilterIterator(new ArrayIterator($data), function (&$current) { + $current['message'] = 'Test message'; + return true; +}); + +$callbackTest->rewind(); +$data = $callbackTest->current(); +$callbackTest->next(); +print_r($data); +?> +--EXPECT-- +Array +( + [0] => 1 + [1] => 2 + [message] => Test message +) diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index 3c7239021f..d7f7722959 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -683,7 +683,6 @@ static int sqlite3_do_callback(struct php_sqlite3_fci *fc, zval *cb, int argc, s fake_argc = argc + is_agg; fc->fci.size = sizeof(fc->fci); - fc->fci.function_table = EG(function_table); ZVAL_COPY_VALUE(&fc->fci.function_name, cb); fc->fci.object = NULL; fc->fci.retval = &retval; @@ -841,7 +840,6 @@ static int php_sqlite3_callback_compare(void *coll, int a_len, const void *a, in int ret; collation->fci.fci.size = (sizeof(collation->fci.fci)); - collation->fci.fci.function_table = EG(function_table); ZVAL_COPY_VALUE(&collation->fci.fci.function_name, &collation->cmp_func); collation->fci.fci.object = NULL; collation->fci.fci.retval = &retval; @@ -1392,6 +1390,26 @@ static int register_bound_parameter_to_sqlite(struct php_sqlite3_bound_param *pa } /* }}} */ +/* {{{ Best try to map between PHP and SQLite. Default is still text. */ +#define PHP_SQLITE3_SET_TYPE(z, p) \ + switch (Z_TYPE_P(z)) { \ + default: \ + (p).type = SQLITE_TEXT; \ + break; \ + case IS_LONG: \ + case IS_TRUE: \ + case IS_FALSE: \ + (p).type = SQLITE_INTEGER; \ + break; \ + case IS_DOUBLE: \ + (p).type = SQLITE_FLOAT; \ + break; \ + case IS_NULL: \ + (p).type = SQLITE_NULL; \ + break; \ + } +/* }}} */ + /* {{{ proto bool SQLite3Stmt::bindParam(int parameter_number, mixed parameter [, int type]) Bind Parameter to a stmt variable. */ PHP_METHOD(sqlite3stmt, bindParam) @@ -1416,6 +1434,10 @@ PHP_METHOD(sqlite3stmt, bindParam) ZVAL_COPY(¶m.parameter, parameter); + if (ZEND_NUM_ARGS() < 3) { + PHP_SQLITE3_SET_TYPE(parameter, param); + } + if (!register_bound_parameter_to_sqlite(¶m, stmt_obj)) { if (!Z_ISUNDEF(param.parameter)) { zval_ptr_dtor(&(param.parameter)); @@ -1451,6 +1473,10 @@ PHP_METHOD(sqlite3stmt, bindValue) ZVAL_COPY(¶m.parameter, parameter); + if (ZEND_NUM_ARGS() < 3) { + PHP_SQLITE3_SET_TYPE(parameter, param); + } + if (!register_bound_parameter_to_sqlite(¶m, stmt_obj)) { if (!Z_ISUNDEF(param.parameter)) { zval_ptr_dtor(&(param.parameter)); @@ -1462,6 +1488,8 @@ PHP_METHOD(sqlite3stmt, bindValue) } /* }}} */ +#undef PHP_SQLITE3_SET_TYPE + /* {{{ proto SQLite3Result SQLite3Stmt::execute() Executes a prepared statement and returns a result set object. */ PHP_METHOD(sqlite3stmt, execute) diff --git a/ext/sqlite3/tests/sqlite3_bind_bug68849.phpt b/ext/sqlite3/tests/sqlite3_bind_bug68849.phpt new file mode 100644 index 0000000000..321f883a8e --- /dev/null +++ b/ext/sqlite3/tests/sqlite3_bind_bug68849.phpt @@ -0,0 +1,71 @@ +--TEST-- +Bug #68849 bindValue is not using the right data type +--SKIPIF-- +<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?> +--FILE-- +<?php + +$db = new SQLite3(':memory:'); + +$db->exec("CREATE TABLE test (a INTEGER, b TEXT, c REAL);" . + "INSERT INTO test VALUES (1, 'hello', 3.14);" . + "INSERT INTO test VALUES (3, 'world', 3.15);" . + "INSERT INTO test VALUES (0, '42', 0.42);" +); + +$s = $db->prepare('SELECT * FROM test WHERE (a+2) = ?;'); +$s->bindValue(1, 3); +$r = $s->execute(); +var_dump($r->fetchArray(SQLITE3_ASSOC)); + +$s = $db->prepare('SELECT * FROM test WHERE a = ?;'); +$s->bindValue(1, true); +$r = $s->execute(); +var_dump($r->fetchArray(SQLITE3_ASSOC)); + +$s = $db->prepare('SELECT * FROM test WHERE a = ?;'); +$s->bindValue(1, false); +$r = $s->execute(); +var_dump($r->fetchArray(SQLITE3_ASSOC)); + +$s = $db->prepare('SELECT * FROM test WHERE c = ?;'); +$s->bindValue(1, 3.15); +$r = $s->execute(); +var_dump($r->fetchArray(SQLITE3_ASSOC)); + +?> +==DONE== +--EXPECTF-- +array(3) { + ["a"]=> + int(1) + ["b"]=> + string(5) "hello" + ["c"]=> + float(3.14) +} +array(3) { + ["a"]=> + int(1) + ["b"]=> + string(5) "hello" + ["c"]=> + float(3.14) +} +array(3) { + ["a"]=> + int(0) + ["b"]=> + string(2) "42" + ["c"]=> + float(0.42) +} +array(3) { + ["a"]=> + int(3) + ["b"]=> + string(5) "world" + ["c"]=> + float(3.15) +} +==DONE== diff --git a/ext/standard/array.c b/ext/standard/array.c index c9a82390a4..a2cc00dc30 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -1843,8 +1843,11 @@ PHP_FUNCTION(extract) if (var_exists && ZSTR_LEN(var_name) == sizeof("GLOBALS")-1 && !strcmp(ZSTR_VAL(var_name), "GLOBALS")) { break; } - if (var_exists && ZSTR_LEN(var_name) == sizeof("this")-1 && !strcmp(ZSTR_VAL(var_name), "this") && EG(scope) && ZSTR_LEN(EG(scope)->name) != 0) { - break; + if (var_exists && ZSTR_LEN(var_name) == sizeof("this")-1 && !strcmp(ZSTR_VAL(var_name), "this")) { + zend_class_entry *scope = zend_get_executed_scope(); + if (scope && ZSTR_LEN(scope->name) != 0) { + break; + } } ZVAL_STR_COPY(&final_name, var_name); break; @@ -2023,6 +2026,7 @@ PHP_FUNCTION(array_fill) Z_ARRVAL_P(return_value)->nNumUsed = start_key + num; Z_ARRVAL_P(return_value)->nNumOfElements = num; Z_ARRVAL_P(return_value)->nInternalPointer = start_key; + Z_ARRVAL_P(return_value)->nNextFreeElement = start_key + num; if (Z_REFCOUNTED_P(val)) { GC_REFCOUNT(Z_COUNTED_P(val)) += num; @@ -3515,15 +3519,20 @@ static inline zval *array_column_fetch_prop(zval *data, zval *name, zval *rv) zval *prop = NULL; if (Z_TYPE_P(data) == IS_OBJECT) { - zend_string *key = zval_get_string(name); + if (!Z_OBJ_HANDLER_P(data, has_property) || !Z_OBJ_HANDLER_P(data, read_property)) { + return NULL; + } - if (!Z_OBJ_HANDLER_P(data, has_property) || Z_OBJ_HANDLER_P(data, has_property)(data, name, 1, NULL)) { - prop = zend_read_property(Z_OBJCE_P(data), data, ZSTR_VAL(key), ZSTR_LEN(key), 1, rv); + /* The has_property check is first performed in "exists" mode (which returns true for + * properties that are null but exist) and then in "has" mode to handle objects that + * implement __isset (which is not called in "exists" mode). */ + if (Z_OBJ_HANDLER_P(data, has_property)(data, name, 2, NULL) + || Z_OBJ_HANDLER_P(data, has_property)(data, name, 0, NULL)) { + prop = Z_OBJ_HANDLER_P(data, read_property)(data, name, BP_VAR_R, NULL, rv); } - zend_string_release(key); } else if (Z_TYPE_P(data) == IS_ARRAY) { if (Z_TYPE_P(name) == IS_STRING) { - prop = zend_hash_find(Z_ARRVAL_P(data), Z_STR_P(name)); + prop = zend_symtable_find(Z_ARRVAL_P(data), Z_STR_P(name)); } else if (Z_TYPE_P(name) == IS_LONG) { prop = zend_hash_index_find(Z_ARRVAL_P(data), Z_LVAL_P(name)); } diff --git a/ext/standard/assert.c b/ext/standard/assert.c index 109ba3ba22..2cb6285f4e 100644 --- a/ext/standard/assert.c +++ b/ext/standard/assert.c @@ -164,7 +164,6 @@ PHP_FUNCTION(assert) if (Z_TYPE_P(assertion) == IS_STRING) { zval retval; int old_error_reporting = 0; /* shut up gcc! */ - zend_class_entry *orig_scope = EG(scope); myeval = Z_STRVAL_P(assertion); @@ -194,8 +193,6 @@ PHP_FUNCTION(assert) EG(error_reporting) = old_error_reporting; } - EG(scope) = orig_scope; - convert_to_boolean(&retval); val = Z_TYPE(retval) == IS_TRUE; } else { diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 6323d18b5f..f887903f26 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -3834,20 +3834,21 @@ PHP_FUNCTION(constant) { zend_string *const_name; zval *c; + zend_class_entry *scope; if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &const_name) == FAILURE) { return; } - c = zend_get_constant_ex(const_name, NULL, ZEND_FETCH_CLASS_SILENT); + scope = zend_get_executed_scope(); + c = zend_get_constant_ex(const_name, scope, ZEND_FETCH_CLASS_SILENT); if (c) { - ZVAL_COPY_VALUE(return_value, c); + ZVAL_DUP(return_value, c); if (Z_CONSTANT_P(return_value)) { - if (UNEXPECTED(zval_update_constant_ex(return_value, 1, NULL) != SUCCESS)) { + if (UNEXPECTED(zval_update_constant_ex(return_value, scope) != SUCCESS)) { return; } } - zval_copy_ctor(return_value); } else { php_error_docref(NULL, E_WARNING, "Couldn't find constant %s", ZSTR_VAL(const_name)); RETURN_NULL(); diff --git a/ext/standard/file.c b/ext/standard/file.c index 535fc44f3f..eef1287b0f 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -262,19 +262,19 @@ PHP_MINIT_FUNCTION(file) REGISTER_LONG_CONSTANT("STREAM_IPPROTO_IP", IPPROTO_IP, CONST_CS|CONST_PERSISTENT); #endif -#ifdef IPPROTO_TCP +#if defined(IPPROTO_TCP) || defined(PHP_WIN32) REGISTER_LONG_CONSTANT("STREAM_IPPROTO_TCP", IPPROTO_TCP, CONST_CS|CONST_PERSISTENT); #endif -#ifdef IPPROTO_UDP +#if defined(IPPROTO_UDP) || defined(PHP_WIN32) REGISTER_LONG_CONSTANT("STREAM_IPPROTO_UDP", IPPROTO_UDP, CONST_CS|CONST_PERSISTENT); #endif -#ifdef IPPROTO_ICMP +#if defined(IPPROTO_ICMP) || defined(PHP_WIN32) REGISTER_LONG_CONSTANT("STREAM_IPPROTO_ICMP", IPPROTO_ICMP, CONST_CS|CONST_PERSISTENT); #endif -#ifdef IPPROTO_RAW +#if defined(IPPROTO_RAW) || defined(PHP_WIN32) REGISTER_LONG_CONSTANT("STREAM_IPPROTO_RAW", IPPROTO_RAW, CONST_CS|CONST_PERSISTENT); #endif diff --git a/ext/standard/streamsfuncs.c b/ext/standard/streamsfuncs.c index def1fb88d7..0e5d0ce79e 100644 --- a/ext/standard/streamsfuncs.c +++ b/ext/standard/streamsfuncs.c @@ -613,6 +613,7 @@ static int stream_array_to_fd_set(zval *stream_array, fd_set *fds, php_socket_t the higher bits of a SOCKET variable uninitialized on systems with little endian. */ php_socket_t this_fd; + ZVAL_DEREF(elem); php_stream_from_zval_no_verify(stream, elem); if (stream == NULL) { continue; @@ -652,6 +653,7 @@ static int stream_array_from_fd_set(zval *stream_array, fd_set *fds) ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(stream_array), num_ind, key, elem) { php_socket_t this_fd; + ZVAL_DEREF(elem); php_stream_from_zval_no_verify(stream, elem); if (stream == NULL) { continue; @@ -698,6 +700,7 @@ static int stream_array_emulate_read_fd_set(zval *stream_array) zend_hash_init(Z_ARRVAL(new_array), zend_hash_num_elements(Z_ARRVAL_P(stream_array)), NULL, ZVAL_PTR_DTOR, 0); ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(stream_array), elem) { + ZVAL_DEREF(elem); php_stream_from_zval_no_verify(stream, elem); if (stream == NULL) { continue; diff --git a/ext/standard/string.c b/ext/standard/string.c index ab793b6217..b2fcfa0ec3 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -1229,16 +1229,16 @@ PHPAPI void php_implode(const zend_string *delim, zval *arr, zval *return_value) ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), tmp) { if (Z_TYPE_P(tmp) == IS_LONG) { - double val = Z_LVAL_P(tmp); + zend_long val = Z_LVAL_P(tmp); + *++strptr = NULL; ((zend_long *) (strings + numelems))[strptr - strings] = Z_LVAL_P(tmp); - if (val < 0) { - val = -10 * val; + if (val <= 0) { + len++; } - if (val < 10) { + while (val) { + val /= 10; len++; - } else { - len += (int) log10(10 * (double) val); } } else { *++strptr = zval_get_string(tmp); @@ -5375,7 +5375,7 @@ PHP_FUNCTION(str_pad) return; } - result = zend_string_safe_alloc(ZSTR_LEN(input), 1, num_pad_chars, 0); + result = zend_string_safe_alloc(1, ZSTR_LEN(input), num_pad_chars, 0); ZSTR_LEN(result) = 0; /* We need to figure out the left/right padding lengths. */ diff --git a/ext/standard/tests/array/array_column_numeric_string_key.phpt b/ext/standard/tests/array/array_column_numeric_string_key.phpt new file mode 100644 index 0000000000..aed3c35ea2 --- /dev/null +++ b/ext/standard/tests/array/array_column_numeric_string_key.phpt @@ -0,0 +1,23 @@ +--TEST-- +array_column() treats numeric string keys as usual +--FILE-- +<?php + +$array = [[42 => 'a'], [42 => 'b']]; +var_dump(array_column($array, 42)); +var_dump(array_column($array, "42")); + +?> +--EXPECT-- +array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "b" +} +array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "b" +} diff --git a/ext/standard/tests/array/array_column_property_visibility.phpt b/ext/standard/tests/array/array_column_property_visibility.phpt new file mode 100644 index 0000000000..4639a3c9c5 --- /dev/null +++ b/ext/standard/tests/array/array_column_property_visibility.phpt @@ -0,0 +1,27 @@ +--TEST-- +array_column() respects property visibility +--FILE-- +<?php + +class Test { + private $prop; + public function __construct($value) { + $this->prop = $value; + } + public function __isset($name) { + return true; + } + public function __get($name) { + return "__get($this->prop)"; + } +} + +$arr = [new Test("foobar")]; +var_dump(array_column($arr, "prop")); + +?> +--EXPECT-- +array(1) { + [0]=> + string(13) "__get(foobar)" +} diff --git a/ext/standard/tests/array/bug72031.phpt b/ext/standard/tests/array/bug72031.phpt new file mode 100644 index 0000000000..541fd3c4ec --- /dev/null +++ b/ext/standard/tests/array/bug72031.phpt @@ -0,0 +1,48 @@ +--TEST-- +Bug #72031: array_column() against an array of objects discards all values matching null +--FILE-- +<?php + +class myObj { + public $prop; + public function __construct($prop) { + $this->prop = $prop; + } +} + +$objects = [ + new myObj(-1), + new myObj(0), + new myObj(1), + new myObj(2), + new myObj(null), + new myObj(true), + new myObj(false), + new myObj('abc'), + new myObj(''), +]; + +var_dump(array_column($objects, 'prop')); + +?> +--EXPECT-- +array(9) { + [0]=> + int(-1) + [1]=> + int(0) + [2]=> + int(1) + [3]=> + int(2) + [4]=> + NULL + [5]=> + bool(true) + [6]=> + bool(false) + [7]=> + string(3) "abc" + [8]=> + string(0) "" +} diff --git a/ext/standard/tests/array/bug72116.phpt b/ext/standard/tests/array/bug72116.phpt new file mode 100644 index 0000000000..7951f69130 --- /dev/null +++ b/ext/standard/tests/array/bug72116.phpt @@ -0,0 +1,18 @@ +--TEST-- +Bug #72116 (insertion after array_fill fails) +--FILE-- +<?php + +$x = array_fill(0, 1, '..'); +$x[] = 'a'; +var_dump($x); + +?> +--EXPECT-- +array(2) { + [0]=> + string(2) ".." + [1]=> + string(1) "a" +} + diff --git a/ext/standard/tests/file/bug72035.phpt b/ext/standard/tests/file/bug72035.phpt new file mode 100644 index 0000000000..a2abbb7f35 --- /dev/null +++ b/ext/standard/tests/file/bug72035.phpt @@ -0,0 +1,40 @@ +--TEST-- +Bug #72035 php-cgi.exe fails to run scripts relative to drive root +--SKIPIF-- +<?php +if(substr(PHP_OS, 0, 3) != 'WIN' ) die('skip windows only test'); +if(php_sapi_name() != "cli") die('skip CLI only test'); + +$cgi = realpath(dirname(PHP_BINARY)) . DIRECTORY_SEPARATOR . "php-cgi.exe"; +if (!file_exists($cgi)) die('skip CGI binary not found'); +?> +--FILE-- +<?php + +$fl = dirname(__FILE__) . DIRECTORY_SEPARATOR . md5(uniqid()) . ".php"; +$fl = substr($fl, 2); + +$cgi = realpath(dirname(PHP_BINARY) . DIRECTORY_SEPARATOR . "php-cgi.exe"); + +file_put_contents($fl, "<?php echo \"hello\", \"\n\"; ?>"); + +$cmd = "$cgi -n -C $fl"; + +/* Need to run CGI with the env reset. */ +$desc = array(0 => array("pipe", "r")); +$proc = proc_open($cmd, $desc, $pipes, getcwd(), array()); +if (is_resource($proc)) { + echo stream_get_contents($pipes[0]); + + proc_close($proc); +} + +unlink($fl); +?> +==DONE== +--EXPECTF-- +X-Powered-By: PHP/%s +Content-type: text/html; charset=UTF-8 + +hello +==DONE== diff --git a/ext/standard/tests/file/file_put_contents_variation7-win32.phpt b/ext/standard/tests/file/file_put_contents_variation7-win32.phpt index d7bfdf9233..e1a94a2043 100644 --- a/ext/standard/tests/file/file_put_contents_variation7-win32.phpt +++ b/ext/standard/tests/file/file_put_contents_variation7-win32.phpt @@ -59,10 +59,10 @@ for($i = 0; $i<count($allDirs); $i++) { $j = $i+1; $dir = $allDirs[$i]; echo "\n-- Iteration $j --\n"; - $res = file_put_contents($dir."\\".$filename, ($data + $i)); + $res = file_put_contents($dir."\\".$filename, ($data . $i)); if ($res !== false) { $in = file_get_contents($absFile); - if ($in == ($data + $i)) { + if ($in == ($data . $i)) { echo "Data written correctly\n"; } else { @@ -127,4 +127,4 @@ No data written -- Iteration 12 -- Data written correctly -*** Done ***
\ No newline at end of file +*** Done *** diff --git a/ext/standard/tests/file/fscanf.phpt b/ext/standard/tests/file/fscanf.phpt index c37bdeb20a..003dd53dfa 100644 --- a/ext/standard/tests/file/fscanf.phpt +++ b/ext/standard/tests/file/fscanf.phpt @@ -7,7 +7,7 @@ $filename = dirname(__FILE__)."/fscanf.dat"; var_dump(fscanf()); var_dump(fscanf(array())); -var_dump(fscanf(array(), array(), new stdclass)); +var_dump(fscanf(array(), array())); file_put_contents($filename, "data"); diff --git a/ext/standard/tests/streams/bug72075.phpt b/ext/standard/tests/streams/bug72075.phpt new file mode 100644 index 0000000000..93dce60350 --- /dev/null +++ b/ext/standard/tests/streams/bug72075.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #72075 (Referencing socket resources breaks stream_select) +--FILE-- +<?php +$r = [stream_socket_server("tcp://127.0.0.1:0", $errno, $errStr)]; +$w = NULL; +$e = NULL; + +// Without this line, all is well: +$dummy =& $r[0]; + +print stream_select($r, $w, $e, 0.5); + +--EXPECT-- +0 diff --git a/ext/standard/tests/streams/stream_context_tcp_nodelay.phpt b/ext/standard/tests/streams/stream_context_tcp_nodelay.phpt new file mode 100644 index 0000000000..ca3289fbc2 --- /dev/null +++ b/ext/standard/tests/streams/stream_context_tcp_nodelay.phpt @@ -0,0 +1,22 @@ +--TEST-- +stream context tcp_nodelay +--SKIPIF-- +<?php if (!extension_loaded("sockets")) die("skip: need sockets") ?> +--FILE-- +<?php +$ctxt = stream_context_create([ + "socket" => [ + "tcp_nodelay" => true + ] +]); + +$stream = stream_socket_client( + "tcp://www.php.net:80", $errno, $errstr, 10, STREAM_CLIENT_CONNECT, $ctxt); + +$socket = + socket_import_stream($stream); + +var_dump(socket_get_option($socket, SOL_TCP, TCP_NODELAY) > 0); +?> +--EXPECT-- +bool(true) diff --git a/ext/standard/tests/streams/stream_context_tcp_nodelay_fopen.phpt b/ext/standard/tests/streams/stream_context_tcp_nodelay_fopen.phpt new file mode 100644 index 0000000000..08ad4c2d2e --- /dev/null +++ b/ext/standard/tests/streams/stream_context_tcp_nodelay_fopen.phpt @@ -0,0 +1,21 @@ +--TEST-- +stream context tcp_nodelay fopen +--SKIPIF-- +<?php if (!extension_loaded("sockets")) die("skip: need sockets") ?> +--FILE-- +<?php +$ctxt = stream_context_create([ + "socket" => [ + "tcp_nodelay" => true + ] +]); + +$stream = fopen("http://www.php.net", "r", false, $ctxt); + +$socket = + @socket_import_stream($stream); + +var_dump(socket_get_option($socket, STREAM_IPPROTO_TCP, TCP_NODELAY) > 0); +?> +--EXPECT-- +bool(true) diff --git a/ext/standard/tests/streams/stream_context_tcp_nodelay_server.phpt b/ext/standard/tests/streams/stream_context_tcp_nodelay_server.phpt new file mode 100644 index 0000000000..6606a15052 --- /dev/null +++ b/ext/standard/tests/streams/stream_context_tcp_nodelay_server.phpt @@ -0,0 +1,47 @@ +--TEST-- +stream context tcp_nodelay server +--SKIPIF-- +<?php if (!extension_loaded("sockets")) die("skip: need sockets") ?> +--FILE-- +<?php +$serverCode = <<<'CODE' + $ctxt = stream_context_create([ + "socket" => [ + "tcp_nodelay" => true + ] + ]); + + $server = stream_socket_server( + "tcp://127.0.0.1:9099", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt); + + $client = stream_socket_accept($server); + + var_dump(socket_get_option( + socket_import_stream($server), + SOL_TCP, TCP_NODELAY) > 0); + + var_dump(socket_get_option( + socket_import_stream($client), + SOL_TCP, TCP_NODELAY) > 0); + + fclose($client); + fclose($server); +CODE; + +$clientCode = <<<'CODE' + $test = stream_socket_client( + "tcp://127.0.0.1:9099", $errno, $errstr, 10); + + sleep(1); + + fclose($test); +CODE; + +include sprintf( + "%s/../../../openssl/tests/ServerClientTestCase.inc", + dirname(__FILE__)); +ServerClientTestCase::getInstance()->run($serverCode, $clientCode); +?> +--EXPECT-- +bool(false) +bool(true) diff --git a/ext/standard/tests/strings/bug72100.phpt b/ext/standard/tests/strings/bug72100.phpt new file mode 100644 index 0000000000..7fcc0831b6 --- /dev/null +++ b/ext/standard/tests/strings/bug72100.phpt @@ -0,0 +1,18 @@ +--TEST-- +Test implode() function, problems with big numbers +--SKIPIF-- +<?php +if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platform only"); +?> +--FILE-- +<?php +var_dump( implode(" ", ["hello long", 999999999999999999, PHP_INT_MAX])); +var_dump( implode(" ", ["hello negative long", -999999999999999999, PHP_INT_MIN] ) ); +var_dump( implode(" ", ["hello small long", -101, -100, -99, -90, -11, -10, -9, -1, 0, 1, 2, 9, 10, 11, 90, 99, 100, 101] ) ); +echo "Done\n"; +?> +--EXPECT-- +string(49) "hello long 999999999999999999 9223372036854775807" +string(60) "hello negative long -999999999999999999 -9223372036854775808" +string(76) "hello small long -101 -100 -99 -90 -11 -10 -9 -1 0 1 2 9 10 11 90 99 100 101" +Done diff --git a/ext/standard/var.c b/ext/standard/var.c index acb1d40c01..76d92a5fd3 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -1080,6 +1080,11 @@ PHP_FUNCTION(unserialize) in case nesting calls to unserialize */ var_push_dtor(&var_hash, return_value); + /* Ensure return value is a value */ + if (Z_ISREF_P(return_value)) { + zend_unwrap_reference(return_value); + } + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); if (class_hash) { zend_hash_destroy(class_hash); diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c index 389c42b3de..3fc074dd6a 100644 --- a/ext/standard/var_unserializer.c +++ b/ext/standard/var_unserializer.c @@ -171,7 +171,7 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx) static zend_string *unserialize_str(const unsigned char **p, size_t len, size_t maxlen) { size_t i, j; - zend_string *str = zend_string_alloc(len, 0); + zend_string *str = zend_string_safe_alloc(1, len, 0, 0); unsigned char *end = *(unsigned char **)p+maxlen; if (end < *p) { diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index c7e0581630..81cc26db9d 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -169,7 +169,7 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx) static zend_string *unserialize_str(const unsigned char **p, size_t len, size_t maxlen) { size_t i, j; - zend_string *str = zend_string_alloc(len, 0); + zend_string *str = zend_string_safe_alloc(1, len, 0, 0); unsigned char *end = *(unsigned char **)p+maxlen; if (end < *p) { diff --git a/ext/wddx/wddx.c b/ext/wddx/wddx.c index 330cb49f08..e848afdeb7 100644 --- a/ext/wddx/wddx.c +++ b/ext/wddx/wddx.c @@ -954,12 +954,8 @@ static void php_wddx_pop_element(void *user_data, const XML_Char *name) /* Clean up class name var entry */ zval_ptr_dtor(&ent1->data); } else if (Z_TYPE(ent2->data) == IS_OBJECT) { - zend_class_entry *old_scope = EG(scope); - - EG(scope) = Z_OBJCE(ent2->data); - add_property_zval(&ent2->data, ent1->varname, &ent1->data); + zend_update_property(Z_OBJCE(ent2->data), &ent2->data, ent1->varname, strlen(ent1->varname), &ent1->data); if Z_REFCOUNTED(ent1->data) Z_DELREF(ent1->data); - EG(scope) = old_scope; } else { zend_symtable_str_update(target_hash, ent1->varname, strlen(ent1->varname), &ent1->data); } diff --git a/ext/xml/tests/bug72099.phpt b/ext/xml/tests/bug72099.phpt new file mode 100644 index 0000000000..50173a6a4c --- /dev/null +++ b/ext/xml/tests/bug72099.phpt @@ -0,0 +1,17 @@ +--TEST-- +Bug #72099: xml_parse_into_struct segmentation fault +--SKIPIF-- +<?php +require_once("skipif.inc"); +?> +--FILE-- +<?php +$var1=xml_parser_create_ns(); +$var2=str_repeat("a", 10); +$var3=[]; +$var4=[]; +xml_parse_into_struct($var1, $var2, $var3, $var4); +var_dump($var3); +--EXPECT-- +array(0) { +}
\ No newline at end of file diff --git a/ext/xml/xml.c b/ext/xml/xml.c index a3a42655d0..6b93e2fcc3 100644 --- a/ext/xml/xml.c +++ b/ext/xml/xml.c @@ -483,7 +483,6 @@ static void xml_call_handler(xml_parser *parser, zval *handler, zend_function *f zend_fcall_info fci; fci.size = sizeof(fci); - fci.function_table = EG(function_table); ZVAL_COPY_VALUE(&fci.function_name, handler); fci.object = Z_OBJ(parser->object); fci.retval = retval; diff --git a/ext/xmlreader/tests/XMLReaderBad_bug71805.xml b/ext/xmlreader/tests/XMLReaderBad_bug71805.xml new file mode 100644 index 0000000000..68ee25ddb8 --- /dev/null +++ b/ext/xmlreader/tests/XMLReaderBad_bug71805.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<records> + +<record><aaa><bbbb><ccc><![CDATA[XXX Xxxxxxxxxxxx]]></ccc><ddd><![CDATA[XXX Xx]]></ddd></bbbb><eee><![CDATA[Xxxxx xxxxxxx: xxxx://xxx.xxx.xx.xx/xxxx?xxxxXx=0xx000x0-000x-0xx0-x000-x0000xx0xx00 +Xxxxxxxxxxxx xx Xxxxxxxxxxxx Xxxxxxxxx xx Xxxxxxxxx Xxxxxxxxxxxx Xxxxxxxxxxx Xxxxxxxxxxxx (XXX Xxxxxxxxxxxx), xxxxxxxxx xxxxxxx xx Xxx Xxxxxxxxxx Xxxxxxxxxx Xxx.]]></eee></aaa><fff><bbbb><ggg><![CDATA[Xxxxxxxxx Xxxxxxxxxxxxxxx Xxxxxxxxxx xx Xxxxxxxxxxxx]]></ggg><ccc><![CDATA[XXX Xxxxxxxxxxxx]]></ccc></bbbb><hhh><![CDATA[Xx xxxxx, xx xxxxxxxxxxx XXX Xxxxxxxxxxxx x xxxxxcé x’xxxxxxxx xxx x’Xxxxxxléx léxxxxxxxxx xx xx xxxxxxxx xx xx Xxxxxxxxxx Xxxxxxxxxx Xxx (xxx xxx xx xxxxxxxxxx xxxxxxxxx). Xxxxx xxx xréxxxx xxx xxxxxx xxx déxxxxxxxx XXX Xxxxxxxxxxxx xx xxxx xx’xxxxxxxxxxxx xxxxxxxxxxxxxxx xxxxréxxxxxxtéx xx xxxxxxx xxx XX, xxx XXX xx xxx XXX xx xx xxxxxxxx xx xxxxx x’xxxxxxxx xx xxxxx xx xxxxxxxxx xxxxxxxxxxxxx xxréé (XXX). (Xxxxxxxxéx XXX - Xxx 0000)]]></hhh></fff></record> + +</records>
\ No newline at end of file diff --git a/ext/xmlreader/tests/XMLReaderGood_bug71805.xml b/ext/xmlreader/tests/XMLReaderGood_bug71805.xml new file mode 100644 index 0000000000..9a59e0c978 --- /dev/null +++ b/ext/xmlreader/tests/XMLReaderGood_bug71805.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<records> + +<record><aaa><bbbb><ddd><![CDATA[XXX Xx]]></ddd></bbbb><eee><![CDATA[Xxxxx xxxxxxx: xxxx://xxx.xxx.xx.xx/xxxx?xxxxXx=0xx000x0-000x-0xx0-x000-x0000xx0xx00 +Xxxxxxxxxxxx xx Xxxxxxxxxxxx Xxxxxxxxx xx Xxxxxxxxx Xxxxxxxxxxxx Xxxxxxxxxxx Xxxxxxxxxxxx (XXX Xxxxxxxxxxxx), xxxxxxxxx xxxxxxx xx Xxx Xxxxxxxxxx Xxxxxxxxxx Xxx.]]></eee></aaa><fff><bbbb><ggg><![CDATA[Xxxxxxxxx Xxxxxxxxxxxxxxx Xxxxxxxxxx xx Xxxxxxxxxxxx]]></ggg><ccc><![CDATA[XXX Xxxxxxxxxxxx]]></ccc></bbbb><hhh><![CDATA[Xx xxxxx, xx xxxxxxxxxxx XXX Xxxxxxxxxxxx x xxxxxcé x’xxxxxxxx xxx x’Xxxxxxléx léxxxxxxxxx xx xx xxxxxxxx xx xx Xxxxxxxxxx Xxxxxxxxxx Xxx (xxx xxx xx xxxxxxxxxx xxxxxxxxx). Xxxxx xxx xréxxxx xxx xxxxxx xxx déxxxxxxxx XXX Xxxxxxxxxxxx xx xxxx xx’xxxxxxxxxxxx xxxxxxxxxxxxxxx xxxxréxxxxxxtéx xx xxxxxxx xxx XX, xxx XXX xx xxx XXX xx xx xxxxxxxx xx xxxxx x’xxxxxxxx xx xxxxx xx xxxxxxxxx xxxxxxxxxxxxx xxréé (XXX). (Xxxxxxxxéx XXX - Xxx 0000)]]></hhh></fff></record> + +</records>
\ No newline at end of file diff --git a/ext/xmlreader/tests/bug71805.phpt b/ext/xmlreader/tests/bug71805.phpt new file mode 100644 index 0000000000..3d1713ace5 --- /dev/null +++ b/ext/xmlreader/tests/bug71805.phpt @@ -0,0 +1,39 @@ +--TEST-- +XMLReader: Bug #71805 XML files can generate UTF-8 error even if they are UTF-8 +--SKIPIF-- +<?php if (!extension_loaded("xmlreader")) print "skip"; ?> +--FILE-- +<?php + +TestXML(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'XMLReaderGood_bug71805.xml'); +TestXML(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'XMLReaderBad_bug71805.xml'); + +function TestXML($file) { + $XR = new XMLReader; + $XR->open($file, null, LIBXML_NOBLANKS); + + while (($lastRead = $XR->read()) && ($XR->name !== 'records')); + while (($lastRead = $XR->read()) && ($XR->name !== 'record')); + while ($lastRead) { + $xml = $XR->readOuterXML(); + if ($xml === '') { + $err = ''; + if ($e = libxml_get_last_error()) { $err = $e->message.' (line: '.$e->line.')'; } + $XR->close(); + echo $file.' : Problem with file'.($err ? ' — '.$err : '').'.'; + echo "\n"; + return; + } + while (($lastRead = $XR->next()) && ($XR->name !== 'record')); + } + $XR->close(); + echo $file.' : Good!'; + echo "\n"; + return; +} +?> +===DONE=== +--EXPECTF-- +%sXMLReaderGood_bug71805.xml : Good! +%sXMLReaderBad_bug71805.xml : Good! +===DONE=== diff --git a/ext/xmlrpc/tests/bug70728.phpt b/ext/xmlrpc/tests/bug70728.phpt index 5510c33936..72f72f85b0 100644 --- a/ext/xmlrpc/tests/bug70728.phpt +++ b/ext/xmlrpc/tests/bug70728.phpt @@ -3,6 +3,7 @@ Bug #70728 (Type Confusion Vulnerability in PHP_to_XMLRPC_worker) --SKIPIF-- <?php if (!extension_loaded("xmlrpc")) print "skip"; +if (PHP_INT_SIZE != 4) die("skip this test is for 32bit platform only"); ?> --FILE-- <?php @@ -26,5 +27,5 @@ object(stdClass)#1 (2) { ["xmlrpc_type"]=> string(6) "base64" ["scalar"]=> - int(73588229205) + float(73588229205) } diff --git a/ext/xmlrpc/tests/bug70728_64bit.phpt b/ext/xmlrpc/tests/bug70728_64bit.phpt new file mode 100644 index 0000000000..3ed5093918 --- /dev/null +++ b/ext/xmlrpc/tests/bug70728_64bit.phpt @@ -0,0 +1,31 @@ +--TEST-- +Bug #70728 (Type Confusion Vulnerability in PHP_to_XMLRPC_worker) +--SKIPIF-- +<?php +if (!extension_loaded("xmlrpc")) print "skip"; +if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platform only"); +?> +--FILE-- +<?php +$obj = new stdClass; +$obj->xmlrpc_type = 'base64'; +$obj->scalar = 0x1122334455; +var_dump(xmlrpc_encode($obj)); +var_dump($obj); +?> +--EXPECTF-- +string(135) "<?xml version="1.0" encoding="utf-8"?> +<params> +<param> + <value> + <base64>NzM1ODgyMjkyMDU= </base64> + </value> +</param> +</params> +" +object(stdClass)#1 (2) { + ["xmlrpc_type"]=> + string(6) "base64" + ["scalar"]=> + int(73588229205) +} diff --git a/ext/xsl/xsltprocessor.c b/ext/xsl/xsltprocessor.c index 1c434039e2..5339812253 100644 --- a/ext/xsl/xsltprocessor.c +++ b/ext/xsl/xsltprocessor.c @@ -295,7 +295,6 @@ static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int t } fci.size = sizeof(fci); - fci.function_table = EG(function_table); if (fci.param_count > 0) { fci.params = args; } else { diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index db201af634..7c9adf4af7 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -1281,7 +1281,7 @@ static PHP_NAMED_FUNCTION(zif_zip_entry_read) } if (zr_rsrc->zf) { - buffer = zend_string_alloc(len, 0); + buffer = zend_string_safe_alloc(1, len, 0, 0); n = zip_fread(zr_rsrc->zf, ZSTR_VAL(buffer), ZSTR_LEN(buffer)); if (n > 0) { ZSTR_VAL(buffer)[n] = '\0'; @@ -2728,7 +2728,7 @@ static void php_zip_get_from(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */ RETURN_FALSE; } - buffer = zend_string_alloc(len, 0); + buffer = zend_string_safe_alloc(1, len, 0, 0); n = zip_fread(zf, ZSTR_VAL(buffer), ZSTR_LEN(buffer)); if (n < 1) { zend_string_free(buffer); |