blob: b02683c42eb6cab5b8c5c798ef28e4a3bb642140 [file] [log] [blame]
Dylan Katz9d5845b2020-05-11 15:44:01 -07001/*
2 * Copyright 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include <functional>
17#include <iostream>
Dylan Katz98e14de2020-09-25 16:22:38 -070018#include <memory>
Dylan Katz9d5845b2020-05-11 15:44:01 -070019
Dylan Katz98e14de2020-09-25 16:22:38 -070020#include "FuzzFormatTypes.h"
Dylan Katz9d5845b2020-05-11 15:44:01 -070021#include "fuzzer/FuzzedDataProvider.h"
22#include "utils/String8.h"
23
24static constexpr int MAX_STRING_BYTES = 256;
25static constexpr uint8_t MAX_OPERATIONS = 50;
Dylan Katz98e14de2020-09-25 16:22:38 -070026// Interestingly, 2147483614 (INT32_MAX - 33) seems to be the max value that is handled for format
27// flags. Unfortunately we need to use a smaller value so we avoid consuming too much memory.
Dylan Katz9d5845b2020-05-11 15:44:01 -070028
Dylan Katz98e14de2020-09-25 16:22:38 -070029void fuzzFormat(FuzzedDataProvider* dataProvider, android::String8* str1, bool shouldAppend);
30std::vector<std::function<void(FuzzedDataProvider*, android::String8*, android::String8*)>>
Dylan Katz9d5845b2020-05-11 15:44:01 -070031 operations = {
Dylan Katz9d5845b2020-05-11 15:44:01 -070032 // Bytes and size
Dylan Katz98e14de2020-09-25 16:22:38 -070033 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
34 str1->bytes();
Dylan Katz9d5845b2020-05-11 15:44:01 -070035 },
Dylan Katz98e14de2020-09-25 16:22:38 -070036 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
37 str1->isEmpty();
Dylan Katz9d5845b2020-05-11 15:44:01 -070038 },
Dylan Katz98e14de2020-09-25 16:22:38 -070039 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
40 str1->length();
Dylan Katz9d5845b2020-05-11 15:44:01 -070041 },
42
43 // Casing
Dylan Katz98e14de2020-09-25 16:22:38 -070044 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
45 str1->toUpper();
Dylan Katz9d5845b2020-05-11 15:44:01 -070046 },
Dylan Katz98e14de2020-09-25 16:22:38 -070047 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
48 str1->toLower();
Dylan Katz9d5845b2020-05-11 15:44:01 -070049 },
Dylan Katz98e14de2020-09-25 16:22:38 -070050 [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
51 str1->removeAll(str2->c_str());
Dylan Katz9d5845b2020-05-11 15:44:01 -070052 },
Dylan Katz98e14de2020-09-25 16:22:38 -070053 [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
54 const android::String8& constRef(*str2);
55 str1->compare(constRef);
Dylan Katz9d5845b2020-05-11 15:44:01 -070056 },
57
58 // Append and format
Dylan Katz98e14de2020-09-25 16:22:38 -070059 [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
60 str1->append(str2->c_str());
Dylan Katz9d5845b2020-05-11 15:44:01 -070061 },
Dylan Katz98e14de2020-09-25 16:22:38 -070062 [](FuzzedDataProvider* dataProvider, android::String8* str1, android::String8*)
63 -> void { fuzzFormat(dataProvider, str1, dataProvider->ConsumeBool()); },
Dylan Katz9d5845b2020-05-11 15:44:01 -070064
65 // Find operation
Dylan Katz98e14de2020-09-25 16:22:38 -070066 [](FuzzedDataProvider* dataProvider, android::String8* str1,
67 android::String8* str2) -> void {
Dylan Katz9d5845b2020-05-11 15:44:01 -070068 // We need to get a value from our fuzzer here.
Dylan Katz98e14de2020-09-25 16:22:38 -070069 int start_index = dataProvider->ConsumeIntegralInRange<int>(0, str1->size());
70 str1->find(str2->c_str(), start_index);
Dylan Katz9d5845b2020-05-11 15:44:01 -070071 },
72
73 // Path handling
Dylan Katz98e14de2020-09-25 16:22:38 -070074 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
75 str1->getBasePath();
Dylan Katz9d5845b2020-05-11 15:44:01 -070076 },
Dylan Katz98e14de2020-09-25 16:22:38 -070077 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
78 str1->getPathExtension();
Dylan Katz9d5845b2020-05-11 15:44:01 -070079 },
Dylan Katz98e14de2020-09-25 16:22:38 -070080 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
81 str1->getPathLeaf();
Dylan Katz9d5845b2020-05-11 15:44:01 -070082 },
Dylan Katz98e14de2020-09-25 16:22:38 -070083 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
84 str1->getPathDir();
Dylan Katz9d5845b2020-05-11 15:44:01 -070085 },
Dylan Katz98e14de2020-09-25 16:22:38 -070086 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
87 str1->convertToResPath();
Dylan Katz9d5845b2020-05-11 15:44:01 -070088 },
Dylan Katz98e14de2020-09-25 16:22:38 -070089 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
90 std::shared_ptr<android::String8> path_out_str =
91 std::make_shared<android::String8>();
92 str1->walkPath(path_out_str.get());
93 path_out_str->clear();
Dylan Katz9d5845b2020-05-11 15:44:01 -070094 },
Dylan Katz98e14de2020-09-25 16:22:38 -070095 [](FuzzedDataProvider* dataProvider, android::String8* str1,
96 android::String8*) -> void {
97 str1->setPathName(dataProvider->ConsumeBytesWithTerminator<char>(5).data());
Dylan Katz9d5845b2020-05-11 15:44:01 -070098 },
Dylan Katz98e14de2020-09-25 16:22:38 -070099 [](FuzzedDataProvider* dataProvider, android::String8* str1,
100 android::String8*) -> void {
101 str1->appendPath(dataProvider->ConsumeBytesWithTerminator<char>(5).data());
Dylan Katz9d5845b2020-05-11 15:44:01 -0700102 },
103};
104
Dylan Katz98e14de2020-09-25 16:22:38 -0700105void fuzzFormat(FuzzedDataProvider* dataProvider, android::String8* str1, bool shouldAppend) {
106 FormatChar formatType = dataProvider->ConsumeEnum<FormatChar>();
107
108 std::string formatString("%");
109 // Width specifier
110 if (dataProvider->ConsumeBool()) {
111 // Left pad with zeroes
112 if (dataProvider->ConsumeBool()) {
113 formatString.push_back('0');
114 }
115 // Right justify (or left justify if negative)
116 int32_t justify = dataProvider->ConsumeIntegralInRange<int32_t>(-kMaxFormatFlagValue,
117 kMaxFormatFlagValue);
118 formatString += std::to_string(justify);
119 }
120
121 // The # specifier only works with o, x, X, a, A, e, E, f, F, g, and G
122 if (canApplyFlag(formatType, '#') && dataProvider->ConsumeBool()) {
123 formatString.push_back('#');
124 }
125
126 // Precision specifier
127 if (canApplyFlag(formatType, '.') && dataProvider->ConsumeBool()) {
128 formatString.push_back('.');
129 formatString +=
130 std::to_string(dataProvider->ConsumeIntegralInRange<int>(0, kMaxFormatFlagValue));
131 }
132
133 formatString.push_back(kFormatChars.at(static_cast<uint8_t>(formatType)));
134
135 switch (formatType) {
136 case SIGNED_DECIMAL: {
137 int val = dataProvider->ConsumeIntegral<int>();
138 if (shouldAppend) {
139 str1->appendFormat(formatString.c_str(), val);
140 } else {
141 str1->format(formatString.c_str(), dataProvider->ConsumeIntegral<int>());
142 }
143 break;
144 }
145
146 case UNSIGNED_DECIMAL:
147 case UNSIGNED_OCTAL:
148 case UNSIGNED_HEX_LOWER:
149 case UNSIGNED_HEX_UPPER: {
150 // Unsigned integers for u, o, x, and X
151 uint val = dataProvider->ConsumeIntegral<uint>();
152 if (shouldAppend) {
153 str1->appendFormat(formatString.c_str(), val);
154 } else {
155 str1->format(formatString.c_str(), val);
156 }
157 break;
158 }
159
160 case FLOAT_LOWER:
161 case FLOAT_UPPER:
162 case EXPONENT_LOWER:
163 case EXPONENT_UPPER:
164 case SHORT_EXP_LOWER:
165 case SHORT_EXP_UPPER:
166 case HEX_FLOAT_LOWER:
167 case HEX_FLOAT_UPPER: {
168 // Floating points for f, F, e, E, g, G, a, and A
169 float val = dataProvider->ConsumeFloatingPoint<float>();
170 if (shouldAppend) {
171 str1->appendFormat(formatString.c_str(), val);
172 } else {
173 str1->format(formatString.c_str(), val);
174 }
175 break;
176 }
177
178 case CHAR: {
179 char val = dataProvider->ConsumeIntegral<char>();
180 if (shouldAppend) {
181 str1->appendFormat(formatString.c_str(), val);
182 } else {
183 str1->format(formatString.c_str(), val);
184 }
185 break;
186 }
187
188 case STRING: {
189 std::string val = dataProvider->ConsumeRandomLengthString(MAX_STRING_BYTES);
190 if (shouldAppend) {
191 str1->appendFormat(formatString.c_str(), val.c_str());
192 } else {
193 str1->format(formatString.c_str(), val.c_str());
194 }
195 break;
196 }
197 case POINTER: {
198 uintptr_t val = dataProvider->ConsumeIntegral<uintptr_t>();
199 if (shouldAppend) {
200 str1->appendFormat(formatString.c_str(), val);
201 } else {
202 str1->format(formatString.c_str(), val);
203 }
204 break;
205 }
206 }
207}
208
209void callFunc(uint8_t index, FuzzedDataProvider* dataProvider, android::String8* str1,
210 android::String8* str2) {
Dylan Katz9d5845b2020-05-11 15:44:01 -0700211 operations[index](dataProvider, str1, str2);
212}
213
214extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
215 FuzzedDataProvider dataProvider(data, size);
216 // Generate vector lengths
217 const size_t kVecOneLen = dataProvider.ConsumeIntegralInRange<size_t>(1, MAX_STRING_BYTES);
218 const size_t kVecTwoLen = dataProvider.ConsumeIntegralInRange<size_t>(1, MAX_STRING_BYTES);
219 // Populate vectors
220 std::vector<char> vec = dataProvider.ConsumeBytesWithTerminator<char>(kVecOneLen);
221 std::vector<char> vec_two = dataProvider.ConsumeBytesWithTerminator<char>(kVecTwoLen);
222 // Create UTF-8 pointers
223 android::String8 str_one_utf8 = android::String8(vec.data());
224 android::String8 str_two_utf8 = android::String8(vec_two.data());
Dylan Katz9d5845b2020-05-11 15:44:01 -0700225 // Run operations against strings
226 int opsRun = 0;
227 while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) {
228 uint8_t op = dataProvider.ConsumeIntegralInRange<uint8_t>(0, operations.size() - 1);
Dylan Katz98e14de2020-09-25 16:22:38 -0700229 operations[op](&dataProvider, &str_one_utf8, &str_two_utf8);
Dylan Katz9d5845b2020-05-11 15:44:01 -0700230 }
Dylan Katz9d5845b2020-05-11 15:44:01 -0700231 // Just to be extra sure these can be freed, we're going to explicitly clear
232 // them
233 str_one_utf8.clear();
234 str_two_utf8.clear();
235 return 0;
236}