Merge branch 'PHP-5.5' of git.php.net:php-src into PHP-5.5

* 'PHP-5.5' of git.php.net:php-src:
  Fixed bug #63988 (Two Date tests fail) only for PHP-5.5
  - Fixed ZTS build
  Dereferencing process-handles no longer waits on those processes.
  revert change. now it doesn't compile again...someone should fix ext/date...
  Use two dtors thus allow allocation based on the alloc model of the connection.
  plug a leak - forgot ot use the dtor already written
  Revert "Apply the fputcsv test fix to SplFileObject_fputcsv.phpt. Mea culpa."
  Revert "Update fputcsv() to escape all characters equally."
  Add support for connect attributes, as of MySQL 5.6
  Bug #62489: dba_insert not working as expected
  UPGRADING.INTERNALS: document zend_qsort_r
  Add zend_qsort_r & use it in strtr
  NEWS for bug #63893
  Update README.PARAMETER_PARSING_API
  Export zend_parse_parameter()
  Expose zend_parse_arg() as zend_parse_parameter()
  zend_parse_parameters: allow ! for non pointers
This commit is contained in:
Stanislav Malyshev 2013-01-18 13:42:19 -08:00
commit cd619b47f3
36 changed files with 416 additions and 130 deletions

12
NEWS
View File

@ -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! >>>

View File

@ -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

View File

@ -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
========================

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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 */

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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) {

View File

@ -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) {

View File

@ -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) {

View File

@ -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) {

View File

@ -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) {

View File

@ -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) {

View File

@ -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) {

View File

@ -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";

View File

@ -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) {

View File

@ -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) {

View File

@ -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) {

View File

@ -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) {

View File

@ -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), &copyv, 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;

View File

@ -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 */

View File

@ -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;

View File

@ -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,

View File

@ -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))

View File

@ -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;
};

View File

@ -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,

View File

@ -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 */

View File

@ -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));
}
/* }}} */

View File

@ -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

View File

@ -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));
}
/* }}} */

View File

@ -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++) {