Select Git revision
      
  machine-vuln4.c
        Forked from
        Toby Murray / swen90006-a2-2018 
 Source project has a limited visibility.
  Fuzzer.java  12.18 KiB 
import java.io.IOException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Random;
/* a stub for your team's fuzzer */
public class Fuzzer {
    // Blah - Test 1
    private static final String OUTPUT_FILE = "fuzz.txt";
    
    // The percentage of outputs that will start with a full stack
    private static final int STACK_FULL_PERCENTAGE = 10;
    // The percentage of inputs that will be incorrect
    private static final int INPUT_ERROR_PERCENTAGE = 5;
    // The percentage of instructions that will be incorrect
    private static final int LINE_ERROR_PERCENTAGE = 2;
    // Limit on generation of inputs
    private static final int NUMBER_TO_GENERATE = 10;
    // Instruction number range for each input
    private static final int INSTRUCTION_MIN = 0;
    private static final int INSTRUCTION_MAX = 500;
    // Maximum variable name length
    private static final int VAR_NAME_LENGTH_MAX = 100;
    private static final int VAR_ASCII_MIN = 33;
    private static final int VAR_ASCII_MAX = 127;
    // Variable range
    private static final int VAR_MIN = -2147483648;
    private static final int VAR_MAX = 2147483647;
    // Maximum number of items in stack
    private static final int MAX_STACK_SIZE = 512;
    // Random number generator
    private static Random rand = new Random(System.currentTimeMillis());
    private static ArrayList<String> vars = new ArrayList<>();
    public static void main(String[] args) throws IOException {
        System.out.println(Instruction.getBNF());
        FileOutputStream out = null;
        PrintWriter pw = null;
        try {
            out = new FileOutputStream(OUTPUT_FILE);
            pw = new PrintWriter(out);
            
            /* We just print one instruction.
               Hint: you might want to make use of the instruction
               grammar which is effectively encoded in Instruction.java */
            // pw.print(getStaticTests());
            pw.println(generateMultipleInputs());
            
        }catch (Exception e){
            e.printStackTrace(System.err);
            System.exit(1);
        }finally{
            if (pw != null){
                pw.flush();
            }
            if (out != null){
                out.close();
            }
        }
    }
    /***
     * Generates a list of different inputs for the program
     *
     * @return list of input strings
     */
    private static String generateMultipleInputs(){
        // Initiate variables
        StringBuilder result = new StringBuilder();
        // For debugging purposes
        int generated = 0;
        // Loop to create list of inputs
        while (generated < NUMBER_TO_GENERATE) {
            // Determine if the line will be correct or not
            result.append(generateInput(false,
                                        INSTRUCTION_MAX));
            // Increment generated
            generated += 1;
        }
        return result.toString();
    }
    /***
     * Generates a line of input for the program
     *
     * @param correct flag, which determines if the line will be correctly formulated
     * @param numInstructions for the line
     * @return the concatenated input for the program as a string
     */
    private static String generateInput(boolean correct, long numInstructions){
        int stackSize = 0;
        int counter = 0;
        StringBuilder result = new StringBuilder();
        if (rand.nextInt(100) < STACK_FULL_PERCENTAGE) {
            for ( int i = 0 ; i < MAX_STACK_SIZE ; i++ ) {
                result.append(completeInstruction(true, Instruction.PUSH));
                stackSize++;
            }
        }
        if (correct) {
            while (counter < numInstructions) {
                Instruction newInstr = Instruction.getRandomInstruction(stackSize);
                stackSize = stackSize + newInstr.getStackChange();
                result.append(completeInstruction(true, newInstr));
                counter += 1;
            }
        } else {
            while (counter < numInstructions) {
                Instruction newInstr;
                if (rand.nextInt(100) < LINE_ERROR_PERCENTAGE){
                    newInstr = Instruction.getRandomInstruction(2);
                    result.append(completeInstruction(false, newInstr));
                } else {
                    newInstr = Instruction.getRandomInstruction(stackSize);
                    result.append(completeInstruction(true, newInstr));
                }
                stackSize = stackSize + newInstr.getStackChange();
                if (stackSize < 0){
                    stackSize = 0;
                }
                counter += 1;
            }
        }
        return result.toString();
    }
    /***
     * Adds parameters to an individual instruction
     *
     * @param correct flag
     * @param instruction type
     * @return string with parameter
     */
    private static String completeInstruction(boolean correct, Instruction instruction){
        
        String name = "";
        switch (instruction) {
            case PUSH:
                if (correct) {
                    // If correct, generate as usual
                    name = " " + ((Integer) randomRange(VAR_MIN, VAR_MAX)).toString();
                } else {
                    // If incorrect, increase the range to outside +- int31_t
                    name = " " + ((Long) (randomRange(-1,1)*((long) VAR_MAX + (long) randomRange(0, VAR_MAX)))).toString();
                }
                break;
            case LOAD:
            case REM:
                // If not correct, make up a name not in the list
                if (!correct){
                    name = generateName();
                }
                // If no variables, return empty string
                else if (vars.size() == 0){
                    return "";
                }
                // Otherwise, get a variable name from the list
                else {
                    int index = rand.nextInt(vars.size());
                    name = " " + vars.get(index);
                    vars.remove(index);
                }
                break;
            case STORE:
                // Make up a name
                name = name + generateName();
                vars.add(name);
                name = " " + name;
                break;
            case SAVE:
                name = " " + generateName() + ".txt";
                break;
            case PLUS:
            case SUB:
            case MULT:
            case DIV:
            case POP:
            case LIST:
            case PRINT:
                break;
        }
        return instruction.getOpcode() + name + "\n";
    }
    /***
     * Generates a random name not longer than VAR_NAME_LENGTH_MAX
     * Characters are bounded by ASCII indexes at VAR_ASCII_MIN and VAR_ASCII_MAX
     *
     * @return the name generated
     */
    private static String generateName(){
        StringBuilder name = new StringBuilder();
        int counter = 0;
        // Randomise the length of the string
        int length = rand.nextInt(VAR_NAME_LENGTH_MAX);
        // Add random bounded characters to string
        while (counter < length){
            name.append((char) randomRange(VAR_ASCII_MIN, VAR_ASCII_MAX));
            counter += 1;
        }
        return name.toString();
    }
    private static int randomRange(int min, int max){
        // Remove negatives and get around int limitations
        if (min == VAR_MIN){
            return 2* (rand.nextInt(max) + (min/2));
        } else if (min < 0){
            max = max - min;
            return rand.nextInt(max) + min;
        }
        return min + rand.nextInt(max - min);
    }
    /***
     * Get the desired static boundary tests
     *
     * @return a string containing all of the boundary tests' instructions
     */
    private static String getStaticTests() {
        // Note. Some operations will crash dc if performed, so they cannot be tested
        // Examples include *, /, -, +, pop, store operations on empty stack
        StringBuilder result = new StringBuilder();
        // Test opreations that need variables on no variables defined
        result.append(Instruction.LIST.getOpcode() + "\n");
        result.append(Instruction.LOAD.getOpcode() + " VAR1\n");
        result.append(Instruction.REM.getOpcode() + " VAR1\n");
        // Test operations that use stack on empty stack
        result.append(Instruction.PRINT.getOpcode() + "\n");
        // Prep for next tests
        result.append(Instruction.PUSH.getOpcode() + " 5\n");
        result.append(Instruction.STORE.getOpcode() + " VAR1\n");
        result.append(Instruction.PUSH.getOpcode() + " 10\n");
        result.append(Instruction.STORE.getOpcode() + " VAR2\n");
        result.append(Instruction.SAVE.getOpcode() + "\n");
        // Test incorrect arguements for operation
        result.append(Instruction.LOAD.getOpcode() + " VAR3\n");
        // Test Variables stored and used corectly
        result.append(Instruction.LIST.getOpcode() + "\n");
        result.append(Instruction.PRINT.getOpcode() + "\n");
        result.append(Instruction.LOAD.getOpcode() + " VAR2\n");
        result.append(Instruction.LOAD.getOpcode() + " VAR1\n");
        result.append(Instruction.PRINT.getOpcode() + "\n");
        result.append(Instruction.POP.getOpcode() + "\n");
        result.append(Instruction.PRINT.getOpcode() + "\n");
        result.append(Instruction.REM.getOpcode() + " VAR2\n");
        result.append(Instruction.LIST.getOpcode() + "\n");
        result.append(Instruction.LOAD.getOpcode() + " VAR2\n");
        result.append(Instruction.PRINT.getOpcode() + "\n");
        result.append(Instruction.STORE.getOpcode() + " VAR1\n");
        result.append(Instruction.LIST.getOpcode() + "\n");
        result.append(Instruction.LOAD.getOpcode() + " VAR1\n");
        result.append(Instruction.STORE.getOpcode() + " VAR1\n");
        result.append(Instruction.LIST.getOpcode() + "\n");
        result.append(Instruction.REM.getOpcode() + " VAR1\n");
        // Test Plus operation
        result.append(Instruction.PUSH.getOpcode() + " "+ VAR_MAX + "\n");        result.append(Instruction.PUSH.getOpcode() + " "+ VAR_MIN + "\n");
        result.append(Instruction.PLUS.getOpcode() + "\n");
        result.append(Instruction.POP.getOpcode() + "\n");
        result.append(Instruction.PUSH.getOpcode() + " "+ VAR_MAX + "\n");
        result.append(Instruction.PUSH.getOpcode() + " 1\n");
        result.append(Instruction.PLUS.getOpcode() + "\n");
        result.append(Instruction.POP.getOpcode() + "\n");
        // Test Subtract operation
        result.append(Instruction.PUSH.getOpcode() + " "+ VAR_MAX + "\n");
        result.append(Instruction.PUSH.getOpcode() + " "+ VAR_MAX + "\n");
        result.append(Instruction.SUB.getOpcode() + "\n");
        result.append(Instruction.POP.getOpcode() + "\n");
        result.append(Instruction.PUSH.getOpcode() + " 1\n");
        result.append(Instruction.PUSH.getOpcode() + " "+ VAR_MIN + "\n");
        result.append(Instruction.SUB.getOpcode() + "\n");
        result.append(Instruction.POP.getOpcode() + "\n");
        // Test Divide operation
        result.append(Instruction.PUSH.getOpcode() + " "+ VAR_MAX + "\n");
        result.append(Instruction.PUSH.getOpcode() + " "+ VAR_MAX + "\n");
        result.append(Instruction.DIV.getOpcode() + "\n");
        result.append(Instruction.POP.getOpcode() + "\n");
        result.append(Instruction.PUSH.getOpcode() + " 1\n");
        result.append(Instruction.PUSH.getOpcode() + " "+ VAR_MIN + "\n");
        result.append(Instruction.DIV.getOpcode() + "\n");
        result.append(Instruction.POP.getOpcode() + "\n");
        // Test Multiply operation
        result.append(Instruction.PUSH.getOpcode() + " "+ VAR_MAX + "\n");
        result.append(Instruction.PUSH.getOpcode() + " 2\n");
        result.append(Instruction.MULT.getOpcode() + "\n");
        result.append(Instruction.POP.getOpcode() + "\n");
        result.append(Instruction.PUSH.getOpcode() + " 2\n");
        result.append(Instruction.PUSH.getOpcode() + " "+ Math.floorDiv(VAR_MIN, 2) + "\n");
        result.append(Instruction.MULT.getOpcode() + "\n");
        result.append(Instruction.POP.getOpcode() + "\n");
        return result.toString();
    }
}