blob: 88205c84cfea63135078d99727ac63f87d1fbb32 [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
17#include <random>
18
19#include <inttypes.h>
20#include <stdlib.h>
21#include <stdio.h>
22#include <string.h>
23#include <unistd.h>
24#include <time.h>
25
26namespace {
27
28/*
Aart Bik842a4f32016-09-21 15:45:18 -070029 * Operators.
Aart Bikb1cd97f2016-08-09 10:49:54 -070030 */
31
32#define EMIT(x) fputs((x)[random0(sizeof(x)/sizeof(const char*))], out_);
33
34static 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/*
Aart Bik842a4f32016-09-21 15:45:18 -070052 * Version of JFuzz. Increase this each time changes are made to the program
53 * to preserve the property that a given version of JFuzz yields the same
54 * fuzzed program for a deterministic random seed.
Aart Bikb1cd97f2016-08-09 10:49:54 -070055 */
Aart Bikb16d4132016-08-19 15:45:11 -070056const char* VERSION = "1.1";
57
58static const uint32_t MAX_DIMS[11] = { 0, 1000, 32, 10, 6, 4, 3, 3, 2, 2, 2 };
Aart Bikb1cd97f2016-08-09 10:49:54 -070059
60/**
Aart Bik842a4f32016-09-21 15:45:18 -070061 * A class that generates a random program that compiles correctly. The program
Aart Bikb1cd97f2016-08-09 10:49:54 -070062 * is generated using rules that generate various programming constructs. Each rule
63 * has a fixed probability to "fire". Running a generated program yields deterministic
64 * output, making it suited to test various modes of execution (e.g an interpreter vs.
65 * an compiler or two different run times) for divergences.
66 *
Aart Bik842a4f32016-09-21 15:45:18 -070067 * TODO: Due to the original scope of this project, the generated program is heavy
68 * on loops, arrays, and basic operations; fuzzing other aspects, like elaborate
69 * typing, class hierarchies, and interfaces is still TBD.
Aart Bikb1cd97f2016-08-09 10:49:54 -070070 */
Aart Bik842a4f32016-09-21 15:45:18 -070071class JFuzz {
Aart Bikb1cd97f2016-08-09 10:49:54 -070072 public:
Aart Bik842a4f32016-09-21 15:45:18 -070073 JFuzz(FILE* out,
74 uint32_t seed,
75 uint32_t expr_depth,
76 uint32_t stmt_length,
77 uint32_t if_nest,
78 uint32_t loop_nest)
Aart Bikb1cd97f2016-08-09 10:49:54 -070079 : out_(out),
80 fuzz_random_engine_(seed),
81 fuzz_seed_(seed),
82 fuzz_expr_depth_(expr_depth),
83 fuzz_stmt_length_(stmt_length),
84 fuzz_if_nest_(if_nest),
85 fuzz_loop_nest_(loop_nest),
86 return_type_(randomType()),
87 array_type_(randomType()),
Aart Bikb16d4132016-08-19 15:45:11 -070088 array_dim_(random1(10)),
89 array_size_(random1(MAX_DIMS[array_dim_])),
Aart Bikb1cd97f2016-08-09 10:49:54 -070090 indentation_(0),
91 expr_depth_(0),
92 stmt_length_(0),
93 if_nest_(0),
94 loop_nest_(0),
95 switch_nest_(0),
96 do_nest_(0),
97 boolean_local_(0),
98 int_local_(0),
99 long_local_(0),
100 float_local_(0),
101 double_local_(0) { }
102
Aart Bik842a4f32016-09-21 15:45:18 -0700103 ~JFuzz() { }
Aart Bikb1cd97f2016-08-09 10:49:54 -0700104
105 void emitProgram() {
106 emitHeader();
107 emitTestClassWithMain();
108 }
109
110 private:
111 //
112 // Types.
113 //
114
115 // Current type of each expression during generation.
116 enum Type {
117 kBoolean,
118 kInt,
119 kLong,
120 kFloat,
121 kDouble
122 };
123
124 // Test for an integral type.
125 static bool isInteger(Type tp) {
126 return tp == kInt || tp == kLong;
127 }
128
129 // Test for a floating-point type.
130 static bool isFP(Type tp) {
131 return tp == kFloat || tp == kDouble;
132 }
133
134 // Emit type.
135 void emitType(Type tp) const {
136 switch (tp) {
137 case kBoolean: fputs("boolean", out_); break;
138 case kInt: fputs("int", out_); break;
139 case kLong: fputs("long", out_); break;
140 case kFloat: fputs("float", out_); break;
141 case kDouble: fputs("double", out_); break;
142 }
143 }
144
145 // Emit type class.
146 void emitTypeClass(Type tp) const {
147 switch (tp) {
148 case kBoolean: fputs("Boolean", out_); break;
149 case kInt: fputs("Integer", out_); break;
150 case kLong: fputs("Long", out_); break;
151 case kFloat: fputs("Float", out_); break;
152 case kDouble: fputs("Double", out_); break;
153 }
154 }
155
156 // Return a random type.
157 Type randomType() {
158 switch (random1(5)) {
159 case 1: return kBoolean;
160 case 2: return kInt;
161 case 3: return kLong;
162 case 4: return kFloat;
163 default: return kDouble;
164 }
165 }
166
167 //
168 // Expressions.
169 //
170
171 // Emit an unary operator (same type in-out).
172 void emitUnaryOp(Type tp) {
173 if (tp == kBoolean) {
Aart Bikb16d4132016-08-19 15:45:11 -0700174 fputc('!', out_);
Aart Bikb1cd97f2016-08-09 10:49:54 -0700175 } else if (isInteger(tp)) {
176 EMIT(kIntUnaryOps);
177 } else { // isFP(tp)
178 EMIT(kFpUnaryOps);
179 }
180 }
181
182 // Emit a pre/post-increment/decrement operator (same type in-out).
183 void emitIncDecOp(Type tp) {
184 if (tp == kBoolean) {
185 // Not applicable, just leave "as is".
186 } else { // isInteger(tp) || isFP(tp)
187 EMIT(kIncDecOps);
188 }
189 }
190
191 // Emit a binary operator (same type in-out).
192 void emitBinaryOp(Type tp) {
193 if (tp == kBoolean) {
194 EMIT(kBoolBinOps);
195 } else if (isInteger(tp)) {
196 EMIT(kIntBinOps);
197 } else { // isFP(tp)
198 EMIT(kFpBinOps);
199 }
200 }
201
202 // Emit an assignment operator (same type in-out).
203 void emitAssignmentOp(Type tp) {
204 if (tp == kBoolean) {
205 EMIT(kBoolAssignOps);
206 } else if (isInteger(tp)) {
207 EMIT(kIntAssignOps);
208 } else { // isFP(tp)
209 EMIT(kFpAssignOps);
210 }
211 }
212
213 // Emit a relational operator (one type in, boolean out).
214 void emitRelationalOp(Type tp) {
215 if (tp == kBoolean) {
216 EMIT(kBoolRelOps);
217 } else { // isInteger(tp) || isFP(tp)
218 EMIT(kRelOps);
219 }
220 }
221
222 // Emit a type conversion operator sequence (out type given, new suitable in type picked).
223 Type emitTypeConversionOp(Type tp) {
224 if (tp == kInt) {
225 switch (random1(5)) {
226 case 1: fputs("(int)", out_); return kLong;
227 case 2: fputs("(int)", out_); return kFloat;
228 case 3: fputs("(int)", out_); return kDouble;
229 // Narrowing-widening.
230 case 4: fputs("(int)(byte)(int)", out_); return kInt;
231 case 5: fputs("(int)(short)(int)", out_); return kInt;
232 }
233 } else if (tp == kLong) {
234 switch (random1(6)) {
235 case 1: /* implicit */ return kInt;
236 case 2: fputs("(long)", out_); return kFloat;
237 case 3: fputs("(long)", out_); return kDouble;
238 // Narrowing-widening.
239 case 4: fputs("(long)(byte)(long)", out_); return kLong;
240 case 5: fputs("(long)(short)(long)", out_); return kLong;
241 case 6: fputs("(long)(int)(long)", out_); return kLong;
242 }
243 } else if (tp == kFloat) {
Aart Bikb16d4132016-08-19 15:45:11 -0700244 switch (random1(4)) {
Aart Bikb1cd97f2016-08-09 10:49:54 -0700245 case 1: fputs("(float)", out_); return kInt;
246 case 2: fputs("(float)", out_); return kLong;
247 case 3: fputs("(float)", out_); return kDouble;
Aart Bikb16d4132016-08-19 15:45:11 -0700248 // Narrowing-widening.
249 case 4: fputs("(float)(int)(float)", out_); return kFloat;
Aart Bikb1cd97f2016-08-09 10:49:54 -0700250 }
251 } else if (tp == kDouble) {
Aart Bikb16d4132016-08-19 15:45:11 -0700252 switch (random1(5)) {
Aart Bikb1cd97f2016-08-09 10:49:54 -0700253 case 1: fputs("(double)", out_); return kInt;
254 case 2: fputs("(double)", out_); return kLong;
255 case 3: fputs("(double)", out_); return kFloat;
Aart Bikb16d4132016-08-19 15:45:11 -0700256 // Narrowing-widening.
257 case 4: fputs("(double)(int)(double)", out_); return kDouble;
258 case 5: fputs("(double)(float)(double)", out_); return kDouble;
Aart Bikb1cd97f2016-08-09 10:49:54 -0700259 }
260 }
261 return tp; // nothing suitable, just keep type
262 }
263
264 // Emit a type conversion (out type given, new suitable in type picked).
265 void emitTypeConversion(Type tp) {
266 if (tp == kBoolean) {
267 Type tp = randomType();
268 emitExpression(tp);
269 fputc(' ', out_);
270 emitRelationalOp(tp);
271 fputc(' ', out_);
272 emitExpression(tp);
273 } else {
274 tp = emitTypeConversionOp(tp);
275 fputc(' ', out_);
276 emitExpression(tp);
277 }
278 }
279
280 // Emit an unary intrinsic (out type given, new suitable in type picked).
281 Type emitIntrinsic1(Type tp) {
282 if (tp == kBoolean) {
Aart Bikb16d4132016-08-19 15:45:11 -0700283 switch (random1(6)) {
Aart Bikb1cd97f2016-08-09 10:49:54 -0700284 case 1: fputs("Float.isNaN", out_); return kFloat;
Aart Bikb16d4132016-08-19 15:45:11 -0700285 case 2: fputs("Float.isFinite", out_); return kFloat;
286 case 3: fputs("Float.isInfinite", out_); return kFloat;
287 case 4: fputs("Double.isNaN", out_); return kDouble;
288 case 5: fputs("Double.isFinite", out_); return kDouble;
289 case 6: fputs("Double.isInfinite", out_); return kDouble;
Aart Bikb1cd97f2016-08-09 10:49:54 -0700290 }
291 } else if (isInteger(tp)) {
292 const char* prefix = tp == kLong ? "Long" : "Integer";
Aart Bikb16d4132016-08-19 15:45:11 -0700293 switch (random1(13)) {
Aart Bikb1cd97f2016-08-09 10:49:54 -0700294 case 1: fprintf(out_, "%s.highestOneBit", prefix); break;
295 case 2: fprintf(out_, "%s.lowestOneBit", prefix); break;
296 case 3: fprintf(out_, "%s.numberOfLeadingZeros", prefix); break;
297 case 4: fprintf(out_, "%s.numberOfTrailingZeros", prefix); break;
298 case 5: fprintf(out_, "%s.bitCount", prefix); break;
299 case 6: fprintf(out_, "%s.signum", prefix); break;
300 case 7: fprintf(out_, "%s.reverse", prefix); break;
301 case 8: fprintf(out_, "%s.reverseBytes", prefix); break;
Aart Bikb16d4132016-08-19 15:45:11 -0700302 case 9: fputs("Math.incrementExact", out_); break;
303 case 10: fputs("Math.decrementExact", out_); break;
304 case 11: fputs("Math.negateExact", out_); break;
305 case 12: fputs("Math.abs", out_); break;
306 case 13: fputs("Math.round", out_);
307 return tp == kLong ? kDouble : kFloat;
Aart Bikb1cd97f2016-08-09 10:49:54 -0700308 }
309 } else { // isFP(tp)
Aart Bikb16d4132016-08-19 15:45:11 -0700310 switch (random1(6)) {
Aart Bikb1cd97f2016-08-09 10:49:54 -0700311 case 1: fputs("Math.abs", out_); break;
312 case 2: fputs("Math.ulp", out_); break;
313 case 3: fputs("Math.signum", out_); break;
314 case 4: fputs("Math.nextUp", out_); break;
315 case 5: fputs("Math.nextDown", out_); break;
Aart Bikb16d4132016-08-19 15:45:11 -0700316 case 6: if (tp == kDouble) {
317 fputs("Double.longBitsToDouble", out_);
318 return kLong;
319 } else {
320 fputs("Float.intBitsToFloat", out_);
321 return kInt;
322 }
Aart Bikb1cd97f2016-08-09 10:49:54 -0700323 }
324 }
325 return tp; // same type in-out
326 }
327
328 // Emit a binary intrinsic (out type given, new suitable in type picked).
329 Type emitIntrinsic2(Type tp) {
330 if (tp == kBoolean) {
331 switch (random1(3)) {
332 case 1: fputs("Boolean.logicalAnd", out_); break;
333 case 2: fputs("Boolean.logicalOr", out_); break;
334 case 3: fputs("Boolean.logicalXor", out_); break;
335 }
336 } else if (isInteger(tp)) {
337 const char* prefix = tp == kLong ? "Long" : "Integer";
Aart Bikb16d4132016-08-19 15:45:11 -0700338 switch (random1(11)) {
Aart Bikb1cd97f2016-08-09 10:49:54 -0700339 case 1: fprintf(out_, "%s.compare", prefix); break;
Aart Bikb16d4132016-08-19 15:45:11 -0700340 case 2: fprintf(out_, "%s.sum", prefix); break;
341 case 3: fprintf(out_, "%s.min", prefix); break;
342 case 4: fprintf(out_, "%s.max", prefix); break;
343 case 5: fputs("Math.min", out_); break;
344 case 6: fputs("Math.max", out_); break;
345 case 7: fputs("Math.floorDiv", out_); break;
346 case 8: fputs("Math.floorMod", out_); break;
347 case 9: fputs("Math.addExact", out_); break;
348 case 10: fputs("Math.subtractExact", out_); break;
349 case 11: fputs("Math.multiplyExact", out_); break;
Aart Bikb1cd97f2016-08-09 10:49:54 -0700350 }
351 } else { // isFP(tp)
Aart Bikb16d4132016-08-19 15:45:11 -0700352 const char* prefix = tp == kDouble ? "Double" : "Float";
353 switch (random1(5)) {
354 case 1: fprintf(out_, "%s.sum", prefix); break;
355 case 2: fprintf(out_, "%s.min", prefix); break;
356 case 3: fprintf(out_, "%s.max", prefix); break;
357 case 4: fputs("Math.min", out_); break;
358 case 5: fputs("Math.max", out_); break;
Aart Bikb1cd97f2016-08-09 10:49:54 -0700359 }
360 }
361 return tp; // same type in-out
362 }
363
364 // Emit an intrinsic (out type given, new suitable in type picked).
365 void emitIntrinsic(Type tp) {
366 if (random1(2) == 1) {
367 tp = emitIntrinsic1(tp);
368 fputc('(', out_);
369 emitExpression(tp);
370 fputc(')', out_);
371 } else {
372 tp = emitIntrinsic2(tp);
373 fputc('(', out_);
374 emitExpression(tp);
375 fputs(", ", out_);
376 emitExpression(tp);
377 fputc(')', out_);
378 }
379 }
380
381 // Emit unboxing boxed object.
382 void emitUnbox(Type tp) {
383 fputc('(', out_);
384 emitType(tp);
385 fputs(") new ", out_);
386 emitTypeClass(tp);
387 fputc('(', out_);
388 emitExpression(tp);
389 fputc(')', out_);
390 }
391
392 // Emit miscellaneous constructs.
393 void emitMisc(Type tp) {
Aart Bikb16d4132016-08-19 15:45:11 -0700394 if (tp == kBoolean) {
395 fputs("this instanceof Test", out_);
396 } else if (isInteger(tp)) {
397 const char* prefix = tp == kLong ? "Long" : "Integer";
398 switch (random1(2)) {
399 case 1: fprintf(out_, "%s.MIN_VALUE", prefix); break;
400 case 2: fprintf(out_, "%s.MAX_VALUE", prefix); break;
401 }
402 } else { // isFP(tp)
403 const char* prefix = tp == kDouble ? "Double" : "Float";
404 switch (random1(6)) {
405 case 1: fprintf(out_, "%s.MIN_NORMAL", prefix); break;
406 case 2: fprintf(out_, "%s.MIN_VALUE", prefix); break;
407 case 3: fprintf(out_, "%s.MAX_VALUE", prefix); break;
408 case 4: fprintf(out_, "%s.POSITIVE_INFINITY", prefix); break;
409 case 5: fprintf(out_, "%s.NEGATIVE_INFINITY", prefix); break;
410 case 6: fprintf(out_, "%s.NaN", prefix); break;
411 }
Aart Bikb1cd97f2016-08-09 10:49:54 -0700412 }
413 }
414
415 // Adjust local of given type and return adjusted value.
416 uint32_t adjustLocal(Type tp, int32_t a) {
417 switch (tp) {
418 case kBoolean: boolean_local_ += a; return boolean_local_;
419 case kInt: int_local_ += a; return int_local_;
420 case kLong: long_local_ += a; return long_local_;
421 case kFloat: float_local_ += a; return float_local_;
422 default: double_local_ += a; return double_local_;
423 }
424 }
425
426 // Emit an expression that is a strict upper bound for an array index.
427 void emitUpperBound() {
428 if (random1(8) == 1) {
429 fputs("mArray.length", out_);
430 } else if (random1(8) == 1) {
431 fprintf(out_, "%u", random1(array_size_)); // random in range
432 } else {
433 fprintf(out_, "%u", array_size_);
434 }
435 }
436
437 // Emit an array index, usually within proper range.
438 void emitArrayIndex() {
439 if (loop_nest_ > 0 && random1(2) == 1) {
440 fprintf(out_, "i%u", random0(loop_nest_));
441 } else if (random1(8) == 1) {
442 fputs("mArray.length - 1", out_);
443 } else {
444 fprintf(out_, "%u", random0(array_size_)); // random in range
445 }
446 // Introduce potential off by one errors with low probability.
447 if (random1(100) == 1) {
448 if (random1(2) == 1) {
449 fputs(" - 1", out_);
450 } else {
451 fputs(" + 1", out_);
452 }
453 }
454 }
455
456 // Emit a literal.
457 void emitLiteral(Type tp) {
458 switch (tp) {
459 case kBoolean: fputs(random1(2) == 1 ? "true" : "false", out_); break;
Aart Bikb16d4132016-08-19 15:45:11 -0700460 case kInt: fprintf(out_, "%d", random()); break;
461 case kLong: fprintf(out_, "%dL", random()); break;
462 case kFloat: fprintf(out_, "%d.0f", random()); break;
463 case kDouble: fprintf(out_, "%d.0", random()); break;
Aart Bikb1cd97f2016-08-09 10:49:54 -0700464 }
465 }
466
467 // Emit array variable, if available.
468 bool emitArrayVariable(Type tp) {
469 if (tp == array_type_) {
470 fputs("mArray", out_);
471 for (uint32_t i = 0; i < array_dim_; i++) {
472 fputc('[', out_);
473 emitArrayIndex();
474 fputc(']', out_);
475 }
476 return true;
477 }
478 return false;
479 }
480
Aart Bikb1cd97f2016-08-09 10:49:54 -0700481 // Emit a local variable, if available.
482 bool emitLocalVariable(Type tp) {
483 uint32_t locals = adjustLocal(tp, 0);
484 if (locals > 0) {
485 uint32_t local = random0(locals);
486 switch (tp) {
487 case kBoolean: fprintf(out_, "lZ%u", local); break;
488 case kInt: fprintf(out_, "lI%u", local); break;
489 case kLong: fprintf(out_, "lJ%u", local); break;
490 case kFloat: fprintf(out_, "lF%u", local); break;
491 case kDouble: fprintf(out_, "lD%u", local); break;
492 }
493 return true;
494 }
495 return false;
496 }
497
498 // Emit a field variable.
499 void emitFieldVariable(Type tp) {
500 switch (tp) {
501 case kBoolean:fputs("mZ", out_); break;
502 case kInt: fputs("mI", out_); break;
503 case kLong: fputs("mJ", out_); break;
504 case kFloat: fputs("mF", out_); break;
505 case kDouble: fputs("mD", out_); break;
506 }
507 }
508
509 // Emit a variable.
510 void emitVariable(Type tp) {
511 switch (random1(4)) {
512 case 1:
513 if (emitArrayVariable(tp))
514 return;
515 // FALL-THROUGH
516 case 2:
517 if (emitLocalVariable(tp))
518 return;
519 // FALL-THROUGH
Aart Bikb1cd97f2016-08-09 10:49:54 -0700520 default:
521 emitFieldVariable(tp);
522 break;
523 }
524 }
525
526 // Emit an expression.
527 void emitExpression(Type tp) {
528 // Continuing expression becomes less likely as the depth grows.
529 if (random1(expr_depth_ + 1) > fuzz_expr_depth_) {
530 if (random1(2) == 1) {
531 emitLiteral(tp);
532 } else {
533 emitVariable(tp);
534 }
535 return;
536 }
537
538 expr_depth_++;
539
540 fputc('(', out_);
541 switch (random1(12)) { // favor binary operations
542 case 1:
Aart Bikb16d4132016-08-19 15:45:11 -0700543 // Unary operator: ~ x
Aart Bikb1cd97f2016-08-09 10:49:54 -0700544 emitUnaryOp(tp);
Aart Bikb16d4132016-08-19 15:45:11 -0700545 fputc(' ', out_);
Aart Bikb1cd97f2016-08-09 10:49:54 -0700546 emitExpression(tp);
547 break;
548 case 2:
549 // Pre-increment: ++x
550 emitIncDecOp(tp);
551 emitVariable(tp);
552 break;
553 case 3:
554 // Post-increment: x++
555 emitVariable(tp);
556 emitIncDecOp(tp);
557 break;
558 case 4:
559 // Ternary operator: b ? x : y
560 emitExpression(kBoolean);
561 fputs(" ? ", out_);
562 emitExpression(tp);
563 fputs(" : ", out_);
564 emitExpression(tp);
565 break;
566 case 5:
567 // Type conversion: (float) x
568 emitTypeConversion(tp);
569 break;
570 case 6:
571 // Intrinsic: foo(x)
572 emitIntrinsic(tp);
573 break;
574 case 7:
575 // Emit unboxing boxed value: (int) Integer(x)
576 emitUnbox(tp);
577 break;
578 case 8:
579 // Miscellaneous constructs: a.length
580 emitMisc(tp);
581 break;
582 default:
583 // Binary operator: x + y
584 emitExpression(tp);
585 fputc(' ', out_);
586 emitBinaryOp(tp);
587 fputc(' ', out_);
588 emitExpression(tp);
589 break;
590 }
591 fputc(')', out_);
592
593 --expr_depth_;
594 }
595
596 //
597 // Statements.
598 //
599
600 // Emit current indentation.
601 void emitIndentation() const {
602 for (uint32_t i = 0; i < indentation_; i++) {
603 fputc(' ', out_);
604 }
605 }
606
607 // Emit a return statement.
608 bool emitReturn(bool mustEmit) {
609 // Only emit when we must, or with low probability inside ifs/loops,
610 // but outside do-while to avoid confusing the may follow status.
611 if (mustEmit || ((if_nest_ + loop_nest_) > 0 && do_nest_ == 0 && random1(10) == 1)) {
612 fputs("return ", out_);
613 emitExpression(return_type_);
614 fputs(";\n", out_);
615 return false;
616 }
617 // Fall back to assignment.
618 return emitAssignment();
619 }
620
621 // Emit a continue statement.
622 bool emitContinue() {
623 // Only emit with low probability inside loops.
624 if (loop_nest_ > 0 && random1(10) == 1) {
625 fputs("continue;\n", out_);
626 return false;
627 }
628 // Fall back to assignment.
629 return emitAssignment();
630 }
631
632 // Emit a break statement.
633 bool emitBreak() {
634 // Only emit with low probability inside loops, but outside switches
635 // to avoid confusing the may follow status.
636 if (loop_nest_ > 0 && switch_nest_ == 0 && random1(10) == 1) {
637 fputs("break;\n", out_);
638 return false;
639 }
640 // Fall back to assignment.
641 return emitAssignment();
642 }
643
644 // Emit a new scope with a local variable declaration statement.
645 bool emitScope() {
646 Type tp = randomType();
647 fputs("{\n", out_);
648 indentation_ += 2;
649 emitIndentation();
650 emitType(tp);
651 switch (tp) {
652 case kBoolean: fprintf(out_, " lZ%u = ", boolean_local_); break;
653 case kInt: fprintf(out_, " lI%u = ", int_local_); break;
654 case kLong: fprintf(out_, " lJ%u = ", long_local_); break;
655 case kFloat: fprintf(out_, " lF%u = ", float_local_); break;
656 case kDouble: fprintf(out_, " lD%u = ", double_local_); break;
657 }
658 emitExpression(tp);
659 fputs(";\n", out_);
660
661 adjustLocal(tp, 1); // local now visible
662
663 bool mayFollow = emitStatementList();
664
665 adjustLocal(tp, -1); // local no longer visible
666
667 indentation_ -= 2;
668 emitIndentation();
669 fputs("}\n", out_);
670 return mayFollow;
671 }
672
673 // Emit a for loop.
674 bool emitForLoop() {
675 // Continuing loop nest becomes less likely as the depth grows.
676 if (random1(loop_nest_ + 1) > fuzz_loop_nest_) {
677 return emitAssignment(); // fall back
678 }
679
680 bool goesUp = random1(2) == 1;
681 fprintf(out_, "for (int i%u = ", loop_nest_);
682 if (goesUp) {
683 fprintf(out_, "0; i%u < ", loop_nest_);
684 emitUpperBound();
685 fprintf(out_, "; i%u++) {\n", loop_nest_);
686 } else {
687 emitUpperBound();
688 fprintf(out_, " - 1; i%d >= 0", loop_nest_);
689 fprintf(out_, "; i%d--) {\n", loop_nest_);
690 }
691
692 ++loop_nest_; // now in loop
693
694 indentation_ += 2;
695 emitStatementList();
696
697 --loop_nest_; // no longer in loop
698
699 indentation_ -= 2;
700 emitIndentation();
701 fprintf(out_, "}\n");
702 return true; // loop-body does not block flow
703 }
704
705 // Emit while or do-while loop.
706 bool emitDoLoop() {
707 // Continuing loop nest becomes less likely as the depth grows.
708 if (random1(loop_nest_ + 1) > fuzz_loop_nest_) {
709 return emitAssignment(); // fall back
710 }
711
712 // TODO: remove this
713 // The jack bug b/28862040 prevents generating while/do-while loops because otherwise
714 // we get dozens of reports on the same issue per nightly/ run.
715 if (true) {
716 return emitAssignment();
717 }
718
719 bool isWhile = random1(2) == 1;
720 fputs("{\n", out_);
721 indentation_ += 2;
722 emitIndentation();
723 fprintf(out_, "int i%u = %d;", loop_nest_, isWhile ? -1 : 0);
724 emitIndentation();
725 if (isWhile) {
726 fprintf(out_, "while (++i%u < ", loop_nest_);
727 emitUpperBound();
728 fputs(") {\n", out_);
729 } else {
730 fputs("do {\n", out_);
731 do_nest_++;
732 }
733
734 ++loop_nest_; // now in loop
735
736 indentation_ += 2;
737 emitStatementList();
738
739 --loop_nest_; // no longer in loop
740
741 indentation_ -= 2;
742 emitIndentation();
743 if (isWhile) {
744 fputs("}\n", out_);
745 } else {
746 fprintf(out_, "} while (++i%u < ", loop_nest_);
747 emitUpperBound();
748 fputs(");\n", out_);
749 --do_nest_;
750 }
751 indentation_ -= 2;
752 emitIndentation();
753 fputs("}\n", out_);
754 return true; // loop-body does not block flow
755 }
756
757 // Emit an if statement.
758 bool emitIfStmt() {
759 // Continuing if nest becomes less likely as the depth grows.
760 if (random1(if_nest_ + 1) > fuzz_if_nest_) {
761 return emitAssignment(); // fall back
762 }
763
764 fputs("if (", out_);
765 emitExpression(kBoolean);
766 fputs(") {\n", out_);
767
768 ++if_nest_; // now in if
769
770 indentation_ += 2;
771 bool mayFollowTrue = emitStatementList();
772 indentation_ -= 2;
773 emitIndentation();
774 fprintf(out_, "} else {\n");
775 indentation_ += 2;
776 bool mayFollowFalse = emitStatementList();
777
778 --if_nest_; // no longer in if
779
780 indentation_ -= 2;
781 emitIndentation();
782 fprintf(out_, "}\n");
783 return mayFollowTrue || mayFollowFalse;
784 }
785
786 // Emit a switch statement.
787 bool emitSwitch() {
788 // Continuing if nest becomes less likely as the depth grows.
789 if (random1(if_nest_ + 1) > fuzz_if_nest_) {
790 return emitAssignment(); // fall back
791 }
792
793 bool mayFollow = false;
794 fputs("switch (", out_);
Aart Bikb16d4132016-08-19 15:45:11 -0700795 emitArrayIndex(); // restrict its range
Aart Bikb1cd97f2016-08-09 10:49:54 -0700796 fputs(") {\n", out_);
797
798 ++if_nest_;
799 ++switch_nest_; // now in switch
800
801 indentation_ += 2;
802 for (uint32_t i = 0; i < 2; i++) {
803 emitIndentation();
804 if (i == 0) {
Aart Bikb16d4132016-08-19 15:45:11 -0700805 fprintf(out_, "case %u: {\n", random0(array_size_));
Aart Bikb1cd97f2016-08-09 10:49:54 -0700806 } else {
807 fprintf(out_, "default: {\n");
808 }
809 indentation_ += 2;
810 if (emitStatementList()) {
811 // Must end with break.
812 emitIndentation();
813 fputs("break;\n", out_);
814 mayFollow = true;
815 }
816 indentation_ -= 2;
817 emitIndentation();
818 fputs("}\n", out_);
819 }
820
821 --if_nest_;
822 --switch_nest_; // no longer in switch
823
824 indentation_ -= 2;
825 emitIndentation();
826 fprintf(out_, "}\n");
827 return mayFollow;
828 }
829
830 // Emit an assignment statement.
831 bool emitAssignment() {
832 Type tp = randomType();
833 emitVariable(tp);
834 fputc(' ', out_);
835 emitAssignmentOp(tp);
836 fputc(' ', out_);
837 emitExpression(tp);
838 fputs(";\n", out_);
839 return true;
840 }
841
842 // Emit a single statement. Returns true if statements may follow.
843 bool emitStatement() {
844 switch (random1(16)) { // favor assignments
845 case 1: return emitReturn(false); break;
846 case 2: return emitContinue(); break;
847 case 3: return emitBreak(); break;
848 case 4: return emitScope(); break;
849 case 5: return emitForLoop(); break;
850 case 6: return emitDoLoop(); break;
851 case 7: return emitIfStmt(); break;
852 case 8: return emitSwitch(); break;
853 default: return emitAssignment(); break;
854 }
855 }
856
857 // Emit a statement list. Returns true if statements may follow.
858 bool emitStatementList() {
859 while (stmt_length_ < 1000) { // avoid run-away
860 stmt_length_++;
861 emitIndentation();
862 if (!emitStatement()) {
863 return false; // rest would be dead code
864 }
865 // Continuing this list becomes less likely as the total statement list grows.
866 if (random1(stmt_length_) > fuzz_stmt_length_) {
867 break;
868 }
869 }
870 return true;
871 }
872
873 // Emit field declarations.
874 void emitFieldDecls() {
875 fputs(" private boolean mZ = false;\n", out_);
876 fputs(" private int mI = 0;\n", out_);
877 fputs(" private long mJ = 0;\n", out_);
878 fputs(" private float mF = 0;\n", out_);
879 fputs(" private double mD = 0;\n\n", out_);
880 }
881
882 // Emit array declaration.
883 void emitArrayDecl() {
884 fputs(" private ", out_);
885 emitType(array_type_);
886 for (uint32_t i = 0; i < array_dim_; i++) {
887 fputs("[]", out_);
888 }
889 fputs(" mArray = new ", out_);
890 emitType(array_type_);
891 for (uint32_t i = 0; i < array_dim_; i++) {
892 fprintf(out_, "[%d]", array_size_);
893 }
894 fputs(";\n\n", out_);
895 }
896
897 // Emit test constructor.
898 void emitTestConstructor() {
899 fputs(" private Test() {\n", out_);
900 indentation_ += 2;
901 emitIndentation();
902 emitType(array_type_);
903 fputs(" a = ", out_);
904 emitLiteral(array_type_);
905 fputs(";\n", out_);
906 for (uint32_t i = 0; i < array_dim_; i++) {
907 emitIndentation();
908 fprintf(out_, "for (int i%u = 0; i%u < %u; i%u++) {\n", i, i, array_size_, i);
909 indentation_ += 2;
910 }
911 emitIndentation();
912 fputs("mArray", out_);
913 for (uint32_t i = 0; i < array_dim_; i++) {
914 fprintf(out_, "[i%u]", i);
915 }
916 fputs(" = a;\n", out_);
917 emitIndentation();
918 if (array_type_ == kBoolean) {
919 fputs("a = !a;\n", out_);
920 } else {
921 fputs("a++;\n", out_);
922 }
923 for (uint32_t i = 0; i < array_dim_; i++) {
924 indentation_ -= 2;
925 emitIndentation();
926 fputs("}\n", out_);
927 }
928 indentation_ -= 2;
929 fputs(" }\n\n", out_);
930 }
931
932 // Emit test method.
933 void emitTestMethod() {
934 fputs(" private ", out_);
935 emitType(return_type_);
936 fputs(" testMethod() {\n", out_);
937 indentation_ += 2;
938 if (emitStatementList()) {
939 // Must end with return.
940 emitIndentation();
941 emitReturn(true);
942 }
943 indentation_ -= 2;
944 fputs(" }\n\n", out_);
945 }
946
947 // Emit main method driver.
948 void emitMainMethod() {
949 fputs(" public static void main(String[] args) {\n", out_);
950 indentation_ += 2;
951 fputs(" Test t = new Test();\n ", out_);
952 emitType(return_type_);
953 fputs(" r = ", out_);
954 emitLiteral(return_type_);
955 fputs(";\n", out_);
956 fputs(" try {\n", out_);
957 fputs(" r = t.testMethod();\n", out_);
958 fputs(" } catch (Exception e) {\n", out_);
959 fputs(" // Arithmetic, null pointer, index out of bounds, etc.\n", out_);
960 fputs(" System.out.println(\"An exception was caught.\");\n", out_);
961 fputs(" }\n", out_);
962 fputs(" System.out.println(\"r = \" + r);\n", out_);
963 fputs(" System.out.println(\"mZ = \" + t.mZ);\n", out_);
964 fputs(" System.out.println(\"mI = \" + t.mI);\n", out_);
965 fputs(" System.out.println(\"mJ = \" + t.mJ);\n", out_);
966 fputs(" System.out.println(\"mF = \" + t.mF);\n", out_);
967 fputs(" System.out.println(\"mD = \" + t.mD);\n", out_);
968 fputs(" System.out.println(\"mArray = \" + ", out_);
969 if (array_dim_ == 1) {
970 fputs("Arrays.toString(t.mArray)", out_);
971 } else {
972 fputs("Arrays.deepToString(t.mArray)", out_);
973 }
974 fputs(");\n", out_);
975 indentation_ -= 2;
976 fputs(" }\n", out_);
977 }
978
979 // Emit program header. Emit command line options in the comments.
980 void emitHeader() {
Aart Bik842a4f32016-09-21 15:45:18 -0700981 fputs("\n/**\n * AOSP JFuzz Tester.\n", out_);
982 fputs(" * Automatically generated program.\n", out_);
Aart Bikb1cd97f2016-08-09 10:49:54 -0700983 fprintf(out_,
Aart Bik842a4f32016-09-21 15:45:18 -0700984 " * jfuzz -s %u -d %u -l %u -i %u -n %u (version %s)\n */\n\n",
Aart Bikb1cd97f2016-08-09 10:49:54 -0700985 fuzz_seed_,
986 fuzz_expr_depth_,
987 fuzz_stmt_length_,
988 fuzz_if_nest_,
989 fuzz_loop_nest_,
990 VERSION);
991 fputs("import java.util.Arrays;\n\n", out_);
992 }
993
994 // Emit single test class with main driver.
995 void emitTestClassWithMain() {
996 fputs("public class Test {\n\n", out_);
997 indentation_ += 2;
998 emitFieldDecls();
999 emitArrayDecl();
1000 emitTestConstructor();
1001 emitTestMethod();
1002 emitMainMethod();
1003 indentation_ -= 2;
1004 fputs("}\n\n", out_);
1005 }
1006
1007 //
1008 // Random integers.
1009 //
1010
Aart Bikb16d4132016-08-19 15:45:11 -07001011 // Return random integer.
1012 int32_t random() {
1013 return fuzz_random_engine_();
1014 }
1015
Aart Bikb1cd97f2016-08-09 10:49:54 -07001016 // Return random integer in range [0,max).
1017 uint32_t random0(uint32_t max) {
1018 std::uniform_int_distribution<uint32_t> gen(0, max - 1);
1019 return gen(fuzz_random_engine_);
1020 }
1021
1022 // Return random integer in range [1,max].
1023 uint32_t random1(uint32_t max) {
1024 std::uniform_int_distribution<uint32_t> gen(1, max);
1025 return gen(fuzz_random_engine_);
1026 }
1027
1028 // Fuzzing parameters.
1029 FILE* out_;
1030 std::mt19937 fuzz_random_engine_;
1031 const uint32_t fuzz_seed_;
1032 const uint32_t fuzz_expr_depth_;
1033 const uint32_t fuzz_stmt_length_;
1034 const uint32_t fuzz_if_nest_;
1035 const uint32_t fuzz_loop_nest_;
1036
1037 // Return and array setup.
1038 const Type return_type_;
1039 const Type array_type_;
1040 const uint32_t array_dim_;
1041 const uint32_t array_size_;
1042
1043 // Current context.
1044 uint32_t indentation_;
1045 uint32_t expr_depth_;
1046 uint32_t stmt_length_;
1047 uint32_t if_nest_;
1048 uint32_t loop_nest_;
1049 uint32_t switch_nest_;
1050 uint32_t do_nest_;
1051 uint32_t boolean_local_;
1052 uint32_t int_local_;
1053 uint32_t long_local_;
1054 uint32_t float_local_;
1055 uint32_t double_local_;
1056};
1057
1058} // anonymous namespace
1059
1060int32_t main(int32_t argc, char** argv) {
1061 // Defaults.
1062 uint32_t seed = time(NULL);
1063 uint32_t expr_depth = 1;
Aart Bikb16d4132016-08-19 15:45:11 -07001064 uint32_t stmt_length = 8;
Aart Bikb1cd97f2016-08-09 10:49:54 -07001065 uint32_t if_nest = 2;
1066 uint32_t loop_nest = 3;
1067
1068 // Parse options.
1069 while (1) {
Wojciech Staszkiewicz18be7b32016-09-21 15:12:54 -07001070 int32_t option = getopt(argc, argv, "s:d:l:i:n:vh");
Aart Bikb1cd97f2016-08-09 10:49:54 -07001071 if (option < 0) {
1072 break; // done
1073 }
1074 switch (option) {
1075 case 's':
1076 seed = strtoul(optarg, nullptr, 0); // deterministic seed
1077 break;
1078 case 'd':
1079 expr_depth = strtoul(optarg, nullptr, 0);
1080 break;
1081 case 'l':
1082 stmt_length = strtoul(optarg, nullptr, 0);
1083 break;
1084 case 'i':
1085 if_nest = strtoul(optarg, nullptr, 0);
1086 break;
1087 case 'n':
1088 loop_nest = strtoul(optarg, nullptr, 0);
1089 break;
Wojciech Staszkiewicz18be7b32016-09-21 15:12:54 -07001090 case 'v':
1091 fprintf(stderr, "jfuzz version %s\n", VERSION);
1092 return 0;
Aart Bikb1cd97f2016-08-09 10:49:54 -07001093 case 'h':
1094 default:
1095 fprintf(stderr,
1096 "usage: %s [-s seed] "
1097 "[-d expr-depth] [-l stmt-length] "
Wojciech Staszkiewicz18be7b32016-09-21 15:12:54 -07001098 "[-i if-nest] [-n loop-nest] [-v] [-h]\n",
Aart Bikb1cd97f2016-08-09 10:49:54 -07001099 argv[0]);
1100 return 1;
1101 }
1102 }
1103
1104 // Seed global random generator.
1105 srand(seed);
1106
Aart Bik842a4f32016-09-21 15:45:18 -07001107 // Generate fuzzed program.
1108 JFuzz fuzz(stdout, seed, expr_depth, stmt_length, if_nest, loop_nest);
Aart Bikb1cd97f2016-08-09 10:49:54 -07001109 fuzz.emitProgram();
1110 return 0;
1111}