]> granicus.if.org Git - php/commitdiff
Disallow version_compare() $operator abbreviations
authorChristoph M. Becker <cmbecker69@gmx.de>
Sun, 13 Dec 2020 18:00:51 +0000 (19:00 +0100)
committerChristoph M. Becker <cmbecker69@gmx.de>
Sun, 13 Dec 2020 22:55:33 +0000 (23:55 +0100)
`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.

UPGRADING
ext/standard/tests/versioning/version_compare_op_abbrev.phpt [new file with mode: 0644]
ext/standard/versioning.c

index c1d4e564c4d5b7229d70c7c996cbe57b7895a437..a8ae9feeeeeaa30124b69a070f1930ccb1ee0e94 100644 (file)
--- a/UPGRADING
+++ b/UPGRADING
@@ -19,6 +19,9 @@ PHP 8.1 UPGRADE NOTES
 1. Backward Incompatible Changes
 ========================================
 
+- Standard:
+  . version_compare() no longer accepts undocumented operator abbreviations.
+
 ========================================
 2. New Features
 ========================================
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 (file)
index 0000000..241c155
--- /dev/null
@@ -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
index dbdae6ecf75329beaf1c33e289b1169c13d18459..f4f20c9850a0d36bc8aab531362121254e81bd70 100644 (file)
@@ -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);
        }