UNPKG

jsfuzz

Version:
153 lines 6.16 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); // const cp = require('child_process'); const corpus_1 = require("./corpus"); const fs = require("fs"); const child_process_1 = require("child_process"); const protocol_1 = require("./protocol"); const versifier_1 = require("./versifier"); const crypto = require('crypto'); const util = require('util'); const pidusage = require('pidusage'); process.on('SIGINT', function () { // ignore sigint as this propagates to worker as well. console.log('Received SIGINT. shutting down gracefully'); }); class Fuzzer { constructor(target, dir, exactArtifactPath, rssLimitMb, timeout, regression, onlyAscii, versifier) { this.target = target; this.corpus = new corpus_1.Corpus(dir, onlyAscii); this.onlyAscii = onlyAscii; this.versifier = versifier; this.verse = null; this.total_executions = 0; this.total_coverage = 0; this.exactArtifactPath = exactArtifactPath; this.rssLimitMb = rssLimitMb; this.timeout = timeout; this.regression = regression; this.worker = child_process_1.fork(`${__dirname}/worker.js`, [this.target], { execArgv: [`--max-old-space-size=${this.rssLimitMb}`] }); this.workerRss = 0; this.rssInterval = null; this.pulseInterval = null; this.lastSampleTime = Date.now(); this.executionsInSample = 0; } logStats(type) { const rss = Math.trunc((process.memoryUsage().rss + this.workerRss) / 1024 / 1024 * 100) / 100; const endTime = Date.now(); const execs_per_second = Math.trunc(this.executionsInSample / (endTime - this.lastSampleTime) * 1000); this.lastSampleTime = Date.now(); this.executionsInSample = 0; console.log(`#${this.total_executions} ${type} cov: ${this.total_coverage} corp: ${this.corpus.getLength()} exec/s: ${execs_per_second} rss: ${rss} MB`); } writeCrash(buf) { let filepath = 'crash-' + crypto.createHash('sha256').update(buf).digest('hex'); if (this.exactArtifactPath) { filepath = this.exactArtifactPath; } fs.writeFileSync(filepath, buf); console.log(`crash was written to ${filepath}`); if (buf.length < 200) { console.log(`crash(hex)=${buf.toString('hex')}`); } } clearIntervals() { if (this.rssInterval) { clearInterval(this.rssInterval); this.rssInterval = null; } if (this.pulseInterval) { clearInterval(this.pulseInterval); this.pulseInterval = null; } pidusage.clear(); } start() { console.log(`#0 READ units: ${this.corpus.getLength()}`); this.startTime = Date.now(); this.lastSampleTime = Date.now(); let executions = 0; let buf = this.corpus.generateInput(); let startTimeOneSample = Date.now(); this.worker.on('message', (m) => { this.total_executions++; this.executionsInSample++; const endTimeOneSample = Date.now(); const diffOneSample = endTimeOneSample - startTimeOneSample; startTimeOneSample = endTimeOneSample; if (m.type === protocol_1.WorkerMessageType.CRASH) { this.writeCrash(buf); this.clearIntervals(); process.exitCode = 1; return; } else if (m.coverage > this.total_coverage) { this.total_coverage = m.coverage; this.corpus.putBuffer(buf); this.logStats('NEW'); if (buf.length > 0 && this.versifier) { this.verse = versifier_1.BuildVerse(this.verse, buf); } } else if ((diffOneSample / 1000) > this.timeout) { console.log("================================================================="); console.log(`timeout reached. testcase took: ${diffOneSample}`); this.worker.kill('SIGKILL'); return; } if (this.total_executions % 10 != 0 || this.verse === null || !this.versifier) { buf = this.corpus.generateInput(); } else { buf = this.verse.Rhyme(); } this.worker.send({ type: protocol_1.ManageMessageType.WORK, buf: buf }); }); this.worker.on('error', (e) => { console.log('error received'); console.log(e); }); this.worker.on('exit', (code, signal) => { if (signal && code !== 0) { console.log('Worker killed'); this.writeCrash(buf); process.exitCode = 1; } console.log('Worker exited'); this.clearIntervals(); }); this.worker.send({ type: protocol_1.ManageMessageType.WORK, buf: buf }); this.pulseInterval = setInterval(() => { this.logStats("PULSE"); }, 3000); this.rssInterval = setInterval(async () => { const stats = await pidusage(this.worker.pid); this.workerRss = stats.memory; if (this.workerRss > this.rssLimitMb * 1024 * 1024) { this.clearIntervals(); console.log(`MEMORY OOM: exceeded ${this.rssLimitMb} MB. Killing worker`); this.worker.kill('SIGKILL'); } const diffOneSample = Date.now() - startTimeOneSample; if ((diffOneSample / 1000) > this.timeout) { console.log("================================================================="); console.log(`timeout reached. testcase took: ${diffOneSample}`); this.worker.kill('SIGKILL'); return; } }, 3000); } } exports.Fuzzer = Fuzzer; // // process.once('SIGTERM', function (code) { // console.log('SIGTERM received...'); // }); //# sourceMappingURL=fuzzer.js.map