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