blob: 4b6b21d0ec455ddf6c282f2cc3503505cbd722a9 [file] [log] [blame]
Jens Geyer72a714e2025-08-26 22:12:07 +02001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
Hasnain Lakhaniaa183322025-08-25 13:54:33 -070020const thrift = require("../../lib/thrift");
21const FuzzTest = require("./gen-nodejs/FuzzTestNoUuid_types");
22// const { FuzzedDataProvider } = require("@jazzer.js/core");
23
24/**
25 * Creates a parser fuzzer function for a specific protocol
26 * @param {Function} protocolFactory - The Thrift protocol factory function
27 * @param {boolean} [readMessageBegin=false] - Whether to call readMessageBegin before reading the test instance
28 * This is needed for protocols that do not support parsing just a struct, such as TJSONProtocol.
29 * @returns {Function} A fuzzer function that can be used with Jazzer.js
30 */
31function createParserFuzzer(protocolFactory, readMessageBegin = false) {
32 return function fuzz(data) {
33 if (data.length < 2) {
34 return;
35 }
36
37 try {
38 // Set up transport with input data
39 const transport = new thrift.TFramedTransport(data);
40 const protocol = protocolFactory(transport);
41 const testInstance = new FuzzTest.FuzzTest();
42 if (readMessageBegin) {
43 protocol.readMessageBegin();
44 }
45 testInstance[Symbol.for("read")](protocol);
46 } catch (e) {
47 if (
48 !(
49 e.name === "InputBufferUnderrunError" ||
50 e.name === "TProtocolException"
51 )
52 ) {
53 // TODO: Are other exceptions expected?
54 // console.log(e);
55 }
56 }
57 };
58}
59
60/**
61 * Creates a roundtrip fuzzer function for a specific protocol
62 * @param {Function} protocolFactory - The Thrift protocol factory function
63 * @param {boolean} [readMessageBegin=false] - Whether to call readMessageBegin before reading the test instance
64 * This is needed for protocols that do not support parsing just a struct, such as TJSONProtocol.
65 * @returns {Function} A fuzzer function that can be used with Jazzer.js
66 */
67function createRoundtripFuzzer(protocolFactory, readMessageBegin = false) {
68 return function fuzz(data) {
69 if (data.length < 2) {
70 return;
71 }
72
73 try {
74 // First deserialize using framed transport for input
75 const transport1 = new thrift.TFramedTransport(data);
76 const protocol1 = protocolFactory(transport1);
77 const testInstance = new FuzzTest.FuzzTest();
78 if (readMessageBegin) {
79 protocol1.readMessageBegin();
80 }
81 testInstance[Symbol.for("read")](protocol1);
82
83 // Then serialize using buffered transport with callback
84 let serializedData;
85 const transport2 = new thrift.TBufferedTransport(null, function (buf) {
86 serializedData = buf;
87 });
88 const protocol2 = protocolFactory(transport2);
89 testInstance[Symbol.for("write")](protocol2);
90 protocol2.flush();
91
92 if (!serializedData) {
93 throw new Error("Serialization failed - no data produced");
94 }
95
96 // Finally deserialize again and compare using framed transport
97 const transport3 = new thrift.TFramedTransport(serializedData);
98 const protocol3 = protocolFactory(transport3);
99 const deserialized = new FuzzTest.FuzzTest();
100 if (readMessageBegin) {
101 protocol3.readMessageBegin();
102 }
103 deserialized[Symbol.for("read")](protocol3);
104
105 // Compare the objects
106 if (!testInstance.equals(deserialized)) {
107 throw new Error("Roundtrip comparison failed");
108 }
109 } catch (e) {
110 if (
111 !(
112 e.name === "InputBufferUnderrunError" ||
113 e.name === "TProtocolException"
114 )
115 ) {
116 // TODO: Are other exceptions expected?
117 // console.log(e);
118 }
119 }
120 };
121}
122
123module.exports = {
124 createParserFuzzer,
125 createRoundtripFuzzer,
126};