/src/thrift/lib/cpp/test/fuzz/FuzzCommon.tcc
Line | Count | Source |
1 | | /* |
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 | | |
36 | | namespace apache { namespace thrift { namespace fuzzer { |
37 | | |
38 | | using namespace apache::thrift::transport; |
39 | | using namespace apache::thrift::protocol; |
40 | | using namespace fuzz; |
41 | | |
42 | | // 10MB message size limit to prevent over-allocation during fuzzing |
43 | | const int FUZZ_MAX_MESSAGE_SIZE = 10 * 1024 * 1024; |
44 | | |
45 | 0 | inline bool is_nan_false_positive(FuzzTest& test1, FuzzTest& test2) { |
46 | 0 | BasicTypes& b1 = test1.basic; |
47 | 0 | BasicTypes& b2 = test2.basic; |
48 | 0 | if (std::isnan(b1.double_field) && std::isnan(b2.double_field)) { |
49 | 0 | b1.double_field = 0.0; |
50 | 0 | b2.double_field = 0.0; |
51 | 0 | } |
52 | 0 |
|
53 | 0 | // Check for NaN in containers if they contain doubles |
54 | 0 | // This is a simplified version - may need adjustment based on actual schema |
55 | 0 | |
56 | 0 | return test1 == test2; |
57 | 0 | } |
58 | | |
59 | | // Simple parse-only fuzzer |
60 | | template<typename ProtocolType> |
61 | 2.51k | int fuzz_parse(const uint8_t* data, size_t size) { |
62 | 2.51k | try { |
63 | 2.51k | std::shared_ptr<TConfiguration> config(new TConfiguration(FUZZ_MAX_MESSAGE_SIZE)); |
64 | 2.51k | std::shared_ptr<TMemoryBuffer> trans(new TMemoryBuffer(const_cast<uint8_t*>(data), size, TMemoryBuffer::OBSERVE, config)); |
65 | 2.51k | std::shared_ptr<TProtocol> proto(new ProtocolType(trans)); |
66 | | |
67 | 2.51k | FuzzTest test; |
68 | 2.51k | test.read(proto.get()); |
69 | 2.51k | } catch (const TException&) { |
70 | | // Ignore any Thrift exceptions - they're expected when fuzzing |
71 | 2.51k | } |
72 | 2.51k | return 0; |
73 | 2.51k | } |
74 | | |
75 | | // Roundtrip fuzzer that verifies serialization/deserialization |
76 | | template<typename ProtocolType> |
77 | | int 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_ |