Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Constant with regular expression literal with global modifier incorrectly replace by literal #1026

Open
bryan-kramer opened this issue Apr 13, 2022 · 0 comments

Comments

@bryan-kramer
Copy link

Describe the bug

The code contains a constant whose value is a regular expression with the g (i.e. global) modifier. Minify replaces the use of this constant with the literal regular expression resulting in an infinite loop.

To Reproduce

Minimal code to reproduce the bug

/**
 * Incorrect minimization of regular expression
 *
 */

function test(data) {
  var re = /a/g;

  let match;
  let result = [];

  while ((match = re.exec(data))) {
    result.push(match);
  }
 
  return result;
}

console.log(test('abababab'));

Actual Output

function test(a){let b,c=[];for(;b=/a/g.exec(a);)c.push(b);return c}console.log(test("abababab"));

The minifier generates exactly the same code if the regular expression literal is replaced by new Regexp('a', 'g').

Expected Output

function test(a){let b=/a/g,c,d=[];for(;c=b.exec(a);)c.push(c);return d}console.log(test("abababab"));

Configuration

How are you using babel-minify?

npx babel --no-comments js/script.js

babel-minify version: 0.5.0

babel version : 7.17.6 (@babel/core 7.17.9)

babel-minify-config: none

babelrc:

{
  "presets": [
    [
      "minify",
      {
        "evaluate": false 
      }
    ]
  ]
}

Possible solution

The while loop must use the same RegExp object through each iteration. At a minimum, the babel minimizer should recognize that the global modifier is present and make sure that the same regular expression object is used.

It turns out that the minifier does the right thing when it cannot determine the modifiers in the case where modifiers is a function parameter, e.g.

function f(modifiers) {
   const re = new RegExp('a', modifiers)

Additional context

In this case the minified code results in a infinite loop at least when run in latest versions of Chrome (Version 102.0.5001.0 (Official Build) canary (64-bit)) and with nodejs (v16.14.0).

It seems that the JavaScript engines must be recreating the regular expression object through each loop iteration or at least resetting the index.

I tried each of the minimizer options that looked relevant one at a time to see if any fixed this problem.

This fix needs to happen in any situation that uses the regular expression

const a = /a/g;
let b = 'ababa';

if (a.exec(b)) { ....}
if(a.exec(b)){ ... }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant