Minor jfuzz improvements.
Rationale:
Added simple class hierarchy to jfuzz output (still rather
rudimentary, but at least covers all method invocation kinds).
Also cleaned up the array dimensions logic.
Finally, increased granularity of time-based seeding.
Test: ./tools/jfuzz/run_jfuzz_test.py
Change-Id: I6582a75e5be593ba56146e1cd56f801e85f051c5
diff --git a/tools/jfuzz/README.md b/tools/jfuzz/README.md
index 1d566a9..48ce295 100644
--- a/tools/jfuzz/README.md
+++ b/tools/jfuzz/README.md
@@ -11,7 +11,7 @@
JFuzz can be combined with DexFuzz to get multi-layered fuzz testing.
How to run JFuzz
-===================
+================
jfuzz [-s seed] [-d expr-depth] [-l stmt-length]
[-i if-nest] [-n loop-nest]
@@ -37,7 +37,7 @@
art -classpath classes.dex Test
How to start JFuzz testing
-=============================
+==========================
run_jfuzz_test.py
[--num_tests=NUM_TESTS]
diff --git a/tools/jfuzz/jfuzz.cc b/tools/jfuzz/jfuzz.cc
index 125b56a..fabfc69 100644
--- a/tools/jfuzz/jfuzz.cc
+++ b/tools/jfuzz/jfuzz.cc
@@ -21,7 +21,8 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
-#include <time.h>
+
+#include <sys/time.h>
namespace {
@@ -53,9 +54,14 @@
* to preserve the property that a given version of JFuzz yields the same
* fuzzed program for a deterministic random seed.
*/
-const char* VERSION = "1.1";
+const char* VERSION = "1.2";
-static const uint32_t MAX_DIMS[11] = { 0, 1000, 32, 10, 6, 4, 3, 3, 2, 2, 2 };
+/*
+ * Maximum number of array dimensions, together with corresponding maximum size
+ * within each dimension (to keep memory/runtime requirements roughly the same).
+ */
+static const uint32_t kMaxDim = 10;
+static const uint32_t kMaxDimSize[kMaxDim + 1] = { 0, 1000, 32, 10, 6, 4, 3, 3, 2, 2, 2 };
/**
* A class that generates a random program that compiles correctly. The program
@@ -63,10 +69,6 @@
* has a fixed probability to "fire". Running a generated program yields deterministic
* output, making it suited to test various modes of execution (e.g an interpreter vs.
* an compiler or two different run times) for divergences.
- *
- * TODO: Due to the original scope of this project, the generated program is heavy
- * on loops, arrays, and basic operations; fuzzing other aspects, like elaborate
- * typing, class hierarchies, and interfaces is still TBD.
*/
class JFuzz {
public:
@@ -85,8 +87,8 @@
fuzz_loop_nest_(loop_nest),
return_type_(randomType()),
array_type_(randomType()),
- array_dim_(random1(10)),
- array_size_(random1(MAX_DIMS[array_dim_])),
+ array_dim_(random1(kMaxDim)),
+ array_size_(random1(kMaxDimSize[array_dim_])),
indentation_(0),
expr_depth_(0),
stmt_length_(0),
@@ -98,7 +100,8 @@
int_local_(0),
long_local_(0),
float_local_(0),
- double_local_(0) { }
+ double_local_(0),
+ in_inner_(false) { }
~JFuzz() { }
@@ -378,6 +381,27 @@
}
}
+ // Emit a method call (out type given).
+ void emitMethodCall(Type tp) {
+ if (tp != kBoolean && !in_inner_) {
+ // Accept all numerical types (implicit conversion) and when not
+ // declaring inner classes (to avoid infinite recursion).
+ switch (random1(8)) {
+ case 1: fputs("mA.a()", out_); break;
+ case 2: fputs("mB.a()", out_); break;
+ case 3: fputs("mB.x()", out_); break;
+ case 4: fputs("mBX.x()", out_); break;
+ case 5: fputs("mC.s()", out_); break;
+ case 6: fputs("mC.c()", out_); break;
+ case 7: fputs("mC.x()", out_); break;
+ case 8: fputs("mCX.x()", out_); break;
+ }
+ } else {
+ // Fall back to intrinsic.
+ emitIntrinsic(tp);
+ }
+ }
+
// Emit unboxing boxed object.
void emitUnbox(Type tp) {
fputc('(', out_);
@@ -392,7 +416,7 @@
// Emit miscellaneous constructs.
void emitMisc(Type tp) {
if (tp == kBoolean) {
- fputs("this instanceof Test", out_);
+ fprintf(out_, "this instanceof %s", in_inner_ ? "X" : "Test");
} else if (isInteger(tp)) {
const char* prefix = tp == kLong ? "Long" : "Integer";
switch (random1(2)) {
@@ -572,10 +596,14 @@
emitIntrinsic(tp);
break;
case 7:
+ // Method call: mA.a()
+ emitMethodCall(tp);
+ break;
+ case 8:
// Emit unboxing boxed value: (int) Integer(x)
emitUnbox(tp);
break;
- case 8:
+ case 9:
// Miscellaneous constructs: a.length
emitMisc(tp);
break;
@@ -870,8 +898,52 @@
return true;
}
+ // Emit interface and class declarations.
+ void emitClassDecls() {
+ in_inner_ = true;
+ fputs(" private interface X {\n", out_);
+ fputs(" int x();\n", out_);
+ fputs(" }\n\n", out_);
+ fputs(" private class A {\n", out_);
+ fputs(" public int a() {\n", out_);
+ fputs(" return ", out_);
+ emitExpression(kInt);
+ fputs(";\n }\n", out_);
+ fputs(" }\n\n", out_);
+ fputs(" private class B extends A implements X {\n", out_);
+ fputs(" public int a() {\n", out_);
+ fputs(" return super.a() + ", out_);
+ emitExpression(kInt);
+ fputs(";\n }\n", out_);
+ fputs(" public int x() {\n", out_);
+ fputs(" return ", out_);
+ emitExpression(kInt);
+ fputs(";\n }\n", out_);
+ fputs(" }\n\n", out_);
+ fputs(" private static class C implements X {\n", out_);
+ fputs(" public static int s() {\n", out_);
+ fputs(" return ", out_);
+ emitLiteral(kInt);
+ fputs(";\n }\n", out_);
+ fputs(" public int c() {\n", out_);
+ fputs(" return ", out_);
+ emitLiteral(kInt);
+ fputs(";\n }\n", out_);
+ fputs(" public int x() {\n", out_);
+ fputs(" return ", out_);
+ emitLiteral(kInt);
+ fputs(";\n }\n", out_);
+ fputs(" }\n\n", out_);
+ in_inner_ = false;
+ }
+
// Emit field declarations.
void emitFieldDecls() {
+ fputs(" private A mA = new B();\n", out_);
+ fputs(" private B mB = new B();\n", out_);
+ fputs(" private X mBX = new B();\n", out_);
+ fputs(" private C mC = new C();\n", out_);
+ fputs(" private X mCX = new C();\n\n", out_);
fputs(" private boolean mZ = false;\n", out_);
fputs(" private int mI = 0;\n", out_);
fputs(" private long mJ = 0;\n", out_);
@@ -995,6 +1067,7 @@
void emitTestClassWithMain() {
fputs("public class Test {\n\n", out_);
indentation_ += 2;
+ emitClassDecls();
emitFieldDecls();
emitArrayDecl();
emitTestConstructor();
@@ -1053,13 +1126,18 @@
uint32_t long_local_;
uint32_t float_local_;
uint32_t double_local_;
+ bool in_inner_;
};
} // anonymous namespace
int32_t main(int32_t argc, char** argv) {
+ // Time-based seed.
+ struct timeval tp;
+ gettimeofday(&tp, NULL);
+
// Defaults.
- uint32_t seed = time(NULL);
+ uint32_t seed = (tp.tv_sec * 1000000 + tp.tv_usec);
uint32_t expr_depth = 1;
uint32_t stmt_length = 8;
uint32_t if_nest = 2;