1 /* 2 * Copyright (C) 2014 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 package dexfuzz.program.mutators; 18 19 import dexfuzz.Log; 20 import dexfuzz.MutationStats; 21 import dexfuzz.program.MInsn; 22 import dexfuzz.program.MInsnWithData; 23 import dexfuzz.program.MutatableCode; 24 import dexfuzz.program.Mutation; 25 26 import java.util.List; 27 import java.util.Random; 28 29 public class InstructionDeleter extends CodeMutator { 30 /** 31 * Every CodeMutator has an AssociatedMutation, representing the 32 * mutation that this CodeMutator can perform, to allow separate 33 * generateMutation() and applyMutation() phases, allowing serialization. 34 */ 35 public static class AssociatedMutation extends Mutation { 36 public int insnToDeleteIdx; 37 38 @Override 39 public String getString() { 40 return Integer.toString(insnToDeleteIdx); 41 } 42 43 @Override 44 public void parseString(String[] elements) { 45 insnToDeleteIdx = Integer.parseInt(elements[2]); 46 } 47 } 48 49 // The following two methods are here for the benefit of MutationSerializer, 50 // so it can create a CodeMutator and get the correct associated Mutation, as it 51 // reads in mutations from a dump of mutations. 52 @Override 53 public Mutation getNewMutation() { 54 return new AssociatedMutation(); 55 } 56 57 public InstructionDeleter() { } 58 59 public InstructionDeleter(Random rng, MutationStats stats, List<Mutation> mutations) { 60 super(rng, stats, mutations); 61 likelihood = 40; 62 } 63 64 @Override 65 protected boolean canMutate(MutatableCode mutatableCode) { 66 if (mutatableCode.getInstructionCount() < 4) { 67 // TODO: Make this more sophisticated - right now this is to avoid problems with 68 // a method that has 3 instructions: fill-array-data; return-void; <data for fill-array-data> 69 Log.debug("Cannot delete insns in a method with only a few."); 70 return false; 71 } 72 return true; 73 } 74 75 @Override 76 protected Mutation generateMutation(MutatableCode mutatableCode) { 77 // Pick an instruction at random... 78 int insnIdx = rng.nextInt(mutatableCode.getInstructionCount()); 79 80 AssociatedMutation mutation = new AssociatedMutation(); 81 mutation.setup(this.getClass(), mutatableCode); 82 mutation.insnToDeleteIdx = insnIdx; 83 return mutation; 84 } 85 86 @Override 87 protected void applyMutation(Mutation uncastMutation) { 88 // Cast the Mutation to our AssociatedMutation, so we can access its fields. 89 AssociatedMutation mutation = (AssociatedMutation) uncastMutation; 90 MutatableCode mutatableCode = mutation.mutatableCode; 91 92 MInsn toBeDeleted = 93 mutatableCode.getInstructionAt(mutation.insnToDeleteIdx); 94 95 Log.info("Deleting " + toBeDeleted); 96 97 stats.incrementStat("Deleted instruction"); 98 99 // Delete the instruction. 100 mutatableCode.deleteInstruction(mutation.insnToDeleteIdx); 101 102 // If we delete a with-data insn, we should delete the associated data insn as well. 103 if (toBeDeleted instanceof MInsnWithData) { 104 Log.info(toBeDeleted + " had associated data, so the data insn was deleted."); 105 // Get the data instruction. 106 MInsn dataInsn = 107 ((MInsnWithData)toBeDeleted).dataTarget; 108 mutatableCode.deleteInstruction(dataInsn); 109 stats.incrementStat("Deleted a with-data insn's data"); 110 } 111 // If we delete a data insn, we should delete the associated with-data insn as well. 112 if (toBeDeleted.insn.justRaw) { 113 // .justRaw implies that this is a data insn. 114 Log.info(toBeDeleted 115 + " was data, so the associated with-data insn was deleted."); 116 117 // First, find the with-data insn that is pointing to this insn. 118 MInsn withDataInsn = null; 119 for (MInsn mInsn : mutatableCode.getInstructions()) { 120 if (mInsn instanceof MInsnWithData) { 121 if (((MInsnWithData)mInsn).dataTarget == toBeDeleted) { 122 withDataInsn = mInsn; 123 break; 124 } 125 } 126 } 127 128 // Now delete the with-data insn. 129 if (withDataInsn != null) { 130 mutatableCode.deleteInstruction(withDataInsn); 131 stats.incrementStat("Deleted a data insn's with-data insn"); 132 } else { 133 Log.errorAndQuit("Tried to delete a data insn, " 134 + "but it didn't have any with-data insn pointing at it?"); 135 } 136 } 137 } 138 } 139