Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/art/art/tools/jfuzz/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 38 kB image not shown  

Quelle  jfuzz.cc

  Sprache: C
 

/*
 * Copyright 2016, The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#include <cmath>
#include <random>

#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <sys/time.h>

namespace {

/*
 * Operators.
 */


static constexpr const char* kIncDecOps[]   = { "++""--" };
static constexpr const char* kIntUnaryOps[] = { "+""-""~" };
static constexpr const char* kFpUnaryOps[]  = { "+""-" };

static constexpr const char* kBoolBinOps[] = { "&&""||""&""|""^" };  // few less common
static constexpr const char* kIntBinOps[]  = { "+""-""*""/""%",
                                               ">>"">>>""<<""&""|""^" };
static constexpr const char* kFpBinOps[]   = { "+""-""*""/" };

static constexpr const char* kBoolAssignOps[] = { "=""&=" , "|=""^=" };  // few less common
static constexpr const char* kIntAssignOps[]  = { "=""+=""-=""*=""/=""%=",
                                                  ">>="">>>=""<<=""&=""|=""^=" };
static constexpr const char* kFpAssignOps[]   = { "=""+=""-=""*=""/=" };

static constexpr const char* kBoolRelOps[] = { "==""!=" };
static constexpr const char* kRelOps[]     = { "==""!="">"">=""<""<=" };

/*
 * Exceptions.
 */

static const char* kExceptionTypes[] = {
  "IllegalStateException",
  "NullPointerException",
  "IllegalArgumentException",
  "ArrayIndexOutOfBoundsException"
};

/*
 * Version of JFuzz. Increase this each time changes are made to the program
 * to preserve the property that a given version of JFuzz yields the same
 * fuzzed program for a deterministic random seed.
 */

const char* VERSION = "1.5";

/*
 * 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] = { 0100032106433222 };

/*
 * Utility function to return the number of elements in an array.
 */

template <typename T, uint32_t N>
constexpr uint32_t countof(T const (&)[N]) {
  return N;
}

/**
 * A class that generates a random program that compiles correctly. The program
 * is generated using rules that generate various programming constructs. Each rule
 * 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.
 */

class JFuzz {
 public:
  JFuzz(FILE* out,
        uint32_t seed,
        uint32_t expr_depth,
        uint32_t stmt_length,
        uint32_t if_nest,
        uint32_t loop_nest,
        uint32_t try_nest)
      : out_(out),
        fuzz_random_engine_(seed),
        fuzz_seed_(seed),
        fuzz_expr_depth_(expr_depth),
        fuzz_stmt_length_(stmt_length),
        fuzz_if_nest_(if_nest),
        fuzz_loop_nest_(loop_nest),
        fuzz_try_nest_(try_nest),
        return_type_(randomType()),
        array_type_(randomType()),
        array_dim_(random1(kMaxDim)),
        array_size_(random1(kMaxDimSize[array_dim_])),
        indentation_(0),
        expr_depth_(0),
        stmt_length_(0),
        if_nest_(0),
        loop_nest_(0),
        switch_nest_(0),
        do_nest_(0),
        try_nest_(0),
        boolean_local_(0),
        int_local_(0),
        long_local_(0),
        float_local_(0),
        double_local_(0),
        in_inner_(false) { }

  ~JFuzz() { }

  void emitProgram() {
    emitHeader();
    emitTestClassWithMain();
  }

 private:
  //
  // Types.
  //

  // Current type of each expression during generation.
  enum Type {
    kBoolean,
    kInt,
    kLong,
    kFloat,
    kDouble
  };

  // Test for an integral type.
  static bool isInteger(Type tp) {
    return tp == kInt || tp == kLong;
  }

  // Test for a floating-point type.
  static bool 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)) {
      case 1:  return kBoolean;
      case 2:  return kInt;
      case 3:  return kLong;
      case 4:  return kFloat;
      defaultreturn kDouble;
    }
  }

  // Emits a random strong selected from an array of operator strings.
  template <std::uint32_t N>
  inline void emitOneOf(const charconst (&ops)[N]) {
    fputs(ops[random0(N)], out_);
  }

  //
  // Expressions.
  //

  // Emit an unary operator (same type in-out).
  void emitUnaryOp(Type tp) {
    if (tp == kBoolean) {
      fputc('!', out_);
    } else if (isInteger(tp)) {
      emitOneOf(kIntUnaryOps);
    } else {  // isFP(tp)
      emitOneOf(kFpUnaryOps);
    }
  }

  // Emit a pre/post-increment/decrement operator (same type in-out).
  void emitIncDecOp(Type tp) {
    if (tp == kBoolean) {
      // Not applicable, just leave "as is".
    } else {  // isInteger(tp) || isFP(tp)
      emitOneOf(kIncDecOps);
    }
  }

  // Emit a binary operator (same type in-out).
  void emitBinaryOp(Type tp) {
    if (tp == kBoolean) {
      emitOneOf(kBoolBinOps);
    } else if (isInteger(tp)) {
      emitOneOf(kIntBinOps);
    } else {  // isFP(tp)
      emitOneOf(kFpBinOps);
    }
  }

  // Emit an assignment operator (same type in-out).
  void emitAssignmentOp(Type tp) {
    if (tp == kBoolean) {
      emitOneOf(kBoolAssignOps);
    } else if (isInteger(tp)) {
      emitOneOf(kIntAssignOps);
    } else {  // isFP(tp)
      emitOneOf(kFpAssignOps);
    }
  }

  // Emit a relational operator (one type in, boolean out).
  void emitRelationalOp(Type tp) {
    if (tp == kBoolean) {
      emitOneOf(kBoolRelOps);
    } else {  // isInteger(tp) || isFP(tp)
      emitOneOf(kRelOps);
    }
  }

  // Emit a type conversion operator sequence (out type given, new suitable in type picked).
  Type emitTypeConversionOp(Type tp) {
    if (tp == kInt) {
      switch (random1(5)) {
        case 1: fputs("(int)", out_); return kLong;
        case 2: fputs("(int)", out_); return kFloat;
        case 3: fputs("(int)", out_); return kDouble;
        // Narrowing-widening.
        case 4: fputs("(int)(byte)(int)",  out_); return kInt;
        case 5: fputs("(int)(short)(int)", out_); return kInt;
      }
    } else if (tp == kLong) {
      switch (random1(6)) {
        case 1/* implicit */         return kInt;
        case 2: fputs("(long)", out_); return kFloat;
        case 3: fputs("(long)", out_); return kDouble;
        // Narrowing-widening.
        case 4: fputs("(long)(byte)(long)",  out_); return kLong;
        case 5: fputs("(long)(short)(long)", out_); return kLong;
        case 6: fputs("(long)(int)(long)",   out_); return kLong;
      }
    } else if (tp == kFloat) {
      switch (random1(4)) {
        case 1: fputs("(float)", out_); return kInt;
        case 2: fputs("(float)", out_); return kLong;
        case 3: fputs("(float)", out_); return kDouble;
        // Narrowing-widening.
        case 4: fputs("(float)(int)(float)", out_); return kFloat;
      }
    } else if (tp == kDouble) {
      switch (random1(5)) {
        case 1: fputs("(double)", out_); return kInt;
        case 2: fputs("(double)", out_); return kLong;
        case 3: fputs("(double)", out_); return kFloat;
        // Narrowing-widening.
        case 4: fputs("(double)(int)(double)",   out_); return kDouble;
        case 5: fputs("(double)(float)(double)", out_); return kDouble;
      }
    }
    return tp;  // nothing suitable, just keep type
  }

  // Emit a type conversion (out type given, new suitable in type picked).
  void emitTypeConversion(Type tp) {
    if (tp == kBoolean) {
      Type tp = randomType();
      emitExpression(tp);
      fputc(' ', out_);
      emitRelationalOp(tp);
      fputc(' ', out_);
      emitExpression(tp);
    } else {
      tp = emitTypeConversionOp(tp);
      fputc(' ', out_);
      emitExpression(tp);
    }
  }

  // Emit an unary intrinsic (out type given, new suitable in type picked).
  Type emitIntrinsic1(Type tp) {
    if (tp == kBoolean) {
      switch (random1(6)) {
        case 1: fputs("Float.isNaN",       out_); return kFloat;
        case 2: fputs("Float.isFinite",    out_); return kFloat;
        case 3: fputs("Float.isInfinite",  out_); return kFloat;
        case 4: fputs("Double.isNaN",      out_); return kDouble;
        case 5: fputs("Double.isFinite",   out_); return kDouble;
        case 6: fputs("Double.isInfinite", out_); return kDouble;
      }
    } else if (isInteger(tp)) {
      const char* prefix = tp == kLong ? "Long" : "Integer";
      switch (random1(13)) {
        case 1: fprintf(out_, "%s.highestOneBit",         prefix); break;
        case 2: fprintf(out_, "%s.lowestOneBit",          prefix); break;
        case 3: fprintf(out_, "%s.numberOfLeadingZeros",  prefix); break;
        case 4: fprintf(out_, "%s.numberOfTrailingZeros", prefix); break;
        case 5: fprintf(out_, "%s.bitCount",              prefix); break;
        case 6: fprintf(out_, "%s.signum",                prefix); break;
        case 7: fprintf(out_, "%s.reverse",               prefix); break;
        case 8: fprintf(out_, "%s.reverseBytes",          prefix); break;
        case 9:  fputs("Math.incrementExact", out_); break;
        case 10: fputs("Math.decrementExact", out_); break;
        case 11: fputs("Math.negateExact",    out_); break;
        case 12: fputs("Math.abs",            out_); break;
        case 13: fputs("Math.round", out_);
                 return tp == kLong ? kDouble : kFloat;
      }
    } else {  // isFP(tp)
      switch (random1(6)) {
        case 1: fputs("Math.abs",      out_); break;
        case 2: fputs("Math.ulp",      out_); break;
        case 3: fputs("Math.signum",   out_); break;
        case 4: fputs("Math.nextUp",   out_); break;
        case 5: fputs("Math.nextDown", out_); break;
        case 6if (tp == kDouble) {
                  fputs("Double.longBitsToDouble", out_);
                  return kLong;
                } else {
                  fputs("Float.intBitsToFloat", out_);
                  return kInt;
                }
      }
    }
    return tp;  // same type in-out
  }

  // Emit a binary intrinsic (out type given, new suitable in type picked).
  Type emitIntrinsic2(Type tp) {
    if (tp == kBoolean) {
      switch (random1(3)) {
        case 1: fputs("Boolean.logicalAnd", out_); break;
        case 2: fputs("Boolean.logicalOr",  out_); break;
        case 3: fputs("Boolean.logicalXor", out_); break;
      }
    } else if (isInteger(tp)) {
      const char* prefix = tp == kLong ? "Long" : "Integer";
      switch (random1(11)) {
        case 1: fprintf(out_, "%s.compare", prefix); break;
        case 2: fprintf(out_, "%s.sum",     prefix); break;
        case 3: fprintf(out_, "%s.min",     prefix); break;
        case 4: fprintf(out_, "%s.max",     prefix); break;
        case 5:  fputs("Math.min",           out_); break;
        case 6:  fputs("Math.max",           out_); break;
        case 7:  fputs("Math.floorDiv",      out_); break;
        case 8:  fputs("Math.floorMod",      out_); break;
        case 9:  fputs("Math.addExact",      out_); break;
        case 10: fputs("Math.subtractExact", out_); break;
        case 11: fputs("Math.multiplyExact", out_); break;
      }
    } else {  // isFP(tp)
      const char* prefix = tp == kDouble ? "Double" : "Float";
      switch (random1(5)) {
        case 1: fprintf(out_, "%s.sum", prefix); break;
        case 2: fprintf(out_, "%s.min", prefix); break;
        case 3: fprintf(out_, "%s.max", prefix); break;
        case 4: fputs("Math.min", out_); break;
        case 5: fputs("Math.max", out_); break;
      }
    }
    return tp;  // same type in-out
  }

  // Emit an intrinsic (out type given, new suitable in type picked).
  void emitIntrinsic(Type tp) {
    if (random1(2) == 1) {
      tp = emitIntrinsic1(tp);
      fputc('(', out_);
      emitExpression(tp);
      fputc(')', out_);
    } else {
      tp = emitIntrinsic2(tp);
      fputc('(', out_);
      emitExpression(tp);
      fputs(", ", out_);
      emitExpression(tp);
      fputc(')', out_);
    }
  }

  // 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_);
    emitType(tp);
    fputs(") new ", out_);
    emitTypeClass(tp);
    fputc('(', out_);
    emitExpression(tp);
    fputc(')', out_);
  }

  // Emit miscellaneous constructs.
  void emitMisc(Type tp) {
    if (tp == kBoolean) {
      fprintf(out_, "this instanceof %s", in_inner_ ? "X" : "Test");
    } else if (isInteger(tp)) {
      const char* prefix = tp == kLong ? "Long" : "Integer";
      switch (random1(2)) {
        case 1: fprintf(out_, "%s.MIN_VALUE", prefix); break;
        case 2: fprintf(out_, "%s.MAX_VALUE", prefix); break;
      }
    } else {  // isFP(tp)
      const char* prefix = tp == kDouble ? "Double" : "Float";
      switch (random1(6)) {
        case 1: fprintf(out_, "%s.MIN_NORMAL", prefix);        break;
        case 2: fprintf(out_, "%s.MIN_VALUE", prefix);         break;
        case 3: fprintf(out_, "%s.MAX_VALUE", prefix);         break;
        case 4: fprintf(out_, "%s.POSITIVE_INFINITY", prefix); break;
        case 5: fprintf(out_, "%s.NEGATIVE_INFINITY", prefix); break;
        case 6: fprintf(out_, "%s.NaN", prefix);               break;
      }
    }
  }

  // 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_);
    } else if (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_));
    } else if (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_);
      }
      return true;
    }
    return false;
  }

  // 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;
      }
      return true;
    }
    return false;
  }

  // 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)) {
      case 1:
        if (emitArrayVariable(tp))
          return;
        [[fallthrough]];
      case 2:
        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;
    }

    expr_depth_++;

    fputc('(', out_);
    switch (random1(12)) {  // favor binary operations
      case 1:
        // Unary operator: ~ x
        emitUnaryOp(tp);
        fputc(' ', out_);
        emitExpression(tp);
        break;
      case 2:
        // Pre-increment: ++x
        emitIncDecOp(tp);
        emitVariable(tp);
        break;
      case 3:
        // Post-increment: x++
        emitVariable(tp);
        emitIncDecOp(tp);
        break;
      case 4:
        // Ternary operator: b ? x : y
        emitExpression(kBoolean);
        fputs(" ? ", out_);
        emitExpression(tp);
        fputs(" : ", out_);
        emitExpression(tp);
        break;
      case 5:
        // Type conversion: (float) x
        emitTypeConversion(tp);
        break;
      case 6:
        // Intrinsic: foo(x)
        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 9:
        // Miscellaneous constructs: a.length
        emitMisc(tp);
        break;
      default:
        // Binary operator: x + y
        emitExpression(tp);
        fputc(' ', out_);
        emitBinaryOp(tp);
        fputc(' ', out_);
        emitExpression(tp);
        break;
    }
    fputc(')', out_);

    --expr_depth_;
  }

  //
  // Statements.
  //

  // 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_);
      return false;
    }
    // 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_);
      return false;
    }
    // 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_);
      return false;
    }
    // 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_);

    adjustLocal(tp, 1);  // local now visible

    bool mayFollow = emitStatementList();

    adjustLocal(tp, -1);  // local no longer visible

    indentation_ -= 2;
    emitIndentation();
    fputs("}\n", out_);
    return mayFollow;
  }

  // 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();
        }
      }

      fputs(",\n", out_);
      indentation_ -= 2;
      emitIndentation();
      fputs("}", out_);
    }
  }

  // Emit an array initializer of the following form.
  //   {
  //     type[]..[] tmp = { .. };
  //     mArray = tmp;
  //   }
  bool emitArrayInit() {
    // Avoid elaborate array initializers.
    uint64_t p = pow(array_size_, array_dim_);
    if (p > 20) {
      return emitAssignment();  // fall back
    }

    fputs("{\n", out_);

    indentation_ += 2;
    emitIndentation();
    emitType(array_type_);
    for (uint32_t i = 0; i < array_dim_; i++) {
      fputs("[]", out_);
    }
    fputs(" tmp = ", out_);
    emitArrayInitDim(array_dim_);
    fputs(";\n", out_);

    emitIndentation();
    fputs("mArray = tmp;\n", out_);

    indentation_ -= 2;
    emitIndentation();
    fputs("}\n", out_);
    return true;
  }

  // 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
    }

    bool goesUp = random1(2) == 1;
    fprintf(out_, "for (int i%u = ", loop_nest_);
    if (goesUp) {
      fprintf(out_, "0; i%u < ", loop_nest_);
      emitUpperBound();
      fprintf(out_, "; i%u++) {\n", loop_nest_);
    } else {
      emitUpperBound();
      fprintf(out_, " - 1; i%d >= 0", loop_nest_);
      fprintf(out_, "; i%d--) {\n", loop_nest_);
    }

    ++loop_nest_;  // now in loop

    indentation_ += 2;
    emitStatementList();

    --loop_nest_;  // no longer in loop

    indentation_ -= 2;
    emitIndentation();
    fprintf(out_, "}\n");
    return true;  // 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
    }

    bool isWhile = random1(2) == 1;
    fputs("{\n", out_);
    indentation_ += 2;
    emitIndentation();
    fprintf(out_, "int i%u = %d;\n", loop_nest_, isWhile ? -1 : 0);
    emitIndentation();
    if (isWhile) {
      fprintf(out_, "while (++i%u < ", loop_nest_);
      emitUpperBound();
      fputs(") {\n", out_);
    } else {
      fputs("do {\n", out_);
      do_nest_++;
    }

    ++loop_nest_;  // now in loop

    indentation_ += 2;
    emitStatementList();

    --loop_nest_;  // no longer in loop

    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_);
    return true;  // 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
    }

    fputs("if (", out_);
    emitExpression(kBoolean);
    fputs(") {\n", out_);

    ++if_nest_;  // now in if

    indentation_ += 2;
    bool mayFollowTrue = emitStatementList();
    indentation_ -= 2;
    emitIndentation();
    fprintf(out_, "} else {\n");
    indentation_ += 2;
    bool mayFollowFalse = emitStatementList();

    --if_nest_;  // no longer in if

    indentation_ -= 2;
    emitIndentation();
    fprintf(out_, "}\n");
    return mayFollowTrue || mayFollowFalse;
  }

  bool emitTry() {
    fputs("try {\n", out_);
    indentation_ += 2;
    bool mayFollow = emitStatementList();
    indentation_ -= 2;
    emitIndentation();
    fputc('}', out_);
    return mayFollow;
  }

  bool emitCatch() {
    uint32_t count = random1(countof(kExceptionTypes));
    bool mayFollow = false;
    for (uint32_t i = 0; i < count; ++i) {
      fprintf(out_, " catch (%s ex%u_%u) {\n", kExceptionTypes[i], try_nest_, i);
      indentation_ += 2;
      mayFollow |= emitStatementList();
      indentation_ -= 2;
      emitIndentation();
      fputc('}', out_);
    }
    return mayFollow;
  }

  bool emitFinally() {
    fputs(" finally {\n", out_);
    indentation_ += 2;
    bool mayFollow = emitStatementList();
    indentation_ -= 2;
    emitIndentation();
    fputc('}', out_);
    return mayFollow;
  }

  // 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)) {
      case 0:  // try..catch
        mayFollow |= emitCatch();
        break;
      case 1:  // try..finally
        mayFollow &= emitFinally();
        break;
      case 2:  // 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_);

    --try_nest_;  // Leaving try-catch-finally
    return mayFollow;
  }

  // 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

    indentation_ -= 2;
    emitIndentation();
    fprintf(out_, "}\n");
    return mayFollow;
  }

  bool emitNopCall() {
    fputs("nop();\n", out_);
    return true;
  }

  // Emit an assignment statement.
  bool emitAssignment() {
    Type tp = randomType();
    emitVariable(tp);
    fputc(' ', out_);
    emitAssignmentOp(tp);
    fputc(' ', out_);
    emitExpression(tp);
    fputs(";\n", out_);
    return true;
  }

  // Emit a single statement. Returns true if statements may follow.
  bool emitStatement() {
    switch (random1(16)) {  // favor assignments
      case 1:  return emitReturn(false);     break;
      case 2:  return emitContinue();        break;
      case 3:  return emitBreak();           break;
      case 4:  return emitScope();           break;
      case 5:  return emitArrayInit();       break;
      case 6:  return emitForLoop();         break;
      case 7:  return emitDoLoop();          break;
      case 8:  return emitIfStmt();          break;
      case 9:  return emitSwitch();          break;
      case 10return emitTryCatchFinally(); break;
      case 11return emitNopCall();         break;
      defaultreturn emitAssignment();      break;
    }
  }

  // Emit a statement list. Returns true if statements may follow.
  bool emitStatementList() {
    while (stmt_length_ < 1000) {  // avoid run-away
      stmt_length_++;
      emitIndentation();
      if (!emitStatement()) {
        return false;  // 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;
      }
    }
    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_);
    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 main method driver.
  void emitMainMethod() {
    fputs("  public static void main(String[] args) {\n", out_);
    indentation_ += 2;
    fputs("    Test t = new Test();\n    ", out_);
    emitType(return_type_);
    fputs(" r = ", out_);
    emitLiteral(return_type_);
    fputs(";\n", out_);
    fputs("    try {\n", out_);
    fputs("      r = t.testMethod();\n", out_);
    fputs("    } catch (Exception e) {\n", out_);
    fputs("      // Arithmetic, null pointer, index out of bounds, etc.\n", out_);
    fputs("      System.out.println(\"An exception was caught.\");\n", out_);
    fputs("    }\n", out_);
    fputs("    System.out.println(\"r  = \" + r);\n",    out_);
    fputs("    System.out.println(\"mZ = \" + t.mZ);\n", out_);
    fputs("    System.out.println(\"mI = \" + t.mI);\n", out_);
    fputs("    System.out.println(\"mJ = \" + t.mJ);\n", out_);
    fputs("    System.out.println(\"mF = \" + t.mF);\n", out_);
    fputs("    System.out.println(\"mD = \" + t.mD);\n", out_);
    fputs("    System.out.println(\"mArray = \" + ", out_);
    if (array_dim_ == 1) {
      fputs("Arrays.toString(t.mArray)", out_);
    } else {
      fputs("Arrays.deepToString(t.mArray)", out_);
    }
    fputs(");\n", out_);
    indentation_ -= 2;
    fputs("  }\n", out_);
  }

  // Emit a static void method.
  void emitStaticNopMethod() {
    fputs("  public static void nop() {}\n\n", out_);
  }

  // Emit program header. Emit command line options in the comments.
  void emitHeader() {
    fputs("\n/**\n * AOSP JFuzz Tester.\n", out_);
    fputs(" * Automatically generated program.\n", out_);
    fprintf(out_,
            " * jfuzz -s %u -d %u -l %u -i %u -n %u (version %s)\n */\n\n",
            fuzz_seed_,
            fuzz_expr_depth_,
            fuzz_stmt_length_,
            fuzz_if_nest_,
            fuzz_loop_nest_,
            VERSION);
    fputs("import java.util.Arrays;\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_);
  }

  // Fuzzing parameters.
  FILE* out_;
  std::mt19937 fuzz_random_engine_;
  const uint32_t fuzz_seed_;
  const uint32_t fuzz_expr_depth_;
  const uint32_t fuzz_stmt_length_;
  const uint32_t fuzz_if_nest_;
  const uint32_t fuzz_loop_nest_;
  const uint32_t fuzz_try_nest_;

  // Return and array setup.
  const Type return_type_;
  const Type array_type_;
  const uint32_t array_dim_;
  const uint32_t array_size_;

  // Current context.
  uint32_t indentation_;
  uint32_t expr_depth_;
  uint32_t stmt_length_;
  uint32_t if_nest_;
  uint32_t loop_nest_;
  uint32_t switch_nest_;
  uint32_t do_nest_;
  uint32_t try_nest_;
  uint32_t boolean_local_;
  uint32_t int_local_;
  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, nullptr);

  // Defaults.
  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;
  uint32_t loop_nest = 3;
  uint32_t try_nest = 2;

  // Parse options.
  while (1) {
    int32_t option = getopt(argc, argv, "s:d:l:i:n:vh");
    if (option < 0) {
      break;  // done
    }
    switch (option) {
      case 's':
        seed = strtoul(optarg, nullptr, 0);  // deterministic seed
        break;
      case 'd':
        expr_depth = strtoul(optarg, nullptr, 0);
        break;
      case 'l':
        stmt_length = strtoul(optarg, nullptr, 0);
        break;
      case 'i':
        if_nest = strtoul(optarg, nullptr, 0);
        break;
      case 'n':
        loop_nest = strtoul(optarg, nullptr, 0);
        break;
      case 't':
        try_nest = strtoul(optarg, nullptr, 0);
        break;
      case 'v':
        fprintf(stderr, "jfuzz version %s\n", VERSION);
        return 0;
      case 'h':
      default:
        fprintf(stderr,
                "usage: %s [-s seed] "
                "[-d expr-depth] [-l stmt-length] "
                "[-i if-nest] [-n loop-nest] [-t try-nest] [-v] [-h]\n",
                argv[0]);
        return 1;
    }
  }

  // Seed global random generator.
  srand(seed);

  // Generate fuzzed program.
  JFuzz fuzz(stdout, seed, expr_depth, stmt_length, if_nest, loop_nest, try_nest);
  fuzz.emitProgram();
  return 0;
}

Messung V0.5 in Prozent
C=83 H=90 G=86

¤ Dauer der Verarbeitung: 0.19 Sekunden  (vorverarbeitet am  2026-06-29) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

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.