Coverage Report

Created: 2026-04-12 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
4.13k
int fuzz_parse(const uint8_t* data, size_t size) {
62
4.13k
  try {
63
4.13k
    std::shared_ptr<TConfiguration> config(new TConfiguration(FUZZ_MAX_MESSAGE_SIZE));
64
4.13k
    std::shared_ptr<TMemoryBuffer> trans(new TMemoryBuffer(const_cast<uint8_t*>(data), size, TMemoryBuffer::OBSERVE, config));
65
4.13k
    std::shared_ptr<TProtocol> proto(new ProtocolType(trans));
66
67
4.13k
    FuzzTest test;
68
4.13k
    test.read(proto.get());
69
4.13k
  } catch (const TException&) {
70
    // Ignore any Thrift exceptions - they're expected when fuzzing
71
4.13k
  }
72
4.13k
  return 0;
73
4.13k
}
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_