blob: da936e48c88156cf7682c4aac63e820de3debf03 [file] [log] [blame]
Hasnain Lakhani37f4e0d2025-08-25 11:21:33 -07001/*
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
20#ifndef THRIFT_TEST_FUZZ_COMMON_TCC_
21#define THRIFT_TEST_FUZZ_COMMON_TCC_
22
23#include <stddef.h>
24#include <stdint.h>
25#include <memory>
26#include <cmath>
27#include <iostream>
28
29#include <thrift/protocol/TDebugProtocol.h>
30#include <thrift/transport/TBufferTransports.h>
31#include <thrift/TToString.h>
32#include <thrift/TConfiguration.h>
33
34#include "gen-cpp/FuzzTest_types.h"
35
36namespace apache { namespace thrift { namespace fuzzer {
37
38using namespace apache::thrift::transport;
39using namespace apache::thrift::protocol;
40using namespace fuzz;
41
42// 10MB message size limit to prevent over-allocation during fuzzing
43const int FUZZ_MAX_MESSAGE_SIZE = 10 * 1024 * 1024;
44
45inline bool is_nan_false_positive(FuzzTest& test1, FuzzTest& test2) {
46 BasicTypes& b1 = test1.basic;
47 BasicTypes& b2 = test2.basic;
48 if (std::isnan(b1.double_field) && std::isnan(b2.double_field)) {
49 b1.double_field = 0.0;
50 b2.double_field = 0.0;
51 }
52
53 // Check for NaN in containers if they contain doubles
54 // This is a simplified version - may need adjustment based on actual schema
55
56 return test1 == test2;
57}
58
59// Simple parse-only fuzzer
60template<typename ProtocolType>
61int fuzz_parse(const uint8_t* data, size_t size) {
62 try {
63 std::shared_ptr<TConfiguration> config(new TConfiguration(FUZZ_MAX_MESSAGE_SIZE));
64 std::shared_ptr<TMemoryBuffer> trans(new TMemoryBuffer(const_cast<uint8_t*>(data), size, TMemoryBuffer::OBSERVE, config));
65 std::shared_ptr<TProtocol> proto(new ProtocolType(trans));
66
67 FuzzTest test;
68 test.read(proto.get());
69 } catch (const TException&) {
70 // Ignore any Thrift exceptions - they're expected when fuzzing
71 }
72 return 0;
73}
74
75// Roundtrip fuzzer that verifies serialization/deserialization
76template<typename ProtocolType>
77int fuzz_roundtrip(const uint8_t* data, size_t size) {
78 try {
79 std::shared_ptr<TConfiguration> config(new TConfiguration(FUZZ_MAX_MESSAGE_SIZE));
80
81 // First parse
82 std::shared_ptr<TMemoryBuffer> trans(new TMemoryBuffer(const_cast<uint8_t*>(data), size, TMemoryBuffer::OBSERVE, config));
83 std::shared_ptr<TProtocol> proto(new ProtocolType(trans));
84
85 FuzzTest test1;
86 test1.read(proto.get());
87
88 // Serialize back
89 std::shared_ptr<TMemoryBuffer> outTrans(new TMemoryBuffer(config));
90 std::shared_ptr<TProtocol> outProto(new ProtocolType(outTrans));
91 test1.write(outProto.get());
92
93 // Get serialized data
94 std::string serialized = outTrans->getBufferAsString();
95
96 // Deserialize again
97 std::shared_ptr<TMemoryBuffer> reTrans(new TMemoryBuffer(config));
98 reTrans->write((const uint8_t*)serialized.data(), static_cast<uint32_t>(serialized.size()));
99 std::shared_ptr<TProtocol> reProto(new ProtocolType(reTrans));
100
101 FuzzTest test2;
102 test2.read(reProto.get());
103
104 // Verify equality
105 if (!(test1 == test2) && !is_nan_false_positive(test1, test2)) {
106 const std::string str1(apache::thrift::ThriftDebugString(test1));
107 const std::string str2(apache::thrift::ThriftDebugString(test2));
108
109 std::cout << "Expected:\n" << str1 << "\nGotten:\n" << str2 << std::endl;
110
111 throw std::runtime_error("Roundtrip failed");
112 }
113 } catch (const TException&) {
114 // Ignore any Thrift exceptions - they're expected when fuzzing
115 }
116 return 0;
117}
118
119}}} // apache::thrift::fuzzer
120
121#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
122__attribute__((weak)) int main(int argc, char** argv) {
123 return 0;
124}
125#endif
126
127#endif // THRIFT_TEST_FUZZ_COMMON_TCC_