blob: 4b6b21d0ec455ddf6c282f2cc3503505cbd722a9 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
const thrift = require("../../lib/thrift");
const FuzzTest = require("./gen-nodejs/FuzzTestNoUuid_types");
// const { FuzzedDataProvider } = require("@jazzer.js/core");
/**
* Creates a parser fuzzer function for a specific protocol
* @param {Function} protocolFactory - The Thrift protocol factory function
* @param {boolean} [readMessageBegin=false] - Whether to call readMessageBegin before reading the test instance
* This is needed for protocols that do not support parsing just a struct, such as TJSONProtocol.
* @returns {Function} A fuzzer function that can be used with Jazzer.js
*/
function createParserFuzzer(protocolFactory, readMessageBegin = false) {
return function fuzz(data) {
if (data.length < 2) {
return;
}
try {
// Set up transport with input data
const transport = new thrift.TFramedTransport(data);
const protocol = protocolFactory(transport);
const testInstance = new FuzzTest.FuzzTest();
if (readMessageBegin) {
protocol.readMessageBegin();
}
testInstance[Symbol.for("read")](protocol);
} catch (e) {
if (
!(
e.name === "InputBufferUnderrunError" ||
e.name === "TProtocolException"
)
) {
// TODO: Are other exceptions expected?
// console.log(e);
}
}
};
}
/**
* Creates a roundtrip fuzzer function for a specific protocol
* @param {Function} protocolFactory - The Thrift protocol factory function
* @param {boolean} [readMessageBegin=false] - Whether to call readMessageBegin before reading the test instance
* This is needed for protocols that do not support parsing just a struct, such as TJSONProtocol.
* @returns {Function} A fuzzer function that can be used with Jazzer.js
*/
function createRoundtripFuzzer(protocolFactory, readMessageBegin = false) {
return function fuzz(data) {
if (data.length < 2) {
return;
}
try {
// First deserialize using framed transport for input
const transport1 = new thrift.TFramedTransport(data);
const protocol1 = protocolFactory(transport1);
const testInstance = new FuzzTest.FuzzTest();
if (readMessageBegin) {
protocol1.readMessageBegin();
}
testInstance[Symbol.for("read")](protocol1);
// Then serialize using buffered transport with callback
let serializedData;
const transport2 = new thrift.TBufferedTransport(null, function (buf) {
serializedData = buf;
});
const protocol2 = protocolFactory(transport2);
testInstance[Symbol.for("write")](protocol2);
protocol2.flush();
if (!serializedData) {
throw new Error("Serialization failed - no data produced");
}
// Finally deserialize again and compare using framed transport
const transport3 = new thrift.TFramedTransport(serializedData);
const protocol3 = protocolFactory(transport3);
const deserialized = new FuzzTest.FuzzTest();
if (readMessageBegin) {
protocol3.readMessageBegin();
}
deserialized[Symbol.for("read")](protocol3);
// Compare the objects
if (!testInstance.equals(deserialized)) {
throw new Error("Roundtrip comparison failed");
}
} catch (e) {
if (
!(
e.name === "InputBufferUnderrunError" ||
e.name === "TProtocolException"
)
) {
// TODO: Are other exceptions expected?
// console.log(e);
}
}
};
}
module.exports = {
createParserFuzzer,
createRoundtripFuzzer,
};