blob: b8a646d8fb1795533fac1503fc75a09d4ac0df4d [file] [log] [blame]
Aart Bikb1cd97f2016-08-09 10:49:54 -07001/*
2 * Copyright 2016, 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
Aart Bik2f6b7db2017-07-12 16:29:19 -070017#include <cmath>
Aart Bikb1cd97f2016-08-09 10:49:54 -070018#include <random>
19
20#include <inttypes.h>
Aart Bikb1cd97f2016-08-09 10:49:54 -070021#include <stdio.h>
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070022#include <stdlib.h>
Aart Bikb1cd97f2016-08-09 10:49:54 -070023#include <string.h>
24#include <unistd.h>
Aart Bikff3920a2016-09-22 13:50:11 -070025
26#include <sys/time.h>
Aart Bikb1cd97f2016-08-09 10:49:54 -070027
28namespace {
29
30/*
Aart Bik842a4f32016-09-21 15:45:18 -070031 * Operators.
Aart Bikb1cd97f2016-08-09 10:49:54 -070032 */
Orion Hodson9c32ada2017-12-11 07:24:43 +000033
Aart Bikb1cd97f2016-08-09 10:49:54 -070034static constexpr const char* kIncDecOps[] = { "++", "--" };
35static constexpr const char* kIntUnaryOps[] = { "+", "-", "~" };
36static constexpr const char* kFpUnaryOps[] = { "+", "-" };
37
38static constexpr const char* kBoolBinOps[] = { "&&", "||", "&", "|", "^" }; // few less common
39static constexpr const char* kIntBinOps[] = { "+", "-", "*", "/", "%",
40 ">>", ">>>", "<<", "&", "|", "^" };
41static constexpr const char* kFpBinOps[] = { "+", "-", "*", "/" };
42
43static constexpr const char* kBoolAssignOps[] = { "=", "&=" , "|=", "^=" }; // few less common
44static constexpr const char* kIntAssignOps[] = { "=", "+=", "-=", "*=", "/=", "%=",
45 ">>=", ">>>=", "<<=", "&=", "|=", "^=" };
46static constexpr const char* kFpAssignOps[] = { "=", "+=", "-=", "*=", "/=" };
47
48static constexpr const char* kBoolRelOps[] = { "==", "!=" };
49static constexpr const char* kRelOps[] = { "==", "!=", ">", ">=", "<", "<=" };
50
51/*
Orion Hodson4a10c752017-12-07 09:33:36 +000052 * Exceptions.
53 */
54static const char* kExceptionTypes[] = {
55 "IllegalStateException",
56 "NullPointerException",
57 "IllegalArgumentException",
58 "ArrayIndexOutOfBoundsException"
59};
60
61/*
Aart Bik842a4f32016-09-21 15:45:18 -070062 * Version of JFuzz. Increase this each time changes are made to the program
63 * to preserve the property that a given version of JFuzz yields the same
64 * fuzzed program for a deterministic random seed.
Aart Bikb1cd97f2016-08-09 10:49:54 -070065 */
Orion Hodson4a10c752017-12-07 09:33:36 +000066const char* VERSION = "1.5";
Aart Bikb16d4132016-08-19 15:45:11 -070067
Aart Bikff3920a2016-09-22 13:50:11 -070068/*
69 * Maximum number of array dimensions, together with corresponding maximum size
70 * within each dimension (to keep memory/runtime requirements roughly the same).
71 */
72static const uint32_t kMaxDim = 10;
73static const uint32_t kMaxDimSize[kMaxDim + 1] = { 0, 1000, 32, 10, 6, 4, 3, 3, 2, 2, 2 };
Aart Bikb1cd97f2016-08-09 10:49:54 -070074
Orion Hodson4a10c752017-12-07 09:33:36 +000075/*
76 * Utility function to return the number of elements in an array.
77 */
78template <typename T, uint32_t N>
79constexpr uint32_t countof(T const (&)[N]) {
80 return N;
81}
82
Aart Bikb1cd97f2016-08-09 10:49:54 -070083/**
Aart Bik842a4f32016-09-21 15:45:18 -070084 * A class that generates a random program that compiles correctly. The program
Aart Bikb1cd97f2016-08-09 10:49:54 -070085 * is generated using rules that generate various programming constructs. Each rule
86 * has a fixed probability to "fire". Running a generated program yields deterministic
87 * output, making it suited to test various modes of execution (e.g an interpreter vs.
88 * an compiler or two different run times) for divergences.
Aart Bikb1cd97f2016-08-09 10:49:54 -070089 */
Aart Bik842a4f32016-09-21 15:45:18 -070090class JFuzz {
Aart Bikb1cd97f2016-08-09 10:49:54 -070091 public:
Aart Bik842a4f32016-09-21 15:45:18 -070092 JFuzz(FILE* out,
93 uint32_t seed,
94 uint32_t expr_depth,
95 uint32_t stmt_length,
96 uint32_t if_nest,
Orion Hodson4a10c752017-12-07 09:33:36 +000097 uint32_t loop_nest,
98 uint32_t try_nest)
Aart Bikb1cd97f2016-08-09 10:49:54 -070099 : out_(out),
100 fuzz_random_engine_(seed),
101 fuzz_seed_(seed),
102 fuzz_expr_depth_(expr_depth),
103 fuzz_stmt_length_(stmt_length),
104 fuzz_if_nest_(if_nest),
105 fuzz_loop_nest_(loop_nest),
Orion Hodson4a10c752017-12-07 09:33:36 +0000106 fuzz_try_nest_(try_nest),
Aart Bikb1cd97f2016-08-09 10:49:54 -0700107 return_type_(randomType()),
108 array_type_(randomType()),
Aart Bikff3920a2016-09-22 13:50:11 -0700109 array_dim_(random1(kMaxDim)),
110 array_size_(random1(kMaxDimSize[array_dim_])),
Aart Bikb1cd97f2016-08-09 10:49:54 -0700111 indentation_(0),
112 expr_depth_(0),
113 stmt_length_(0),
114 if_nest_(0),
115 loop_nest_(0),
116 switch_nest_(0),
117 do_nest_(0),
Orion Hodson4a10c752017-12-07 09:33:36 +0000118 try_nest_(0),
Aart Bikb1cd97f2016-08-09 10:49:54 -0700119 boolean_local_(0),
120 int_local_(0),
121 long_local_(0),
122 float_local_(0),
Aart Bikff3920a2016-09-22 13:50:11 -0700123 double_local_(0),
124 in_inner_(false) { }
Aart Bikb1cd97f2016-08-09 10:49:54 -0700125
Aart Bik842a4f32016-09-21 15:45:18 -0700126 ~JFuzz() { }
Aart Bikb1cd97f2016-08-09 10:49:54 -0700127
128 void emitProgram() {
129 emitHeader();
130 emitTestClassWithMain();
131 }
132
133 private:
134 //
135 // Types.
136 //
137
138 // Current type of each expression during generation.
139 enum Type {
140 kBoolean,
141 kInt,
142 kLong,
143 kFloat,
144 kDouble
145 };
146
147 // Test for an integral type.
148 static bool isInteger(Type tp) {
149 return tp == kInt || tp == kLong;
150 }
151
152 // Test for a floating-point type.
153 static bool isFP(Type tp) {
154 return tp == kFloat || tp == kDouble;
155 }
156
157 // Emit type.
158 void emitType(Type tp) const {
159 switch (tp) {
160 case kBoolean: fputs("boolean", out_); break;
161 case kInt: fputs("int", out_); break;
162 case kLong: fputs("long", out_); break;
163 case kFloat: fputs("float", out_); break;
164 case kDouble: fputs("double", out_); break;
165 }
166 }
167
168 // Emit type class.
169 void emitTypeClass(Type tp) const {
170 switch (tp) {
171 case kBoolean: fputs("Boolean", out_); break;
172 case kInt: fputs("Integer", out_); break;
173 case kLong: fputs("Long", out_); break;
174 case kFloat: fputs("Float", out_); break;
175 case kDouble: fputs("Double", out_); break;
176 }
177 }
178
179 // Return a random type.
180 Type randomType() {
181 switch (random1(5)) {
182 case 1: return kBoolean;
183 case 2: return kInt;
184 case 3: return kLong;
185 case 4: return kFloat;
186 default: return kDouble;
187 }
188 }
189
Orion Hodson4a10c752017-12-07 09:33:36 +0000190 // Emits a random strong selected from an array of operator strings.
191 template <std::uint32_t N>
192 inline void emitOneOf(const char* const (&ops)[N]) {
193 fputs(ops[random0(N)], out_);
194 }
195
Aart Bikb1cd97f2016-08-09 10:49:54 -0700196 //
197 // Expressions.
198 //
199
200 // Emit an unary operator (same type in-out).
201 void emitUnaryOp(Type tp) {
202 if (tp == kBoolean) {
Aart Bikb16d4132016-08-19 15:45:11 -0700203 fputc('!', out_);
Aart Bikb1cd97f2016-08-09 10:49:54 -0700204 } else if (isInteger(tp)) {
Orion Hodson4a10c752017-12-07 09:33:36 +0000205 emitOneOf(kIntUnaryOps);
Aart Bikb1cd97f2016-08-09 10:49:54 -0700206 } else { // isFP(tp)
Orion Hodson4a10c752017-12-07 09:33:36 +0000207 emitOneOf(kFpUnaryOps);
Aart Bikb1cd97f2016-08-09 10:49:54 -0700208 }
209 }
210
211 // Emit a pre/post-increment/decrement operator (same type in-out).
212 void emitIncDecOp(Type tp) {
213 if (tp == kBoolean) {
214 // Not applicable, just leave "as is".
215 } else { // isInteger(tp) || isFP(tp)
Orion Hodson4a10c752017-12-07 09:33:36 +0000216 emitOneOf(kIncDecOps);
Aart Bikb1cd97f2016-08-09 10:49:54 -0700217 }
218 }
219
220 // Emit a binary operator (same type in-out).
221 void emitBinaryOp(Type tp) {
222 if (tp == kBoolean) {
Orion Hodson4a10c752017-12-07 09:33:36 +0000223 emitOneOf(kBoolBinOps);
Aart Bikb1cd97f2016-08-09 10:49:54 -0700224 } else if (isInteger(tp)) {
Orion Hodson4a10c752017-12-07 09:33:36 +0000225 emitOneOf(kIntBinOps);
Aart Bikb1cd97f2016-08-09 10:49:54 -0700226 } else { // isFP(tp)
Orion Hodson4a10c752017-12-07 09:33:36 +0000227 emitOneOf(kFpBinOps);
Aart Bikb1cd97f2016-08-09 10:49:54 -0700228 }
229 }
230
231 // Emit an assignment operator (same type in-out).
232 void emitAssignmentOp(Type tp) {
233 if (tp == kBoolean) {
Orion Hodson4a10c752017-12-07 09:33:36 +0000234 emitOneOf(kBoolAssignOps);
Aart Bikb1cd97f2016-08-09 10:49:54 -0700235 } else if (isInteger(tp)) {
Orion Hodson4a10c752017-12-07 09:33:36 +0000236 emitOneOf(kIntAssignOps);
Aart Bikb1cd97f2016-08-09 10:49:54 -0700237 } else { // isFP(tp)
Orion Hodson4a10c752017-12-07 09:33:36 +0000238 emitOneOf(kFpAssignOps);
Aart Bikb1cd97f2016-08-09 10:49:54 -0700239 }
240 }
241
242 // Emit a relational operator (one type in, boolean out).
243 void emitRelationalOp(Type tp) {
244 if (tp == kBoolean) {
Orion Hodson4a10c752017-12-07 09:33:36 +0000245 emitOneOf(kBoolRelOps);
Aart Bikb1cd97f2016-08-09 10:49:54 -0700246 } else { // isInteger(tp) || isFP(tp)
Orion Hodson4a10c752017-12-07 09:33:36 +0000247 emitOneOf(kRelOps);
Aart Bikb1cd97f2016-08-09 10:49:54 -0700248 }
249 }
250
251 // Emit a type conversion operator sequence (out type given, new suitable in type picked).
252 Type emitTypeConversionOp(Type tp) {
253 if (tp == kInt) {
254 switch (random1(5)) {
255 case 1: fputs("(int)", out_); return kLong;
256 case 2: fputs("(int)", out_); return kFloat;
257 case 3: fputs("(int)", out_); return kDouble;
258 // Narrowing-widening.
259 case 4: fputs("(int)(byte)(int)", out_); return kInt;
260 case 5: fputs("(int)(short)(int)", out_); return kInt;
261 }
262 } else if (tp == kLong) {
263 switch (random1(6)) {
264 case 1: /* implicit */ return kInt;
265 case 2: fputs("(long)", out_); return kFloat;
266 case 3: fputs("(long)", out_); return kDouble;
267 // Narrowing-widening.
268 case 4: fputs("(long)(byte)(long)", out_); return kLong;
269 case 5: fputs("(long)(short)(long)", out_); return kLong;
270 case 6: fputs("(long)(int)(long)", out_); return kLong;
271 }
272 } else if (tp == kFloat) {
Aart Bikb16d4132016-08-19 15:45:11 -0700273 switch (random1(4)) {
Aart Bikb1cd97f2016-08-09 10:49:54 -0700274 case 1: fputs("(float)", out_); return kInt;
275 case 2: fputs("(float)", out_); return kLong;
276 case 3: fputs("(float)", out_); return kDouble;
Aart Bikb16d4132016-08-19 15:45:11 -0700277 // Narrowing-widening.
278 case 4: fputs("(float)(int)(float)", out_); return kFloat;
Aart Bikb1cd97f2016-08-09 10:49:54 -0700279 }
280 } else if (tp == kDouble) {
Aart Bikb16d4132016-08-19 15:45:11 -0700281 switch (random1(5)) {
Aart Bikb1cd97f2016-08-09 10:49:54 -0700282 case 1: fputs("(double)", out_); return kInt;
283 case 2: fputs("(double)", out_); return kLong;
284 case 3: fputs("(double)", out_); return kFloat;
Aart Bikb16d4132016-08-19 15:45:11 -0700285 // Narrowing-widening.
286 case 4: fputs("(double)(int)(double)", out_); return kDouble;
287 case 5: fputs("(double)(float)(double)", out_); return kDouble;
Aart Bikb1cd97f2016-08-09 10:49:54 -0700288 }
289 }
290 return tp; // nothing suitable, just keep type
291 }
292
293 // Emit a type conversion (out type given, new suitable in type picked).
294 void emitTypeConversion(Type tp) {
295 if (tp == kBoolean) {
296 Type tp = randomType();
297 emitExpression(tp);
298 fputc(' ', out_);
299 emitRelationalOp(tp);
300 fputc(' ', out_);
301 emitExpression(tp);
302 } else {
303 tp = emitTypeConversionOp(tp);
304 fputc(' ', out_);
305 emitExpression(tp);
306 }
307 }
308
309 // Emit an unary intrinsic (out type given, new suitable in type picked).
310 Type emitIntrinsic1(Type tp) {
311 if (tp == kBoolean) {
Aart Bikb16d4132016-08-19 15:45:11 -0700312 switch (random1(6)) {
Aart Bikb1cd97f2016-08-09 10:49:54 -0700313 case 1: fputs("Float.isNaN", out_); return kFloat;
Aart Bikb16d4132016-08-19 15:45:11 -0700314 case 2: fputs("Float.isFinite", out_); return kFloat;
315 case 3: fputs("Float.isInfinite", out_); return kFloat;
316 case 4: fputs("Double.isNaN", out_); return kDouble;
317 case 5: fputs("Double.isFinite", out_); return kDouble;
318 case 6: fputs("Double.isInfinite", out_); return kDouble;
Aart Bikb1cd97f2016-08-09 10:49:54 -0700319 }
320 } else if (isInteger(tp)) {
321 const char* prefix = tp == kLong ? "Long" : "Integer";
Aart Bikb16d4132016-08-19 15:45:11 -0700322 switch (random1(13)) {
Aart Bikb1cd97f2016-08-09 10:49:54 -0700323 case 1: fprintf(out_, "%s.highestOneBit", prefix); break;
324 case 2: fprintf(out_, "%s.lowestOneBit", prefix); break;
325 case 3: fprintf(out_, "%s.numberOfLeadingZeros", prefix); break;
326 case 4: fprintf(out_, "%s.numberOfTrailingZeros", prefix); break;
327 case 5: fprintf(out_, "%s.bitCount", prefix); break;
328 case 6: fprintf(out_, "%s.signum", prefix); break;
329 case 7: fprintf(out_, "%s.reverse", prefix); break;
330 case 8: fprintf(out_, "%s.reverseBytes", prefix); break;
Aart Bikb16d4132016-08-19 15:45:11 -0700331 case 9: fputs("Math.incrementExact", out_); break;
332 case 10: fputs("Math.decrementExact", out_); break;
333 case 11: fputs("Math.negateExact", out_); break;
334 case 12: fputs("Math.abs", out_); break;
335 case 13: fputs("Math.round", out_);
336 return tp == kLong ? kDouble : kFloat;
Aart Bikb1cd97f2016-08-09 10:49:54 -0700337 }
338 } else { // isFP(tp)
Aart Bikb16d4132016-08-19 15:45:11 -0700339 switch (random1(6)) {
Aart Bikb1cd97f2016-08-09 10:49:54 -0700340 case 1: fputs("Math.abs", out_); break;
341 case 2: fputs("Math.ulp", out_); break;
342 case 3: fputs("Math.signum", out_); break;
343 case 4: fputs("Math.nextUp", out_); break;
344 case 5: fputs("Math.nextDown", out_); break;
Aart Bikb16d4132016-08-19 15:45:11 -0700345 case 6: if (tp == kDouble) {
346 fputs("Double.longBitsToDouble", out_);
347 return kLong;
348 } else {
349 fputs("Float.intBitsToFloat", out_);
350 return kInt;
351 }
Aart Bikb1cd97f2016-08-09 10:49:54 -0700352 }
353 }
354 return tp; // same type in-out
355 }
356
357 // Emit a binary intrinsic (out type given, new suitable in type picked).
358 Type emitIntrinsic2(Type tp) {
359 if (tp == kBoolean) {
360 switch (random1(3)) {
361 case 1: fputs("Boolean.logicalAnd", out_); break;
362 case 2: fputs("Boolean.logicalOr", out_); break;
363 case 3: fputs("Boolean.logicalXor", out_); break;
364 }
365 } else if (isInteger(tp)) {
366 const char* prefix = tp == kLong ? "Long" : "Integer";
Aart Bikb16d4132016-08-19 15:45:11 -0700367 switch (random1(11)) {
Aart Bikb1cd97f2016-08-09 10:49:54 -0700368 case 1: fprintf(out_, "%s.compare", prefix); break;
Aart Bikb16d4132016-08-19 15:45:11 -0700369 case 2: fprintf(out_, "%s.sum", prefix); break;
370 case 3: fprintf(out_, "%s.min", prefix); break;
371 case 4: fprintf(out_, "%s.max", prefix); break;
372 case 5: fputs("Math.min", out_); break;
373 case 6: fputs("Math.max", out_); break;
374 case 7: fputs("Math.floorDiv", out_); break;
375 case 8: fputs("Math.floorMod", out_); break;
376 case 9: fputs("Math.addExact", out_); break;
377 case 10: fputs("Math.subtractExact", out_); break;
378 case 11: fputs("Math.multiplyExact", out_); break;
Aart Bikb1cd97f2016-08-09 10:49:54 -0700379 }
380 } else { // isFP(tp)
Aart Bikb16d4132016-08-19 15:45:11 -0700381 const char* prefix = tp == kDouble ? "Double" : "Float";
382 switch (random1(5)) {
383 case 1: fprintf(out_, "%s.sum", prefix); break;
384 case 2: fprintf(out_, "%s.min", prefix); break;
385 case 3: fprintf(out_, "%s.max", prefix); break;
386 case 4: fputs("Math.min", out_); break;
387 case 5: fputs("Math.max", out_); break;
Aart Bikb1cd97f2016-08-09 10:49:54 -0700388 }
389 }
390 return tp; // same type in-out
391 }
392
393 // Emit an intrinsic (out type given, new suitable in type picked).
394 void emitIntrinsic(Type tp) {
395 if (random1(2) == 1) {
396 tp = emitIntrinsic1(tp);
397 fputc('(', out_);
398 emitExpression(tp);
399 fputc(')', out_);
400 } else {
401 tp = emitIntrinsic2(tp);
402 fputc('(', out_);
403 emitExpression(tp);
404 fputs(", ", out_);
405 emitExpression(tp);
406 fputc(')', out_);
407 }
408 }
409
Aart Bikff3920a2016-09-22 13:50:11 -0700410 // Emit a method call (out type given).
411 void emitMethodCall(Type tp) {
412 if (tp != kBoolean && !in_inner_) {
413 // Accept all numerical types (implicit conversion) and when not
414 // declaring inner classes (to avoid infinite recursion).
415 switch (random1(8)) {
416 case 1: fputs("mA.a()", out_); break;
417 case 2: fputs("mB.a()", out_); break;
418 case 3: fputs("mB.x()", out_); break;
419 case 4: fputs("mBX.x()", out_); break;
420 case 5: fputs("mC.s()", out_); break;
421 case 6: fputs("mC.c()", out_); break;
422 case 7: fputs("mC.x()", out_); break;
423 case 8: fputs("mCX.x()", out_); break;
424 }
425 } else {
426 // Fall back to intrinsic.
427 emitIntrinsic(tp);
428 }
429 }
430
Aart Bikb1cd97f2016-08-09 10:49:54 -0700431 // Emit unboxing boxed object.
432 void emitUnbox(Type tp) {
433 fputc('(', out_);
434 emitType(tp);
435 fputs(") new ", out_);
436 emitTypeClass(tp);
437 fputc('(', out_);
438 emitExpression(tp);
439 fputc(')', out_);
440 }
441
442 // Emit miscellaneous constructs.
443 void emitMisc(Type tp) {
Aart Bikb16d4132016-08-19 15:45:11 -0700444 if (tp == kBoolean) {
Aart Bikff3920a2016-09-22 13:50:11 -0700445 fprintf(out_, "this instanceof %s", in_inner_ ? "X" : "Test");
Aart Bikb16d4132016-08-19 15:45:11 -0700446 } else if (isInteger(tp)) {
447 const char* prefix = tp == kLong ? "Long" : "Integer";
448 switch (random1(2)) {
449 case 1: fprintf(out_, "%s.MIN_VALUE", prefix); break;
450 case 2: fprintf(out_, "%s.MAX_VALUE", prefix); break;
451 }
452 } else { // isFP(tp)
453 const char* prefix = tp == kDouble ? "Double" : "Float";
454 switch (random1(6)) {
455 case 1: fprintf(out_, "%s.MIN_NORMAL", prefix); break;
456 case 2: fprintf(out_, "%s.MIN_VALUE", prefix); break;
457 case 3: fprintf(out_, "%s.MAX_VALUE", prefix); break;
458 case 4: fprintf(out_, "%s.POSITIVE_INFINITY", prefix); break;
459 case 5: fprintf(out_, "%s.NEGATIVE_INFINITY", prefix); break;
460 case 6: fprintf(out_, "%s.NaN", prefix); break;
461 }
Aart Bikb1cd97f2016-08-09 10:49:54 -0700462 }
463 }
464
465 // Adjust local of given type and return adjusted value.
466 uint32_t adjustLocal(Type tp, int32_t a) {
467 switch (tp) {
468 case kBoolean: boolean_local_ += a; return boolean_local_;
469 case kInt: int_local_ += a; return int_local_;
470 case kLong: long_local_ += a; return long_local_;
471 case kFloat: float_local_ += a; return float_local_;
472 default: double_local_ += a; return double_local_;
473 }
474 }
475
476 // Emit an expression that is a strict upper bound for an array index.
477 void emitUpperBound() {
478 if (random1(8) == 1) {
479 fputs("mArray.length", out_);
480 } else if (random1(8) == 1) {
481 fprintf(out_, "%u", random1(array_size_)); // random in range
482 } else {
483 fprintf(out_, "%u", array_size_);
484 }
485 }
486
487 // Emit an array index, usually within proper range.
488 void emitArrayIndex() {
489 if (loop_nest_ > 0 && random1(2) == 1) {
490 fprintf(out_, "i%u", random0(loop_nest_));
491 } else if (random1(8) == 1) {
492 fputs("mArray.length - 1", out_);
493 } else {
494 fprintf(out_, "%u", random0(array_size_)); // random in range
495 }
496 // Introduce potential off by one errors with low probability.
497 if (random1(100) == 1) {
498 if (random1(2) == 1) {
499 fputs(" - 1", out_);
500 } else {
501 fputs(" + 1", out_);
502 }
503 }
504 }
505
506 // Emit a literal.
507 void emitLiteral(Type tp) {
508 switch (tp) {
509 case kBoolean: fputs(random1(2) == 1 ? "true" : "false", out_); break;
Aart Bikb16d4132016-08-19 15:45:11 -0700510 case kInt: fprintf(out_, "%d", random()); break;
511 case kLong: fprintf(out_, "%dL", random()); break;
512 case kFloat: fprintf(out_, "%d.0f", random()); break;
513 case kDouble: fprintf(out_, "%d.0", random()); break;
Aart Bikb1cd97f2016-08-09 10:49:54 -0700514 }
515 }
516
517 // Emit array variable, if available.
518 bool emitArrayVariable(Type tp) {
519 if (tp == array_type_) {
520 fputs("mArray", out_);
521 for (uint32_t i = 0; i < array_dim_; i++) {
522 fputc('[', out_);
523 emitArrayIndex();
524 fputc(']', out_);
525 }
526 return true;
527 }
528 return false;
529 }
530
Aart Bikb1cd97f2016-08-09 10:49:54 -0700531 // Emit a local variable, if available.
532 bool emitLocalVariable(Type tp) {
533 uint32_t locals = adjustLocal(tp, 0);
534 if (locals > 0) {
535 uint32_t local = random0(locals);
536 switch (tp) {
537 case kBoolean: fprintf(out_, "lZ%u", local); break;
538 case kInt: fprintf(out_, "lI%u", local); break;
539 case kLong: fprintf(out_, "lJ%u", local); break;
540 case kFloat: fprintf(out_, "lF%u", local); break;
541 case kDouble: fprintf(out_, "lD%u", local); break;
542 }
543 return true;
544 }
545 return false;
546 }
547
548 // Emit a field variable.
549 void emitFieldVariable(Type tp) {
550 switch (tp) {
551 case kBoolean:fputs("mZ", out_); break;
552 case kInt: fputs("mI", out_); break;
553 case kLong: fputs("mJ", out_); break;
554 case kFloat: fputs("mF", out_); break;
555 case kDouble: fputs("mD", out_); break;
556 }
557 }
558
559 // Emit a variable.
560 void emitVariable(Type tp) {
561 switch (random1(4)) {
562 case 1:
563 if (emitArrayVariable(tp))
564 return;
Chih-Hung Hsieh12218752018-10-16 11:45:50 -0700565 [[fallthrough]];
Aart Bikb1cd97f2016-08-09 10:49:54 -0700566 case 2:
567 if (emitLocalVariable(tp))
568 return;
Chih-Hung Hsieh12218752018-10-16 11:45:50 -0700569 [[fallthrough]];
Aart Bikb1cd97f2016-08-09 10:49:54 -0700570 default:
571 emitFieldVariable(tp);
572 break;
573 }
574 }
575
576 // Emit an expression.
577 void emitExpression(Type tp) {
578 // Continuing expression becomes less likely as the depth grows.
579 if (random1(expr_depth_ + 1) > fuzz_expr_depth_) {
580 if (random1(2) == 1) {
581 emitLiteral(tp);
582 } else {
583 emitVariable(tp);
584 }
585 return;
586 }
587
588 expr_depth_++;
589
590 fputc('(', out_);
591 switch (random1(12)) { // favor binary operations
592 case 1:
Aart Bikb16d4132016-08-19 15:45:11 -0700593 // Unary operator: ~ x
Aart Bikb1cd97f2016-08-09 10:49:54 -0700594 emitUnaryOp(tp);
Aart Bikb16d4132016-08-19 15:45:11 -0700595 fputc(' ', out_);
Aart Bikb1cd97f2016-08-09 10:49:54 -0700596 emitExpression(tp);
597 break;
598 case 2:
599 // Pre-increment: ++x
600 emitIncDecOp(tp);
601 emitVariable(tp);
602 break;
603 case 3:
604 // Post-increment: x++
605 emitVariable(tp);
606 emitIncDecOp(tp);
607 break;
608 case 4:
609 // Ternary operator: b ? x : y
610 emitExpression(kBoolean);
611 fputs(" ? ", out_);
612 emitExpression(tp);
613 fputs(" : ", out_);
614 emitExpression(tp);
615 break;
616 case 5:
617 // Type conversion: (float) x
618 emitTypeConversion(tp);
619 break;
620 case 6:
621 // Intrinsic: foo(x)
622 emitIntrinsic(tp);
623 break;
624 case 7:
Aart Bikff3920a2016-09-22 13:50:11 -0700625 // Method call: mA.a()
626 emitMethodCall(tp);
627 break;
628 case 8:
Aart Bikb1cd97f2016-08-09 10:49:54 -0700629 // Emit unboxing boxed value: (int) Integer(x)
630 emitUnbox(tp);
631 break;
Aart Bikff3920a2016-09-22 13:50:11 -0700632 case 9:
Aart Bikb1cd97f2016-08-09 10:49:54 -0700633 // Miscellaneous constructs: a.length
634 emitMisc(tp);
635 break;
636 default:
637 // Binary operator: x + y
638 emitExpression(tp);
639 fputc(' ', out_);
640 emitBinaryOp(tp);
641 fputc(' ', out_);
642 emitExpression(tp);
643 break;
644 }
645 fputc(')', out_);
646
647 --expr_depth_;
648 }
649
650 //
651 // Statements.
652 //
653
654 // Emit current indentation.
655 void emitIndentation() const {
656 for (uint32_t i = 0; i < indentation_; i++) {
657 fputc(' ', out_);
658 }
659 }
660
661 // Emit a return statement.
662 bool emitReturn(bool mustEmit) {
663 // Only emit when we must, or with low probability inside ifs/loops,
664 // but outside do-while to avoid confusing the may follow status.
665 if (mustEmit || ((if_nest_ + loop_nest_) > 0 && do_nest_ == 0 && random1(10) == 1)) {
666 fputs("return ", out_);
667 emitExpression(return_type_);
668 fputs(";\n", out_);
669 return false;
670 }
671 // Fall back to assignment.
672 return emitAssignment();
673 }
674
675 // Emit a continue statement.
676 bool emitContinue() {
677 // Only emit with low probability inside loops.
678 if (loop_nest_ > 0 && random1(10) == 1) {
679 fputs("continue;\n", out_);
680 return false;
681 }
682 // Fall back to assignment.
683 return emitAssignment();
684 }
685
686 // Emit a break statement.
687 bool emitBreak() {
688 // Only emit with low probability inside loops, but outside switches
689 // to avoid confusing the may follow status.
690 if (loop_nest_ > 0 && switch_nest_ == 0 && random1(10) == 1) {
691 fputs("break;\n", out_);
692 return false;
693 }
694 // Fall back to assignment.
695 return emitAssignment();
696 }
697
698 // Emit a new scope with a local variable declaration statement.
699 bool emitScope() {
700 Type tp = randomType();
701 fputs("{\n", out_);
702 indentation_ += 2;
703 emitIndentation();
704 emitType(tp);
705 switch (tp) {
706 case kBoolean: fprintf(out_, " lZ%u = ", boolean_local_); break;
707 case kInt: fprintf(out_, " lI%u = ", int_local_); break;
708 case kLong: fprintf(out_, " lJ%u = ", long_local_); break;
709 case kFloat: fprintf(out_, " lF%u = ", float_local_); break;
710 case kDouble: fprintf(out_, " lD%u = ", double_local_); break;
711 }
712 emitExpression(tp);
713 fputs(";\n", out_);
714
715 adjustLocal(tp, 1); // local now visible
716
717 bool mayFollow = emitStatementList();
718
719 adjustLocal(tp, -1); // local no longer visible
720
721 indentation_ -= 2;
722 emitIndentation();
723 fputs("}\n", out_);
724 return mayFollow;
725 }
726
Aart Bik2f6b7db2017-07-12 16:29:19 -0700727 // Emit one dimension of an array initializer, where parameter dim >= 1
728 // denotes the number of remaining dimensions that should be emitted.
729 void emitArrayInitDim(int dim) {
730 if (dim == 1) {
731 // Last dimension: set of values.
732 fputs("{ ", out_);
733 for (uint32_t i = 0; i < array_size_; i++) {
734 emitExpression(array_type_);
735 fputs(", ", out_);
736 }
737 fputs("}", out_);
738
739 } else {
740 // Outer dimensions: set of sets.
741 fputs("{\n", out_);
742 indentation_ += 2;
743 emitIndentation();
744
745 for (uint32_t i = 0; i < array_size_; i++) {
746 emitArrayInitDim(dim - 1);
747 if (i != array_size_ - 1) {
748 fputs(",\n", out_);
749 emitIndentation();
750 }
751 }
752
753 fputs(",\n", out_);
754 indentation_ -= 2;
755 emitIndentation();
756 fputs("}", out_);
757 }
758 }
759
760 // Emit an array initializer of the following form.
761 // {
762 // type[]..[] tmp = { .. };
763 // mArray = tmp;
764 // }
765 bool emitArrayInit() {
766 // Avoid elaborate array initializers.
767 uint64_t p = pow(array_size_, array_dim_);
768 if (p > 20) {
769 return emitAssignment(); // fall back
770 }
771
772 fputs("{\n", out_);
773
774 indentation_ += 2;
775 emitIndentation();
776 emitType(array_type_);
777 for (uint32_t i = 0; i < array_dim_; i++) {
778 fputs("[]", out_);
779 }
780 fputs(" tmp = ", out_);
781 emitArrayInitDim(array_dim_);
782 fputs(";\n", out_);
783
784 emitIndentation();
785 fputs("mArray = tmp;\n", out_);
786
787 indentation_ -= 2;
788 emitIndentation();
789 fputs("}\n", out_);
790 return true;
791 }
792
Aart Bikb1cd97f2016-08-09 10:49:54 -0700793 // Emit a for loop.
794 bool emitForLoop() {
795 // Continuing loop nest becomes less likely as the depth grows.
796 if (random1(loop_nest_ + 1) > fuzz_loop_nest_) {
797 return emitAssignment(); // fall back
798 }
799
800 bool goesUp = random1(2) == 1;
801 fprintf(out_, "for (int i%u = ", loop_nest_);
802 if (goesUp) {
803 fprintf(out_, "0; i%u < ", loop_nest_);
804 emitUpperBound();
805 fprintf(out_, "; i%u++) {\n", loop_nest_);
806 } else {
807 emitUpperBound();
808 fprintf(out_, " - 1; i%d >= 0", loop_nest_);
809 fprintf(out_, "; i%d--) {\n", loop_nest_);
810 }
811
812 ++loop_nest_; // now in loop
813
814 indentation_ += 2;
815 emitStatementList();
816
817 --loop_nest_; // no longer in loop
818
819 indentation_ -= 2;
820 emitIndentation();
821 fprintf(out_, "}\n");
822 return true; // loop-body does not block flow
823 }
824
825 // Emit while or do-while loop.
826 bool emitDoLoop() {
827 // Continuing loop nest becomes less likely as the depth grows.
828 if (random1(loop_nest_ + 1) > fuzz_loop_nest_) {
829 return emitAssignment(); // fall back
830 }
831
Aart Bikb1cd97f2016-08-09 10:49:54 -0700832 bool isWhile = random1(2) == 1;
833 fputs("{\n", out_);
834 indentation_ += 2;
835 emitIndentation();
Orion Hodson4a10c752017-12-07 09:33:36 +0000836 fprintf(out_, "int i%u = %d;\n", loop_nest_, isWhile ? -1 : 0);
Aart Bikb1cd97f2016-08-09 10:49:54 -0700837 emitIndentation();
838 if (isWhile) {
839 fprintf(out_, "while (++i%u < ", loop_nest_);
840 emitUpperBound();
841 fputs(") {\n", out_);
842 } else {
843 fputs("do {\n", out_);
844 do_nest_++;
845 }
846
847 ++loop_nest_; // now in loop
848
849 indentation_ += 2;
850 emitStatementList();
851
852 --loop_nest_; // no longer in loop
853
854 indentation_ -= 2;
855 emitIndentation();
856 if (isWhile) {
857 fputs("}\n", out_);
858 } else {
859 fprintf(out_, "} while (++i%u < ", loop_nest_);
860 emitUpperBound();
861 fputs(");\n", out_);
862 --do_nest_;
863 }
864 indentation_ -= 2;
865 emitIndentation();
866 fputs("}\n", out_);
867 return true; // loop-body does not block flow
868 }
869
870 // Emit an if statement.
871 bool emitIfStmt() {
872 // Continuing if nest becomes less likely as the depth grows.
873 if (random1(if_nest_ + 1) > fuzz_if_nest_) {
874 return emitAssignment(); // fall back
875 }
876
877 fputs("if (", out_);
878 emitExpression(kBoolean);
879 fputs(") {\n", out_);
880
881 ++if_nest_; // now in if
882
883 indentation_ += 2;
884 bool mayFollowTrue = emitStatementList();
885 indentation_ -= 2;
886 emitIndentation();
887 fprintf(out_, "} else {\n");
888 indentation_ += 2;
889 bool mayFollowFalse = emitStatementList();
890
891 --if_nest_; // no longer in if
892
893 indentation_ -= 2;
894 emitIndentation();
895 fprintf(out_, "}\n");
896 return mayFollowTrue || mayFollowFalse;
897 }
898
Orion Hodson4a10c752017-12-07 09:33:36 +0000899 bool emitTry() {
900 fputs("try {\n", out_);
901 indentation_ += 2;
902 bool mayFollow = emitStatementList();
903 indentation_ -= 2;
904 emitIndentation();
905 fputc('}', out_);
906 return mayFollow;
907 }
908
909 bool emitCatch() {
910 uint32_t count = random1(countof(kExceptionTypes));
911 bool mayFollow = false;
912 for (uint32_t i = 0; i < count; ++i) {
913 fprintf(out_, " catch (%s ex%u_%u) {\n", kExceptionTypes[i], try_nest_, i);
914 indentation_ += 2;
915 mayFollow |= emitStatementList();
916 indentation_ -= 2;
917 emitIndentation();
918 fputc('}', out_);
919 }
920 return mayFollow;
921 }
922
923 bool emitFinally() {
924 fputs(" finally {\n", out_);
925 indentation_ += 2;
926 bool mayFollow = emitStatementList();
927 indentation_ -= 2;
928 emitIndentation();
929 fputc('}', out_);
930 return mayFollow;
931 }
932
933 // Emit a try-catch-finally block.
934 bool emitTryCatchFinally() {
935 // Apply a hard limit on the number of catch blocks. This is for
936 // javac which fails if blocks within try-catch-finally are too
937 // large (much less than you'd expect).
938 if (try_nest_ > fuzz_try_nest_) {
939 return emitAssignment(); // fall back
940 }
941
942 ++try_nest_; // Entering try-catch-finally
943
944 bool mayFollow = emitTry();
945 switch (random0(3)) {
946 case 0: // try..catch
947 mayFollow |= emitCatch();
948 break;
949 case 1: // try..finally
950 mayFollow &= emitFinally();
951 break;
952 case 2: // try..catch..finally
953 // When determining whether code may follow, we observe that a
954 // finally block always follows after try and catch
955 // block. Code may only follow if the finally block permits
956 // and either the try or catch block allows code to follow.
957 mayFollow = (mayFollow | emitCatch()) & emitFinally();
958 break;
959 }
960 fputc('\n', out_);
961
962 --try_nest_; // Leaving try-catch-finally
963 return mayFollow;
964 }
965
Aart Bikb1cd97f2016-08-09 10:49:54 -0700966 // Emit a switch statement.
967 bool emitSwitch() {
968 // Continuing if nest becomes less likely as the depth grows.
969 if (random1(if_nest_ + 1) > fuzz_if_nest_) {
970 return emitAssignment(); // fall back
971 }
972
973 bool mayFollow = false;
974 fputs("switch (", out_);
Aart Bikb16d4132016-08-19 15:45:11 -0700975 emitArrayIndex(); // restrict its range
Aart Bikb1cd97f2016-08-09 10:49:54 -0700976 fputs(") {\n", out_);
977
978 ++if_nest_;
979 ++switch_nest_; // now in switch
980
981 indentation_ += 2;
982 for (uint32_t i = 0; i < 2; i++) {
983 emitIndentation();
984 if (i == 0) {
Aart Bikb16d4132016-08-19 15:45:11 -0700985 fprintf(out_, "case %u: {\n", random0(array_size_));
Aart Bikb1cd97f2016-08-09 10:49:54 -0700986 } else {
987 fprintf(out_, "default: {\n");
988 }
989 indentation_ += 2;
990 if (emitStatementList()) {
991 // Must end with break.
992 emitIndentation();
993 fputs("break;\n", out_);
994 mayFollow = true;
995 }
996 indentation_ -= 2;
997 emitIndentation();
998 fputs("}\n", out_);
999 }
1000
1001 --if_nest_;
1002 --switch_nest_; // no longer in switch
1003
1004 indentation_ -= 2;
1005 emitIndentation();
1006 fprintf(out_, "}\n");
1007 return mayFollow;
1008 }
1009
Orion Hodson4a10c752017-12-07 09:33:36 +00001010 bool emitNopCall() {
1011 fputs("nop();\n", out_);
1012 return true;
1013 }
1014
Aart Bikb1cd97f2016-08-09 10:49:54 -07001015 // Emit an assignment statement.
1016 bool emitAssignment() {
1017 Type tp = randomType();
1018 emitVariable(tp);
1019 fputc(' ', out_);
1020 emitAssignmentOp(tp);
1021 fputc(' ', out_);
1022 emitExpression(tp);
1023 fputs(";\n", out_);
1024 return true;
1025 }
1026
1027 // Emit a single statement. Returns true if statements may follow.
1028 bool emitStatement() {
1029 switch (random1(16)) { // favor assignments
Orion Hodson4a10c752017-12-07 09:33:36 +00001030 case 1: return emitReturn(false); break;
1031 case 2: return emitContinue(); break;
1032 case 3: return emitBreak(); break;
1033 case 4: return emitScope(); break;
1034 case 5: return emitArrayInit(); break;
1035 case 6: return emitForLoop(); break;
1036 case 7: return emitDoLoop(); break;
1037 case 8: return emitIfStmt(); break;
1038 case 9: return emitSwitch(); break;
1039 case 10: return emitTryCatchFinally(); break;
1040 case 11: return emitNopCall(); break;
1041 default: return emitAssignment(); break;
Aart Bikb1cd97f2016-08-09 10:49:54 -07001042 }
1043 }
1044
1045 // Emit a statement list. Returns true if statements may follow.
1046 bool emitStatementList() {
1047 while (stmt_length_ < 1000) { // avoid run-away
1048 stmt_length_++;
1049 emitIndentation();
1050 if (!emitStatement()) {
1051 return false; // rest would be dead code
1052 }
1053 // Continuing this list becomes less likely as the total statement list grows.
1054 if (random1(stmt_length_) > fuzz_stmt_length_) {
1055 break;
1056 }
1057 }
1058 return true;
1059 }
1060
Aart Bikff3920a2016-09-22 13:50:11 -07001061 // Emit interface and class declarations.
1062 void emitClassDecls() {
1063 in_inner_ = true;
1064 fputs(" private interface X {\n", out_);
1065 fputs(" int x();\n", out_);
1066 fputs(" }\n\n", out_);
1067 fputs(" private class A {\n", out_);
1068 fputs(" public int a() {\n", out_);
1069 fputs(" return ", out_);
1070 emitExpression(kInt);
1071 fputs(";\n }\n", out_);
1072 fputs(" }\n\n", out_);
1073 fputs(" private class B extends A implements X {\n", out_);
1074 fputs(" public int a() {\n", out_);
1075 fputs(" return super.a() + ", out_);
1076 emitExpression(kInt);
1077 fputs(";\n }\n", out_);
1078 fputs(" public int x() {\n", out_);
1079 fputs(" return ", out_);
1080 emitExpression(kInt);
1081 fputs(";\n }\n", out_);
1082 fputs(" }\n\n", out_);
1083 fputs(" private static class C implements X {\n", out_);
1084 fputs(" public static int s() {\n", out_);
1085 fputs(" return ", out_);
1086 emitLiteral(kInt);
1087 fputs(";\n }\n", out_);
1088 fputs(" public int c() {\n", out_);
1089 fputs(" return ", out_);
1090 emitLiteral(kInt);
1091 fputs(";\n }\n", out_);
1092 fputs(" public int x() {\n", out_);
1093 fputs(" return ", out_);
1094 emitLiteral(kInt);
1095 fputs(";\n }\n", out_);
1096 fputs(" }\n\n", out_);
1097 in_inner_ = false;
1098 }
1099
Aart Bikb1cd97f2016-08-09 10:49:54 -07001100 // Emit field declarations.
1101 void emitFieldDecls() {
Aart Bikff3920a2016-09-22 13:50:11 -07001102 fputs(" private A mA = new B();\n", out_);
1103 fputs(" private B mB = new B();\n", out_);
1104 fputs(" private X mBX = new B();\n", out_);
1105 fputs(" private C mC = new C();\n", out_);
1106 fputs(" private X mCX = new C();\n\n", out_);
Aart Bikb1cd97f2016-08-09 10:49:54 -07001107 fputs(" private boolean mZ = false;\n", out_);
1108 fputs(" private int mI = 0;\n", out_);
1109 fputs(" private long mJ = 0;\n", out_);
1110 fputs(" private float mF = 0;\n", out_);
1111 fputs(" private double mD = 0;\n\n", out_);
1112 }
1113
1114 // Emit array declaration.
1115 void emitArrayDecl() {
1116 fputs(" private ", out_);
1117 emitType(array_type_);
1118 for (uint32_t i = 0; i < array_dim_; i++) {
1119 fputs("[]", out_);
1120 }
1121 fputs(" mArray = new ", out_);
1122 emitType(array_type_);
1123 for (uint32_t i = 0; i < array_dim_; i++) {
1124 fprintf(out_, "[%d]", array_size_);
1125 }
1126 fputs(";\n\n", out_);
1127 }
1128
1129 // Emit test constructor.
1130 void emitTestConstructor() {
1131 fputs(" private Test() {\n", out_);
1132 indentation_ += 2;
1133 emitIndentation();
1134 emitType(array_type_);
1135 fputs(" a = ", out_);
1136 emitLiteral(array_type_);
1137 fputs(";\n", out_);
1138 for (uint32_t i = 0; i < array_dim_; i++) {
1139 emitIndentation();
1140 fprintf(out_, "for (int i%u = 0; i%u < %u; i%u++) {\n", i, i, array_size_, i);
1141 indentation_ += 2;
1142 }
1143 emitIndentation();
1144 fputs("mArray", out_);
1145 for (uint32_t i = 0; i < array_dim_; i++) {
1146 fprintf(out_, "[i%u]", i);
1147 }
1148 fputs(" = a;\n", out_);
1149 emitIndentation();
1150 if (array_type_ == kBoolean) {
1151 fputs("a = !a;\n", out_);
1152 } else {
1153 fputs("a++;\n", out_);
1154 }
1155 for (uint32_t i = 0; i < array_dim_; i++) {
1156 indentation_ -= 2;
1157 emitIndentation();
1158 fputs("}\n", out_);
1159 }
1160 indentation_ -= 2;
1161 fputs(" }\n\n", out_);
1162 }
1163
1164 // Emit test method.
1165 void emitTestMethod() {
1166 fputs(" private ", out_);
1167 emitType(return_type_);
1168 fputs(" testMethod() {\n", out_);
1169 indentation_ += 2;
1170 if (emitStatementList()) {
1171 // Must end with return.
1172 emitIndentation();
1173 emitReturn(true);
1174 }
1175 indentation_ -= 2;
1176 fputs(" }\n\n", out_);
1177 }
1178
1179 // Emit main method driver.
1180 void emitMainMethod() {
1181 fputs(" public static void main(String[] args) {\n", out_);
1182 indentation_ += 2;
1183 fputs(" Test t = new Test();\n ", out_);
1184 emitType(return_type_);
1185 fputs(" r = ", out_);
1186 emitLiteral(return_type_);
1187 fputs(";\n", out_);
1188 fputs(" try {\n", out_);
1189 fputs(" r = t.testMethod();\n", out_);
1190 fputs(" } catch (Exception e) {\n", out_);
1191 fputs(" // Arithmetic, null pointer, index out of bounds, etc.\n", out_);
1192 fputs(" System.out.println(\"An exception was caught.\");\n", out_);
1193 fputs(" }\n", out_);
1194 fputs(" System.out.println(\"r = \" + r);\n", out_);
1195 fputs(" System.out.println(\"mZ = \" + t.mZ);\n", out_);
1196 fputs(" System.out.println(\"mI = \" + t.mI);\n", out_);
1197 fputs(" System.out.println(\"mJ = \" + t.mJ);\n", out_);
1198 fputs(" System.out.println(\"mF = \" + t.mF);\n", out_);
1199 fputs(" System.out.println(\"mD = \" + t.mD);\n", out_);
1200 fputs(" System.out.println(\"mArray = \" + ", out_);
1201 if (array_dim_ == 1) {
1202 fputs("Arrays.toString(t.mArray)", out_);
1203 } else {
1204 fputs("Arrays.deepToString(t.mArray)", out_);
1205 }
1206 fputs(");\n", out_);
1207 indentation_ -= 2;
1208 fputs(" }\n", out_);
1209 }
1210
Orion Hodson4a10c752017-12-07 09:33:36 +00001211 // Emit a static void method.
1212 void emitStaticNopMethod() {
Aart Bikbd82d172017-12-15 11:31:57 -08001213 fputs(" public static void nop() {}\n\n", out_);
Orion Hodson4a10c752017-12-07 09:33:36 +00001214 }
1215
Aart Bikb1cd97f2016-08-09 10:49:54 -07001216 // Emit program header. Emit command line options in the comments.
1217 void emitHeader() {
Aart Bik842a4f32016-09-21 15:45:18 -07001218 fputs("\n/**\n * AOSP JFuzz Tester.\n", out_);
1219 fputs(" * Automatically generated program.\n", out_);
Aart Bikb1cd97f2016-08-09 10:49:54 -07001220 fprintf(out_,
Aart Bik842a4f32016-09-21 15:45:18 -07001221 " * jfuzz -s %u -d %u -l %u -i %u -n %u (version %s)\n */\n\n",
Aart Bikb1cd97f2016-08-09 10:49:54 -07001222 fuzz_seed_,
1223 fuzz_expr_depth_,
1224 fuzz_stmt_length_,
1225 fuzz_if_nest_,
1226 fuzz_loop_nest_,
1227 VERSION);
1228 fputs("import java.util.Arrays;\n\n", out_);
1229 }
1230
1231 // Emit single test class with main driver.
1232 void emitTestClassWithMain() {
1233 fputs("public class Test {\n\n", out_);
1234 indentation_ += 2;
Aart Bikff3920a2016-09-22 13:50:11 -07001235 emitClassDecls();
Aart Bikb1cd97f2016-08-09 10:49:54 -07001236 emitFieldDecls();
1237 emitArrayDecl();
1238 emitTestConstructor();
1239 emitTestMethod();
Orion Hodson4a10c752017-12-07 09:33:36 +00001240 emitStaticNopMethod();
Aart Bikb1cd97f2016-08-09 10:49:54 -07001241 emitMainMethod();
1242 indentation_ -= 2;
1243 fputs("}\n\n", out_);
1244 }
1245
1246 //
1247 // Random integers.
1248 //
1249
Aart Bikb16d4132016-08-19 15:45:11 -07001250 // Return random integer.
1251 int32_t random() {
1252 return fuzz_random_engine_();
1253 }
1254
Aart Bikb1cd97f2016-08-09 10:49:54 -07001255 // Return random integer in range [0,max).
1256 uint32_t random0(uint32_t max) {
1257 std::uniform_int_distribution<uint32_t> gen(0, max - 1);
1258 return gen(fuzz_random_engine_);
1259 }
1260
1261 // Return random integer in range [1,max].
1262 uint32_t random1(uint32_t max) {
1263 std::uniform_int_distribution<uint32_t> gen(1, max);
1264 return gen(fuzz_random_engine_);
1265 }
1266
1267 // Fuzzing parameters.
1268 FILE* out_;
1269 std::mt19937 fuzz_random_engine_;
1270 const uint32_t fuzz_seed_;
1271 const uint32_t fuzz_expr_depth_;
1272 const uint32_t fuzz_stmt_length_;
1273 const uint32_t fuzz_if_nest_;
1274 const uint32_t fuzz_loop_nest_;
Orion Hodson4a10c752017-12-07 09:33:36 +00001275 const uint32_t fuzz_try_nest_;
Aart Bikb1cd97f2016-08-09 10:49:54 -07001276
1277 // Return and array setup.
1278 const Type return_type_;
1279 const Type array_type_;
1280 const uint32_t array_dim_;
1281 const uint32_t array_size_;
1282
1283 // Current context.
1284 uint32_t indentation_;
1285 uint32_t expr_depth_;
1286 uint32_t stmt_length_;
1287 uint32_t if_nest_;
1288 uint32_t loop_nest_;
1289 uint32_t switch_nest_;
1290 uint32_t do_nest_;
Orion Hodson4a10c752017-12-07 09:33:36 +00001291 uint32_t try_nest_;
Aart Bikb1cd97f2016-08-09 10:49:54 -07001292 uint32_t boolean_local_;
1293 uint32_t int_local_;
1294 uint32_t long_local_;
1295 uint32_t float_local_;
1296 uint32_t double_local_;
Aart Bikff3920a2016-09-22 13:50:11 -07001297 bool in_inner_;
Aart Bikb1cd97f2016-08-09 10:49:54 -07001298};
1299
1300} // anonymous namespace
1301
1302int32_t main(int32_t argc, char** argv) {
Aart Bikff3920a2016-09-22 13:50:11 -07001303 // Time-based seed.
1304 struct timeval tp;
Yi Kong4b22b342018-08-02 14:43:21 -07001305 gettimeofday(&tp, nullptr);
Aart Bikff3920a2016-09-22 13:50:11 -07001306
Aart Bikb1cd97f2016-08-09 10:49:54 -07001307 // Defaults.
Aart Bikff3920a2016-09-22 13:50:11 -07001308 uint32_t seed = (tp.tv_sec * 1000000 + tp.tv_usec);
Aart Bikb1cd97f2016-08-09 10:49:54 -07001309 uint32_t expr_depth = 1;
Aart Bikb16d4132016-08-19 15:45:11 -07001310 uint32_t stmt_length = 8;
Aart Bikb1cd97f2016-08-09 10:49:54 -07001311 uint32_t if_nest = 2;
1312 uint32_t loop_nest = 3;
Orion Hodson4a10c752017-12-07 09:33:36 +00001313 uint32_t try_nest = 2;
Aart Bikb1cd97f2016-08-09 10:49:54 -07001314
1315 // Parse options.
1316 while (1) {
Wojciech Staszkiewicz18be7b32016-09-21 15:12:54 -07001317 int32_t option = getopt(argc, argv, "s:d:l:i:n:vh");
Aart Bikb1cd97f2016-08-09 10:49:54 -07001318 if (option < 0) {
1319 break; // done
1320 }
1321 switch (option) {
1322 case 's':
1323 seed = strtoul(optarg, nullptr, 0); // deterministic seed
1324 break;
1325 case 'd':
1326 expr_depth = strtoul(optarg, nullptr, 0);
1327 break;
1328 case 'l':
1329 stmt_length = strtoul(optarg, nullptr, 0);
1330 break;
1331 case 'i':
1332 if_nest = strtoul(optarg, nullptr, 0);
1333 break;
1334 case 'n':
1335 loop_nest = strtoul(optarg, nullptr, 0);
1336 break;
Orion Hodson4a10c752017-12-07 09:33:36 +00001337 case 't':
1338 try_nest = strtoul(optarg, nullptr, 0);
1339 break;
Wojciech Staszkiewicz18be7b32016-09-21 15:12:54 -07001340 case 'v':
1341 fprintf(stderr, "jfuzz version %s\n", VERSION);
1342 return 0;
Aart Bikb1cd97f2016-08-09 10:49:54 -07001343 case 'h':
1344 default:
1345 fprintf(stderr,
1346 "usage: %s [-s seed] "
1347 "[-d expr-depth] [-l stmt-length] "
Orion Hodson4a10c752017-12-07 09:33:36 +00001348 "[-i if-nest] [-n loop-nest] [-t try-nest] [-v] [-h]\n",
Aart Bikb1cd97f2016-08-09 10:49:54 -07001349 argv[0]);
1350 return 1;
1351 }
1352 }
1353
1354 // Seed global random generator.
1355 srand(seed);
1356
Aart Bik842a4f32016-09-21 15:45:18 -07001357 // Generate fuzzed program.
Orion Hodson4a10c752017-12-07 09:33:36 +00001358 JFuzz fuzz(stdout, seed, expr_depth, stmt_length, if_nest, loop_nest, try_nest);
Aart Bikb1cd97f2016-08-09 10:49:54 -07001359 fuzz.emitProgram();
1360 return 0;
1361}