diff options
author | James M Snell <jasnell@gmail.com> | 2016-05-17 21:56:01 -0700 |
---|---|---|
committer | James M Snell <jasnell@gmail.com> | 2016-05-19 17:40:00 -0700 |
commit | baeed8b3d93efb337a09c902e259c0695d179a15 (patch) | |
tree | f1e00b0817491ec65ce3ead78188bc2015eb0ede /doc/api/vm.md | |
parent | 395cc885f4eb21c2002dbfe405d31da275699aa8 (diff) | |
download | android-node-v8-baeed8b3d93efb337a09c902e259c0695d179a15.tar.gz android-node-v8-baeed8b3d93efb337a09c902e259c0695d179a15.tar.bz2 android-node-v8-baeed8b3d93efb337a09c902e259c0695d179a15.zip |
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>
Diffstat (limited to 'doc/api/vm.md')
-rw-r--r-- | doc/api/vm.md | 397 |
1 files changed, 234 insertions, 163 deletions
diff --git a/doc/api/vm.md b/doc/api/vm.md index b212cc6e29..8de2775dcc 100644 --- a/doc/api/vm.md +++ b/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 |