首页 > 解决方案 > 以编程方式过滤 V8 堆快照中不需要的字符串(无需开发工具 GUI)

问题描述

我有一个 Node 应用程序,它将 JavaScript 源代码作为字符串发送到在 Node 的 VM api 中执行它的工作线程。我只拍摄工作线程堆的快照。这是为了检测 JavaScript 源代码中的任何字符串分配。但是,我得到了很多晦涩的注释,因为字符串会使堆膨胀。

在此处输入图像描述

我最初怀疑这是由于 Node VM 如何将代码作为字符串执行,所以我评论了我的代码的 VM 部分,但我仍然得到这些不需要的字符串。也许这是由于使用require()and import

我的代码如下。同样,app.js只需将源代码作为字符串传递给我的工作线程,worker.mjs. worker.mjs将在 VM 沙箱中运行传递的字符串数据,然后将其堆快照写入文件。

// App.js file
const { Worker, isMainThread } = require('worker_threads');

if (isMainThread) {
    // JavaScript source code passed as String.
    let workerData = `
    var nop = unescape("%u9090%u9090");
    while (nop.length <= 0x100000/2) {nop += nop;}`;

    const worker = new Worker('./worker.mjs', { workerData });

    worker.once('message', (filename) => {
      console.log(`worker heapdump: ${filename}`);
    });
  
    // Tell the worker to create a heapdump.
    worker.postMessage('heapdump');
};
// worker.mjs
import { workerData, parentPort, threadId } from 'worker_threads';
import { createContext, runInContext } from 'vm';
import { writeHeapSnapshot, getHeapSnapshot } from 'v8';

parentPort.once('message', (message) => {
    if (message === 'heapdump') {
        const sandbox = {};
        const strict = '"use strict";'

        createContext(sandbox);

        runInContext(strict+workerData, sandbox, {timeout: 10000 });

        parentPort.postMessage(writeHeapSnapshot());
    }
});

我的最终目标是收集仅从字符串源代码中创建的所有字符串和串联字符串workerData。在这个例子中,nop变量的值。

在此处输入图像描述

但如图所示,连接字符串中也有很多绒毛数据。

"encodingOps.ucs2.byteLength"@29509
"encodingOps.utf16le.byteLength"@29531
"encodingOps.latin1.byteLength"@29555
"encodingOps.ascii.byteLength"@29579
"encodingOps.base64.byteLength"@29603
"encodingOps.hex.byteLength"@29627
"module.exports.getModuleFromWrap"@39059
...
...
"internal/modules/package_json_reader.js"@10997
"internal/modules/esm/translators.js"@11001
"internal/modules/esm/transform_source.js"@11011
"internal/modules/esm/resolve.js"@11021
"internal/modules/esm/module_map.js"@11025
"internal/modules/esm/module_job.js"@11029
"internal/modules/esm/loader.js"@11033
"internal/modules/esm/get_source.js"@11043
"internal/modules/esm/get_format.js"

vm 模块支持在 V8 虚拟机上下文中编译和运行代码。vm 模块不是安全机制。不要使用它来运行不受信任的代码。https://nodejs.org/api/vm.html

我了解 Node VM 在其自己的上下文中执行代码。是否可以检索 VM 的上下文 id,然后过滤堆快照以查找存在于该特定上下文中的字符串?在这种情况下,我只想要nop变量。我希望有某种方法可以在不使用chrome dev-tools.

标签: javascriptnode.jsv8

解决方案


也许这是由于使用require()and import

基本上是的。你想要所有的字符串,你得到所有的字符串。JavaScript 使用大量字符串。(具体的导入机制无关紧要。如果您执行任何代码,您将在堆快照中看到它的字符串/等。)

是否可以检索 VM 的上下文 id,然后过滤堆快照以查找存在于该特定上下文中的字符串?

不,堆对象和上下文之间没有关联。


推荐阅读