UNPKG

jsfuzz

Version:
837 lines 26.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); // This is ported from go-fuzz versifier const assert = require("assert"); const DeepEqual = require('deep-equal'); const CHAR_CODE_A = 65; const CHAR_CODE_Z = 90; const CHAR_CODE_a = 97; const CHAR_CODE_z = 122; const CHAR_CODE__ = 95; const CHAR_CODE_0 = 48; const CHAR_CODE_9 = 57; const CHAR_CODE_SPACE = 32; const CHAR_CODE_TAB = 9; const CHAR_CODE_MINUS = 45; const CHAR_CODE_DOT = 46; const CHAR_CODE_NEWLINE = 10; const CHAR_CODE_WIN_NEWLINE = 13; class DynamicBuffer { constructor(len) { this.len = len ? len : 1024; this.buffer = Buffer.alloc(this.len); this.offset = 0; } Write(p) { if (this.offset + p.length > this.len) { this.buffer = Buffer.concat([this.buffer, Buffer.alloc(this.len)]); this.len = this.len * 2; } p.copy(this.buffer, this.offset); this.offset += p.length; } Bytes() { return this.buffer.slice(0, this.offset); } } function makeDict(s) { // @ts-ignore let res = {}; // @ts-ignore res[s.toString()] = {}; return res; } function randTerm(v, dict) { const terms = Object.keys(dict); return Buffer.from(terms[v.Rand(terms.length)]); } function singleTerm(dict) { for (let k in dict) { return k; } return 'BAD'; } class BlockNode { constructor(nodes) { this.nodes = nodes; } Visit(f) { f(this); for (let i of this.nodes) { i.Visit(f); } } Generate(w, v) { let nodes = this.nodes; if (v.Rand(10) == 0) { while (nodes.length > 0 && v.Rand(2) == 0) { const idx = v.Rand(nodes.length); nodes.copyWithin(0, idx + 1, Math.min(idx, nodes.length - (idx + 1))); nodes = nodes.slice(0, nodes.length - 1); } } if (v.Rand(10) == 0) { while (nodes.length > 0 && v.Rand(2) == 0) { const idx = v.Rand(nodes.length); nodes.copyWithin(idx + 1, idx); } } if (v.Rand(10) == 0) { while (nodes.length > 0 && v.Rand(2) == 0) { const idx1 = v.Rand(nodes.length); const idx2 = v.Rand(nodes.length); [nodes[idx1], nodes[idx2]] = [nodes[idx2], nodes[idx1]]; } } for (let n of this.nodes) { if (v.Rand(20) == 0) { continue; } if (v.Rand(20) == 0) { } n.Generate(w, v); } } } exports.BlockNode = BlockNode; function BuildVerse(oldv, data) { let printable = 0; for (let b of data) { if (b >= 0x20 && b < 0x7f) { printable++; } } if (printable < (data.length * 9 / 10)) { return oldv; } const newv = new Verse(); if (oldv != null) { newv.blocks = oldv.blocks; newv.allNodes = oldv.allNodes; } let n = tokenize(data); n = structure(n); const b = new BlockNode(n); newv.blocks = newv.blocks.concat(b); b.Visit((n) => { newv.allNodes = newv.allNodes.concat(n); }); return newv; } exports.BuildVerse = BuildVerse; class Verse { constructor() { this.blocks = []; this.allNodes = []; } Rhyme() { let buf = new DynamicBuffer(); this.blocks[this.Rand(this.blocks.length)].Generate(buf, this); return buf.Bytes(); } Rand(n) { return Math.floor(Math.random() * Math.floor(n)); } } exports.Verse = Verse; class WsNode { constructor(dict) { this.dict = dict; } Visit(f) { f(this); } Generate(w, v) { if (v.Rand(5) != 0) { w.Write(randTerm(v, this.dict)); } else { while (true) { const r = v.Rand(3); if (r === 0) { break; } else if (r === 1) { w.Write(Buffer.from(' ')); } else if (r === 2) { w.Write(Buffer.from('\t')); } } } } } class AlphaNumNode { constructor(dict) { this.dict = dict; } Visit(f) { f(this); } Generate(w, v) { if (v.Rand(5) != 0) { w.Write(randTerm(v, this.dict)); } else { let len = 0; const r = v.Rand(3); if (r === 0) { len = v.Rand(4); } else if (r === 1) { len = v.Rand(20); } else if (r === 2) { len = v.Rand(100); } const res = Buffer.alloc(len); for (let i = 0; i < res.length; i++) { const r = v.Rand(4); if (r === 0) { res[i] = '_'.charCodeAt(0); } else if (r === 1) { res[i] = '0'.charCodeAt(0) + v.Rand(10); } else if (r === 2) { res[i] = 'a'.charCodeAt(0) + v.Rand(26); } else if (r === 3) { res[i] = 'A'.charCodeAt(0) + v.Rand(26); } } w.Write(res); } } } class NumNode { constructor(dict, hex) { this.dict = dict; this.hex = hex; } Visit(f) { f(this); } Generate(w, v) { if (v.Rand(2) === 0) { w.Write(randTerm(v, this.dict)); } else { const randNum = function () { const base = [8, 10, 16][v.Rand(3)]; let len = 0; const r = v.Rand(3); if (r === 0) { len = v.Rand(4); } else if (r === 1) { len = v.Rand(16); } else if (r === 2) { len = v.Rand(40); } let num = Buffer.alloc(len + 1); for (let i = 0; i < num.length; i++) { switch (base) { case 8: num[i] = '0'.charCodeAt(0) + v.Rand(8); break; case 10: num[i] = '0'.charCodeAt(0) + v.Rand(10); break; case 16: const r = v.Rand(3); switch (r) { case 0: num[i] = '0'.charCodeAt(0) + v.Rand(10); break; case 1: num[i] = 'a'.charCodeAt(0) + v.Rand(6); break; case 2: num[i] = 'A'.charCodeAt(0) + v.Rand(6); } } } switch (base) { case 8: num = Buffer.concat([Buffer.from('0'), num]); break; case 10: case 16: num = Buffer.concat([Buffer.from('0x'), num]); break; default: assert.fail("bad"); } if (v.Rand(2) == 0) { num = Buffer.concat([Buffer.from('-'), num]); } return num; }; switch (v.Rand(3)) { case 0: w.Write(randNum()); break; case 1: w.Write(randNum()); w.Write(Buffer.from('.')); w.Write(randNum()); break; case 2: w.Write(randNum()); w.Write(Buffer.from('e')); w.Write(randNum()); break; } } } } class ControlNode { constructor(ch) { this.ch = ch; } Visit(f) { f(this); } Generate(w, v) { if (v.Rand(10) !== 0) { w.Write(Buffer.alloc(1, this.ch)); } else { while (true) { const b = v.Rand(128); if ((b >= CHAR_CODE_0 && b <= CHAR_CODE_9) || (b >= CHAR_CODE_a && b <= CHAR_CODE_z) || (b >= CHAR_CODE_A && b <= CHAR_CODE_Z)) { continue; } w.Write(Buffer.alloc(1, b)); break; } } } } class BracketNode { constructor(open, clos, b) { this.open = open; this.clos = clos; this.b = b; } Visit(f) { f(this); this.b.Visit(f); } Generate(w, v) { if (v.Rand(10) != 0) { w.Write(Buffer.alloc(1, this.open)); this.b.Generate(w, v); w.Write(Buffer.alloc(1, this.clos)); } else { const brk = ['<', '[', '(', '{', '\'', '"', '`']; const open = brk[v.Rand(brk.length)]; // @ts-ignore let clos = brackets[open]; if (v.Rand(5) == 0) { // @ts-ignore clos = brackets[brk[v.Rand(brk.length)]]; } w.Write(Buffer.from(open)); this.b.Generate(w, v); w.Write(Buffer.from(clos)); } } } class KeyValNode { constructor(delim, key, value) { this.delim = delim; this.key = key; this.value = value; } Visit(f) { f(this); this.key.Visit(f); this.value.Visit(f); } Generate(w, v) { const delim = ['='.charCodeAt(0), ':'.charCodeAt(0)]; this.delim = delim[v.Rand(delim.length)]; this.key.Generate(w, v); w.Write(Buffer.alloc(1, this.delim)); this.value.Generate(w, v); } } class ListNode { constructor(delim, blocks) { this.delim = delim; this.blocks = blocks; } Visit(f) { f(this); for (let b of this.blocks) { b.Visit(f); } } Generate(w, v) { let blocks = this.blocks; if (v.Rand(5) === 0) { blocks = []; while (v.Rand(3) !== 0) { blocks = blocks.concat([this.blocks[v.Rand(this.blocks.length)]]); } } for (let i = 0; i < this.blocks.length; i++) { if (i != 0) { w.Write(Buffer.alloc(1, this.delim)); } this.blocks[i].Generate(w, v); } } } class LineNode { constructor(r, b) { this.r = r; this.b = b; } Visit(f) { f(this); this.b.Visit(f); } Generate(w, v) { this.b.Generate(w, v); if (this.r) { w.Write(Buffer.from('\r\n')); } else { w.Write(Buffer.from('\n')); } } } function DecodeRune(data) { return [1, 2]; } function tokenize(data) { let res = []; let StateType; (function (StateType) { StateType[StateType["stateControl"] = 0] = "stateControl"; StateType[StateType["stateWs"] = 1] = "stateWs"; StateType[StateType["stateAlpha"] = 2] = "stateAlpha"; StateType[StateType["stateNum"] = 3] = "stateNum"; })(StateType || (StateType = {})); let state = StateType.stateControl; let start = 0; for (let i = 0; i < data.length; i++) { const [r, s] = DecodeRune(data.slice(i)); if ((r >= CHAR_CODE_a && r <= CHAR_CODE_z) || (r >= CHAR_CODE_A && r <= CHAR_CODE_Z) || r === CHAR_CODE__) { if (state === StateType.stateControl) { start = i; state = StateType.stateAlpha; } else if (state === StateType.stateWs) { res.push(new WsNode(makeDict(data.slice(start, i)))); start = i; state = StateType.stateAlpha; } else if (state === StateType.stateAlpha || state == StateType.stateNum) { state = StateType.stateAlpha; } } else if (r >= CHAR_CODE_0 && r <= CHAR_CODE_9) { if (state === StateType.stateControl) { start = i; state = StateType.stateNum; } else if (state === StateType.stateWs) { res.push(new WsNode(makeDict(data.slice(start, i)))); start = i; state = StateType.stateNum; } } else if (r === CHAR_CODE_SPACE || r === CHAR_CODE_TAB) { if (state === StateType.stateControl) { start = i; state = StateType.stateWs; } else if (state === StateType.stateAlpha) { res.push(new AlphaNumNode(makeDict(data.slice(start, i)))); start = i; state = StateType.stateWs; } else if (state == StateType.stateNum) { res.push(new NumNode(makeDict(data.slice(start, i)), false)); start = i; state = StateType.stateWs; } } else { if (state === StateType.stateControl || state === StateType.stateWs) { res.push(new WsNode(makeDict(data.slice(start, i)))); } else if (state === StateType.stateAlpha) { res.push(new AlphaNumNode(makeDict(data.slice(start, i)))); } else if (state === StateType.stateNum) { res.push(new NumNode(makeDict(data.slice(start, i)), false)); } state = StateType.stateControl; res.push(new ControlNode(r)); } i += s; } if (state === StateType.stateAlpha) { res.push(new AlphaNumNode(makeDict(data.slice(start)))); } else if (state === StateType.stateNum) { res.push(new NumNode(makeDict(data.slice(start)), false)); } return res; } function structure(nn) { nn = extractNumbers(nn); nn = structureBrackets(nn); nn = structureKeyValue(nn); nn = structureLists(nn); nn = structureLines(nn); return nn; } function isHexNum(s) { if (s.length) { return false; } for (let i = 0; i < s.length; i++) { const c = s[i]; if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { continue; } return false; } return true; } function isDecNum(s) { if (s.length === 0) { return false; } for (let i = 0; i < s.length; i++) { if (s[i] >= '0' && s[i] <= '9') { continue; } return false; } return true; } function extractNumbers(nn) { let changed = true; while (changed) { changed = false; for (let i = 0; i < nn.length; i++) { const n = nn[i]; if (n instanceof AlphaNumNode) { const v = singleTerm(n.dict); if (v.length >= 3) { if (v[0] === '0' && v[1] === 'x' && isHexNum(v.slice(2))) { nn[i] = new NumNode(n.dict, true); changed = true; } const e = v.indexOf('e'); if (e !== -1) { if (isDecNum(v.slice(0, e)) && isDecNum(v.slice(e + 1))) { nn[i] = new NumNode(n.dict, false); changed = true; continue; } if (e == (v.length - 1) && i !== (nn.length - 1)) { const num1 = nn[i + 1]; if (num1 instanceof NumNode) { nn[i + 1] = new NumNode(makeDict(Buffer.from(v + singleTerm(num1.dict))), false); nn.copyWithin(i, i + 1); changed = true; continue; } } } } } if (n instanceof ControlNode && n.ch === CHAR_CODE_MINUS && i !== nn.length - 1) { const num = nn[i + 1]; if (num instanceof NumNode) { let prev = undefined; if (i != 0) { prev = nn[i - 1]; } if (prev instanceof AlphaNumNode && singleTerm(prev.dict).length > 1 && singleTerm(prev.dict)[singleTerm(prev.dict).length - 1] == 'e') { nn.copyWithin(i, i + 1); changed = true; continue; } } } if (n instanceof ControlNode && n.ch === CHAR_CODE_DOT && i != 0 && i != nn.length - 1) { const num1 = nn[i - 1]; const num2 = nn[i + 1]; if (num1 instanceof NumNode && num2 instanceof NumNode) { nn[i + 1] = new NumNode(makeDict(Buffer.from(singleTerm(num1.dict) + "." + singleTerm(num2.dict))), false); nn.copyWithin(i - 1, i + 1); changed = true; continue; } } } } return nn; } function structureKeyValue(nn) { const delims = { '=': true, ':': true }; for (let n of nn) { if (n instanceof BracketNode) { n.b.nodes = structureKeyValue(n.b.nodes); } } for (let i = 0; i < nn.length; i++) { const n = nn[i]; if (!(n instanceof ControlNode)) { continue; } // @ts-ignore if (delims[n.ch] && !(i == 0 || i == nn.length - 1)) { const key = nn[i - 1]; if (!(key instanceof AlphaNumNode)) { continue; } const value = nn[i + 1]; if (!(value instanceof AlphaNumNode)) { continue; } nn[i + 1] = new KeyValNode(n.ch, key, value); nn.copyWithin(i - 1, i + 1); nn = nn.slice(0, nn.length - 2); } } return nn; } const brackets = { '<': '>', '[': ']', '(': ')', '{': '}', '\'': '\'', '"': '"', '`': '`', }; function structureBrackets(nn) { let stk = []; loop: for (let i = 0; i < nn.length; i++) { const n = nn[i]; if (!(n instanceof ControlNode)) { continue; } for (let si = stk.length - 1; si >= 0; si--) { if (n.ch === stk[si].clos) { const b = new BracketNode(stk[si].open, stk[si].clos, new BlockNode(nn.slice(stk[si].pos + 1, i))); nn[stk[si].pos] = b; nn.copyWithin(stk[si].pos + 1, i + 1); nn = nn.slice(0, nn.length - i + stk[si].pos); i = stk[si].pos; stk = stk.slice(0, si); continue loop; } } // @ts-ignore const clos = brackets[String.fromCharCode(n.ch)]; if (clos) { stk.push({ clos: clos, open: n.ch, pos: i, }); } } return nn; } function structureLists(nn) { const delims = { ',': true, ';': true }; for (let n of nn) { if (n instanceof BracketNode) { n.b.nodes = structureLists(n.b.nodes); } } // TODO: fails on: // "f1": "v1", "f2": "v2", "f3": "v3" // the first detected list is "v2", "f3" for (let i = nn.length - 1; i >= 0; i--) { const n = nn[i]; // @ts-ignore if (n instanceof ControlNode && delims[n.ch]) { const elems = [ { tok: {}, done: false, pos: i - 1, inc: -1 }, { tok: {}, done: false, pos: i + 1, inc: 1 } ]; while (true) { for (let e of elems) { if (e.done || e.pos < 0 || e.pos >= nn.length) { e.done = true; continue; } const ctrl1 = nn[e.pos]; if (ctrl1 instanceof ControlNode) { if (ctrl1.ch == n.ch) { e.done = true; continue; } // @ts-ignore e.tok[ctrl1.ch] = true; } const brk1 = nn[e.pos]; if (brk1 instanceof BracketNode) { // @ts-ignore e.tok[brk1.open] = true; // @ts-ignore e.tok[brk1.clos] = true; } e.pos += e.inc; } if (elems[0].done && elems[1].done) { break; } const union = {}; for (let k in elems[0].tok) { // @ts-ignore union[k] = true; } for (let k in elems[1].tok) { // @ts-ignore union[k] = true; } if (DeepEqual(elems[0].tok, union) || DeepEqual(elems[1].tok, union)) { break; } } for (let k in elems[1].tok) { // @ts-ignore elems[0].tok[k] = true; } elemLoop: for (let e of elems) { for (; e.pos >= 0 && e.pos < nn.length; e.pos += e.inc) { const ctrl1 = nn[e.pos]; // @ts-ignore if (ctrl1 instanceof ControlNode && !elems[0].tok[ctrl1.ch]) { continue elemLoop; } const brk1 = nn[e.pos]; // @ts-ignore if (brk1 instanceof ControlNode && !elems[0].tok[brk1.ch]) { continue elemLoop; } } } for (let e of elems) { while (true) { if (e.done || e.pos < 0 || e.pos >= nn.length) { break; } const ctrl1 = nn[e.pos]; if (ctrl1 instanceof ControlNode) { if (ctrl1.ch == n.ch) { break; } // @ts-ignore if (!elems[0].tok[ctrl1.ch]) { break; } } const brk1 = nn[e.pos]; if (brk1 instanceof BracketNode) { // @ts-ignore if (!elems[0].tok[brk1.open] || !elems[0].tok[brk1.clos]) { break; } } e.pos += e.inc; } } const lst = new ListNode(n.ch, [ new BlockNode(nn.slice(elems[0].pos + 1, i)), new BlockNode(nn.slice(i + 1, elems[1].pos)) ]); let start = elems[0].pos; const end = elems[1].pos; while (true) { if (start < 0) { break; } const ctrl1 = nn[start]; if (!(ctrl1 instanceof ControlNode) || ctrl1.ch != n.ch) { break; } let pos = start - 1; while (true) { if (pos < 0) { break; } const ctrl1 = nn[pos]; if (ctrl1 instanceof ControlNode) { if (ctrl1.ch == n.ch) { break; } // @ts-ignore if (!elems[0].tok[ctrl1.ch]) { break; } } const brk1 = nn[pos]; if (brk1 instanceof BracketNode) { // @ts-ignore if (!elems[0].tok[brk1.open] || !elems[0].tok[brk1.clos]) { break; } } pos--; } lst.blocks = [new BlockNode(nn.slice(pos + 1, start))].concat(lst.blocks); start = pos; } nn[start + 1] = lst; nn.copyWithin(start + 2, end); nn = nn.slice(0, nn.length - end + start + 2); i = start + 1; } } return nn; } function structureLines(nn) { let res = []; for (let i = 0; i < nn.length; i++) { const n = nn[i]; if (n instanceof BracketNode) { n.b.nodes = structureLines(n.b.nodes); continue; } if (!(n instanceof ControlNode) || n.ch != CHAR_CODE_NEWLINE) { continue; } let r = false; let end = i; if (i != 0) { const prev = nn[i - 1]; if (prev instanceof ControlNode && prev.ch == CHAR_CODE_WIN_NEWLINE) { r = true; end--; } } res = res.concat(new LineNode(r, new BlockNode(nn.slice(0, end)))); nn = nn.slice(i + 1, nn.length); i = -1; } if (nn.length != 0) { res = res.concat(nn); } return res; } //# sourceMappingURL=versifier.js.map