Browse Source

doc: improve vm.md copy

General improvements to vm module documentation

PR-URL: https://github.com/nodejs/node/pull/6827
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
v7.x
James M Snell 9 years ago
parent
commit
baeed8b3d9
  1. 397
      doc/api/vm.md

397
doc/api/vm.md

@ -4,7 +4,8 @@
<!--name=vm-->
You can access this module with:
The `vm` module provides APIs for compiling and running code within V8 Virtual
Machine contexts. It can be accessed using:
```js
const vm = require('vm');
@ -13,66 +14,81 @@ const vm = require('vm');
JavaScript code can be compiled and run immediately or compiled, saved, and run
later.
## Class: Script
## Class: vm.Script
A class for holding precompiled scripts, and running them in specific sandboxes.
Instances of the `vm.Script` class contain precompiled scripts that can be
executed in specific sandboxes (or "contexts").
### new vm.Script(code, options)
Creating a new `Script` compiles `code` but does not run it. Instead, the
created `vm.Script` object represents this compiled code. This script can be run
later many times using methods below. The returned script is not bound to any
global object. It is bound before each run, just for that run.
The options when creating a script are:
- `filename`: allows you to control the filename that shows up in any stack
traces produced from this script.
- `lineOffset`: allows you to add an offset to the line number that is
displayed in stack traces
- `columnOffset`: allows you to add an offset to the column number that is
displayed in stack traces
- `displayErrors`: if `true`, on error, attach the line of code that caused
the error to the stack trace. Applies only to syntax errors compiling the
code; errors while running the code are controlled by the options to the
script's methods.
- `timeout`: a number of milliseconds to execute `code` before terminating
execution. If execution is terminated, an [`Error`][] will be thrown.
- `cachedData`: an optional `Buffer` with V8's code cache data for the supplied
source. When supplied `cachedDataRejected` value will be set to either
`true` or `false` depending on acceptance of the data by V8.
- `produceCachedData`: if `true` and no `cachedData` is present - V8 tries to
produce code cache data for `code`. Upon success, a `Buffer` with V8's code
cache data will be produced and stored in `cachedData` property of the
returned `vm.Script` instance. `cachedDataProduced` value will be set to
either `true` or `false` depending on whether code cache data is produced
successfully.
* `code` {string} The JavaScript code to compile.
* `options`
* `filename` {string} Specifies the filename used in stack traces produced
by this script.
* `lineOffset` {number} Specifies the line number offset that is displayed
in stack traces produced by this script.
* `columnOffset` {number} Specifies the column number offset that is displayed
in stack traces produced by this script.
* `displayErrors` {boolean} When `true`, if an [`Error`][] error occurs
while compiling the `code`, the line of code causing the error is attached
to the stack trace.
* `timeout` {number} Specifies the number of milliseconds to execute `code`
before terminating execution. If execution is terminated, an [`Error`][]
will be thrown.
* `cachedData` {Buffer} Provides an optional `Buffer` with V8's code cache
data for the supplied source. When supplied, the `cachedDataRejected` value
will be set to either `true` or `false` depending on acceptance of the data
by V8.
* `produceCachedData` {boolean} When `true` and no `cachedData` is present, V8
will attempt to produce code cache data for `code`. Upon success, a
`Buffer` with V8's code cache data will be produced and stored in the
`cachedData` property of the returned `vm.Script` instance.
The `cachedDataProduced` value will be set to either `true` or `false`
depending on whether code cache data is produced successfully.
Creating a new `vm.Script` object compiles `code` but does not run it. The
compiled `vm.Script` can be run later multiple times. It is important to note
that the `code` is not bound to any global object; rather, it is bound before
each run, just for that run.
### script.runInContext(contextifiedSandbox[, options])
Similar to [`vm.runInContext()`][] but a method of a precompiled `Script`
object. `script.runInContext()` runs `script`'s compiled code in
* `contextifiedSandbox` {Object} A [contextified][] object as returned by the
`vm.createContext()` method.
* `options` {Object}
* `filename` {string} Specifies the filename used in stack traces produced
by this script.
* `lineOffset` {number} Specifies the line number offset that is displayed
in stack traces produced by this script.
* `columnOffset` {number} Specifies the column number offset that is displayed
in stack traces produced by this script.
* `displayErrors` {boolean} When `true`, if an [`Error`][] error occurs
while compiling the `code`, the line of code causing the error is attached
to the stack trace.
* `timeout` {number} Specifies the number of milliseconds to execute `code`
before terminating execution. If execution is terminated, an [`Error`][]
will be thrown.
Runs the compiled code contained by the `vm.Script` object within the given
`contextifiedSandbox` and returns the result. Running code does not have access
to local scope.
`script.runInContext()` takes the same options as
[`script.runInThisContext()`][].
Example: compile code that increments a global variable and sets one, then
execute the code multiple times. These globals are contained in the sandbox.
The following example compiles code that increments a global variable, sets
the value of another global variable, then execute the code multiple times.
The globals are contained in the `sandbox` object.
```js
const util = require('util');
const vm = require('vm');
var sandbox = {
const sandbox = {
animal: 'cat',
count: 2
};
var context = new vm.createContext(sandbox);
var script = new vm.Script('count += 1; name = "kitty"');
const script = new vm.Script('count += 1; name = "kitty";');
const context = new vm.createContext(sandbox);
for (var i = 0; i < 10; ++i) {
script.runInContext(context);
}
@ -82,33 +98,39 @@ console.log(util.inspect(sandbox));
// { animal: 'cat', count: 12, name: 'kitty' }
```
Note that running untrusted code is a tricky business requiring great care.
`script.runInContext()` is quite useful, but safely running untrusted code
requires a separate process.
### script.runInNewContext([sandbox][, options])
Similar to [`vm.runInNewContext()`][] but a method of a precompiled `Script`
object. `script.runInNewContext()` contextifies `sandbox` if passed or creates a
new contextified sandbox if it's omitted, and then runs `script`'s compiled code
with the sandbox as the global object and returns the result. Running code does
not have access to local scope.
`script.runInNewContext()` takes the same options as
[`script.runInThisContext()`][].
Example: compile code that sets a global variable, then execute the code
multiple times in different contexts. These globals are set on and contained in
the sandboxes.
* `sandbox` {Object} An object that will be [contextified][]. If `undefined`, a
new object will be created.
* `options` {Object}
* `filename` {string} Specifies the filename used in stack traces produced
by this script.
* `lineOffset` {number} Specifies the line number offset that is displayed
in stack traces produced by this script.
* `columnOffset` {number} Specifies the column number offset that is displayed
in stack traces produced by this script.
* `displayErrors` {boolean} When `true`, if an [`Error`][] error occurs
while compiling the `code`, the line of code causing the error is attached
to the stack trace.
* `timeout` {number} Specifies the number of milliseconds to execute `code`
before terminating execution. If execution is terminated, an [`Error`][]
will be thrown.
First contextifies the given `sandbox`, runs the compiled code contained by
the `vm.Script` object within the created sandbox, and returns the result.
Running code does not have access to local scope.
The following example compiles code that sets a global variable, then executes
the code multiple times in different contexts. The globals are set on and
contained within each individual `sandbox`.
```js
const util = require('util');
const vm = require('vm');
const sandboxes = [{}, {}, {}];
const script = new vm.Script('globalVar = "set"');
const sandboxes = [{}, {}, {}];
sandboxes.forEach((sandbox) => {
script.runInNewContext(sandbox);
});
@ -118,19 +140,28 @@ console.log(util.inspect(sandboxes));
// [{ globalVar: 'set' }, { globalVar: 'set' }, { globalVar: 'set' }]
```
Note that running untrusted code is a tricky business requiring great care.
`script.runInNewContext()` is quite useful, but safely running untrusted code
requires a separate process.
### script.runInThisContext([options])
Similar to [`vm.runInThisContext()`][] but a method of a precompiled `Script`
object. `script.runInThisContext()` runs `script`'s compiled code and returns
the result. Running code does not have access to local scope, but does have
access to the current `global` object.
Example of using `script.runInThisContext()` to compile code once and run it
multiple times:
* `options` {Object}
* `filename` {string} Specifies the filename used in stack traces produced
by this script.
* `lineOffset` {number} Specifies the line number offset that is displayed
in stack traces produced by this script.
* `columnOffset` {number} Specifies the column number offset that is displayed
in stack traces produced by this script.
* `displayErrors` {boolean} When `true`, if an [`Error`][] error occurs
while compiling the `code`, the line of code causing the error is attached
to the stack trace.
* `timeout` {number} Specifies the number of milliseconds to execute `code`
before terminating execution. If execution is terminated, an [`Error`][]
will be thrown.
Runs the compiled code contained by the `vm.Script` within the context of the
current `global` object. Running code does not have access to local scope, but
*does* have access to the current `global` object.
The following example compiles code that increments a `global` variable then
executes that code multiple times:
```js
const vm = require('vm');
@ -148,53 +179,60 @@ console.log(globalVar);
// 1000
```
The options for running a script are:
- `filename`: allows you to control the filename that shows up in any stack
traces produced.
- `lineOffset`: allows you to add an offset to the line number that is
displayed in stack traces
- `columnOffset`: allows you to add an offset to the column number that is
displayed in stack traces
- `displayErrors`: if `true`, on error, attach the line of code that caused
the error to the stack trace. Applies only to runtime errors executing the
code; it is impossible to create a `Script` instance with syntax errors, as
the constructor will throw.
- `timeout`: a number of milliseconds to execute the script before terminating
execution. If execution is terminated, an [`Error`][] will be thrown.
## vm.createContext([sandbox])
If given a `sandbox` object, will "contextify" that sandbox so that it can be
* `sandbox` {Object}
If given a `sandbox` object, the `vm.createContext()` method will [prepare
that sandbox][#vm_what_does_it_mean_to_contextify_an_object] so that it can be
used in calls to [`vm.runInContext()`][] or [`script.runInContext()`][]. Inside
scripts run as such, `sandbox` will be the global object, retaining all its
existing properties but also having the built-in objects and functions any
such scripts, the `sandbox` object will be the global object, retaining all of
its existing properties but also having the built-in objects and functions any
standard [global object][] has. Outside of scripts run by the vm module,
`sandbox` will be unchanged.
`sandbox` will remain unchanged.
If not given a sandbox object, returns a new, empty contextified sandbox object
you can use.
If `sandbox` is omitted (or passed explicitly as `undefined`), a new, empty
[contextified][] sandbox object will be returned.
This function is useful for creating a sandbox that can be used to run multiple
scripts, e.g. if you were emulating a web browser it could be used to create a
single sandbox representing a window's global object, then run all `<script>`
tags together inside that sandbox.
The `vm.createContext()` method is primarily useful for creating a single
sandbox that can be used to run multiple scripts. For instance, if emulating a
web browser, the method can be used to create a single sandbox representing a
window's global object, then run all `<script>` tags together within the context
of that sandbox.
## vm.isContext(sandbox)
Returns whether or not a sandbox object has been contextified by calling
[`vm.createContext()`][] on it.
## vm.runInContext(code, contextifiedSandbox[, options])
* `sandbox` {Object}
`vm.runInContext()` compiles `code`, then runs it in `contextifiedSandbox` and
returns the result. Running code does not have access to local scope. The
`contextifiedSandbox` object must have been previously contextified via
[`vm.createContext()`][]; it will be used as the global object for `code`.
Returns `true` if the given `sandbox` object has been [contextified][] using
[`vm.createContext()`][].
`vm.runInContext()` takes the same options as [`vm.runInThisContext()`][].
## vm.runInContext(code, contextifiedSandbox[, options])
Example: compile and execute different scripts in a single existing context.
* `code` {string} The JavaScript code to compile and run.
* `contextifiedSandbox` {Object} The [contextified][] object that will be used
as the `global` when the `code` is compiled and run.
* `options`
* `filename` {string} Specifies the filename used in stack traces produced
by this script.
* `lineOffset` {number} Specifies the line number offset that is displayed
in stack traces produced by this script.
* `columnOffset` {number} Specifies the column number offset that is displayed
in stack traces produced by this script.
* `displayErrors` {boolean} When `true`, if an [`Error`][] error occurs
while compiling the `code`, the line of code causing the error is attached
to the stack trace.
* `timeout` {number} Specifies the number of milliseconds to execute `code`
before terminating execution. If execution is terminated, an [`Error`][]
will be thrown.
The `vm.runInContext()` method compiles `code`, runs it within the context of
the `contextifiedSandbox`, then returns the result. Running code does not have
access to the local scope. The `contextifiedSandbox` object *must* have been
previously [contextified][] using the [`vm.createContext()`][] method.
The following example compiles and executes different scripts using a single
[contextified][] object:
```js
const util = require('util');
@ -204,21 +242,19 @@ const sandbox = { globalVar: 1 };
vm.createContext(sandbox);
for (var i = 0; i < 10; ++i) {
vm.runInContext('globalVar *= 2;', sandbox);
vm.runInContext('globalVar *= 2;', sandbox);
}
console.log(util.inspect(sandbox));
// { globalVar: 1024 }
```
Note that running untrusted code is a tricky business requiring great care.
`vm.runInContext()` is quite useful, but safely running untrusted code requires
a separate process.
## vm.runInDebugContext(code)
`vm.runInDebugContext()` compiles and executes `code` inside the V8 debug
context. The primary use case is to get access to the V8 debug object:
* `code` {string} The JavaScript code to compile and run.
The `vm.runInDebugContext()` method compiles and executes `code` inside the V8
debug context. The primary use case is to gain access to the V8 `Debug` object:
```js
const vm = require('vm');
@ -227,21 +263,38 @@ console.log(Debug.findScript(process.emit).name); // 'events.js'
console.log(Debug.findScript(process.exit).name); // 'internal/process.js'
```
Note that the debug context and object are intrinsically tied to V8's debugger
implementation and may change (or even get removed) without prior warning.
*Note*: The debug context and object are intrinsically tied to V8's debugger
implementation and may change (or even be removed) without prior warning.
The debug object can also be exposed with the `--expose_debug_as=` switch.
The `Debug` object can also be made available using the V8-specific
`--expose_debug_as=` [command line option][cli.md].
## vm.runInNewContext(code[, sandbox][, options])
`vm.runInNewContext()` compiles `code`, contextifies `sandbox` if passed or
creates a new contextified sandbox if it's omitted, and then runs the code with
the sandbox as the global object and returns the result.
`vm.runInNewContext()` takes the same options as [`vm.runInThisContext()`][].
Example: compile and execute code that increments a global variable and sets a
new one. These globals are contained in the sandbox.
* `code` {string} The JavaScript code to compile and run.
* `sandbox` {Object} An object that will be [contextified][]. If `undefined`, a
new object will be created.
* `options`
* `filename` {string} Specifies the filename used in stack traces produced
by this script.
* `lineOffset` {number} Specifies the line number offset that is displayed
in stack traces produced by this script.
* `columnOffset` {number} Specifies the column number offset that is displayed
in stack traces produced by this script.
* `displayErrors` {boolean} When `true`, if an [`Error`][] error occurs
while compiling the `code`, the line of code causing the error is attached
to the stack trace.
* `timeout` {number} Specifies the number of milliseconds to execute `code`
before terminating execution. If execution is terminated, an [`Error`][]
will be thrown.
The `vm.runInContext()` first contextifies the given `sandbox` object (or
creates a new `sandbox` if passed as `undefined`), compiles the `code`, runs it
within the context of the created context, then returns the result. Running code
does not have access to the local scope.
The following example compiles and executes code that increments a global
variable and sets a new one. These globals are contained in the `sandbox`.
```js
const util = require('util');
@ -258,17 +311,29 @@ console.log(util.inspect(sandbox));
// { animal: 'cat', count: 3, name: 'kitty' }
```
Note that running untrusted code is a tricky business requiring great care.
`vm.runInNewContext()` is quite useful, but safely running untrusted code requires
a separate process.
## vm.runInThisContext(code[, options])
`vm.runInThisContext()` compiles `code`, runs it and returns the result. Running
code does not have access to local scope, but does have access to the current
`global` object.
Example of using `vm.runInThisContext()` and [`eval()`][] to run the same code:
* `code` {string} The JavaScript code to compile and run.
* `options`
* `filename` {string} Specifies the filename used in stack traces produced
by this script.
* `lineOffset` {number} Specifies the line number offset that is displayed
in stack traces produced by this script.
* `columnOffset` {number} Specifies the column number offset that is displayed
in stack traces produced by this script.
* `displayErrors` {boolean} When `true`, if an [`Error`][] error occurs
while compiling the `code`, the line of code causing the error is attached
to the stack trace.
* `timeout` {number} Specifies the number of milliseconds to execute `code`
before terminating execution. If execution is terminated, an [`Error`][]
will be thrown.
`vm.runInThisContext()` compiles `code`, runs it within the context of the
current `global` and returns the result. Running code does not have access to
local scope, but does have access to the current `global` object.
The following example illustrates using both `vm.runInThisContext()` and
the JavaScript [`eval()`][] function to run the same code:
```js
const vm = require('vm');
@ -286,33 +351,21 @@ console.log('localVar: ', localVar);
// evalResult: 'eval', localVar: 'eval'
```
`vm.runInThisContext()` does not have access to the local scope, so `localVar`
is unchanged. [`eval()`][] does have access to the local scope, so `localVar` is
changed.
In this way `vm.runInThisContext()` is much like an [indirect `eval()` call][],
e.g. `(0,eval)('code')`. However, it also has the following additional options:
- `filename`: allows you to control the filename that shows up in any stack
traces produced.
- `lineOffset`: allows you to add an offset to the line number that is
displayed in stack traces
- `columnOffset`: allows you to add an offset to the column number that is
displayed in stack traces
- `displayErrors`: if `true`, on error, attach the line of code that caused
the error to the stack trace. Will capture both syntax errors from compiling
`code` and runtime errors thrown by executing the compiled code. Defaults to
`true`.
- `timeout`: a number of milliseconds to execute `code` before terminating
execution. If execution is terminated, an [`Error`][] will be thrown.
## Example: Run a Server within a VM
The context of `.runInThisContext()` refers to the V8 context. The code passed
to this VM context will have it's own isolated scope. To run a simple web server
using the `http` module, for instance, the code passed to the context must either
call `require('http')` on its own, or have a reference to the `http` module passed
to it. For instance:
Because `vm.runInThisContext()` does not have access to the local scope,
`localVar` is unchanged. In contrast, [`eval()`][] *does* have access to the
local scope, so the value `localVar` is changed. In this way
`vm.runInThisContext()` is much like an [indirect `eval()` call][], e.g.
`(0,eval)('code')`.
## Example: Running an HTTP Server within a VM
When using either `script.runInThisContext()` or `vm.runInThisContext()`, the
code is executed within the current V8 global context. The code passed
to this VM context will have its own isolated scope.
In order to run a simple web server using the `http` module the code passed to
the context must either call `require('http')` on its own, or have a reference
to the `http` module passed to it. For instance:
```js
'use strict';
@ -334,10 +387,26 @@ let code =
vm.runInThisContext(code)(require);
```
_Note: `require()` in the above case shares the state with context it is passed
from. This might introduce risks when unknown code is executed, e.g. altering
objects from the calling thread's context in unwanted ways. It is advisable to
run `vm` code in a separate process._
*Note*: The `require()` in the above case shares the state with context it is
passed from. This may introduce risks when untrusted code is executed, e.g.
altering objects from the calling thread's context in unwanted ways.
## What does it mean to "contextify" an object?
All JavaScript executed within Node.js runs within the scope of a "context".
According to the [V8 Embedder's Guide][]:
> In V8, a context is an execution environment that allows separate, unrelated,
> JavaScript applications to run in a single instance of V8. You must explicitly
> specify the context in which you want any JavaScript code to be run.
When the method `vm.createContext()` is called, the `sandbox` object that is
passed in (or a newly created object if `sandbox` is `undefined`) is associated
internally with a new instance of a V8 Context. This V8 Context provides the
`code` run using the `vm` modules methods with an isolated global environment
within which it can operate. The process of creating the V8 Context and
associating it with the `sandbox` object is what this document refers to as
"contextifying" the `sandbox`.
[indirect `eval()` call]: https://es5.github.io/#x10.4.2
[global object]: https://es5.github.io/#x15.1
@ -349,3 +418,5 @@ run `vm` code in a separate process._
[`vm.runInNewContext()`]: #vm_vm_runinnewcontext_code_sandbox_options
[`vm.runInThisContext()`]: #vm_vm_runinthiscontext_code_options
[`eval()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
[V8 Embedder's Guide]: https://developers.google.com/v8/embed#contexts
[contextified]: #vm_what_does_it_mean_to_contextify_an_object

Loading…
Cancel
Save