6

Consider the following code:

vm = require('vm');
context = vm.createContext({});
vm.runInContext("Buffer.from('abc').toString()", context);

Observe that this produces ReferenceError: Buffer is not defined as Buffer is a Node.js specific construct that Node.js has added as a Node Specific Global Object. (Note that other JS globals like Math and Array do not share this problem.) This particular problem can be solved by modifying the above code to

vm = require('vm');
context = vm.createContext({Buffer});
vm.runInContext("Buffer.from('abc').toString()", context);

However, if I want every single Node Specific Global to be imported, then it appears as though I must list them one by one. Given that Node.js adds Global objects relatively frequetly, is there a way I can pass all of Node.JS' global objects to a vm context? Alternatively, is there a programatic way to construct a list of all of Node Globals?

Note: Using global isn't consistent across different node versions: e.g. Buffer is in global for node v8 and v10 but not v12.

Jacob Horbulyk
  • 2,366
  • 5
  • 22
  • 34

2 Answers2

1

I got this.


const cloneGlobal = () => Object.defineProperties(
    {...global},
    Object.getOwnPropertyDescriptors(global)
)

Test:

> const nG = cloneGlobal()
> nG.myVar = 'a';
'a'
> myVar
Uncaught ReferenceError: myVar is not defined
> 'myVar' in global
false
> 'myVar' in nG
true
> 'Buffer' in nG
true

Edit: add Example code for the author's example:

vm = require('vm');

const cloneGlobal = () => Object.defineProperties(
    {...global},
    Object.getOwnPropertyDescriptors(global)
)

context = vm.createContext(cloneGlobal());
const ret = vm.runInContext("Buffer.from('abc').toString()", context);

console.log(ret); // abc
-3

The whole reason to use the "vm" module is to isolate the context of the running program from the code being executed.

If you want to execute arbitrary JavaScript inside the current context you can just use eval. No reason to use vm.createContext.

eval("Buffer.from('abc').toString()");
Yinzara
  • 783
  • 8
  • 15
  • Actually, there are lots of reasons to clone the current context and pass it to a new vm instance, including wanting to operate on what is now essentially a read-only copy of the context. Since the vm may make changes to its global context, those changes will be discarded when the vm instance is destroyed, leaving the original parent context unmodified. This, alone, is reason enough not to tell OP to use eval instead. – cshotton Feb 21 '23 at 13:33