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
2
inline bool is_nan_false_positive(FuzzTest& test1, FuzzTest& test2) {
46
2
  BasicTypes& b1 = test1.basic;
47
2
  BasicTypes& b2 = test2.basic;
48
2
  if (std::isnan(b1.double_field) && std::isnan(b2.double_field)) {
49
2
    b1.double_field = 0.0;
50
2
    b2.double_field = 0.0;
51
2
  }
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
2
  return test1 == test2;
57
2
}
58
59
// Simple parse-only fuzzer
60
template<typename ProtocolType>
61
9.38k
int fuzz_parse(const uint8_t* data, size_t size) {
62
9.38k
  try {
63
9.38k
    std::shared_ptr<TConfiguration> config(new TConfiguration(FUZZ_MAX_MESSAGE_SIZE));
64
9.38k
    std::shared_ptr<TMemoryBuffer> trans(new TMemoryBuffer(const_cast<uint8_t*>(data), size, TMemoryBuffer::OBSERVE, config));
65
9.38k
    std::shared_ptr<TProtocol> proto(new ProtocolType(trans));
66
67
9.38k
    FuzzTest test;
68
9.38k
    test.read(proto.get());
69
9.38k
  } catch (const TException&) {
70
    // Ignore any Thrift exceptions - they're expected when fuzzing
71
9.38k
  }
72
9.38k
  return 0;
73
9.38k
}
int apache::thrift::fuzzer::fuzz_parse<apache::thrift::protocol::TJSONProtocol>(unsigned char const*, unsigned long)
Line
Count
Source
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
}
int apache::thrift::fuzzer::fuzz_parse<apache::thrift::protocol::TCompactProtocolT<apache::thrift::transport::TTransport> >(unsigned char const*, unsigned long)
Line
Count
Source
61
2.73k
int fuzz_parse(const uint8_t* data, size_t size) {
62
2.73k
  try {
63
2.73k
    std::shared_ptr<TConfiguration> config(new TConfiguration(FUZZ_MAX_MESSAGE_SIZE));
64
2.73k
    std::shared_ptr<TMemoryBuffer> trans(new TMemoryBuffer(const_cast<uint8_t*>(data), size, TMemoryBuffer::OBSERVE, config));
65
2.73k
    std::shared_ptr<TProtocol> proto(new ProtocolType(trans));
66
67
2.73k
    FuzzTest test;
68
2.73k
    test.read(proto.get());
69
2.73k
  } catch (const TException&) {
70
    // Ignore any Thrift exceptions - they're expected when fuzzing
71
2.72k
  }
72
2.73k
  return 0;
73
2.73k
}
int apache::thrift::fuzzer::fuzz_parse<apache::thrift::protocol::TBinaryProtocolT<apache::thrift::transport::TTransport, apache::thrift::protocol::TNetworkBigEndian> >(unsigned char const*, unsigned long)
Line
Count
Source
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
9.65k
int fuzz_roundtrip(const uint8_t* data, size_t size) {
78
9.65k
  try {
79
9.65k
    std::shared_ptr<TConfiguration> config(new TConfiguration(FUZZ_MAX_MESSAGE_SIZE));
80
    
81
    // First parse
82
9.65k
    std::shared_ptr<TMemoryBuffer> trans(new TMemoryBuffer(const_cast<uint8_t*>(data), size, TMemoryBuffer::OBSERVE, config));
83
9.65k
    std::shared_ptr<TProtocol> proto(new ProtocolType(trans));
84
85
9.65k
    FuzzTest test1;
86
9.65k
    test1.read(proto.get());
87
88
    // Serialize back
89
9.65k
    std::shared_ptr<TMemoryBuffer> outTrans(new TMemoryBuffer(config));
90
9.65k
    std::shared_ptr<TProtocol> outProto(new ProtocolType(outTrans));
91
9.65k
    test1.write(outProto.get());
92
93
    // Get serialized data
94
9.65k
    std::string serialized = outTrans->getBufferAsString();
95
96
    // Deserialize again
97
9.65k
    std::shared_ptr<TMemoryBuffer> reTrans(new TMemoryBuffer(config));
98
9.65k
    reTrans->write((const uint8_t*)serialized.data(), static_cast<uint32_t>(serialized.size()));
99
9.65k
    std::shared_ptr<TProtocol> reProto(new ProtocolType(reTrans));
100
101
9.65k
    FuzzTest test2;
102
9.65k
    test2.read(reProto.get());
103
104
    // Verify equality
105
9.65k
    if (!(test1 == test2) && !is_nan_false_positive(test1, test2)) {
106
0
      const std::string str1(apache::thrift::ThriftDebugString(test1));
107
0
      const std::string str2(apache::thrift::ThriftDebugString(test2));
108
109
0
      std::cout << "Expected:\n" << str1 << "\nGotten:\n" << str2 << std::endl;
110
111
0
      throw std::runtime_error("Roundtrip failed");
112
0
    }
113
9.65k
  } catch (const TException&) {
114
    // Ignore any Thrift exceptions - they're expected when fuzzing
115
9.12k
  }
116
9.65k
  return 0;
117
9.65k
}
int apache::thrift::fuzzer::fuzz_roundtrip<apache::thrift::protocol::TJSONProtocol>(unsigned char const*, unsigned long)
Line
Count
Source
77
2.54k
int fuzz_roundtrip(const uint8_t* data, size_t size) {
78
2.54k
  try {
79
2.54k
    std::shared_ptr<TConfiguration> config(new TConfiguration(FUZZ_MAX_MESSAGE_SIZE));
80
    
81
    // First parse
82
2.54k
    std::shared_ptr<TMemoryBuffer> trans(new TMemoryBuffer(const_cast<uint8_t*>(data), size, TMemoryBuffer::OBSERVE, config));
83
2.54k
    std::shared_ptr<TProtocol> proto(new ProtocolType(trans));
84
85
2.54k
    FuzzTest test1;
86
2.54k
    test1.read(proto.get());
87
88
    // Serialize back
89
2.54k
    std::shared_ptr<TMemoryBuffer> outTrans(new TMemoryBuffer(config));
90
2.54k
    std::shared_ptr<TProtocol> outProto(new ProtocolType(outTrans));
91
2.54k
    test1.write(outProto.get());
92
93
    // Get serialized data
94
2.54k
    std::string serialized = outTrans->getBufferAsString();
95
96
    // Deserialize again
97
2.54k
    std::shared_ptr<TMemoryBuffer> reTrans(new TMemoryBuffer(config));
98
2.54k
    reTrans->write((const uint8_t*)serialized.data(), static_cast<uint32_t>(serialized.size()));
99
2.54k
    std::shared_ptr<TProtocol> reProto(new ProtocolType(reTrans));
100
101
2.54k
    FuzzTest test2;
102
2.54k
    test2.read(reProto.get());
103
104
    // Verify equality
105
2.54k
    if (!(test1 == test2) && !is_nan_false_positive(test1, test2)) {
106
0
      const std::string str1(apache::thrift::ThriftDebugString(test1));
107
0
      const std::string str2(apache::thrift::ThriftDebugString(test2));
108
109
0
      std::cout << "Expected:\n" << str1 << "\nGotten:\n" << str2 << std::endl;
110
111
0
      throw std::runtime_error("Roundtrip failed");
112
0
    }
113
2.54k
  } catch (const TException&) {
114
    // Ignore any Thrift exceptions - they're expected when fuzzing
115
2.54k
  }
116
2.54k
  return 0;
117
2.54k
}
int apache::thrift::fuzzer::fuzz_roundtrip<apache::thrift::protocol::TCompactProtocolT<apache::thrift::transport::TTransport> >(unsigned char const*, unsigned long)
Line
Count
Source
77
3.34k
int fuzz_roundtrip(const uint8_t* data, size_t size) {
78
3.34k
  try {
79
3.34k
    std::shared_ptr<TConfiguration> config(new TConfiguration(FUZZ_MAX_MESSAGE_SIZE));
80
    
81
    // First parse
82
3.34k
    std::shared_ptr<TMemoryBuffer> trans(new TMemoryBuffer(const_cast<uint8_t*>(data), size, TMemoryBuffer::OBSERVE, config));
83
3.34k
    std::shared_ptr<TProtocol> proto(new ProtocolType(trans));
84
85
3.34k
    FuzzTest test1;
86
3.34k
    test1.read(proto.get());
87
88
    // Serialize back
89
3.34k
    std::shared_ptr<TMemoryBuffer> outTrans(new TMemoryBuffer(config));
90
3.34k
    std::shared_ptr<TProtocol> outProto(new ProtocolType(outTrans));
91
3.34k
    test1.write(outProto.get());
92
93
    // Get serialized data
94
3.34k
    std::string serialized = outTrans->getBufferAsString();
95
96
    // Deserialize again
97
3.34k
    std::shared_ptr<TMemoryBuffer> reTrans(new TMemoryBuffer(config));
98
3.34k
    reTrans->write((const uint8_t*)serialized.data(), static_cast<uint32_t>(serialized.size()));
99
3.34k
    std::shared_ptr<TProtocol> reProto(new ProtocolType(reTrans));
100
101
3.34k
    FuzzTest test2;
102
3.34k
    test2.read(reProto.get());
103
104
    // Verify equality
105
3.34k
    if (!(test1 == test2) && !is_nan_false_positive(test1, test2)) {
106
0
      const std::string str1(apache::thrift::ThriftDebugString(test1));
107
0
      const std::string str2(apache::thrift::ThriftDebugString(test2));
108
109
0
      std::cout << "Expected:\n" << str1 << "\nGotten:\n" << str2 << std::endl;
110
111
0
      throw std::runtime_error("Roundtrip failed");
112
0
    }
113
3.34k
  } catch (const TException&) {
114
    // Ignore any Thrift exceptions - they're expected when fuzzing
115
3.00k
  }
116
3.34k
  return 0;
117
3.34k
}
int apache::thrift::fuzzer::fuzz_roundtrip<apache::thrift::protocol::TBinaryProtocolT<apache::thrift::transport::TTransport, apache::thrift::protocol::TNetworkBigEndian> >(unsigned char const*, unsigned long)
Line
Count
Source
77
3.76k
int fuzz_roundtrip(const uint8_t* data, size_t size) {
78
3.76k
  try {
79
3.76k
    std::shared_ptr<TConfiguration> config(new TConfiguration(FUZZ_MAX_MESSAGE_SIZE));
80
    
81
    // First parse
82
3.76k
    std::shared_ptr<TMemoryBuffer> trans(new TMemoryBuffer(const_cast<uint8_t*>(data), size, TMemoryBuffer::OBSERVE, config));
83
3.76k
    std::shared_ptr<TProtocol> proto(new ProtocolType(trans));
84
85
3.76k
    FuzzTest test1;
86
3.76k
    test1.read(proto.get());
87
88
    // Serialize back
89
3.76k
    std::shared_ptr<TMemoryBuffer> outTrans(new TMemoryBuffer(config));
90
3.76k
    std::shared_ptr<TProtocol> outProto(new ProtocolType(outTrans));
91
3.76k
    test1.write(outProto.get());
92
93
    // Get serialized data
94
3.76k
    std::string serialized = outTrans->getBufferAsString();
95
96
    // Deserialize again
97
3.76k
    std::shared_ptr<TMemoryBuffer> reTrans(new TMemoryBuffer(config));
98
3.76k
    reTrans->write((const uint8_t*)serialized.data(), static_cast<uint32_t>(serialized.size()));
99
3.76k
    std::shared_ptr<TProtocol> reProto(new ProtocolType(reTrans));
100
101
3.76k
    FuzzTest test2;
102
3.76k
    test2.read(reProto.get());
103
104
    // Verify equality
105
3.76k
    if (!(test1 == test2) && !is_nan_false_positive(test1, test2)) {
106
0
      const std::string str1(apache::thrift::ThriftDebugString(test1));
107
0
      const std::string str2(apache::thrift::ThriftDebugString(test2));
108
109
0
      std::cout << "Expected:\n" << str1 << "\nGotten:\n" << str2 << std::endl;
110
111
0
      throw std::runtime_error("Roundtrip failed");
112
0
    }
113
3.76k
  } catch (const TException&) {
114
    // Ignore any Thrift exceptions - they're expected when fuzzing
115
3.58k
  }
116
3.76k
  return 0;
117
3.76k
}
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_