summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorChristoph M. Becker <cmbecker69@gmx.de>2020-12-13 19:00:51 +0100
committerChristoph M. Becker <cmbecker69@gmx.de>2020-12-13 23:55:33 +0100
commit2b7eb0e26a1816a3c5ddb28dd53f98ae0ecef047 (patch)
treed2c2a44268678ce0beb01dad86e66803db613fdc /ext
parent269a8841ae6edae3bc0ed8675390c78bd9f09bd8 (diff)
downloadphp-git-2b7eb0e26a1816a3c5ddb28dd53f98ae0ecef047.tar.gz
Disallow version_compare() $operator abbreviations
`version_compare()` does a sloppy check for the `$operators` argument which allows arbitrary abbreviations of the supported operators to be accepted. This is both undocumented and unexpected, and could lead to subtle BC breaks, if the order of the comparisions will be changed. Therefore we change to strict comparisons. Closes GH-6510.
Diffstat (limited to 'ext')
-rw-r--r--ext/standard/tests/versioning/version_compare_op_abbrev.phpt21
-rw-r--r--ext/standard/versioning.c19
2 files changed, 31 insertions, 9 deletions
diff --git a/ext/standard/tests/versioning/version_compare_op_abbrev.phpt b/ext/standard/tests/versioning/version_compare_op_abbrev.phpt
new file mode 100644
index 0000000000..241c1559fe
--- /dev/null
+++ b/ext/standard/tests/versioning/version_compare_op_abbrev.phpt
@@ -0,0 +1,21 @@
+--TEST--
+version_compare() no longer supports operator abbreviations
+--FILE--
+<?php
+$abbrevs = ['', 'l', 'g', 'e', '!', 'n'];
+foreach ($abbrevs as $op) {
+ try {
+ version_compare('1', '2', $op);
+ echo "'$op' succeeded\n";
+ } catch (ValueError $err) {
+ echo "'$op' failed\n";
+ }
+}
+?>
+--EXPECT--
+'' failed
+'l' failed
+'g' failed
+'e' failed
+'!' failed
+'n' failed
diff --git a/ext/standard/versioning.c b/ext/standard/versioning.c
index dbdae6ecf7..f4f20c9850 100644
--- a/ext/standard/versioning.c
+++ b/ext/standard/versioning.c
@@ -203,37 +203,38 @@ php_version_compare(const char *orig_ver1, const char *orig_ver2)
PHP_FUNCTION(version_compare)
{
- char *v1, *v2, *op = NULL;
- size_t v1_len, v2_len, op_len = 0;
+ char *v1, *v2;
+ zend_string *op = NULL;
+ size_t v1_len, v2_len;
int compare;
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STRING(v1, v1_len)
Z_PARAM_STRING(v2, v2_len)
Z_PARAM_OPTIONAL
- Z_PARAM_STRING_OR_NULL(op, op_len)
+ Z_PARAM_STR_OR_NULL(op)
ZEND_PARSE_PARAMETERS_END();
compare = php_version_compare(v1, v2);
if (!op) {
RETURN_LONG(compare);
}
- if (!strncmp(op, "<", op_len) || !strncmp(op, "lt", op_len)) {
+ if (zend_string_equals_literal(op, "<") || zend_string_equals_literal(op, "lt")) {
RETURN_BOOL(compare == -1);
}
- if (!strncmp(op, "<=", op_len) || !strncmp(op, "le", op_len)) {
+ if (zend_string_equals_literal(op, "<=") || zend_string_equals_literal(op, "le")) {
RETURN_BOOL(compare != 1);
}
- if (!strncmp(op, ">", op_len) || !strncmp(op, "gt", op_len)) {
+ if (zend_string_equals_literal(op, ">") || zend_string_equals_literal(op, "gt")) {
RETURN_BOOL(compare == 1);
}
- if (!strncmp(op, ">=", op_len) || !strncmp(op, "ge", op_len)) {
+ if (zend_string_equals_literal(op, ">=") || zend_string_equals_literal(op, "ge")) {
RETURN_BOOL(compare != -1);
}
- if (!strncmp(op, "==", op_len) || !strncmp(op, "=", op_len) || !strncmp(op, "eq", op_len)) {
+ if (zend_string_equals_literal(op, "==") || zend_string_equals_literal(op, "=") || zend_string_equals_literal(op, "eq")) {
RETURN_BOOL(compare == 0);
}
- if (!strncmp(op, "!=", op_len) || !strncmp(op, "<>", op_len) || !strncmp(op, "ne", op_len)) {
+ if (zend_string_equals_literal(op, "!=") || zend_string_equals_literal(op, "<>") || zend_string_equals_literal(op, "ne")) {
RETURN_BOOL(compare != 0);
}