Skip to content

Commit 09e29e6

Browse files
committed
Fixed possible crash with opcache (We should never edit a zval in place)
1 parent 399c95c commit 09e29e6

File tree

1 file changed

+44
-50
lines changed

1 file changed

+44
-50
lines changed

php_memcached.c

Lines changed: 44 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1819,8 +1819,7 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke
18191819
s_memc_set_status(intern, MEMCACHED_SUCCESS, 0);
18201820

18211821
ZEND_HASH_FOREACH_KEY_VAL (Z_ARRVAL_P(entries), num_key, skey, value) {
1822-
1823-
zend_string *str_key;
1822+
zend_string *str_key = NULL;
18241823

18251824
if (skey) {
18261825
str_key = skey;
@@ -2337,7 +2336,6 @@ PHP_METHOD(Memcached, addServers)
23372336
zval *servers;
23382337
zval *entry;
23392338
zval *z_host, *z_port, *z_weight = NULL;
2340-
uint32_t weight = 0;
23412339
HashPosition pos;
23422340
int entry_size, i = 0;
23432341
memcached_server_st *list = NULL;
@@ -2361,6 +2359,10 @@ PHP_METHOD(Memcached, addServers)
23612359
entry_size = zend_hash_num_elements(Z_ARRVAL_P(entry));
23622360

23632361
if (entry_size > 1) {
2362+
zend_string *host;
2363+
zend_long port;
2364+
uint32_t weight;
2365+
23642366
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(entry), &pos);
23652367

23662368
/* Check that we have a host */
@@ -2378,8 +2380,8 @@ PHP_METHOD(Memcached, addServers)
23782380
continue;
23792381
}
23802382

2381-
convert_to_string_ex(z_host);
2382-
convert_to_long_ex(z_port);
2383+
host = zval_get_string(z_host);
2384+
port = zval_get_long(z_port);
23832385

23842386
weight = 0;
23852387
if (entry_size > 2) {
@@ -2389,12 +2391,12 @@ PHP_METHOD(Memcached, addServers)
23892391
php_error_docref(NULL, E_WARNING, "could not get server weight for entry #%d", i+1);
23902392
}
23912393

2392-
convert_to_long_ex(z_weight);
2393-
weight = Z_LVAL_P(z_weight);
2394+
weight = zval_get_long(z_weight);
23942395
}
23952396

2396-
list = memcached_server_list_append_with_weight(list, Z_STRVAL_P(z_host),
2397-
Z_LVAL_P(z_port), weight, &status);
2397+
list = memcached_server_list_append_with_weight(list, ZSTR_VAL(host), port, weight, &status);
2398+
2399+
zend_string_release(host);
23982400

23992401
if (s_memc_status_handle_result_code(intern, status) == SUCCESS) {
24002402
i++;
@@ -2839,21 +2841,21 @@ static PHP_METHOD(Memcached, getOption)
28392841
static
28402842
int php_memc_set_option(php_memc_object_t *intern, long option, zval *value)
28412843
{
2844+
zend_long lval;
28422845
memcached_return rc = MEMCACHED_FAILURE;
28432846
memcached_behavior flag;
28442847
php_memc_user_data_t *memc_user_data = memcached_get_user_data(intern->memc);
28452848

28462849
switch (option) {
28472850
case MEMC_OPT_COMPRESSION:
2848-
convert_to_long(value);
2849-
memc_user_data->compression_enabled = Z_LVAL_P(value) ? 1 : 0;
2851+
memc_user_data->compression_enabled = zval_get_long(value) ? 1 : 0;
28502852
break;
28512853

28522854
case MEMC_OPT_COMPRESSION_TYPE:
2853-
convert_to_long(value);
2854-
if (Z_LVAL_P(value) == COMPRESSION_TYPE_FASTLZ ||
2855-
Z_LVAL_P(value) == COMPRESSION_TYPE_ZLIB) {
2856-
memc_user_data->compression_type = Z_LVAL_P(value);
2855+
lval = zval_get_long(value);
2856+
if (lval == COMPRESSION_TYPE_FASTLZ ||
2857+
lval == COMPRESSION_TYPE_ZLIB) {
2858+
memc_user_data->compression_type = lval;
28572859
} else {
28582860
/* invalid compression type */
28592861
intern->rescode = MEMCACHED_INVALID_ARGUMENTS;
@@ -2863,38 +2865,41 @@ int php_memc_set_option(php_memc_object_t *intern, long option, zval *value)
28632865

28642866
case MEMC_OPT_PREFIX_KEY:
28652867
{
2868+
zend_string *str;
28662869
char *key;
28672870
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX == 0x00049000
28682871
char tmp[MEMCACHED_PREFIX_KEY_MAX_SIZE - 1];
28692872
#endif
2870-
convert_to_string(value);
2871-
if (Z_STRLEN_P(value) == 0) {
2873+
str = zval_get_string(value);
2874+
if (ZSTR_VAL(str) == 0) {
28722875
key = NULL;
28732876
} else {
28742877
/*
28752878
work-around a bug in libmemcached in version 0.49 that truncates the trailing
28762879
character of the key prefix, to avoid the issue we pad it with a '0'
28772880
*/
28782881
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX == 0x00049000
2879-
snprintf(tmp, sizeof(tmp), "%s0", Z_STRVAL_P(value));
2882+
snprintf(tmp, sizeof(tmp), "%s0", ZSTR_VAL(str));
28802883
key = tmp;
28812884
#else
2882-
key = Z_STRVAL_P(value);
2885+
key = ZSTR_VAL(str);
28832886
#endif
28842887
}
28852888
if (memcached_callback_set(intern->memc, MEMCACHED_CALLBACK_PREFIX_KEY, key) == MEMCACHED_BAD_KEY_PROVIDED) {
2889+
zend_string_release(str);
28862890
intern->rescode = MEMCACHED_INVALID_ARGUMENTS;
28872891
php_error_docref(NULL, E_WARNING, "bad key provided");
28882892
return 0;
28892893
}
2894+
zend_string_release(str);
28902895
}
28912896
break;
28922897

28932898
case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED:
28942899
flag = (memcached_behavior) option;
28952900

2896-
convert_to_long(value);
2897-
rc = memcached_behavior_set(intern->memc, flag, (uint64_t) Z_LVAL_P(value));
2901+
lval = zval_get_long(value);
2902+
rc = memcached_behavior_set(intern->memc, flag, (uint64_t)lval);
28982903

28992904
if (s_memc_status_handle_result_code(intern, rc) == FAILURE) {
29002905
php_error_docref(NULL, E_WARNING, "error setting memcached option: %s", memcached_strerror (intern->memc, rc));
@@ -2906,7 +2911,7 @@ int php_memc_set_option(php_memc_object_t *intern, long option, zval *value)
29062911
* options on false case, like it does for MEMCACHED_BEHAVIOR_KETAMA
29072912
* (non-weighted) case. We have to clean up ourselves.
29082913
*/
2909-
if (!Z_LVAL_P(value)) {
2914+
if (!lval) {
29102915
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX > 0x00037000
29112916
(void)memcached_behavior_set_key_hash(intern->memc, MEMCACHED_HASH_DEFAULT);
29122917
(void)memcached_behavior_set_distribution_hash(intern->memc, MEMCACHED_HASH_DEFAULT);
@@ -2920,28 +2925,28 @@ int php_memc_set_option(php_memc_object_t *intern, long option, zval *value)
29202925

29212926
case MEMC_OPT_SERIALIZER:
29222927
{
2923-
convert_to_long(value);
2928+
lval = zval_get_long(value);
29242929
/* igbinary serializer */
29252930
#ifdef HAVE_MEMCACHED_IGBINARY
2926-
if (Z_LVAL_P(value) == SERIALIZER_IGBINARY) {
2931+
if (lval == SERIALIZER_IGBINARY) {
29272932
memc_user_data->serializer = SERIALIZER_IGBINARY;
29282933
} else
29292934
#endif
29302935
#ifdef HAVE_JSON_API
2931-
if (Z_LVAL_P(value) == SERIALIZER_JSON) {
2936+
if (lval == SERIALIZER_JSON) {
29322937
memc_user_data->serializer = SERIALIZER_JSON;
2933-
} else if (Z_LVAL_P(value) == SERIALIZER_JSON_ARRAY) {
2938+
} else if (lval == SERIALIZER_JSON_ARRAY) {
29342939
memc_user_data->serializer = SERIALIZER_JSON_ARRAY;
29352940
} else
29362941
#endif
29372942
/* msgpack serializer */
29382943
#ifdef HAVE_MEMCACHED_MSGPACK
2939-
if (Z_LVAL_P(value) == SERIALIZER_MSGPACK) {
2944+
if (lval == SERIALIZER_MSGPACK) {
29402945
memc_user_data->serializer = SERIALIZER_MSGPACK;
29412946
} else
29422947
#endif
29432948
/* php serializer */
2944-
if (Z_LVAL_P(value) == SERIALIZER_PHP) {
2949+
if (lval == SERIALIZER_PHP) {
29452950
memc_user_data->serializer = SERIALIZER_PHP;
29462951
} else {
29472952
memc_user_data->serializer = SERIALIZER_PHP;
@@ -2953,23 +2958,23 @@ int php_memc_set_option(php_memc_object_t *intern, long option, zval *value)
29532958
}
29542959

29552960
case MEMC_OPT_USER_FLAGS:
2956-
convert_to_long(value);
2961+
lval = zval_get_long(value);
29572962

2958-
if (Z_LVAL_P(value) < 0) {
2963+
if (lval < 0) {
29592964
memc_user_data->set_udf_flags = -1;
29602965
return 1;
29612966
}
29622967

2963-
if (Z_LVAL_P(value) > MEMC_VAL_USER_FLAGS_MAX) {
2968+
if (lval > MEMC_VAL_USER_FLAGS_MAX) {
29642969
php_error_docref(NULL, E_WARNING, "MEMC_OPT_USER_FLAGS must be < %u", MEMC_VAL_USER_FLAGS_MAX);
29652970
return 0;
29662971
}
2967-
memc_user_data->set_udf_flags = Z_LVAL_P(value);
2972+
memc_user_data->set_udf_flags = lval;
29682973
break;
29692974

29702975
case MEMC_OPT_STORE_RETRY_COUNT:
2971-
convert_to_long(value);
2972-
memc_user_data->store_retry_count = Z_LVAL_P(value);
2976+
lval = zval_get_long(value);
2977+
memc_user_data->store_retry_count = lval;
29732978
break;
29742979

29752980
default:
@@ -2981,10 +2986,10 @@ int php_memc_set_option(php_memc_object_t *intern, long option, zval *value)
29812986
}
29822987
else {
29832988
flag = (memcached_behavior) option;
2984-
convert_to_long(value);
2989+
lval = zval_get_long(value);
29852990

29862991
if (flag < MEMCACHED_BEHAVIOR_MAX) {
2987-
rc = memcached_behavior_set(intern->memc, flag, (uint64_t) Z_LVAL_P(value));
2992+
rc = memcached_behavior_set(intern->memc, flag, (uint64_t)lval);
29882993
}
29892994
else {
29902995
rc = MEMCACHED_INVALID_ARGUMENTS;
@@ -3016,15 +3021,9 @@ uint32_t *s_zval_to_uint32_array (zval *input, size_t *num_elements)
30163021
retval = ecalloc(*num_elements, sizeof(uint32_t));
30173022

30183023
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(input), pzval) {
3019-
long value = 0;
3020-
3021-
if (Z_TYPE_P(pzval) == IS_LONG) {
3022-
value = Z_LVAL_P(pzval);
3023-
} else {
3024-
value = zval_get_long(pzval);
3025-
value = value > 0? value : 0;
3026-
}
3024+
zend_long value = 0;
30273025

3026+
value = zval_get_long(pzval);
30283027
if (value < 0) {
30293028
php_error_docref(NULL, E_WARNING, "the map must contain positive integers");
30303029
efree (retval);
@@ -3126,14 +3125,9 @@ static PHP_METHOD(Memcached, setOptions)
31263125
php_error_docref(NULL, E_WARNING, "invalid configuration option");
31273126
ok = 0;
31283127
} else {
3129-
zval copy;
3130-
ZVAL_DUP(&copy, value);
3131-
3132-
if (!php_memc_set_option(intern, (long) key_index, &copy)) {
3128+
if (!php_memc_set_option(intern, (long) key_index, value)) {
31333129
ok = 0;
31343130
}
3135-
3136-
zval_dtor(&copy);
31373131
}
31383132
} ZEND_HASH_FOREACH_END();
31393133

0 commit comments

Comments
 (0)