]> git.kaiwu.me - njs.git/commitdiff
Fix String.prototype.match() returning an empty array on no match
authorDmitry Volyntsev <xeioex@nginx.com>
Thu, 12 Nov 2026 02:21:53 +0000 (18:21 -0800)
committerDmitry Volyntsev <xeioexception@gmail.com>
Thu, 12 Nov 2026 20:57:17 +0000 (12:57 -0800)
Previously, global matching replaced the initial null result with an
array even when no matches were collected.  This differs from the
ECMA-262 RegExp.prototype [ @@match ] algorithm, which returns null
when the first execution finds no match.

The issue was introduced in 83645861 (0.3.2), which moved
array allocation outside the matching loop.

Return the array only when it contains matches.  Empty-string matches
still count as matches, and lastIndex continues to be reset to zero.

This closes #1152 issue on GitHub.

src/njs_string.c
src/test/njs_unit_test.c

index 272ac4e2de5a68be17f2001a0499afd8cadc2763..9a601e26ccbbfd81fdc1a6ad12ea3267d7188543 100644 (file)
@@ -2777,7 +2777,9 @@ njs_string_match_multiple(njs_vm_t *vm, njs_value_t *args,
 
         } while (p <= end);
 
-        njs_set_array(retval, array);
+        if (array->length != 0) {
+            njs_set_array(retval, array);
+        }
     }
 
     return NJS_OK;
index efc64d82ebb2a921ba4248e51774f3e3f6fe378a..e70beff91e63eb1bf58391f467e01454b079c477 100644 (file)
@@ -10639,6 +10639,34 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("'ab]cd'.match(/\\]/)"),
       njs_str("]") },
 
+    { njs_str("'abc'.match(/x/g) === null"),
+      njs_str("true") },
+
+    { njs_str("'abc'.match(/(x)/gi) === null"),
+      njs_str("true") },
+
+    { njs_str("''.match(/x/g) === null"),
+      njs_str("true") },
+
+    { njs_str("'αβγ'.match(/x/g) === null"),
+      njs_str("true") },
+
+    { njs_str("'abc'.match(/x/) === null"),
+      njs_str("true") },
+
+    { njs_str("var re = /x/g; re.lastIndex = 2;"
+              "['abc'.match(re) === null, re.lastIndex]"),
+      njs_str("true,0") },
+
+    { njs_str("JSON.stringify(''.match(/(?:)/g))"),
+      njs_str("[\"\"]") },
+
+    { njs_str("JSON.stringify('abc'.match(/b/g))"),
+      njs_str("[\"b\"]") },
+
+    { njs_str("JSON.stringify('αβα'.match(/α/g))"),
+      njs_str("[\"α\",\"α\"]") },
+
     { njs_str("'abc'.match(/a*/g)"),
       njs_str("a,,,") },