Home | History | Annotate | Download | only in mutators
      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.MutatableCode;
     23 import dexfuzz.program.Mutation;
     24 import dexfuzz.rawdex.Instruction;
     25 import dexfuzz.rawdex.Opcode;
     26 import dexfuzz.rawdex.OpcodeInfo;
     27 
     28 import java.util.ArrayList;
     29 import java.util.List;
     30 import java.util.Random;
     31 
     32 public class ArithOpChanger extends CodeMutator {
     33   /**
     34    * Every CodeMutator has an AssociatedMutation, representing the
     35    * mutation that this CodeMutator can perform, to allow separate
     36    * generateMutation() and applyMutation() phases, allowing serialization.
     37    */
     38   public static class AssociatedMutation extends Mutation {
     39     public int arithmeticInsnIdx;
     40     public int newOpcode;
     41 
     42     @Override
     43     public String getString() {
     44       StringBuilder builder = new StringBuilder();
     45       builder.append(arithmeticInsnIdx).append(" ");
     46       builder.append(newOpcode);
     47       return builder.toString();
     48     }
     49 
     50     @Override
     51     public void parseString(String[] elements) {
     52       arithmeticInsnIdx = Integer.parseInt(elements[2]);
     53       newOpcode = Integer.parseInt(elements[3]);
     54     }
     55   }
     56 
     57   // The following two methods are here for the benefit of MutationSerializer,
     58   // so it can create a CodeMutator and get the correct associated Mutation, as it
     59   // reads in mutations from a dump of mutations.
     60   @Override
     61   public Mutation getNewMutation() {
     62     return new AssociatedMutation();
     63   }
     64 
     65   public ArithOpChanger() { }
     66 
     67   public ArithOpChanger(Random rng, MutationStats stats, List<Mutation> mutations) {
     68     super(rng, stats, mutations);
     69     likelihood = 75;
     70   }
     71 
     72   // A cache that should only exist between generateMutation() and applyMutation(),
     73   // or be created at the start of applyMutation(), if we're reading in mutations from
     74   // a file.
     75   private List<MInsn> arithmeticInsns = null;
     76 
     77   private void generateCachedArithmeticInsns(MutatableCode mutatableCode) {
     78     if (arithmeticInsns != null) {
     79       return;
     80     }
     81 
     82     arithmeticInsns = new ArrayList<MInsn>();
     83 
     84     for (MInsn mInsn : mutatableCode.getInstructions()) {
     85       if (isArithmeticOperation(mInsn)) {
     86         arithmeticInsns.add(mInsn);
     87       }
     88     }
     89   }
     90 
     91   @Override
     92   protected boolean canMutate(MutatableCode mutatableCode) {
     93     for (MInsn mInsn : mutatableCode.getInstructions()) {
     94       if (isArithmeticOperation(mInsn)) {
     95         return true;
     96       }
     97     }
     98 
     99     Log.debug("No arithmetic operations in method, skipping...");
    100     return false;
    101   }
    102 
    103   @Override
    104   protected Mutation generateMutation(MutatableCode mutatableCode) {
    105     generateCachedArithmeticInsns(mutatableCode);
    106 
    107     int arithmeticInsnIdx = rng.nextInt(arithmeticInsns.size());
    108 
    109     MInsn randomInsn = arithmeticInsns.get(arithmeticInsnIdx);
    110 
    111     OpcodeInfo oldOpcodeInfo = randomInsn.insn.info;
    112 
    113     OpcodeInfo newOpcodeInfo = oldOpcodeInfo;
    114 
    115     while (newOpcodeInfo.value == oldOpcodeInfo.value) {
    116       newOpcodeInfo = Instruction.getOpcodeInfo(getLegalDifferentOpcode(randomInsn));
    117     }
    118 
    119     AssociatedMutation mutation = new AssociatedMutation();
    120     mutation.setup(this.getClass(), mutatableCode);
    121     mutation.arithmeticInsnIdx = arithmeticInsnIdx;
    122     mutation.newOpcode = newOpcodeInfo.value;
    123     return mutation;
    124   }
    125 
    126   @Override
    127   protected void applyMutation(Mutation uncastMutation) {
    128     // Cast the Mutation to our AssociatedMutation, so we can access its fields.
    129     AssociatedMutation mutation = (AssociatedMutation) uncastMutation;
    130     MutatableCode mutatableCode = mutation.mutatableCode;
    131 
    132     generateCachedArithmeticInsns(mutatableCode);
    133 
    134     MInsn randomInsn = arithmeticInsns.get(mutation.arithmeticInsnIdx);
    135 
    136     String oldInsnString = randomInsn.toString();
    137 
    138     OpcodeInfo newOpcodeInfo = Instruction.getOpcodeInfo(mutation.newOpcode);
    139 
    140     randomInsn.insn.info = newOpcodeInfo;
    141 
    142     Log.info("Changed " + oldInsnString + " to " + randomInsn);
    143 
    144     stats.incrementStat("Changed arithmetic opcode");
    145 
    146     // Clear the cache.
    147     arithmeticInsns = null;
    148   }
    149 
    150   private boolean isArithmeticOperation(MInsn mInsn) {
    151     Opcode opcode = mInsn.insn.info.opcode;
    152     if (Opcode.isBetween(opcode, Opcode.ADD_INT, Opcode.USHR_INT_LIT8)) {
    153       return true;
    154     }
    155     return false;
    156   }
    157 
    158   private Opcode getLegalDifferentOpcode(MInsn mInsn) {
    159     Opcode opcode = mInsn.insn.info.opcode;
    160 
    161     for (List<Opcode> opcodeList : opcodeLists) {
    162       Opcode first = opcodeList.get(0);
    163       Opcode last = opcodeList.get(opcodeList.size() - 1);
    164       if (Opcode.isBetween(opcode, first, last)) {
    165         int newOpcodeIdx = rng.nextInt(opcodeList.size());
    166         return opcodeList.get(newOpcodeIdx);
    167       }
    168     }
    169 
    170     return opcode;
    171   }
    172 
    173   private static List<Opcode> intOpcodes = new ArrayList<Opcode>();
    174   private static List<Opcode> int2addrOpcodes = new ArrayList<Opcode>();
    175   private static List<Opcode> longOpcodes = new ArrayList<Opcode>();
    176   private static List<Opcode> long2addrOpcodes = new ArrayList<Opcode>();
    177   private static List<Opcode> floatOpcodes = new ArrayList<Opcode>();
    178   private static List<Opcode> float2addrOpcodes = new ArrayList<Opcode>();
    179   private static List<Opcode> doubleOpcodes = new ArrayList<Opcode>();
    180   private static List<Opcode> double2addrOpcodes = new ArrayList<Opcode>();
    181   private static List<Opcode> intLit8Opcodes = new ArrayList<Opcode>();
    182   private static List<Opcode> intLit16Opcodes = new ArrayList<Opcode>();
    183   private static List<List<Opcode>> opcodeLists = new ArrayList<List<Opcode>>();
    184 
    185   static {
    186     intOpcodes.add(Opcode.ADD_INT);
    187     intOpcodes.add(Opcode.SUB_INT);
    188     intOpcodes.add(Opcode.MUL_INT);
    189     intOpcodes.add(Opcode.DIV_INT);
    190     intOpcodes.add(Opcode.REM_INT);
    191     intOpcodes.add(Opcode.AND_INT);
    192     intOpcodes.add(Opcode.OR_INT);
    193     intOpcodes.add(Opcode.XOR_INT);
    194     intOpcodes.add(Opcode.SHL_INT);
    195     intOpcodes.add(Opcode.SHR_INT);
    196     intOpcodes.add(Opcode.USHR_INT);
    197 
    198     int2addrOpcodes.add(Opcode.ADD_INT_2ADDR);
    199     int2addrOpcodes.add(Opcode.SUB_INT_2ADDR);
    200     int2addrOpcodes.add(Opcode.MUL_INT_2ADDR);
    201     int2addrOpcodes.add(Opcode.DIV_INT_2ADDR);
    202     int2addrOpcodes.add(Opcode.REM_INT_2ADDR);
    203     int2addrOpcodes.add(Opcode.AND_INT_2ADDR);
    204     int2addrOpcodes.add(Opcode.OR_INT_2ADDR);
    205     int2addrOpcodes.add(Opcode.XOR_INT_2ADDR);
    206     int2addrOpcodes.add(Opcode.SHL_INT_2ADDR);
    207     int2addrOpcodes.add(Opcode.SHR_INT_2ADDR);
    208     int2addrOpcodes.add(Opcode.USHR_INT_2ADDR);
    209 
    210     longOpcodes.add(Opcode.ADD_LONG);
    211     longOpcodes.add(Opcode.SUB_LONG);
    212     longOpcodes.add(Opcode.MUL_LONG);
    213     longOpcodes.add(Opcode.DIV_LONG);
    214     longOpcodes.add(Opcode.REM_LONG);
    215     longOpcodes.add(Opcode.AND_LONG);
    216     longOpcodes.add(Opcode.OR_LONG);
    217     longOpcodes.add(Opcode.XOR_LONG);
    218     longOpcodes.add(Opcode.SHL_LONG);
    219     longOpcodes.add(Opcode.SHR_LONG);
    220     longOpcodes.add(Opcode.USHR_LONG);
    221 
    222     long2addrOpcodes.add(Opcode.ADD_LONG_2ADDR);
    223     long2addrOpcodes.add(Opcode.SUB_LONG_2ADDR);
    224     long2addrOpcodes.add(Opcode.MUL_LONG_2ADDR);
    225     long2addrOpcodes.add(Opcode.DIV_LONG_2ADDR);
    226     long2addrOpcodes.add(Opcode.REM_LONG_2ADDR);
    227     long2addrOpcodes.add(Opcode.AND_LONG_2ADDR);
    228     long2addrOpcodes.add(Opcode.OR_LONG_2ADDR);
    229     long2addrOpcodes.add(Opcode.XOR_LONG_2ADDR);
    230     long2addrOpcodes.add(Opcode.SHL_LONG_2ADDR);
    231     long2addrOpcodes.add(Opcode.SHR_LONG_2ADDR);
    232     long2addrOpcodes.add(Opcode.USHR_LONG_2ADDR);
    233 
    234     floatOpcodes.add(Opcode.ADD_FLOAT);
    235     floatOpcodes.add(Opcode.SUB_FLOAT);
    236     floatOpcodes.add(Opcode.MUL_FLOAT);
    237     floatOpcodes.add(Opcode.DIV_FLOAT);
    238     floatOpcodes.add(Opcode.REM_FLOAT);
    239 
    240     float2addrOpcodes.add(Opcode.ADD_FLOAT_2ADDR);
    241     float2addrOpcodes.add(Opcode.SUB_FLOAT_2ADDR);
    242     float2addrOpcodes.add(Opcode.MUL_FLOAT_2ADDR);
    243     float2addrOpcodes.add(Opcode.DIV_FLOAT_2ADDR);
    244     float2addrOpcodes.add(Opcode.REM_FLOAT_2ADDR);
    245 
    246     doubleOpcodes.add(Opcode.ADD_DOUBLE);
    247     doubleOpcodes.add(Opcode.SUB_DOUBLE);
    248     doubleOpcodes.add(Opcode.MUL_DOUBLE);
    249     doubleOpcodes.add(Opcode.DIV_DOUBLE);
    250     doubleOpcodes.add(Opcode.REM_DOUBLE);
    251 
    252     double2addrOpcodes.add(Opcode.ADD_DOUBLE_2ADDR);
    253     double2addrOpcodes.add(Opcode.SUB_DOUBLE_2ADDR);
    254     double2addrOpcodes.add(Opcode.MUL_DOUBLE_2ADDR);
    255     double2addrOpcodes.add(Opcode.DIV_DOUBLE_2ADDR);
    256     double2addrOpcodes.add(Opcode.REM_DOUBLE_2ADDR);
    257 
    258     intLit8Opcodes.add(Opcode.ADD_INT_LIT8);
    259     intLit8Opcodes.add(Opcode.RSUB_INT_LIT8);
    260     intLit8Opcodes.add(Opcode.MUL_INT_LIT8);
    261     intLit8Opcodes.add(Opcode.DIV_INT_LIT8);
    262     intLit8Opcodes.add(Opcode.REM_INT_LIT8);
    263     intLit8Opcodes.add(Opcode.AND_INT_LIT8);
    264     intLit8Opcodes.add(Opcode.OR_INT_LIT8);
    265     intLit8Opcodes.add(Opcode.XOR_INT_LIT8);
    266     intLit8Opcodes.add(Opcode.SHL_INT_LIT8);
    267     intLit8Opcodes.add(Opcode.SHR_INT_LIT8);
    268     intLit8Opcodes.add(Opcode.USHR_INT_LIT8);
    269 
    270     intLit16Opcodes.add(Opcode.ADD_INT_LIT16);
    271     intLit16Opcodes.add(Opcode.RSUB_INT);
    272     intLit16Opcodes.add(Opcode.MUL_INT_LIT16);
    273     intLit16Opcodes.add(Opcode.DIV_INT_LIT16);
    274     intLit16Opcodes.add(Opcode.REM_INT_LIT16);
    275     intLit16Opcodes.add(Opcode.AND_INT_LIT16);
    276     intLit16Opcodes.add(Opcode.OR_INT_LIT16);
    277     intLit16Opcodes.add(Opcode.XOR_INT_LIT16);
    278 
    279     opcodeLists.add(intOpcodes);
    280     opcodeLists.add(longOpcodes);
    281     opcodeLists.add(floatOpcodes);
    282     opcodeLists.add(doubleOpcodes);
    283     opcodeLists.add(int2addrOpcodes);
    284     opcodeLists.add(long2addrOpcodes);
    285     opcodeLists.add(float2addrOpcodes);
    286     opcodeLists.add(double2addrOpcodes);
    287     opcodeLists.add(intLit8Opcodes);
    288     opcodeLists.add(intLit16Opcodes);
    289   }
    290 }
    291