diff options
36 files changed, 416 insertions, 130 deletions
@@ -27,12 +27,19 @@ PHP NEWS - DateTime . Added DateTimeImmutable - a variant of DateTime that only returns the - modified state instead of changing itself. (Derick) + modified state instead of changing itself. (Derick) + +- FPM: + . Fixed bug #63999 (php with fpm fails to build on Solaris 10 or 11). (Adam) - pgsql: . Bug #46408: Locale number format settings can cause pg_query_params to break with numerics. (asmecher, Lars) +- dba: + . Bug #62489: dba_insert not working as expected. + (marc-bennewitz at arcor dot de, Lars) + 18 Dec 2012, PHP 5.5.0 Alpha 2 - General improvements: @@ -243,4 +250,7 @@ PHP NEWS . Fixed bug #63248 (Load multiple magic files from a directory under Windows). (Anatoliy) +- General improvements: + . Implemented FR #46487 (Dereferencing process-handles no longer waits on those processes). (Jille Timmermans) + <<< NOTE: Insert NEWS from last stable release here prior to actual release! >>> diff --git a/README.PARAMETER_PARSING_API b/README.PARAMETER_PARSING_API index 927e48188c..edcee0f2ea 100644 --- a/README.PARAMETER_PARSING_API +++ b/README.PARAMETER_PARSING_API @@ -28,6 +28,17 @@ Both functions return SUCCESS or FAILURE depending on the result. The auto-conversions are performed as necessary. Arrays, objects, and resources cannot be auto-converted. +PHP 5.5 includes a new function: + +int zend_parse_parameter(int flags, int arg_num TSRMLS_DC, zval **arg, const char *spec, ...); + +This function behaves like zend_parse_parameters_ex() except that instead of +reading the arguments from the stack, it receives a single zval to convert +(passed with double indirection). The passed zval may be changed in place as +part of the conversion process. + +See also https://wiki.php.net/rfc/zpp_improv#expose_zend_parse_arg_as_zend_parse_parameter + Type specifiers --------------- @@ -65,9 +76,13 @@ Type specifiers will not be touched by the parsing function if they are not passed to it. / - use SEPARATE_ZVAL_IF_NOT_REF() on the parameter it follows - ! - the parameter it follows can be of specified type or NULL (applies - to all specifiers except for 'b', 'l', and 'd'). If NULL is passed, the - results pointer is set to NULL as well. + ! - the parameter it follows can be of specified type or NULL. If NULL is + passed and the output for such type is a pointer, then the output + pointer is set to a native NULL pointer. + For 'b', 'l' and 'd', an extra argument of type zend_bool* must be + passed after the corresponding bool*, long* or double* arguments, + respectively. A non-zero value will be written to the zend_bool iif a + PHP NULL is passed. Note on 64bit compatibility diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 90c7a4394f..44cdfaee6c 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -5,6 +5,7 @@ UPGRADE NOTES - PHP X.Y 1. Internal API changes a. Streams pooling API b. Lowercasing and locales + c. zend_qsort_r 2. Build system changes a. Unix build system changes @@ -53,6 +54,16 @@ such as strcasecmp, will be using locale rules. Two new functions - zend_binary_strncasecmp_l and zend_binary_strcasecmp_l - added as locale-based counterparts to zend_binary_strcasecmp and zend_binary_strncasecmp. + c. zend_qsort_r + +Added the function zend_qsort_r(): + +typedef int (*compare_r_func_t)(const void *, const void * TSRMLS_DC, void *); +void zend_qsort_r(void *base, size_t nmemb, size_t siz, compare_r_func_t compare, void *arg TSRMLS_DC); + +The extra argument it has (relatively to zend_qsort()) is passed to the +comparison function. + ======================== 2. Build system changes ======================== diff --git a/Zend/zend_API.c b/Zend/zend_API.c index eec4ab0bb1..95c90ea753 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -306,16 +306,14 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con { const char *spec_walk = *spec; char c = *spec_walk++; - int return_null = 0; + int check_null = 0; /* scan through modifiers */ while (1) { if (*spec_walk == '/') { SEPARATE_ZVAL_IF_NOT_REF(arg); } else if (*spec_walk == '!') { - if (Z_TYPE_PP(arg) == IS_NULL) { - return_null = 1; - } + check_null = 1; } else { break; } @@ -327,6 +325,12 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con case 'L': { long *p = va_arg(*va, long *); + + if (check_null) { + zend_bool *p = va_arg(*va, zend_bool *); + *p = (Z_TYPE_PP(arg) == IS_NULL); + } + switch (Z_TYPE_PP(arg)) { case IS_STRING: { @@ -380,6 +384,12 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con case 'd': { double *p = va_arg(*va, double *); + + if (check_null) { + zend_bool *p = va_arg(*va, zend_bool *); + *p = (Z_TYPE_PP(arg) == IS_NULL); + } + switch (Z_TYPE_PP(arg)) { case IS_STRING: { @@ -418,7 +428,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con int *pl = va_arg(*va, int *); switch (Z_TYPE_PP(arg)) { case IS_NULL: - if (return_null) { + if (check_null) { *p = NULL; *pl = 0; break; @@ -462,6 +472,12 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con case 'b': { zend_bool *p = va_arg(*va, zend_bool *); + + if (check_null) { + zend_bool *p = va_arg(*va, zend_bool *); + *p = (Z_TYPE_PP(arg) == IS_NULL); + } + switch (Z_TYPE_PP(arg)) { case IS_NULL: case IS_STRING: @@ -484,7 +500,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con case 'r': { zval **p = va_arg(*va, zval **); - if (return_null) { + if (check_null && Z_TYPE_PP(arg) == IS_NULL) { *p = NULL; break; } @@ -499,7 +515,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con case 'a': { zval **p = va_arg(*va, zval **); - if (return_null) { + if (check_null && Z_TYPE_PP(arg) == IS_NULL) { *p = NULL; break; } @@ -514,7 +530,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con case 'h': { HashTable **p = va_arg(*va, HashTable **); - if (return_null) { + if (check_null && Z_TYPE_PP(arg) == IS_NULL) { *p = NULL; break; } @@ -534,7 +550,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con case 'o': { zval **p = va_arg(*va, zval **); - if (return_null) { + if (check_null && Z_TYPE_PP(arg) == IS_NULL) { *p = NULL; break; } @@ -551,7 +567,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con zval **p = va_arg(*va, zval **); zend_class_entry *ce = va_arg(*va, zend_class_entry *); - if (return_null) { + if (check_null && Z_TYPE_PP(arg) == IS_NULL) { *p = NULL; break; } @@ -573,7 +589,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con zend_class_entry **lookup, **pce = va_arg(*va, zend_class_entry **); zend_class_entry *ce_base = *pce; - if (return_null) { + if (check_null && Z_TYPE_PP(arg) == IS_NULL) { *pce = NULL; break; } @@ -607,7 +623,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con zend_fcall_info_cache *fcc = va_arg(*va, zend_fcall_info_cache *); char *is_callable_error = NULL; - if (return_null) { + if (check_null && Z_TYPE_PP(arg) == IS_NULL) { fci->size = 0; fcc->initialized = 0; break; @@ -637,7 +653,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con case 'z': { zval **p = va_arg(*va, zval **); - if (return_null) { + if (check_null && Z_TYPE_PP(arg) == IS_NULL) { *p = NULL; } else { *p = *arg; @@ -648,7 +664,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con case 'Z': { zval ***p = va_arg(*va, zval ***); - if (return_null) { + if (check_null && Z_TYPE_PP(arg) == IS_NULL) { *p = NULL; } else { *p = arg; @@ -697,6 +713,19 @@ static int zend_parse_arg(int arg_num, zval **arg, va_list *va, const char **spe } /* }}} */ +ZEND_API int zend_parse_parameter(int flags, int arg_num TSRMLS_DC, zval **arg, const char *spec, ...) +{ + va_list va; + int ret; + int quiet = flags & ZEND_PARSE_PARAMS_QUIET; + + va_start(va, spec); + ret = zend_parse_arg(arg_num, arg, &va, &spec, quiet TSRMLS_CC); + va_end(va); + + return ret; +} + static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, int flags TSRMLS_DC) /* {{{ */ { const char *spec_walk; diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 4a3985e0f4..8574f90eb5 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -258,6 +258,8 @@ ZEND_API char *zend_zval_type_name(const zval *arg); ZEND_API int zend_parse_method_parameters(int num_args TSRMLS_DC, zval *this_ptr, const char *type_spec, ...); ZEND_API int zend_parse_method_parameters_ex(int flags, int num_args TSRMLS_DC, zval *this_ptr, const char *type_spec, ...); +ZEND_API int zend_parse_parameter(int flags, int arg_num TSRMLS_DC, zval **arg, const char *spec, ...); + /* End of parameter parsing API -- andrei */ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_function_entry *functions, HashTable *function_table, int type TSRMLS_DC); diff --git a/Zend/zend_qsort.c b/Zend/zend_qsort.c index bf179904ef..128c48dfc8 100644 --- a/Zend/zend_qsort.c +++ b/Zend/zend_qsort.c @@ -19,6 +19,7 @@ /* $Id$ */ #include "zend.h" +#include "zend_qsort.h" #include <limits.h> @@ -53,7 +54,7 @@ static void _zend_qsort_swap(void *a, void *b, size_t siz) } } -ZEND_API void zend_qsort(void *base, size_t nmemb, size_t siz, compare_func_t compare TSRMLS_DC) +ZEND_API void zend_qsort_r(void *base, size_t nmemb, size_t siz, compare_r_func_t compare, void *arg TSRMLS_DC) { void *begin_stack[QSORT_STACK_SIZE]; void *end_stack[QSORT_STACK_SIZE]; @@ -80,10 +81,10 @@ ZEND_API void zend_qsort(void *base, size_t nmemb, size_t siz, compare_func_t co seg2 = end; while (1) { - for (; seg1 < seg2 && compare(begin, seg1 TSRMLS_CC) > 0; + for (; seg1 < seg2 && compare(begin, seg1 TSRMLS_CC, arg) > 0; seg1 += siz); - for (; seg2 >= seg1 && compare(seg2, begin TSRMLS_CC) > 0; + for (; seg2 >= seg1 && compare(seg2, begin TSRMLS_CC, arg) > 0; seg2 -= siz); if (seg1 >= seg2) @@ -117,6 +118,11 @@ ZEND_API void zend_qsort(void *base, size_t nmemb, size_t siz, compare_func_t co } } +ZEND_API void zend_qsort(void *base, size_t nmemb, size_t siz, compare_func_t compare TSRMLS_DC) +{ + zend_qsort_r(base, nmemb, siz, (compare_r_func_t)compare, NULL TSRMLS_CC); +} + /* * Local Variables: * c-basic-offset: 4 diff --git a/Zend/zend_qsort.h b/Zend/zend_qsort.h index 58c99f26c2..0ce32a77c1 100644 --- a/Zend/zend_qsort.h +++ b/Zend/zend_qsort.h @@ -22,7 +22,9 @@ #define ZEND_QSORT_H BEGIN_EXTERN_C() +typedef int (*compare_r_func_t)(const void *, const void * TSRMLS_DC, void *); ZEND_API void zend_qsort(void *base, size_t nmemb, size_t siz, compare_func_t compare TSRMLS_DC); +ZEND_API void zend_qsort_r(void *base, size_t nmemb, size_t siz, compare_r_func_t compare, void *arg TSRMLS_DC); END_EXTERN_C() #endif /* ZEND_QSORT_H */ diff --git a/ext/date/php_date.c b/ext/date/php_date.c index cc83130e1c..f4115dc7e1 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -2066,12 +2066,12 @@ static zend_object_value date_object_clone_date(zval *this_ptr TSRMLS_DC) return new_ov; } -static zval* date_clone_immutable(zval *object) +static zval* date_clone_immutable(zval *object TSRMLS_DC) { zval *new_object; ALLOC_ZVAL(new_object); - Z_OBJVAL_P(new_object) = date_object_clone_date(object); + Z_OBJVAL_P(new_object) = date_object_clone_date(object TSRMLS_CC); Z_SET_REFCOUNT_P(new_object, 1); Z_SET_ISREF_P(new_object); Z_TYPE_P(new_object) = IS_OBJECT; @@ -2883,14 +2883,18 @@ PHP_FUNCTION(date_format) } /* }}} */ -static void php_date_modify(zval *object, char *modify, int modify_len, zval *return_value TSRMLS_DC) +static int php_date_modify(zval *object, char *modify, int modify_len TSRMLS_DC) { php_date_obj *dateobj; timelib_time *tmp_time; timelib_error_container *err = NULL; dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + + if (!(dateobj->time)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "The DateTime object has not been correctly initialized by its constructor"); + return 0; + } tmp_time = timelib_strtotime(modify, modify_len, &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper); @@ -2901,7 +2905,7 @@ static void php_date_modify(zval *object, char *modify, int modify_len, zval *re php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse time string (%s) at position %d (%c): %s", modify, err->error_messages[0].position, err->error_messages[0].character, err->error_messages[0].message); timelib_time_dtor(tmp_time); - RETURN_FALSE; + return 0; } memcpy(&dateobj->time->relative, &tmp_time->relative, sizeof(struct timelib_rel_time)); @@ -2937,6 +2941,8 @@ static void php_date_modify(zval *object, char *modify, int modify_len, zval *re timelib_update_ts(dateobj->time, NULL); timelib_update_from_sse(dateobj->time); dateobj->time->have_relative = 0; + + return 1; } /* {{{ proto DateTime date_modify(DateTime object, string modify) @@ -2952,9 +2958,11 @@ PHP_FUNCTION(date_modify) RETURN_FALSE; } - php_date_modify(object, modify, modify_len, return_value TSRMLS_CC); + if (php_date_modify(object, modify, modify_len TSRMLS_CC)) { + RETURN_ZVAL(object, 1, 0); + } - RETURN_ZVAL(object, 1, 0); + RETURN_FALSE; } /* }}} */ @@ -2970,10 +2978,12 @@ PHP_METHOD(DateTimeImmutable, modify) RETURN_FALSE; } - new_object = date_clone_immutable(object); - php_date_modify(new_object, modify, modify_len, return_value TSRMLS_CC); + new_object = date_clone_immutable(object TSRMLS_CC); + if (php_date_modify(new_object, modify, modify_len TSRMLS_CC)) { + RETURN_ZVAL(new_object, 0, 1); + } - RETURN_ZVAL(new_object, 0, 1); + RETURN_FALSE; } /* }}} */ @@ -3037,7 +3047,7 @@ PHP_METHOD(DateTimeImmutable, add) RETURN_FALSE; } - new_object = date_clone_immutable(object); + new_object = date_clone_immutable(object TSRMLS_CC); php_date_add(new_object, interval, return_value TSRMLS_CC); RETURN_ZVAL(new_object, 0, 1); @@ -3107,7 +3117,7 @@ PHP_METHOD(DateTimeImmutable, sub) RETURN_FALSE; } - new_object = date_clone_immutable(object); + new_object = date_clone_immutable(object TSRMLS_CC); php_date_sub(new_object, interval, return_value TSRMLS_CC); RETURN_ZVAL(new_object, 0, 1); @@ -3197,7 +3207,7 @@ PHP_METHOD(DateTimeImmutable, setTimezone) RETURN_FALSE; } - new_object = date_clone_immutable(object); + new_object = date_clone_immutable(object TSRMLS_CC); php_date_timezone_set(new_object, timezone_object, return_value TSRMLS_CC); RETURN_ZVAL(new_object, 0, 1); @@ -3280,7 +3290,7 @@ PHP_METHOD(DateTimeImmutable, setTime) RETURN_FALSE; } - new_object = date_clone_immutable(object); + new_object = date_clone_immutable(object TSRMLS_CC); php_date_time_set(new_object, h, i, s, return_value TSRMLS_CC); RETURN_ZVAL(new_object, 0, 1); @@ -3328,7 +3338,7 @@ PHP_METHOD(DateTimeImmutable, setDate) RETURN_FALSE; } - new_object = date_clone_immutable(object); + new_object = date_clone_immutable(object TSRMLS_CC); php_date_date_set(new_object, y, m, d, return_value TSRMLS_CC); RETURN_ZVAL(new_object, 0, 1); @@ -3380,7 +3390,7 @@ PHP_METHOD(DateTimeImmutable, setISODate) RETURN_FALSE; } - new_object = date_clone_immutable(object); + new_object = date_clone_immutable(object TSRMLS_CC); php_date_isodate_set(new_object, y, w, d, return_value TSRMLS_CC); RETURN_ZVAL(new_object, 0, 1); @@ -3426,7 +3436,7 @@ PHP_METHOD(DateTimeImmutable, setTimestamp) RETURN_FALSE; } - new_object = date_clone_immutable(object); + new_object = date_clone_immutable(object TSRMLS_CC); php_date_timestamp_set(new_object, timestamp, return_value TSRMLS_CC); RETURN_ZVAL(new_object, 0, 1); diff --git a/ext/dba/dba_flatfile.c b/ext/dba/dba_flatfile.c index 082aa5cdb6..34aa635a54 100644 --- a/ext/dba/dba_flatfile.c +++ b/ext/dba/dba_flatfile.c @@ -88,15 +88,16 @@ DBA_UPDATE_FUNC(flatfile) gval.dsize = vallen; switch(flatfile_store(dba, gkey, gval, mode==1 ? FLATFILE_INSERT : FLATFILE_REPLACE TSRMLS_CC)) { - case -1: - php_error_docref1(NULL TSRMLS_CC, key, E_WARNING, "Operation not possible"); - return FAILURE; - default: - case 0: - return SUCCESS; - case 1: - php_error_docref1(NULL TSRMLS_CC, key, E_WARNING, "Key already exists"); - return FAILURE; + case 0: + return SUCCESS; + case 1: + return FAILURE; + case -1: + php_error_docref1(NULL TSRMLS_CC, key, E_WARNING, "Operation not possible"); + return FAILURE; + default: + php_error_docref2(NULL TSRMLS_CC, key, val, E_WARNING, "Unknown return value"); + return FAILURE; } } diff --git a/ext/dba/dba_gdbm.c b/ext/dba/dba_gdbm.c index 7534568d39..47dd576496 100644 --- a/ext/dba/dba_gdbm.c +++ b/ext/dba/dba_gdbm.c @@ -104,11 +104,18 @@ DBA_UPDATE_FUNC(gdbm) gval.dptr = (char *) val; gval.dsize = vallen; - if(gdbm_store(dba->dbf, gkey, gval, - mode == 1 ? GDBM_INSERT : GDBM_REPLACE) == 0) - return SUCCESS; - php_error_docref2(NULL TSRMLS_CC, key, val, E_WARNING, "%s", gdbm_strerror(gdbm_errno)); - return FAILURE; + switch (gdbm_store(dba->dbf, gkey, gval, mode == 1 ? GDBM_INSERT : GDBM_REPLACE)) { + case 0: + return SUCCESS; + case 1: + return FAILURE; + case -1: + php_error_docref2(NULL TSRMLS_CC, key, val, E_WARNING, "%s", gdbm_strerror(gdbm_errno)); + return FAILURE; + default: + php_error_docref2(NULL TSRMLS_CC, key, val, E_WARNING, "Unknown return value"); + return FAILURE; + } } DBA_EXISTS_FUNC(gdbm) diff --git a/ext/dba/dba_inifile.c b/ext/dba/dba_inifile.c index e1359b65e9..05ee95c0ec 100644 --- a/ext/dba/dba_inifile.c +++ b/ext/dba/dba_inifile.c @@ -101,7 +101,6 @@ DBA_UPDATE_FUNC(inifile) case 0: return SUCCESS; case 1: - php_error_docref1(NULL TSRMLS_CC, key, E_WARNING, "Key already exists"); return FAILURE; } } diff --git a/ext/dba/dba_qdbm.c b/ext/dba/dba_qdbm.c index 485b1997e6..eeece57011 100644 --- a/ext/dba/dba_qdbm.c +++ b/ext/dba/dba_qdbm.c @@ -96,13 +96,15 @@ DBA_FETCH_FUNC(qdbm) DBA_UPDATE_FUNC(qdbm) { QDBM_DATA; - int result; - result = dpput(dba->dbf, key, keylen, val, vallen, mode == 1 ? DP_DKEEP : DP_DOVER); - if (result) + if (dpput(dba->dbf, key, keylen, val, vallen, mode == 1 ? DP_DKEEP : DP_DOVER)) { return SUCCESS; + } + + if (dpecode != DP_EKEEP) { + php_error_docref2(NULL TSRMLS_CC, key, val, E_WARNING, "%s", dperrmsg(dpecode)); + } - php_error_docref2(NULL TSRMLS_CC, key, val, E_WARNING, "%s", dperrmsg(dpecode)); return FAILURE; } diff --git a/ext/dba/tests/dba_db1.phpt b/ext/dba/tests/dba_db1.phpt index a24600350f..d0e530e026 100644 --- a/ext/dba/tests/dba_db1.phpt +++ b/ext/dba/tests/dba_db1.phpt @@ -18,6 +18,8 @@ database handler: db1 Content String 2 Content 2 replaced Read during write: not allowed +"key number 6" written +Failed to write "key number 6" 2nd time Content 2 replaced 2nd time The 6th value array(3) { @@ -33,6 +35,8 @@ array(3) { Content String 2 Content 2 replaced Read during write: not allowed +"key number 6" written +Failed to write "key number 6" 2nd time Content 2 replaced 2nd time The 6th value array(3) { diff --git a/ext/dba/tests/dba_db2.phpt b/ext/dba/tests/dba_db2.phpt index 89d8a926e1..1cfbb3e340 100644 --- a/ext/dba/tests/dba_db2.phpt +++ b/ext/dba/tests/dba_db2.phpt @@ -18,6 +18,8 @@ database handler: db2 Content String 2 Content 2 replaced Read during write: not allowed +"key number 6" written +Failed to write "key number 6" 2nd time Content 2 replaced 2nd time The 6th value array(3) { @@ -33,6 +35,8 @@ array(3) { Content String 2 Content 2 replaced Read during write: not allowed +"key number 6" written +Failed to write "key number 6" 2nd time Content 2 replaced 2nd time The 6th value array(3) { diff --git a/ext/dba/tests/dba_db3.phpt b/ext/dba/tests/dba_db3.phpt index 257c882175..5de7e5a041 100644 --- a/ext/dba/tests/dba_db3.phpt +++ b/ext/dba/tests/dba_db3.phpt @@ -18,6 +18,8 @@ database handler: db3 Content String 2 Content 2 replaced Read during write: not allowed +"key number 6" written +Failed to write "key number 6" 2nd time Content 2 replaced 2nd time The 6th value array(3) { @@ -33,6 +35,8 @@ array(3) { Content String 2 Content 2 replaced Read during write: not allowed +"key number 6" written +Failed to write "key number 6" 2nd time Content 2 replaced 2nd time The 6th value array(3) { diff --git a/ext/dba/tests/dba_db4_000.phpt b/ext/dba/tests/dba_db4_000.phpt index bbbc52c9f1..17db4bb62d 100644 --- a/ext/dba/tests/dba_db4_000.phpt +++ b/ext/dba/tests/dba_db4_000.phpt @@ -22,6 +22,8 @@ database handler: db4 Content String 2 Content 2 replaced Read during write: not allowed +"key number 6" written +Failed to write "key number 6" 2nd time Content 2 replaced 2nd time The 6th value array(3) { @@ -37,6 +39,8 @@ array(3) { Content String 2 Content 2 replaced Read during write: not allowed +"key number 6" written +Failed to write "key number 6" 2nd time Content 2 replaced 2nd time The 6th value array(3) { diff --git a/ext/dba/tests/dba_dbm.phpt b/ext/dba/tests/dba_dbm.phpt index dd1fe1e31c..8bea8463da 100644 --- a/ext/dba/tests/dba_dbm.phpt +++ b/ext/dba/tests/dba_dbm.phpt @@ -18,6 +18,8 @@ database handler: dbm Content String 2 Content 2 replaced Read during write: not allowed +"key number 6" written +Failed to write "key number 6" 2nd time Content 2 replaced 2nd time The 6th value array(3) { @@ -33,6 +35,8 @@ array(3) { Content String 2 Content 2 replaced Read during write: not allowed +"key number 6" written +Failed to write "key number 6" 2nd time Content 2 replaced 2nd time The 6th value array(3) { diff --git a/ext/dba/tests/dba_flatfile.phpt b/ext/dba/tests/dba_flatfile.phpt index 8e1ca6a933..ac7f86ebda 100644 --- a/ext/dba/tests/dba_flatfile.phpt +++ b/ext/dba/tests/dba_flatfile.phpt @@ -22,6 +22,8 @@ database handler: flatfile Content String 2 Content 2 replaced Read during write: not allowed +"key number 6" written +Failed to write "key number 6" 2nd time Content 2 replaced 2nd time The 6th value array(3) { @@ -37,6 +39,8 @@ array(3) { Content String 2 Content 2 replaced Read during write: not allowed +"key number 6" written +Failed to write "key number 6" 2nd time Content 2 replaced 2nd time The 6th value array(3) { diff --git a/ext/dba/tests/dba_gdbm.phpt b/ext/dba/tests/dba_gdbm.phpt index 33d7d20615..e68e8b7409 100644 --- a/ext/dba/tests/dba_gdbm.phpt +++ b/ext/dba/tests/dba_gdbm.phpt @@ -21,6 +21,8 @@ database handler: gdbm Content String 2 Content 2 replaced Read during write:%sallowed +"key number 6" written +Failed to write "key number 6" 2nd time Content 2 replaced 2nd time The 6th value array(3) { diff --git a/ext/dba/tests/dba_handler.inc b/ext/dba/tests/dba_handler.inc index 1c3f5127ef..a950e903af 100644 --- a/ext/dba/tests/dba_handler.inc +++ b/ext/dba/tests/dba_handler.inc @@ -46,8 +46,16 @@ do { echo "Read during write: allowed\n"; } if ($db_writer!==FALSE) { - dba_insert("key number 6", "The 6th value", $db_writer); - @dba_insert("key number 6", "The 6th value inserted again would be an error", $db_writer); + if (dba_insert("key number 6", "The 6th value", $db_writer)) { + echo '"key number 6" written' . "\n"; + } else { + echo 'Failed to write "key number 6"' . "\n"; + } + if (dba_insert("key number 6", "The 6th value inserted again would be an error", $db_writer)) { + echo '"key number 6" written 2nd time' . "\n"; + } else { + echo 'Failed to write "key number 6" 2nd time' . "\n"; + } dba_replace("key2", "Content 2 replaced 2nd time", $db_writer); dba_delete("key4", $db_writer); echo dba_fetch("key2", $db_writer)."\n"; diff --git a/ext/dba/tests/dba_inifile.phpt b/ext/dba/tests/dba_inifile.phpt index 81ab738796..5975d25f4d 100644 --- a/ext/dba/tests/dba_inifile.phpt +++ b/ext/dba/tests/dba_inifile.phpt @@ -18,6 +18,8 @@ database handler: inifile Content String 2 Content 2 replaced Read during write: not allowed +"key number 6" written +Failed to write "key number 6" 2nd time Content 2 replaced 2nd time The 6th value array(3) { @@ -33,6 +35,8 @@ array(3) { Content String 2 Content 2 replaced Read during write: not allowed +"key number 6" written +Failed to write "key number 6" 2nd time Content 2 replaced 2nd time The 6th value array(3) { diff --git a/ext/dba/tests/dba_ndbm.phpt b/ext/dba/tests/dba_ndbm.phpt index b0f5542de4..193db6f94d 100644 --- a/ext/dba/tests/dba_ndbm.phpt +++ b/ext/dba/tests/dba_ndbm.phpt @@ -18,6 +18,8 @@ database handler: ndbm Content String 2 Content 2 replaced Read during write: not allowed +"key number 6" written +Failed to write "key number 6" 2nd time Content 2 replaced 2nd time The 6th value array(3) { @@ -33,6 +35,8 @@ array(3) { Content String 2 Content 2 replaced Read during write: not allowed +"key number 6" written +Failed to write "key number 6" 2nd time Content 2 replaced 2nd time The 6th value array(3) { diff --git a/ext/dba/tests/dba_qdbm.phpt b/ext/dba/tests/dba_qdbm.phpt index ef216d9258..e2205baa26 100644 --- a/ext/dba/tests/dba_qdbm.phpt +++ b/ext/dba/tests/dba_qdbm.phpt @@ -19,6 +19,8 @@ database handler: qdbm Content String 2 Content 2 replaced Read during write:%sallowed +"key number 6" written +Failed to write "key number 6" 2nd time Content 2 replaced 2nd time The 6th value array(3) { diff --git a/ext/dba/tests/dba_tcadb.phpt b/ext/dba/tests/dba_tcadb.phpt index 52dd4de336..28b6dd8f0b 100644 --- a/ext/dba/tests/dba_tcadb.phpt +++ b/ext/dba/tests/dba_tcadb.phpt @@ -22,6 +22,8 @@ database handler: tcadb Content String 2 Content 2 replaced Read during write: not allowed +"key number 6" written +Failed to write "key number 6" 2nd time Content 2 replaced 2nd time The 6th value array(3) { @@ -37,6 +39,8 @@ array(3) { Content String 2 Content 2 replaced Read during write: not allowed +"key number 6" written +Failed to write "key number 6" 2nd time Content 2 replaced 2nd time The 6th value array(3) { diff --git a/ext/mysqlnd/mysqlnd.c b/ext/mysqlnd/mysqlnd.c index ebc4a774a6..96c420dee9 100644 --- a/ext/mysqlnd/mysqlnd.c +++ b/ext/mysqlnd/mysqlnd.c @@ -95,6 +95,11 @@ MYSQLND_METHOD(mysqlnd_conn_data, free_options)(MYSQLND_CONN_DATA * conn TSRMLS_ mnd_pefree(conn->options->cfg_section, pers); conn->options->cfg_section = NULL; } + if (conn->options->connect_attr) { + zend_hash_destroy(conn->options->connect_attr); + mnd_pefree(conn->options->connect_attr, pers); + conn->options->connect_attr = NULL; + } } /* }}} */ @@ -797,13 +802,14 @@ MYSQLND_METHOD(mysqlnd_conn_data, connect_handshake)(MYSQLND_CONN_DATA * conn, goto err; } + conn->client_flag = mysql_flags; + conn->server_capabilities = greet_packet->server_capabilities; + if (FAIL == mysqlnd_connect_run_authentication(conn, user, passwd, db, db_len, (size_t) passwd_len, greet_packet, conn->options, mysql_flags TSRMLS_CC)) { goto err; } - conn->client_flag = mysql_flags; - conn->server_capabilities = greet_packet->server_capabilities; conn->upsert_status->warning_count = 0; conn->upsert_status->server_status = greet_packet->server_status; conn->upsert_status->affected_rows = 0; @@ -811,6 +817,8 @@ MYSQLND_METHOD(mysqlnd_conn_data, connect_handshake)(MYSQLND_CONN_DATA * conn, PACKET_FREE(greet_packet); DBG_RETURN(PASS); err: + conn->client_flag = 0; + conn->server_capabilities = 0; PACKET_FREE(greet_packet); DBG_RETURN(FAIL); } @@ -1086,6 +1094,7 @@ MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn_handle, DBG_ENTER("mysqlnd_conn::connect"); if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) { + mysqlnd_options4(conn_handle, MYSQL_OPT_CONNECT_ATTR_ADD, "_client_name", "mysqlnd"); ret = conn->m->connect(conn, host, user, passwd, passwd_len, db, db_len, port, socket_or_pipe, mysql_flags TSRMLS_CC); conn->m->local_tx_end(conn, this_func, FAIL TSRMLS_CC); @@ -1094,6 +1103,7 @@ MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn_handle, } /* }}} */ + /* {{{ mysqlnd_connect */ PHPAPI MYSQLND * mysqlnd_connect(MYSQLND * conn_handle, const char * host, const char * user, @@ -2375,6 +2385,19 @@ MYSQLND_METHOD(mysqlnd_conn_data, set_client_option)(MYSQLND_CONN_DATA * const c conn->options->flags &= ~CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS; } break; + case MYSQL_OPT_CONNECT_ATTR_RESET: + if (conn->options->connect_attr) { + DBG_INF_FMT("Before reset %d attribute(s)", zend_hash_num_elements(conn->options->connect_attr)); + zend_hash_clean(conn->options->connect_attr); + } + break; + case MYSQL_OPT_CONNECT_ATTR_DELETE: + if (conn->options->connect_attr && value) { + DBG_INF_FMT("Before delete %d attribute(s)", zend_hash_num_elements(conn->options->connect_attr)); + zend_hash_del(conn->options->connect_attr, value, strlen(value)); + DBG_INF_FMT("%d left", zend_hash_num_elements(conn->options->connect_attr)); + } + break; #ifdef WHEN_SUPPORTED_BY_MYSQLI case MYSQL_SHARED_MEMORY_BASE_NAME: case MYSQL_OPT_USE_RESULT: @@ -2395,6 +2418,83 @@ end: /* }}} */ +/* {{{ connect_attr_item_edtor */ +static void +connect_attr_item_edtor(void * pDest) +{ +#ifdef ZTS + TSRMLS_FETCH(); +#endif + DBG_ENTER("connect_attr_item_edtor"); + mnd_efree(*(char **) pDest); + DBG_VOID_RETURN; +} +/* }}} */ + + +/* {{{ connect_attr_item_pdtor */ +static void +connect_attr_item_pdtor(void * pDest) +{ +#ifdef ZTS + TSRMLS_FETCH(); +#endif + DBG_ENTER("connect_attr_item_pdtor"); + mnd_pefree(*(char **) pDest, 1); + DBG_VOID_RETURN; +} +/* }}} */ + + +/* {{{ mysqlnd_conn_data::set_client_option_2d */ +static enum_func_status +MYSQLND_METHOD(mysqlnd_conn_data, set_client_option_2d)(MYSQLND_CONN_DATA * const conn, + enum mysqlnd_option option, + const char * const key, + const char * const value + TSRMLS_DC) +{ + size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, set_client_option_2d); + enum_func_status ret = PASS; + DBG_ENTER("mysqlnd_conn_data::set_client_option_2d"); + DBG_INF_FMT("conn=%llu option=%u", conn->thread_id, option); + + if (PASS != conn->m->local_tx_start(conn, this_func TSRMLS_CC)) { + goto end; + } + switch (option) { + case MYSQL_OPT_CONNECT_ATTR_ADD: + if (!conn->options->connect_attr) { + DBG_INF("Initializing connect_attr hash"); + conn->options->connect_attr = mnd_pemalloc(sizeof(HashTable), conn->persistent); + if (!conn->options->connect_attr) { + goto oom; + } + zend_hash_init(conn->options->connect_attr, 0, NULL, conn->persistent? connect_attr_item_pdtor:connect_attr_item_edtor, conn->persistent); + } + DBG_INF_FMT("Adding [%s][%s]", key, value); + { + const char * copyv = mnd_pestrdup(value, conn->persistent); + if (!copyv) { + goto oom; + } + zend_hash_update(conn->options->connect_attr, key, strlen(key), ©v, sizeof(char *), NULL); + } + break; + default: + ret = FAIL; + } + conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC); + DBG_RETURN(ret); +oom: + SET_OOM_ERROR(*conn->error_info); + conn->m->local_tx_end(conn, this_func, FAIL TSRMLS_CC); +end: + DBG_RETURN(FAIL); +} +/* }}} */ + + /* {{{ mysqlnd_conn_data::use_result */ static MYSQLND_RES * MYSQLND_METHOD(mysqlnd_conn_data, use_result)(MYSQLND_CONN_DATA * const conn TSRMLS_DC) @@ -2662,7 +2762,9 @@ MYSQLND_CLASS_METHODS_START(mysqlnd_conn_data) MYSQLND_METHOD(mysqlnd_conn_data, get_updated_connect_flags), MYSQLND_METHOD(mysqlnd_conn_data, connect_handshake), MYSQLND_METHOD(mysqlnd_conn_data, simple_command_send_request), - MYSQLND_METHOD(mysqlnd_conn_data, fetch_auth_plugin_by_name) + MYSQLND_METHOD(mysqlnd_conn_data, fetch_auth_plugin_by_name), + + MYSQLND_METHOD(mysqlnd_conn_data, set_client_option_2d) MYSQLND_CLASS_METHODS_END; diff --git a/ext/mysqlnd/mysqlnd.h b/ext/mysqlnd/mysqlnd.h index 7e02126f3b..bf0f70b405 100644 --- a/ext/mysqlnd/mysqlnd.h +++ b/ext/mysqlnd/mysqlnd.h @@ -207,6 +207,7 @@ PHPAPI void mysqlnd_set_local_infile_handler(MYSQLND_CONN_DATA * const conn, con #define mysqlnd_set_character_set(conn, cs) ((conn)->data)->m->set_charset((conn)->data, (cs) TSRMLS_CC) #define mysqlnd_stat(conn, msg, msg_len) ((conn)->data)->m->get_server_statistics(((conn)->data), (msg), (msg_len) TSRMLS_CC) #define mysqlnd_options(conn, opt, value) ((conn)->data)->m->set_client_option((conn)->data, (opt), (value) TSRMLS_CC) +#define mysqlnd_options4(conn, opt, k, v) ((conn)->data)->m->set_client_option_2d((conn)->data, (opt), (k), (v) TSRMLS_CC) #define mysqlnd_set_server_option(conn, op) ((conn)->data)->m->set_server_option((conn)->data, (op) TSRMLS_CC) /* Escaping */ diff --git a/ext/mysqlnd/mysqlnd_auth.c b/ext/mysqlnd/mysqlnd_auth.c index a3b4f36a2e..8611d99864 100644 --- a/ext/mysqlnd/mysqlnd_auth.c +++ b/ext/mysqlnd/mysqlnd_auth.c @@ -28,7 +28,6 @@ #include "mysqlnd_charset.h" #include "mysqlnd_debug.h" - /* {{{ mysqlnd_auth_handshake */ enum_func_status mysqlnd_auth_handshake(MYSQLND_CONN_DATA * conn, @@ -99,6 +98,10 @@ mysqlnd_auth_handshake(MYSQLND_CONN_DATA * conn, auth_packet->auth_data = auth_plugin_data; auth_packet->auth_data_len = auth_plugin_data_len; auth_packet->auth_plugin_name = auth_protocol; + + if (conn->server_capabilities & CLIENT_CONNECT_ATTRS) { + auth_packet->connect_attr = conn->options->connect_attr; + } if (!PACKET_WRITE(auth_packet, conn)) { goto end; diff --git a/ext/mysqlnd/mysqlnd_enum_n_def.h b/ext/mysqlnd/mysqlnd_enum_n_def.h index abaaf1f43e..cf5b02728b 100644 --- a/ext/mysqlnd/mysqlnd_enum_n_def.h +++ b/ext/mysqlnd/mysqlnd_enum_n_def.h @@ -168,6 +168,9 @@ typedef enum mysqlnd_option MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH, + MYSQL_OPT_CONNECT_ATTR_RESET, + MYSQL_OPT_CONNECT_ATTR_ADD, + MYSQL_OPT_CONNECT_ATTR_DELETE, MYSQL_SERVER_PUBLIC_KEY, MYSQL_ENABLE_CLEARTEXT_PLUGIN, MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS, diff --git a/ext/mysqlnd/mysqlnd_libmysql_compat.h b/ext/mysqlnd/mysqlnd_libmysql_compat.h index c967fb3a9f..e3ab9eefa9 100644 --- a/ext/mysqlnd/mysqlnd_libmysql_compat.h +++ b/ext/mysqlnd/mysqlnd_libmysql_compat.h @@ -106,7 +106,8 @@ #define mysql_stmt_more_results(s) mysqlnd_stmt_more_results((s)) #define mysql_thread_safe() mysqlnd_thread_safe() #define mysql_info(r) mysqlnd_info((r)) -#define mysql_options(r,a,b) mysqlnd_options((r), (a), (b)) +#define mysql_options(c,a,v) mysqlnd_options((c), (a), (v)) +#define mysql_options4(c,a,k,v) mysqlnd_options4((c), (a), (k), (v)) #define mysql_stmt_init(r) mysqlnd_stmt_init((r)) #define mysql_free_result(r) mysqlnd_free_result((r), FALSE) #define mysql_store_result(r) mysqlnd_store_result((r)) diff --git a/ext/mysqlnd/mysqlnd_structs.h b/ext/mysqlnd/mysqlnd_structs.h index 6302c81c6a..ecb1d89216 100644 --- a/ext/mysqlnd/mysqlnd_structs.h +++ b/ext/mysqlnd/mysqlnd_structs.h @@ -172,7 +172,7 @@ typedef struct st_mysqlnd_options The ABI will be broken and the methods structure will be somewhere else in the memory which can crash external code. Feel free to reuse these. */ - char * unused2; + HashTable * connect_attr; char * unused3; char * unused4; char * unused5; @@ -489,6 +489,8 @@ typedef enum_func_status (*func_mysqlnd_conn_data__connect_handshake)(MYSQLND_CO typedef enum_func_status (*func_mysqlnd_conn_data__simple_command_send_request)(MYSQLND_CONN_DATA * conn, enum php_mysqlnd_server_command command, const zend_uchar * const arg, size_t arg_len, zend_bool silent, zend_bool ignore_upsert_status TSRMLS_DC); typedef struct st_mysqlnd_authentication_plugin * (*func_mysqlnd_conn_data__fetch_auth_plugin_by_name)(const char * const requested_protocol TSRMLS_DC); +typedef enum_func_status (*func_mysqlnd_conn_data__set_client_option_2d)(MYSQLND_CONN_DATA * const conn, enum mysqlnd_option option, const char * const key, const char * const value TSRMLS_DC); + struct st_mysqlnd_conn_data_methods { func_mysqlnd_conn_data__init init; @@ -573,6 +575,8 @@ struct st_mysqlnd_conn_data_methods func_mysqlnd_conn_data__connect_handshake connect_handshake; func_mysqlnd_conn_data__simple_command_send_request simple_command_send_request; func_mysqlnd_conn_data__fetch_auth_plugin_by_name fetch_auth_plugin_by_name; + + func_mysqlnd_conn_data__set_client_option_2d set_client_option_2d; }; diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.c b/ext/mysqlnd/mysqlnd_wireprotocol.c index 7c3bf1395f..669970789b 100644 --- a/ext/mysqlnd/mysqlnd_wireprotocol.c +++ b/ext/mysqlnd/mysqlnd_wireprotocol.c @@ -212,6 +212,24 @@ php_mysqlnd_net_store_length(zend_uchar *packet, uint64_t length) /* }}} */ +/* {{{ php_mysqlnd_net_store_length_size */ +size_t +php_mysqlnd_net_store_length_size(uint64_t length) +{ + if (length < (uint64_t) L64(251)) { + return 1; + } + if (length < (uint64_t) L64(65536)) { + return 3; + } + if (length < (uint64_t) L64(16777216)) { + return 4; + } + return 8; +} +/* }}} */ + + /* {{{ php_mysqlnd_read_error_from_line */ static enum_func_status php_mysqlnd_read_error_from_line(zend_uchar *buf, size_t buf_len, @@ -459,7 +477,7 @@ void php_mysqlnd_greet_free_mem(void * _packet, zend_bool stack_allocation TSRML /* }}} */ -#define AUTH_WRITE_BUFFER_LEN (MYSQLND_HEADER_SIZE + MYSQLND_MAX_ALLOWED_USER_LEN + SCRAMBLE_LENGTH + MYSQLND_MAX_ALLOWED_DB_LEN + 1 + 1024) +#define AUTH_WRITE_BUFFER_LEN (MYSQLND_HEADER_SIZE + MYSQLND_MAX_ALLOWED_USER_LEN + SCRAMBLE_LENGTH + MYSQLND_MAX_ALLOWED_DB_LEN + 1 + 4096) /* {{{ php_mysqlnd_auth_write */ static @@ -540,6 +558,52 @@ size_t php_mysqlnd_auth_write(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC p+= len; *p++= '\0'; } + + if (packet->connect_attr && zend_hash_num_elements(packet->connect_attr)) { + HashPosition pos_value; + const char ** entry_value; + size_t ca_payload_len = 0; + zend_hash_internal_pointer_reset_ex(packet->connect_attr, &pos_value); + while (SUCCESS == zend_hash_get_current_data_ex(packet->connect_attr, (void **)&entry_value, &pos_value)) { + char *s_key; + unsigned int s_len; + unsigned long num_key; + size_t value_len = strlen(*entry_value); + + if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(packet->connect_attr, &s_key, &s_len, &num_key, 0, &pos_value)) { + ca_payload_len += php_mysqlnd_net_store_length_size(s_len); + ca_payload_len += s_len; + ca_payload_len += php_mysqlnd_net_store_length_size(value_len); + ca_payload_len += value_len; + } + zend_hash_move_forward_ex(conn->options->connect_attr, &pos_value); + } + + if ((sizeof(buffer) - (p - buffer)) >= (ca_payload_len + php_mysqlnd_net_store_length_size(ca_payload_len))) { + p = php_mysqlnd_net_store_length(p, ca_payload_len); + + zend_hash_internal_pointer_reset_ex(packet->connect_attr, &pos_value); + while (SUCCESS == zend_hash_get_current_data_ex(packet->connect_attr, (void **)&entry_value, &pos_value)) { + char *s_key; + unsigned int s_len; + unsigned long num_key; + size_t value_len = strlen(*entry_value); + if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(packet->connect_attr, &s_key, &s_len, &num_key, 0, &pos_value)) { + /* copy key */ + p = php_mysqlnd_net_store_length(p, s_len); + memcpy(p, s_key, s_len); + p+= s_len; + /* copy value */ + p = php_mysqlnd_net_store_length(p, value_len); + memcpy(p, *entry_value, value_len); + p+= value_len; + } + zend_hash_move_forward_ex(conn->options->connect_attr, &pos_value); + } + } else { + /* cannot put the data - skip */ + } + } } if (packet->is_change_user_packet) { if (PASS != conn->m->simple_command(conn, COM_CHANGE_USER, buffer + MYSQLND_HEADER_SIZE, p - buffer - MYSQLND_HEADER_SIZE, diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.h b/ext/mysqlnd/mysqlnd_wireprotocol.h index e9c9024d04..26dd4c65ae 100644 --- a/ext/mysqlnd/mysqlnd_wireprotocol.h +++ b/ext/mysqlnd/mysqlnd_wireprotocol.h @@ -103,7 +103,7 @@ typedef struct st_mysqlnd_packet_auth { zend_bool send_auth_data; zend_bool is_change_user_packet; zend_bool silent; - + HashTable *connect_attr; } MYSQLND_PACKET_AUTH; /* Auth response packet */ diff --git a/ext/standard/file.c b/ext/standard/file.c index 74577ac495..cf8b159556 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -159,6 +159,7 @@ static ZEND_RSRC_DTOR_FUNC(file_context_dtor) static void file_globals_ctor(php_file_globals *file_globals_p TSRMLS_DC) { FG(pclose_ret) = 0; + FG(pclose_wait) = 0; FG(user_stream_current_filename) = NULL; FG(def_chunk_size) = PHP_SOCK_CHUNK_SIZE; FG(wrapper_errors) = NULL; @@ -960,7 +961,9 @@ PHP_FUNCTION(pclose) PHP_STREAM_TO_ZVAL(stream, &arg1); + FG(pclose_wait) = 1; zend_list_delete(stream->rsrc_id); + FG(pclose_wait) = 0; RETURN_LONG(FG(pclose_ret)); } /* }}} */ diff --git a/ext/standard/file.h b/ext/standard/file.h index 0a4512ecd4..2bcdfd64bf 100644 --- a/ext/standard/file.h +++ b/ext/standard/file.h @@ -115,7 +115,7 @@ typedef struct _php_meta_tags_data { php_meta_tags_token php_next_meta_token(php_meta_tags_data * TSRMLS_DC); typedef struct { - int pclose_ret; + int pclose_ret; size_t def_chunk_size; long auto_detect_line_endings; long default_socket_timeout; @@ -126,6 +126,7 @@ typedef struct { HashTable *stream_wrappers; /* per-request copy of url_stream_wrappers_hash */ HashTable *stream_filters; /* per-request copy of stream_filters_hash */ HashTable *wrapper_errors; /* key: wrapper address; value: linked list of char* */ + int pclose_wait; } php_file_globals; #ifdef ZTS diff --git a/ext/standard/proc_open.c b/ext/standard/proc_open.c index 1edfe78849..4e39a40be4 100644 --- a/ext/standard/proc_open.c +++ b/ext/standard/proc_open.c @@ -208,6 +208,7 @@ static void proc_open_rsrc_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) DWORD wstatus; #elif HAVE_SYS_WAIT_H int wstatus; + int waitpid_options = 0; pid_t wait_pid; #endif @@ -220,18 +221,27 @@ static void proc_open_rsrc_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) } #ifdef PHP_WIN32 - WaitForSingleObject(proc->childHandle, INFINITE); + if (FG(pclose_wait)) { + WaitForSingleObject(proc->childHandle, INFINITE); + } GetExitCodeProcess(proc->childHandle, &wstatus); - FG(pclose_ret) = wstatus; + if (wstatus == STILL_ACTIVE) { + FG(pclose_ret) = -1; + } else { + FG(pclose_ret) = wstatus; + } CloseHandle(proc->childHandle); #elif HAVE_SYS_WAIT_H + if (!FG(pclose_wait)) { + waitpid_options = WNOHANG; + } do { - wait_pid = waitpid(proc->child, &wstatus, 0); + wait_pid = waitpid(proc->child, &wstatus, waitpid_options); } while (wait_pid == -1 && errno == EINTR); - if (wait_pid == -1) { + if (wait_pid <= 0) { FG(pclose_ret) = -1; } else { if (WIFEXITED(wstatus)) @@ -300,7 +310,9 @@ PHP_FUNCTION(proc_close) ZEND_FETCH_RESOURCE(proc, struct php_process_handle *, &zproc, -1, "process", le_proc_open); + FG(pclose_wait) = 1; zend_list_delete(Z_LVAL_P(zproc)); + FG(pclose_wait) = 0; RETURN_LONG(FG(pclose_ret)); } /* }}} */ diff --git a/ext/standard/string.c b/ext/standard/string.c index b4f4fcbd2d..e245ce3fb6 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -2851,7 +2851,7 @@ static inline void php_strtr_populate_shift(PATNREPL *patterns, int patnum, int } /* }}} */ /* {{{ php_strtr_compare_hash_suffix */ -static int php_strtr_compare_hash_suffix(const void *a, const void *b, void *ctx_g) +static int php_strtr_compare_hash_suffix(const void *a, const void *b TSRMLS_DC, void *ctx_g) { const PPRES *res = ctx_g; const PATNREPL *pnr_a = a, @@ -2877,62 +2877,6 @@ static int php_strtr_compare_hash_suffix(const void *a, const void *b, void *ctx } } /* }}} */ -/* {{{ Sorting (no zend_qsort_r in this PHP version) */ -#define HS_LEFT(i) ((i) * 2 + 1) -#define HS_RIGHT(i) ((i) * 2 + 2) -#define HS_PARENT(i) (((i) - 1) / 2); -#define HS_OFF(data, i) ((void *)(&((data)->arr)[i])) -#define HS_CMP_CALL(data, i1, i2) \ - (php_strtr_compare_hash_suffix(HS_OFF((data), (i1)), HS_OFF((data), (i2)), (data)->res)) -struct hs_data { - PATNREPL *arr; - size_t nel; - size_t heapel; - PPRES *res; -}; -static inline void php_strtr_swap(PATNREPL *a, PATNREPL *b) -{ - PATNREPL tmp = *a; - *a = *b; - *b = tmp; -} -static inline void php_strtr_fix_heap(struct hs_data *data, size_t i) -{ - size_t li = HS_LEFT(i), - ri = HS_RIGHT(i), - largei; - if (li < data->heapel && HS_CMP_CALL(data, li, i) > 0) { - largei = li; - } else { - largei = i; - } - if (ri < data->heapel && HS_CMP_CALL(data, ri, largei) > 0) { - largei = ri; - } - if (largei != i) { - php_strtr_swap(HS_OFF(data, i), HS_OFF(data, largei)); - php_strtr_fix_heap(data, largei); - } -} -static inline void php_strtr_build_heap(struct hs_data *data) -{ - size_t i; - for (i = data->nel / 2; i > 0; i--) { - php_strtr_fix_heap(data, i - 1); - } -} -static inline void php_strtr_heapsort(PATNREPL *arr, size_t nel, PPRES *res) -{ - struct hs_data data = { arr, nel, nel, res }; - size_t i; - php_strtr_build_heap(&data); - for (i = nel; i > 1; i--) { - php_strtr_swap(arr, HS_OFF(&data, i - 1)); - data.heapel--; - php_strtr_fix_heap(&data, 0); - } -} -/* }}} */ /* {{{ php_strtr_free_strp */ static void php_strtr_free_strp(void *strp) { @@ -3030,7 +2974,13 @@ static PPRES *php_strtr_array_prepare(STR *text, PATNREPL *patterns, int patnum, res->patterns = safe_emalloc(patnum, sizeof(*res->patterns), 0); memcpy(res->patterns, patterns, sizeof(*patterns) * patnum); - php_strtr_heapsort(res->patterns, patnum, res); +#ifdef ZTS + zend_qsort_r(res->patterns, patnum, sizeof(*res->patterns), + php_strtr_compare_hash_suffix, res, NULL); /* tsrmls not needed */ +#else + zend_qsort_r(res->patterns, patnum, sizeof(*res->patterns), + php_strtr_compare_hash_suffix, res); +#endif res->prefix = safe_emalloc(patnum, sizeof(*res->prefix), 0); for (i = 0; i < patnum; i++) { |