Skip to content

Commit 3b74eb1

Browse files
committed
Print warning if comparison result will change
1 parent ade5474 commit 3b74eb1

File tree

1 file changed

+109
-0
lines changed

1 file changed

+109
-0
lines changed

Zend/zend_operators.c

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1965,6 +1965,89 @@ static void ZEND_FASTCALL convert_compare_result_to_long(zval *result) /* {{{ */
19651965
}
19661966
/* }}} */
19671967

1968+
static int compare_long_to_string(zend_long lval, zend_string *str) /* {{{ */
1969+
{
1970+
zend_long str_lval;
1971+
double str_dval;
1972+
int num_cmp_result;
1973+
zend_uchar type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 1);
1974+
1975+
if (type == IS_LONG) {
1976+
num_cmp_result = lval > str_lval ? 1 : lval < str_lval ? -1 : 0;
1977+
} else if (type == IS_DOUBLE) {
1978+
double diff = (double) lval - str_dval;
1979+
num_cmp_result = ZEND_NORMALIZE_BOOL(diff);
1980+
} else {
1981+
num_cmp_result = ZEND_NORMALIZE_BOOL(lval);
1982+
}
1983+
1984+
/* TODO Avoid duplicate is_numeric_string call. */
1985+
zend_bool is_numeric = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0);
1986+
if (is_numeric) {
1987+
/* For numeric strings, the comparison result stays the same. */
1988+
return num_cmp_result;
1989+
}
1990+
1991+
zend_string *lval_as_str = zend_long_to_str(lval);
1992+
int str_cmp_result = zend_binary_strcmp(
1993+
ZSTR_VAL(lval_as_str), ZSTR_LEN(lval_as_str), ZSTR_VAL(str), ZSTR_LEN(str));
1994+
str_cmp_result = ZEND_NORMALIZE_BOOL(str_cmp_result);
1995+
zend_string_release(lval_as_str);
1996+
1997+
if (str_cmp_result != num_cmp_result) {
1998+
zend_error(E_WARNING,
1999+
"Result of comparison between " ZEND_LONG_FMT " and \"%s\" will change (%d to %d)",
2000+
lval, ZSTR_VAL(str), num_cmp_result, str_cmp_result);
2001+
}
2002+
2003+
/* Return old (numeric) comparison result. */
2004+
return num_cmp_result;
2005+
}
2006+
/* }}} */
2007+
2008+
static int compare_double_to_string(double dval, zend_string *str) /* {{{ */
2009+
{
2010+
zend_long str_lval;
2011+
double str_dval;
2012+
int num_cmp_result;
2013+
zend_uchar type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0);
2014+
2015+
if (type == IS_LONG) {
2016+
double diff = dval - (double) str_lval;
2017+
num_cmp_result = ZEND_NORMALIZE_BOOL(diff);
2018+
} else if (type == IS_DOUBLE) {
2019+
if (dval == str_dval) {
2020+
return 0;
2021+
}
2022+
num_cmp_result = ZEND_NORMALIZE_BOOL(dval - str_dval);
2023+
} else {
2024+
num_cmp_result = ZEND_NORMALIZE_BOOL(dval);
2025+
}
2026+
2027+
/* TODO Avoid duplicate is_numeric_string call. */
2028+
zend_bool is_numeric = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0);
2029+
if (is_numeric) {
2030+
/* For numeric strings, the comparison result stays the same. */
2031+
return num_cmp_result;
2032+
}
2033+
2034+
zend_string *dval_as_str = zend_strpprintf(0, "%.*G", (int) EG(precision), dval);
2035+
int str_cmp_result = zend_binary_strcmp(
2036+
ZSTR_VAL(dval_as_str), ZSTR_LEN(dval_as_str), ZSTR_VAL(str), ZSTR_LEN(str));
2037+
str_cmp_result = ZEND_NORMALIZE_BOOL(str_cmp_result);
2038+
zend_string_release(dval_as_str);
2039+
2040+
if (str_cmp_result != num_cmp_result) {
2041+
zend_error(E_WARNING,
2042+
"Result of comparison between %G and \"%s\" will change (%d to %d)",
2043+
dval, ZSTR_VAL(str), num_cmp_result, str_cmp_result);
2044+
}
2045+
2046+
/* Return old (numeric) comparison result. */
2047+
return num_cmp_result;
2048+
}
2049+
/* }}} */
2050+
19682051
ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) /* {{{ */
19692052
{
19702053
int ret;
@@ -2033,6 +2116,32 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2)
20332116
ZVAL_LONG(result, Z_STRLEN_P(op1) == 0 ? 0 : 1);
20342117
return SUCCESS;
20352118

2119+
case TYPE_PAIR(IS_LONG, IS_STRING):
2120+
ZVAL_LONG(result, compare_long_to_string(Z_LVAL_P(op1), Z_STR_P(op2)));
2121+
return SUCCESS;
2122+
2123+
case TYPE_PAIR(IS_STRING, IS_LONG):
2124+
ZVAL_LONG(result, -compare_long_to_string(Z_LVAL_P(op2), Z_STR_P(op1)));
2125+
return SUCCESS;
2126+
2127+
case TYPE_PAIR(IS_DOUBLE, IS_STRING):
2128+
if (zend_isnan(Z_DVAL_P(op1))) {
2129+
ZVAL_LONG(result, 1);
2130+
return SUCCESS;
2131+
}
2132+
2133+
ZVAL_LONG(result, compare_double_to_string(Z_DVAL_P(op1), Z_STR_P(op2)));
2134+
return SUCCESS;
2135+
2136+
case TYPE_PAIR(IS_STRING, IS_DOUBLE):
2137+
if (zend_isnan(Z_DVAL_P(op2))) {
2138+
ZVAL_LONG(result, 1);
2139+
return SUCCESS;
2140+
}
2141+
2142+
ZVAL_LONG(result, -compare_double_to_string(Z_DVAL_P(op2), Z_STR_P(op1)));
2143+
return SUCCESS;
2144+
20362145
case TYPE_PAIR(IS_OBJECT, IS_NULL):
20372146
ZVAL_LONG(result, 1);
20382147
return SUCCESS;

0 commit comments

Comments
 (0)