| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 97496f0 commit 1851cf4
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -962,6 +962,38 @@ within which it can operate. The process of creating the V8 Context and | |||
| 962 | 962 | associating it with the `sandbox` object is what this document refers to as | |
| 963 | 963 | "contextifying" the `sandbox`. | |
| 964 | 964 | ||
| 965 | + ## Timeout limitations when using process.nextTick(), Promises, and queueMicrotask() | ||
| 966 | + | ||
| 967 | + Because of the internal mechanics of how the `process.nextTick()` queue and | ||
| 968 | + the microtask queue that underlies Promises are implemented within V8 and | ||
| 969 | + Node.js, it is possible for code running within a context to "escape" the | ||
| 970 | + `timeout` set using `vm.runInContext()`, `vm.runInNewContext()`, and | ||
| 971 | + `vm.runInThisContext()`. | ||
| 972 | + | ||
| 973 | + For example, the following code executed by `vm.runInNewContext()` with a | ||
| 974 | + timeout of 5 milliseconds schedules an infinite loop to run after a promise | ||
| 975 | + resolves. The scheduled loop is never interrupted by the timeout: | ||
| 976 | + | ||
| 977 | + ```js | ||
| 978 | + const vm = require('vm'); | ||
| 979 | + | ||
| 980 | + function loop() { | ||
| 981 | + while (1) console.log(Date.now()); | ||
| 982 | + } | ||
| 983 | + | ||
| 984 | + vm.runInNewContext( | ||
| 985 | + 'Promise.resolve().then(loop);', | ||
| 986 | + { loop, console }, | ||
| 987 | + { timeout: 5 } | ||
| 988 | + ); | ||
| 989 | + ``` | ||
| 990 | + | ||
| 991 | + This issue also occurs when the `loop()` call is scheduled using | ||
| 992 | + the `process.nextTick()` and `queueMicrotask()` functions. | ||
| 993 | + | ||
| 994 | + This issue occurs because all contexts share the same microtask and nextTick | ||
| 995 | + queues. | ||
| 996 | + | ||
| 965 | 997 | [`Error`]: errors.html#errors_class_error | |
| 966 | 998 | [`ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING`]: errors.html#ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING | |
| 967 | 999 | [`URL`]: url.html#url_class_url | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,41 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + // https://github.com/nodejs/node/issues/3020 | ||
| 4 | + // Promises, nextTick, and queueMicrotask allow code to escape the timeout | ||
| 5 | + // set for runInContext, runInNewContext, and runInThisContext | ||
| 6 | + | ||
| 7 | + require('../common'); | ||
| 8 | + const assert = require('assert'); | ||
| 9 | + const vm = require('vm'); | ||
| 10 | + | ||
| 11 | + const NS_PER_MS = 1000000n; | ||
| 12 | + | ||
| 13 | + const hrtime = process.hrtime.bigint; | ||
| 14 | + const nextTick = process.nextTick; | ||
| 15 | + | ||
| 16 | + function loop() { | ||
| 17 | + const start = hrtime(); | ||
| 18 | + while (1) { | ||
| 19 | + const current = hrtime(); | ||
| 20 | + const span = (current - start) / NS_PER_MS; | ||
| 21 | + if (span >= 100n) { | ||
| 22 | + throw new Error( | ||
| 23 | + `escaped timeout at ${span} milliseconds!`); | ||
| 24 | + } | ||
| 25 | + } | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + assert.throws(() => { | ||
| 29 | + vm.runInNewContext( | ||
| 30 | + 'nextTick(loop); loop();', | ||
| 31 | + { | ||
| 32 | + hrtime, | ||
| 33 | + nextTick, | ||
| 34 | + loop | ||
| 35 | + }, | ||
| 36 | + { timeout: 5 } | ||
| 37 | + ); | ||
| 38 | + }, { | ||
| 39 | + code: 'ERR_SCRIPT_EXECUTION_TIMEOUT', | ||
| 40 | + message: 'Script execution timed out after 5ms' | ||
| 41 | + }); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,39 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + // https://github.com/nodejs/node/issues/3020 | ||
| 4 | + // Promises, nextTick, and queueMicrotask allow code to escape the timeout | ||
| 5 | + // set for runInContext, runInNewContext, and runInThisContext | ||
| 6 | + | ||
| 7 | + require('../common'); | ||
| 8 | + const assert = require('assert'); | ||
| 9 | + const vm = require('vm'); | ||
| 10 | + | ||
| 11 | + const NS_PER_MS = 1000000n; | ||
| 12 | + | ||
| 13 | + const hrtime = process.hrtime.bigint; | ||
| 14 | + | ||
| 15 | + function loop() { | ||
| 16 | + const start = hrtime(); | ||
| 17 | + while (1) { | ||
| 18 | + const current = hrtime(); | ||
| 19 | + const span = (current - start) / NS_PER_MS; | ||
| 20 | + if (span >= 100n) { | ||
| 21 | + throw new Error( | ||
| 22 | + `escaped timeout at ${span} milliseconds!`); | ||
| 23 | + } | ||
| 24 | + } | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + assert.throws(() => { | ||
| 28 | + vm.runInNewContext( | ||
| 29 | + 'Promise.resolve().then(loop); loop();', | ||
| 30 | + { | ||
| 31 | + hrtime, | ||
| 32 | + loop | ||
| 33 | + }, | ||
| 34 | + { timeout: 5 } | ||
| 35 | + ); | ||
| 36 | + }, { | ||
| 37 | + code: 'ERR_SCRIPT_EXECUTION_TIMEOUT', | ||
| 38 | + message: 'Script execution timed out after 5ms' | ||
| 39 | + }); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,40 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + // https://github.com/nodejs/node/issues/3020 | ||
| 4 | + // Promises, nextTick, and queueMicrotask allow code to escape the timeout | ||
| 5 | + // set for runInContext, runInNewContext, and runInThisContext | ||
| 6 | + | ||
| 7 | + require('../common'); | ||
| 8 | + const assert = require('assert'); | ||
| 9 | + const vm = require('vm'); | ||
| 10 | + | ||
| 11 | + const NS_PER_MS = 1000000n; | ||
| 12 | + | ||
| 13 | + const hrtime = process.hrtime.bigint; | ||
| 14 | + | ||
| 15 | + function loop() { | ||
| 16 | + const start = hrtime(); | ||
| 17 | + while (1) { | ||
| 18 | + const current = hrtime(); | ||
| 19 | + const span = (current - start) / NS_PER_MS; | ||
| 20 | + if (span >= 100n) { | ||
| 21 | + throw new Error( | ||
| 22 | + `escaped timeout at ${span} milliseconds!`); | ||
| 23 | + } | ||
| 24 | + } | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + assert.throws(() => { | ||
| 28 | + vm.runInNewContext( | ||
| 29 | + 'queueMicrotask(loop); loop();', | ||
| 30 | + { | ||
| 31 | + hrtime, | ||
| 32 | + queueMicrotask, | ||
| 33 | + loop | ||
| 34 | + }, | ||
| 35 | + { timeout: 5 } | ||
| 36 | + ); | ||
| 37 | + }, { | ||
| 38 | + code: 'ERR_SCRIPT_EXECUTION_TIMEOUT', | ||
| 39 | + message: 'Script execution timed out after 5ms' | ||
| 40 | + }); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments