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

repl: no RegExp side effects for static properties #18937

Closed

Conversation

princejwesley
Copy link
Contributor

Preserve all RegExp static properties

  • RegExp.$1 to RegExp.9
  • input, lastMatch, lastParen
  • leftContext and rightContext

Fixes: #18931

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines
Affected core subsystem(s)

repl

cc: @bnoordhuis

@nodejs-github-bot nodejs-github-bot added the repl Issues and PRs related to the REPL subsystem. label Feb 22, 2018
@princejwesley princejwesley changed the title repl: no RegExp side effects for static properties [WIP] repl: no RegExp side effects for static properties Feb 22, 2018
Preserve all RegExp static properties
  - RegExp.$1 to RegExp.9
  - input, lastMatch, lastParen
  - leftContext and rightContext

Fixes: nodejs#18931
@princejwesley princejwesley changed the title [WIP] repl: no RegExp side effects for static properties repl: no RegExp side effects for static properties Feb 22, 2018
@bnoordhuis
Copy link
Member

Just food for thought but a simpler solution would be to use RegExp from a different context:

const RE = vm.runInNewContext('RegExp');
// ...
if (RE('pattern').test(input)) {
  // ...
}
// RegExp.$_, RegExp.$_, etc. unaltered here.

@princejwesley
Copy link
Contributor Author

@bnoordhuis Yes, I thought about it! but we can't use global context (useGlobal flag), right? we may have used RegExp anywhere in our code execution path( I mean, not necessarily in repl.js) and all shares the same static properties.

@bnoordhuis
Copy link
Member

@princejwesley vm.runInNewContext() always creates a new context. It won't fix everything but it should be enough to eradicate direct side effects from the REPL. Everything in small steps, right? :-)

@princejwesley
Copy link
Contributor Author

princejwesley commented Feb 23, 2018

@bnoordhuis User input from terminal to REPL eval call, we may have many regex calls - for instance emit key functions has to handle varies terminal character combinations with regular expression. if we try to fix side effect from REPL when the useGlobal is true, we suppose to save/restore RegExp states right?

We can create new context and use it inside repl.js but we can't do the same for the whole code execution path (I mean from user key stroke to run code in vm).

Am I wrong? BTW, why do we need useGlobal ? any special use case for it ?

Also whatever we do to avoid side effects is only applicable when useGlobal is true.

@princejwesley
Copy link
Contributor Author

why don't we set useGlobal as false by default and when the user set it to true, its user's call to accept the side effect, right?

@bnoordhuis
Copy link
Member

@princejwesley Sorry, missed your replies.

We can create new context and use it inside repl.js but we can't do the same for the whole code execution path (I mean from user key stroke to run code in vm).

We could if all of core switched over to the new technique. You could start with repl.js, readline.js and tty.js. Cache the result of vm.runInNewContext() though! :-)

why don't we set useGlobal as false by default

It caused ecosystem fallout last time we tried that, IIRC.

@princejwesley
Copy link
Contributor Author

princejwesley commented Mar 4, 2018

@bnoordhuis
What about doing the reverse like below?

  // Cache global and contextual RegExp binding 
  const regExpInstances = {
    global: RegExp,
    current: vm.runInNewContext('RegExp', vm.createContext())
  };

  ...
  try {
    const scriptOptions = {
      displayErrors: false,
      breakOnSigint: self.breakEvalOnSigint
    };

    if (self.useGlobal) {
      global.RegExp = regExps.context;	// switch
      result = script.runInThisContext(scriptOptions);
    } else {
      result = script.runInContext(context, scriptOptions);
    }
  } finally {
    if (self.useGlobal) {
      global.RegExp = regExps.global;	// reset
    }
    ...

its not working for regex literal! :(

@bnoordhuis
Copy link
Member

That's too much of a hack. Too many ways it can go wrong.

@BridgeAR
Copy link
Member

BridgeAR commented Apr 9, 2018

@bnoordhuis are you fine with landing this as is? As I see it, it will already improve the current situation, no matter that the solution is not elegant.

@jdalton
Copy link
Member

jdalton commented Apr 10, 2018

Is simply deleting these props with Reflect.deleteProperty or setting them to undefined before entering the repl an option?

Update:
Ah, I see it's at every turn of the REPL.

Update:
You could create the regexes of a new context (once) and grab references to them.

@BridgeAR
Copy link
Member

I am unsure how to move forward here. Any further recommendations / notes from anyone?

@bnoordhuis would you be fine with landing it as is or do you definitely want this to be reworked?
@princejwesley would you also please take another look?

@bnoordhuis
Copy link
Member

isInsideNodeModules() creates a new VM context to do something with error stacks. Since we're already using a different VM context for one thing, we might as well go all the way.

@princejwesley
Copy link
Contributor Author

I'll start with repl.js, tty.js and readline.js and update the PR.

@@ -440,7 +440,7 @@ const errorTests = [
},
// Regression test for https://github.com/nodejs/node/issues/597
{
send: '/(.)(.)(.)(.)(.)(.)(.)(.)(.)/.test(\'123456789\')\n',
send: '/(.)(.)(.)(.)(.)(.)(.)(.)(.)/.test(\'123456789abc\')\n',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps add a new block instead of changing this one?

@jdalton
Copy link
Member

jdalton commented Apr 29, 2018

Related to #18795 (comment).
@benjamingr will be experimenting with isolating internals in its own context.

@princejwesley
Copy link
Contributor Author

closing this PR.
New PR: #20549

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
repl Issues and PRs related to the REPL subsystem.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

repl: no RegExp side effects
8 participants