Skip to content

Commit 9feb988

Browse files
committed
Clean up setlocale implementation
Factor out the core logic into a separate function and drop the "clever" code that combines iteration through variadic arguments and arrays. This fixes bug #79829 as a side effect.
1 parent 8c3574b commit 9feb988

File tree

1 file changed

+92
-96
lines changed

1 file changed

+92
-96
lines changed

ext/standard/string.c

Lines changed: 92 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -4600,116 +4600,112 @@ PHP_FUNCTION(strip_tags)
46004600
}
46014601
/* }}} */
46024602

4603-
/* {{{ Set locale information */
4604-
PHP_FUNCTION(setlocale)
4605-
{
4606-
zval *args = NULL;
4607-
zval *plocale;
4608-
zend_string *loc;
4603+
static zend_string *try_setlocale_str(zend_long cat, zend_string *loc) {
46094604
const char *retval;
4610-
zend_long cat;
4611-
int num_args, i = 0;
4612-
uint32_t idx;
46134605

4614-
ZEND_PARSE_PARAMETERS_START(2, -1)
4615-
Z_PARAM_LONG(cat)
4616-
Z_PARAM_VARIADIC('+', args, num_args)
4617-
ZEND_PARSE_PARAMETERS_END();
4618-
4619-
idx = 0;
4620-
while (1) {
4621-
if (Z_TYPE(args[0]) == IS_ARRAY) {
4622-
while (idx < Z_ARRVAL(args[0])->nNumUsed) {
4623-
plocale = &Z_ARRVAL(args[0])->arData[idx].val;
4624-
if (Z_TYPE_P(plocale) != IS_UNDEF) {
4625-
break;
4626-
}
4627-
idx++;
4628-
}
4629-
if (idx >= Z_ARRVAL(args[0])->nNumUsed) {
4630-
break;
4631-
}
4632-
} else {
4633-
plocale = &args[i];
4634-
}
4635-
4636-
loc = zval_try_get_string(plocale);
4637-
if (UNEXPECTED(!loc)) {
4638-
return;
4639-
}
4640-
4641-
if (!strcmp("0", ZSTR_VAL(loc))) {
4642-
zend_string_release_ex(loc, 0);
4643-
loc = NULL;
4644-
} else {
4645-
if (ZSTR_LEN(loc) >= 255) {
4646-
php_error_docref(NULL, E_WARNING, "Specified locale name is too long");
4647-
zend_string_release_ex(loc, 0);
4648-
break;
4649-
}
4606+
if (!strcmp("0", ZSTR_VAL(loc))) {
4607+
loc = NULL;
4608+
} else {
4609+
if (ZSTR_LEN(loc) >= 255) {
4610+
php_error_docref(NULL, E_WARNING, "Specified locale name is too long");
4611+
return NULL;
46504612
}
4613+
}
46514614

46524615
# ifndef PHP_WIN32
4653-
retval = setlocale(cat, loc ? ZSTR_VAL(loc) : NULL);
4616+
retval = setlocale(cat, loc ? ZSTR_VAL(loc) : NULL);
46544617
# else
4655-
if (loc) {
4656-
/* BC: don't try /^[a-z]{2}_[A-Z]{2}($|\..*)/ except for /^u[ks]_U[KS]$/ */
4657-
char *locp = ZSTR_VAL(loc);
4658-
if (ZSTR_LEN(loc) >= 5 && locp[2] == '_'
4659-
&& locp[0] >= 'a' && locp[0] <= 'z' && locp[1] >= 'a' && locp[1] <= 'z'
4660-
&& locp[3] >= 'A' && locp[3] <= 'Z' && locp[4] >= 'A' && locp[4] <= 'Z'
4661-
&& (locp[5] == '\0' || locp[5] == '.')
4662-
&& !(locp[0] == 'u' && (locp[1] == 'k' || locp[1] == 's')
4663-
&& locp[3] == 'U' && (locp[4] == 'K' || locp[4] == 'S')
4664-
&& locp[5] == '\0')
4665-
) {
4666-
retval = NULL;
4667-
} else {
4668-
retval = setlocale(cat, ZSTR_VAL(loc));
4669-
}
4618+
if (loc) {
4619+
/* BC: don't try /^[a-z]{2}_[A-Z]{2}($|\..*)/ except for /^u[ks]_U[KS]$/ */
4620+
char *locp = ZSTR_VAL(loc);
4621+
if (ZSTR_LEN(loc) >= 5 && locp[2] == '_'
4622+
&& locp[0] >= 'a' && locp[0] <= 'z' && locp[1] >= 'a' && locp[1] <= 'z'
4623+
&& locp[3] >= 'A' && locp[3] <= 'Z' && locp[4] >= 'A' && locp[4] <= 'Z'
4624+
&& (locp[5] == '\0' || locp[5] == '.')
4625+
&& !(locp[0] == 'u' && (locp[1] == 'k' || locp[1] == 's')
4626+
&& locp[3] == 'U' && (locp[4] == 'K' || locp[4] == 'S')
4627+
&& locp[5] == '\0')
4628+
) {
4629+
retval = NULL;
46704630
} else {
4671-
retval = setlocale(cat, NULL);
4631+
retval = setlocale(cat, ZSTR_VAL(loc));
46724632
}
4633+
} else {
4634+
retval = setlocale(cat, NULL);
4635+
}
46734636
# endif
4674-
zend_update_current_locale();
4675-
if (retval) {
4676-
if (loc) {
4677-
/* Remember if locale was changed */
4678-
size_t len = strlen(retval);
4679-
4680-
BG(locale_changed) = 1;
4681-
if (cat == LC_CTYPE || cat == LC_ALL) {
4682-
if (BG(ctype_string)) {
4683-
zend_string_release_ex(BG(ctype_string), 0);
4684-
}
4685-
if (len == 1 && *retval == 'C') {
4686-
/* C locale is represented as NULL. */
4687-
BG(ctype_string) = NULL;
4688-
zend_string_release_ex(loc, 0);
4689-
RETURN_CHAR('C');
4690-
} else if (len == ZSTR_LEN(loc) && !memcmp(ZSTR_VAL(loc), retval, len)) {
4691-
BG(ctype_string) = zend_string_copy(loc);
4692-
RETURN_STR(BG(ctype_string));
4693-
} else {
4694-
BG(ctype_string) = zend_string_init(retval, len, 0);
4695-
zend_string_release_ex(loc, 0);
4696-
RETURN_STR_COPY(BG(ctype_string));
4697-
}
4698-
} else if (len == ZSTR_LEN(loc) && !memcmp(ZSTR_VAL(loc), retval, len)) {
4699-
RETURN_STR(loc);
4700-
}
4637+
zend_update_current_locale();
4638+
if (!retval) {
4639+
return NULL;
4640+
}
4641+
4642+
if (loc) {
4643+
/* Remember if locale was changed */
4644+
size_t len = strlen(retval);
4645+
4646+
BG(locale_changed) = 1;
4647+
if (cat == LC_CTYPE || cat == LC_ALL) {
4648+
if (BG(ctype_string)) {
4649+
zend_string_release_ex(BG(ctype_string), 0);
4650+
}
4651+
if (len == 1 && *retval == 'C') {
4652+
/* C locale is represented as NULL. */
4653+
BG(ctype_string) = NULL;
47014654
zend_string_release_ex(loc, 0);
4655+
return ZSTR_CHAR('C');
4656+
} else if (len == ZSTR_LEN(loc) && !memcmp(ZSTR_VAL(loc), retval, len)) {
4657+
BG(ctype_string) = zend_string_copy(loc);
4658+
return zend_string_copy(BG(ctype_string));
4659+
} else {
4660+
BG(ctype_string) = zend_string_init(retval, len, 0);
4661+
return zend_string_copy(BG(ctype_string));
47024662
}
4703-
RETURN_STRING(retval);
4704-
}
4705-
if (loc) {
4706-
zend_string_release_ex(loc, 0);
4663+
} else if (len == ZSTR_LEN(loc) && !memcmp(ZSTR_VAL(loc), retval, len)) {
4664+
return zend_string_copy(loc);
47074665
}
4666+
}
4667+
return zend_string_init(retval, strlen(retval), 0);
4668+
}
4669+
4670+
static zend_string *try_setlocale_zval(zend_long cat, zval *loc_zv) {
4671+
zend_string *loc_str = zval_try_get_string(loc_zv);
4672+
zend_string *result = try_setlocale_str(cat, loc_str);
4673+
zend_string_release_ex(loc_str, 0);
4674+
return result;
4675+
}
4676+
4677+
/* {{{ Set locale information */
4678+
PHP_FUNCTION(setlocale)
4679+
{
4680+
zend_long cat;
4681+
zval *args = NULL;
4682+
int num_args;
4683+
4684+
ZEND_PARSE_PARAMETERS_START(2, -1)
4685+
Z_PARAM_LONG(cat)
4686+
Z_PARAM_VARIADIC('+', args, num_args)
4687+
ZEND_PARSE_PARAMETERS_END();
47084688

4709-
if (Z_TYPE(args[0]) == IS_ARRAY) {
4710-
idx++;
4689+
for (uint32_t i = 0; i < num_args; i++) {
4690+
if (Z_TYPE(args[i]) == IS_ARRAY) {
4691+
zval *elem;
4692+
ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL(args[i]), elem) {
4693+
zend_string *result = try_setlocale_zval(cat, elem);
4694+
if (EG(exception)) {
4695+
RETURN_THROWS();
4696+
}
4697+
if (result) {
4698+
RETURN_STR(result);
4699+
}
4700+
} ZEND_HASH_FOREACH_END();
47114701
} else {
4712-
if (++i >= num_args) break;
4702+
zend_string *result = try_setlocale_zval(cat, &args[i]);
4703+
if (EG(exception)) {
4704+
RETURN_THROWS();
4705+
}
4706+
if (result) {
4707+
RETURN_STR(result);
4708+
}
47134709
}
47144710
}
47154711

0 commit comments

Comments
 (0)