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+ import Foundation
19+ import Thrift
20+ import Fuzz
21+
22+ /// Generic parser that returns a parsed object from binary data - for use as a converter
23+ public func parseObjectWithProtocol< P: TProtocol > (
24+ start: UnsafeRawPointer ,
25+ count: Int ,
26+ protocolType: P . Type ) -> Fuzz . FuzzTest ? {
27+ let data = Data ( bytes: start, count: count)
28+ let transport = TMemoryBufferTransport ( readBuffer: data)
29+ let proto = P ( on: transport)
30+
31+ do {
32+ return try Fuzz . FuzzTest. read ( from: proto)
33+ } catch {
34+ return nil
35+ }
36+ }
37+
38+ /// Test roundtrip serialization/deserialization with the specified protocol and conversion function
39+ public func roundtripWithProtocol< P: TProtocol > (
40+ start: UnsafeRawPointer ,
41+ count: Int ,
42+ protocolType: P . Type
43+ ) -> Int32 {
44+ // Try to convert data to a test object
45+ guard let testObj = parseObjectWithProtocol ( start: start, count: count, protocolType: protocolType) else {
46+ return 0
47+ }
48+
49+ // Now do a roundtrip test with the converted object
50+ do {
51+ // Serialize
52+ let writeTransport = TMemoryBufferTransport ( )
53+ let writeProto = P ( on: writeTransport)
54+
55+ try testObj. write ( to: writeProto)
56+ try writeTransport. flush ( )
57+
58+ // Deserialize
59+ let readTransport = TMemoryBufferTransport ( readBuffer: writeTransport. writeBuffer)
60+ let readProto = P ( on: readTransport)
61+
62+ let deserialized = try Fuzz . FuzzTest. read ( from: readProto)
63+
64+ // This should always be true, but we check just to be sure
65+ guard deserialized == testObj else {
66+ fatalError ( " Roundtrip test failed: objects not equal after serialization/deserialization " )
67+ }
68+
69+ } catch {
70+ // Catch expected exceptions
71+ }
72+
73+ return 0
74+ }
75+
76+ /// Typedef for the fuzzer function signature required by libFuzzer
77+ public typealias FuzzTarget = @convention ( c) ( UnsafeRawPointer , Int ) -> Int32
78+
79+ // Import the libFuzzer driver function
80+ @_silgen_name ( " LLVMFuzzerRunDriver " )
81+ public func LLVMFuzzerRunDriver(
82+ _ argc: UnsafeMutablePointer < Int32 > ,
83+ _ argv: UnsafeMutablePointer < UnsafeMutablePointer < UnsafeMutablePointer < CChar > > > ,
84+ _ userCb: @escaping @convention ( c) ( UnsafeRawPointer , Int ) -> Int32 ) -> Int32
85+
86+ // Run the libFuzzer driver with the given test function
87+ // We use this to get around swift compilation issues, which create main functions that otherwise
88+ // conflict with the libfuzzer main.
89+ // See more documentation here: https://llvm.org/docs/LibFuzzer.html#using-libfuzzer-as-a-library
90+ public func runLibFuzzerDriver( testOneInput: @escaping FuzzTarget ) -> Never {
91+ // Create C-style arguments to pass to LLVMFuzzerRunDriver
92+ var args = CommandLine . arguments. map { strdup ( $0) }
93+ var argc = Int32 ( args. count)
94+ var argv = args. map { UnsafeMutablePointer < CChar > ( $0!) }
95+ let argvPtr = UnsafeMutablePointer< UnsafeMutablePointer< CChar>>. allocate( capacity: args. count)
96+ argvPtr. initialize ( from: & argv, count: args. count)
97+ let argvPtrPtr = UnsafeMutablePointer< UnsafeMutablePointer< UnsafeMutablePointer< CChar>>> . allocate( capacity: 1 )
98+ argvPtrPtr. pointee = argvPtr
99+
100+ // Start the fuzzer engine with our test function
101+ let result = LLVMFuzzerRunDriver ( & argc, argvPtrPtr, testOneInput)
102+
103+ // Clean up
104+ argvPtrPtr. deallocate ( )
105+ argvPtr. deallocate ( )
106+
107+ exit ( Int32 ( result) )
108+ }
0 commit comments