1 // Copyright 2021 Code Intelligence GmbH
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 package com.code_intelligence.jazzer.driver;
16 
17 import com.code_intelligence.jazzer.api.FuzzedDataProvider;
18 import java.io.ByteArrayOutputStream;
19 import java.io.IOException;
20 import java.io.ObjectOutputStream;
21 import java.util.ArrayList;
22 import java.util.Base64;
23 
24 // Wraps the native FuzzedDataProviderImpl and serializes all its return values
25 // into a Base64-encoded string.
26 public final class RecordingFuzzedDataProvider implements FuzzedDataProvider {
27   private final FuzzedDataProvider target;
28   private final ArrayList<Object> recordedReplies = new ArrayList<>();
29 
RecordingFuzzedDataProvider(FuzzedDataProvider target)30   private RecordingFuzzedDataProvider(FuzzedDataProvider target) {
31     this.target = target;
32   }
33 
makeFuzzedDataProviderProxy(FuzzedDataProvider target)34   public static FuzzedDataProvider makeFuzzedDataProviderProxy(FuzzedDataProvider target) {
35     return new RecordingFuzzedDataProvider(target);
36   }
37 
serializeFuzzedDataProviderProxy(FuzzedDataProvider proxy)38   public static String serializeFuzzedDataProviderProxy(FuzzedDataProvider proxy)
39       throws IOException {
40     return ((RecordingFuzzedDataProvider) proxy).serialize();
41   }
42 
recordAndReturn(T object)43   private <T> T recordAndReturn(T object) {
44     recordedReplies.add(object);
45     return object;
46   }
47 
serialize()48   private String serialize() throws IOException {
49     byte[] rawOut;
50     try (ByteArrayOutputStream byteStream = new ByteArrayOutputStream()) {
51       try (ObjectOutputStream objectStream = new ObjectOutputStream(byteStream)) {
52         objectStream.writeObject(recordedReplies);
53       }
54       rawOut = byteStream.toByteArray();
55     }
56     return Base64.getEncoder().encodeToString(rawOut);
57   }
58 
59   @Override
consumeBoolean()60   public boolean consumeBoolean() {
61     return recordAndReturn(target.consumeBoolean());
62   }
63 
64   @Override
consumeBooleans(int maxLength)65   public boolean[] consumeBooleans(int maxLength) {
66     return recordAndReturn(target.consumeBooleans(maxLength));
67   }
68 
69   @Override
consumeByte()70   public byte consumeByte() {
71     return recordAndReturn(target.consumeByte());
72   }
73 
74   @Override
consumeByte(byte min, byte max)75   public byte consumeByte(byte min, byte max) {
76     return recordAndReturn(target.consumeByte(min, max));
77   }
78 
79   @Override
consumeBytes(int maxLength)80   public byte[] consumeBytes(int maxLength) {
81     return recordAndReturn(target.consumeBytes(maxLength));
82   }
83 
84   @Override
consumeRemainingAsBytes()85   public byte[] consumeRemainingAsBytes() {
86     return recordAndReturn(target.consumeRemainingAsBytes());
87   }
88 
89   @Override
consumeShort()90   public short consumeShort() {
91     return recordAndReturn(target.consumeShort());
92   }
93 
94   @Override
consumeShort(short min, short max)95   public short consumeShort(short min, short max) {
96     return recordAndReturn(target.consumeShort(min, max));
97   }
98 
99   @Override
consumeShorts(int maxLength)100   public short[] consumeShorts(int maxLength) {
101     return recordAndReturn(target.consumeShorts(maxLength));
102   }
103 
104   @Override
consumeInt()105   public int consumeInt() {
106     return recordAndReturn(target.consumeInt());
107   }
108 
109   @Override
consumeInt(int min, int max)110   public int consumeInt(int min, int max) {
111     return recordAndReturn(target.consumeInt(min, max));
112   }
113 
114   @Override
consumeInts(int maxLength)115   public int[] consumeInts(int maxLength) {
116     return recordAndReturn(target.consumeInts(maxLength));
117   }
118 
119   @Override
consumeLong()120   public long consumeLong() {
121     return recordAndReturn(target.consumeLong());
122   }
123 
124   @Override
consumeLong(long min, long max)125   public long consumeLong(long min, long max) {
126     return recordAndReturn(target.consumeLong(min, max));
127   }
128 
129   @Override
consumeLongs(int maxLength)130   public long[] consumeLongs(int maxLength) {
131     return recordAndReturn(target.consumeLongs(maxLength));
132   }
133 
134   @Override
consumeFloat()135   public float consumeFloat() {
136     return recordAndReturn(target.consumeFloat());
137   }
138 
139   @Override
consumeRegularFloat()140   public float consumeRegularFloat() {
141     return recordAndReturn(target.consumeRegularFloat());
142   }
143 
144   @Override
consumeRegularFloat(float min, float max)145   public float consumeRegularFloat(float min, float max) {
146     return recordAndReturn(target.consumeRegularFloat(min, max));
147   }
148 
149   @Override
consumeProbabilityFloat()150   public float consumeProbabilityFloat() {
151     return recordAndReturn(target.consumeProbabilityFloat());
152   }
153 
154   @Override
consumeDouble()155   public double consumeDouble() {
156     return recordAndReturn(target.consumeDouble());
157   }
158 
159   @Override
consumeRegularDouble()160   public double consumeRegularDouble() {
161     return recordAndReturn(target.consumeRegularDouble());
162   }
163 
164   @Override
consumeRegularDouble(double min, double max)165   public double consumeRegularDouble(double min, double max) {
166     return recordAndReturn(target.consumeRegularDouble(min, max));
167   }
168 
169   @Override
consumeProbabilityDouble()170   public double consumeProbabilityDouble() {
171     return recordAndReturn(target.consumeProbabilityDouble());
172   }
173 
174   @Override
consumeChar()175   public char consumeChar() {
176     return recordAndReturn(target.consumeChar());
177   }
178 
179   @Override
consumeChar(char min, char max)180   public char consumeChar(char min, char max) {
181     return recordAndReturn(target.consumeChar(min, max));
182   }
183 
184   @Override
consumeCharNoSurrogates()185   public char consumeCharNoSurrogates() {
186     return recordAndReturn(target.consumeCharNoSurrogates());
187   }
188 
189   @Override
consumeString(int maxLength)190   public String consumeString(int maxLength) {
191     return recordAndReturn(target.consumeString(maxLength));
192   }
193 
194   @Override
consumeRemainingAsString()195   public String consumeRemainingAsString() {
196     return recordAndReturn(target.consumeRemainingAsString());
197   }
198 
199   @Override
consumeAsciiString(int maxLength)200   public String consumeAsciiString(int maxLength) {
201     return recordAndReturn(target.consumeAsciiString(maxLength));
202   }
203 
204   @Override
consumeRemainingAsAsciiString()205   public String consumeRemainingAsAsciiString() {
206     return recordAndReturn(target.consumeRemainingAsAsciiString());
207   }
208 
209   @Override
remainingBytes()210   public int remainingBytes() {
211     return recordAndReturn(target.remainingBytes());
212   }
213 }
214