// Current type of each expression during generation. enum Type {
kBoolean,
kInt,
kLong,
kFloat,
kDouble
};
// Test for an integral type. staticbool isInteger(Type tp) { return tp == kInt || tp == kLong;
}
// Test for a floating-point type. staticbool isFP(Type tp) { return tp == kFloat || tp == kDouble;
}
// Emit type. void emitType(Type tp) const { switch (tp) { case kBoolean: fputs("boolean", out_); break; case kInt: fputs("int", out_); break; case kLong: fputs("long", out_); break; case kFloat: fputs("float", out_); break; case kDouble: fputs("double", out_); break;
}
}
// Emit type class. void emitTypeClass(Type tp) const { switch (tp) { case kBoolean: fputs("Boolean", out_); break; case kInt: fputs("Integer", out_); break; case kLong: fputs("Long", out_); break; case kFloat: fputs("Float", out_); break; case kDouble: fputs("Double", out_); break;
}
}
// Return a random type.
Type randomType() { switch (random1(5)) { case1: return kBoolean; case2: return kInt; case3: return kLong; case4: return kFloat; default: return kDouble;
}
}
// Emits a random strong selected from an array of operator strings. template <std::uint32_t N> inlinevoid emitOneOf(constchar* const (&ops)[N]) {
fputs(ops[random0(N)], out_);
}
// Adjust local of given type and return adjusted value.
uint32_t adjustLocal(Type tp, int32_t a) { switch (tp) { case kBoolean: boolean_local_ += a; return boolean_local_; case kInt: int_local_ += a; return int_local_; case kLong: long_local_ += a; return long_local_; case kFloat: float_local_ += a; return float_local_; default: double_local_ += a; return double_local_;
}
}
// Emit an expression that is a strict upper bound for an array index. void emitUpperBound() { if (random1(8) == 1) {
fputs("mArray.length", out_);
} elseif (random1(8) == 1) {
fprintf(out_, "%u", random1(array_size_)); // random in range
} else {
fprintf(out_, "%u", array_size_);
}
}
// Emit an array index, usually within proper range. void emitArrayIndex() { if (loop_nest_ > 0 && random1(2) == 1) {
fprintf(out_, "i%u", random0(loop_nest_));
} elseif (random1(8) == 1) {
fputs("mArray.length - 1", out_);
} else {
fprintf(out_, "%u", random0(array_size_)); // random in range
} // Introduce potential off by one errors with low probability. if (random1(100) == 1) { if (random1(2) == 1) {
fputs(" - 1", out_);
} else {
fputs(" + 1", out_);
}
}
}
// Emit a literal. void emitLiteral(Type tp) { switch (tp) { case kBoolean: fputs(random1(2) == 1 ? "true" : "false", out_); break; case kInt: fprintf(out_, "%d", random()); break; case kLong: fprintf(out_, "%dL", random()); break; case kFloat: fprintf(out_, "%d.0f", random()); break; case kDouble: fprintf(out_, "%d.0", random()); break;
}
}
// Emit array variable, if available. bool emitArrayVariable(Type tp) { if (tp == array_type_) {
fputs("mArray", out_); for (uint32_t i = 0; i < array_dim_; i++) {
fputc('[', out_);
emitArrayIndex();
fputc(']', out_);
} returntrue;
} returnfalse;
}
// Emit a local variable, if available. bool emitLocalVariable(Type tp) {
uint32_t locals = adjustLocal(tp, 0); if (locals > 0) {
uint32_t local = random0(locals); switch (tp) { case kBoolean: fprintf(out_, "lZ%u", local); break; case kInt: fprintf(out_, "lI%u", local); break; case kLong: fprintf(out_, "lJ%u", local); break; case kFloat: fprintf(out_, "lF%u", local); break; case kDouble: fprintf(out_, "lD%u", local); break;
} returntrue;
} returnfalse;
}
// Emit a field variable. void emitFieldVariable(Type tp) { switch (tp) { case kBoolean:fputs("mZ", out_); break; case kInt: fputs("mI", out_); break; case kLong: fputs("mJ", out_); break; case kFloat: fputs("mF", out_); break; case kDouble: fputs("mD", out_); break;
}
}
// Emit a variable. void emitVariable(Type tp) { switch (random1(4)) { case1: if (emitArrayVariable(tp)) return;
[[fallthrough]]; case2: if (emitLocalVariable(tp)) return;
[[fallthrough]]; default:
emitFieldVariable(tp); break;
}
}
// Emit an expression. void emitExpression(Type tp) { // Continuing expression becomes less likely as the depth grows. if (random1(expr_depth_ + 1) > fuzz_expr_depth_) { if (random1(2) == 1) {
emitLiteral(tp);
} else {
emitVariable(tp);
} return;
}
// Emit current indentation. void emitIndentation() const { for (uint32_t i = 0; i < indentation_; i++) {
fputc(' ', out_);
}
}
// Emit a return statement. bool emitReturn(bool mustEmit) { // Only emit when we must, or with low probability inside ifs/loops, // but outside do-while to avoid confusing the may follow status. if (mustEmit || ((if_nest_ + loop_nest_) > 0 && do_nest_ == 0 && random1(10) == 1)) {
fputs("return ", out_);
emitExpression(return_type_);
fputs(";\n", out_); returnfalse;
} // Fall back to assignment. return emitAssignment();
}
// Emit a continue statement. bool emitContinue() { // Only emit with low probability inside loops. if (loop_nest_ > 0 && random1(10) == 1) {
fputs("continue;\n", out_); returnfalse;
} // Fall back to assignment. return emitAssignment();
}
// Emit a break statement. bool emitBreak() { // Only emit with low probability inside loops, but outside switches // to avoid confusing the may follow status. if (loop_nest_ > 0 && switch_nest_ == 0 && random1(10) == 1) {
fputs("break;\n", out_); returnfalse;
} // Fall back to assignment. return emitAssignment();
}
// Emit a new scope with a local variable declaration statement. bool emitScope() {
Type tp = randomType();
fputs("{\n", out_);
indentation_ += 2;
emitIndentation();
emitType(tp); switch (tp) { case kBoolean: fprintf(out_, " lZ%u = ", boolean_local_); break; case kInt: fprintf(out_, " lI%u = ", int_local_); break; case kLong: fprintf(out_, " lJ%u = ", long_local_); break; case kFloat: fprintf(out_, " lF%u = ", float_local_); break; case kDouble: fprintf(out_, " lD%u = ", double_local_); break;
}
emitExpression(tp);
fputs(";\n", out_);
// Emit one dimension of an array initializer, where parameter dim >= 1 // denotes the number of remaining dimensions that should be emitted. void emitArrayInitDim(int dim) { if (dim == 1) { // Last dimension: set of values.
fputs("{ ", out_); for (uint32_t i = 0; i < array_size_; i++) {
emitExpression(array_type_);
fputs(", ", out_);
}
fputs("}", out_);
} else { // Outer dimensions: set of sets.
fputs("{\n", out_);
indentation_ += 2;
emitIndentation();
for (uint32_t i = 0; i < array_size_; i++) {
emitArrayInitDim(dim - 1); if (i != array_size_ - 1) {
fputs(",\n", out_);
emitIndentation();
}
}
// Emit a for loop. bool emitForLoop() { // Continuing loop nest becomes less likely as the depth grows. if (random1(loop_nest_ + 1) > fuzz_loop_nest_) { return emitAssignment(); // fall back
}
indentation_ -= 2;
emitIndentation();
fprintf(out_, "}\n"); returntrue; // loop-body does not block flow
}
// Emit while or do-while loop. bool emitDoLoop() { // Continuing loop nest becomes less likely as the depth grows. if (random1(loop_nest_ + 1) > fuzz_loop_nest_) { return emitAssignment(); // fall back
}
indentation_ -= 2;
emitIndentation(); if (isWhile) {
fputs("}\n", out_);
} else {
fprintf(out_, "} while (++i%u < ", loop_nest_);
emitUpperBound();
fputs(");\n", out_);
--do_nest_;
}
indentation_ -= 2;
emitIndentation();
fputs("}\n", out_); returntrue; // loop-body does not block flow
}
// Emit an if statement. bool emitIfStmt() { // Continuing if nest becomes less likely as the depth grows. if (random1(if_nest_ + 1) > fuzz_if_nest_) { return emitAssignment(); // fall back
}
// Emit a try-catch-finally block. bool emitTryCatchFinally() { // Apply a hard limit on the number of catch blocks. This is for // javac which fails if blocks within try-catch-finally are too // large (much less than you'd expect). if (try_nest_ > fuzz_try_nest_) { return emitAssignment(); // fall back
}
++try_nest_; // Entering try-catch-finally
bool mayFollow = emitTry(); switch (random0(3)) { case0: // try..catch
mayFollow |= emitCatch(); break; case1: // try..finally
mayFollow &= emitFinally(); break; case2: // try..catch..finally // When determining whether code may follow, we observe that a // finally block always follows after try and catch // block. Code may only follow if the finally block permits // and either the try or catch block allows code to follow.
mayFollow = (mayFollow | emitCatch());
mayFollow &= emitFinally(); break;
}
fputc('\n', out_);
// Emit a switch statement. bool emitSwitch() { // Continuing if nest becomes less likely as the depth grows. if (random1(if_nest_ + 1) > fuzz_if_nest_) { return emitAssignment(); // fall back
}
bool mayFollow = false;
fputs("switch (", out_);
emitArrayIndex(); // restrict its range
fputs(") {\n", out_);
++if_nest_;
++switch_nest_; // now in switch
indentation_ += 2; for (uint32_t i = 0; i < 2; i++) {
emitIndentation(); if (i == 0) {
fprintf(out_, "case %u: {\n", random0(array_size_));
} else {
fprintf(out_, "default: {\n");
}
indentation_ += 2; if (emitStatementList()) { // Must end with break.
emitIndentation();
fputs("break;\n", out_);
mayFollow = true;
}
indentation_ -= 2;
emitIndentation();
fputs("}\n", out_);
}
--if_nest_;
--switch_nest_; // no longer in switch
// Emit a statement list. Returns true if statements may follow. bool emitStatementList() { while (stmt_length_ < 1000) { // avoid run-away
stmt_length_++;
emitIndentation(); if (!emitStatement()) { returnfalse; // rest would be dead code
} // Continuing this list becomes less likely as the total statement list grows. if (random1(stmt_length_) > fuzz_stmt_length_) { break;
}
} returntrue;
}
// 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_);
fputs(" private float mF = 0;\n", out_);
fputs(" private double mD = 0;\n\n", out_);
}
// Emit array declaration. void emitArrayDecl() {
fputs(" private ", out_);
emitType(array_type_); for (uint32_t i = 0; i < array_dim_; i++) {
fputs("[]", out_);
}
fputs(" mArray = new ", out_);
emitType(array_type_); for (uint32_t i = 0; i < array_dim_; i++) {
fprintf(out_, "[%d]", array_size_);
}
fputs(";\n\n", out_);
}
// Emit test constructor. void emitTestConstructor() {
fputs(" private Test() {\n", out_);
indentation_ += 2;
emitIndentation();
emitType(array_type_);
fputs(" a = ", out_);
emitLiteral(array_type_);
fputs(";\n", out_); for (uint32_t i = 0; i < array_dim_; i++) {
emitIndentation();
fprintf(out_, "for (int i%u = 0; i%u < %u; i%u++) {\n", i, i, array_size_, i);
indentation_ += 2;
}
emitIndentation();
fputs("mArray", out_); for (uint32_t i = 0; i < array_dim_; i++) {
fprintf(out_, "[i%u]", i);
}
fputs(" = a;\n", out_);
emitIndentation(); if (array_type_ == kBoolean) {
fputs("a = !a;\n", out_);
} else {
fputs("a++;\n", out_);
} for (uint32_t i = 0; i < array_dim_; i++) {
indentation_ -= 2;
emitIndentation();
fputs("}\n", out_);
}
indentation_ -= 2;
fputs(" }\n\n", out_);
}
// Emit test method. void emitTestMethod() {
fputs(" private ", out_);
emitType(return_type_);
fputs(" testMethod() {\n", out_);
indentation_ += 2; if (emitStatementList()) { // Must end with return.
emitIndentation();
emitReturn(true);
}
indentation_ -= 2;
fputs(" }\n\n", out_);
}
// Emit single test class with main driver. void emitTestClassWithMain() {
fputs("public class Test {\n\n", out_);
indentation_ += 2;
emitClassDecls();
emitFieldDecls();
emitArrayDecl();
emitTestConstructor();
emitTestMethod();
emitStaticNopMethod();
emitMainMethod();
indentation_ -= 2;
fputs("}\n\n", out_);
}
// // Random integers. //
// Return random integer.
int32_t random() { return fuzz_random_engine_();
}
// Return random integer in range [0,max).
uint32_t random0(uint32_t max) {
std::uniform_int_distribution<uint32_t> gen(0, max - 1); return gen(fuzz_random_engine_);
}
// Return random integer in range [1,max].
uint32_t random1(uint32_t max) {
std::uniform_int_distribution<uint32_t> gen(1, max); return gen(fuzz_random_engine_);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.