1+ // Licensed to the Apache Software Foundation(ASF) under one
2+ // or more contributor license agreements.See the NOTICE file
3+ // distributed with this work for additional information
4+ // regarding copyright ownership.The ASF licenses this file
5+ // to you under the Apache License, Version 2.0 (the
6+ // "License"); you may not use this file except in compliance
7+ // with the License. You may obtain a copy of the License at
8+ //
9+ // http://www.apache.org/licenses/LICENSE-2.0
10+ //
11+ // Unless required by applicable law or agreed to in writing,
12+ // software distributed under the License is distributed on an
13+ // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+ // KIND, either express or implied. See the License for the
15+ // specific language governing permissions and limitations
16+ // under the License.
17+
18+ using System ;
19+ using System . IO ;
20+ using SharpFuzz ;
21+ using Thrift . Protocol ;
22+ using Thrift . Transport ;
23+ using Thrift . Transport . Client ;
24+
25+ namespace Thrift . Tests . Protocols . Fuzzers
26+ {
27+ /// <summary>
28+ /// Base class for protocol round-trip fuzzers that handles the common fuzzing logic.
29+ /// </summary>
30+ /// <typeparam name="FuzzProtocol">The type of protocol to use for serialization/deserialization.</typeparam>
31+ public abstract class ProtocolRoundtripFuzzerBase < FuzzProtocol > where FuzzProtocol : TProtocol
32+ {
33+ /// <summary>
34+ /// Environment variable that controls whether to use in-process fuzzing for AFL.
35+ /// When set to "1", uses Fuzzer.Run instead of Fuzzer.OutOfProcess.Run.
36+ /// </summary>
37+ protected const string UseInProcessFuzzingEnvVar = "THRIFT_AFL_IN_PROCESS" ;
38+
39+ /// <summary>
40+ /// 10MB message size limit to prevent over-allocation during fuzzing
41+ /// </summary>
42+ protected const int FUZZ_MAX_MESSAGE_SIZE = 10 * 1024 * 1024 ;
43+
44+ /// <summary>
45+ /// Creates a new instance of the protocol for the given transport.
46+ /// </summary>
47+ protected abstract FuzzProtocol CreateProtocol ( TTransport transport ) ;
48+
49+ /// <summary>
50+ /// Helper method that contains the core fuzzing logic.
51+ /// </summary>
52+ private void ProcessFuzzStream ( Stream stream )
53+ {
54+ try
55+ {
56+ // First deserialize the input
57+ var config = new TConfiguration ( ) ;
58+ config . MaxMessageSize = FUZZ_MAX_MESSAGE_SIZE ;
59+ var inputTransport = new TStreamTransport ( stream , null , config ) ;
60+ var inputProtocol = CreateProtocol ( inputTransport ) ;
61+
62+ var inputObj = new FuzzTest ( ) ;
63+ inputObj . ReadAsync ( inputProtocol , default ) . GetAwaiter ( ) . GetResult ( ) ;
64+
65+ // Now serialize it back
66+ using var outputStream = new MemoryStream ( ) ;
67+ var outputTransport = new TStreamTransport ( null , outputStream , config ) ;
68+ var outputProtocol = CreateProtocol ( outputTransport ) ;
69+ inputObj . WriteAsync ( outputProtocol , default ) . GetAwaiter ( ) . GetResult ( ) ;
70+ outputTransport . FlushAsync ( default ) . GetAwaiter ( ) . GetResult ( ) ;
71+
72+ // Get the serialized bytes and deserialize again
73+ var serialized = outputStream . ToArray ( ) ;
74+ using var reStream = new MemoryStream ( serialized ) ;
75+ var reTransport = new TStreamTransport ( reStream , null , config ) ;
76+ var reProtocol = CreateProtocol ( reTransport ) ;
77+
78+ var outputObj = new FuzzTest ( ) ;
79+ outputObj . ReadAsync ( reProtocol , default ) . GetAwaiter ( ) . GetResult ( ) ;
80+
81+ // Compare the objects
82+ if ( ! inputObj . Equals ( outputObj ) )
83+ {
84+ throw new Exception ( "Round-trip objects are not equal" ) ;
85+ }
86+ }
87+ catch ( TException ) { /* Expected for malformed input */ }
88+ catch ( Exception ) { /* Expected for malformed input */ }
89+ }
90+
91+ /// <summary>
92+ /// The core fuzzing logic that processes a single input.
93+ /// </summary>
94+ protected void ProcessFuzzInput ( ReadOnlySpan < byte > span )
95+ {
96+ using var stream = new MemoryStream ( span . ToArray ( ) ) ;
97+ ProcessFuzzStream ( stream ) ;
98+ }
99+
100+ /// <summary>
101+ /// Runs the fuzzer with LibFuzzer.
102+ /// </summary>
103+ protected void RunLibFuzzer ( )
104+ {
105+ Fuzzer . LibFuzzer . Run ( ProcessFuzzInput ) ;
106+ }
107+
108+ /// <summary>
109+ /// Runs the fuzzer with AFL.
110+ /// </summary>
111+ protected void RunAFL ( )
112+ {
113+ var useInProcess = Environment . GetEnvironmentVariable ( UseInProcessFuzzingEnvVar ) == "1" ;
114+ if ( useInProcess )
115+ {
116+ Fuzzer . Run ( ProcessFuzzStream ) ;
117+ }
118+ else
119+ {
120+ Fuzzer . OutOfProcess . Run ( ProcessFuzzStream ) ;
121+ }
122+ }
123+ }
124+ }
0 commit comments