1959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle/*
2959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Copyright (C) 2014 The Android Open Source Project
3959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle *
4959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Licensed under the Apache License, Version 2.0 (the "License");
5959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * you may not use this file except in compliance with the License.
6959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * You may obtain a copy of the License at
7959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle *
8959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle *      http://www.apache.org/licenses/LICENSE-2.0
9959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle *
10959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Unless required by applicable law or agreed to in writing, software
11959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * distributed under the License is distributed on an "AS IS" BASIS,
12959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * See the License for the specific language governing permissions and
14959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * limitations under the License.
15959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */
16959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
17959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kylepackage dexfuzz.program.mutators;
18959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
19959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.Log;
20959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.MutationStats;
21959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.program.MInsn;
22959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.program.MutatableCode;
23959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.program.Mutation;
24959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.rawdex.formats.ContainsConst;
25959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
26959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.util.ArrayList;
27959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.util.List;
28959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.util.Random;
29959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
30959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kylepublic class ConstantValueChanger extends CodeMutator {
31959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
32959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * Every CodeMutator has an AssociatedMutation, representing the
33959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * mutation that this CodeMutator can perform, to allow separate
34959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * generateMutation() and applyMutation() phases, allowing serialization.
35959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
36959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public static class AssociatedMutation extends Mutation {
37959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    public int constInsnIdx;
38959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    public long newConstant;
39959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
40959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    @Override
41959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    public String getString() {
42959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      StringBuilder builder = new StringBuilder();
43959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      builder.append(constInsnIdx).append(" ");
44959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      builder.append(newConstant);
45959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      return builder.toString();
46959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
47959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
48959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    @Override
49959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    public void parseString(String[] elements) {
50959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      constInsnIdx = Integer.parseInt(elements[2]);
51959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      newConstant = Long.parseLong(elements[3]);
52959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
53959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
54959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
55959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  // The following two methods are here for the benefit of MutationSerializer,
56959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  // so it can create a CodeMutator and get the correct associated Mutation, as it
57959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  // reads in mutations from a dump of mutations.
58959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  @Override
59959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public Mutation getNewMutation() {
60959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    return new AssociatedMutation();
61959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
62959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
63959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public ConstantValueChanger() { }
64959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
65959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public ConstantValueChanger(Random rng, MutationStats stats, List<Mutation> mutations) {
66959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    super(rng, stats, mutations);
67959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    likelihood = 70;
68959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
69959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
70959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  // A cache that should only exist between generateMutation() and applyMutation(),
71959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  // or be created at the start of applyMutation(), if we're reading in mutations from
72959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  // a file.
73959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  private List<MInsn> constInsns = null;
74959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
75959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  private void generateCachedConstInsns(MutatableCode mutatableCode) {
76959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if (constInsns != null) {
77959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      return;
78959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
79959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
80959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    constInsns = new ArrayList<MInsn>();
81959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (MInsn mInsn : mutatableCode.getInstructions()) {
82959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      if (mInsn.insn.info.format instanceof ContainsConst) {
83959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        constInsns.add(mInsn);
84959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
85959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
86959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
87959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
88959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  @Override
89959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  protected boolean canMutate(MutatableCode mutatableCode) {
90959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (MInsn mInsn : mutatableCode.getInstructions()) {
91959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      if (mInsn.insn.info.format instanceof ContainsConst) {
92959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        return true;
93959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
94959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
95959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
96959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    Log.debug("Method contains no const instructions.");
97959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    return false;
98959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
99959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
100959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  @Override
101959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  protected Mutation generateMutation(MutatableCode mutatableCode) {
102959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    generateCachedConstInsns(mutatableCode);
103959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
104959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Pick a random const instruction.
105959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int constInsnIdx = rng.nextInt(constInsns.size());
106959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    MInsn constInsn = constInsns.get(constInsnIdx);
107959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
108959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Get the constant.
109959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    long oldConstant = ((ContainsConst)constInsn.insn.info.format).getConst(constInsn.insn);
110959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
111959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    long newConstant = oldConstant;
112959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
113959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Make a new constant.
114959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    while (newConstant == oldConstant) {
115959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      newConstant = rng.nextLong()
116959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          % ((ContainsConst)constInsn.insn.info.format).getConstRange();
117959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
118959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
119959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    AssociatedMutation mutation = new AssociatedMutation();
120959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    mutation.setup(this.getClass(), mutatableCode);
121959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    mutation.constInsnIdx = constInsnIdx;
122959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    mutation.newConstant = newConstant;
123959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    return mutation;
124959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
125959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
126959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  @Override
127959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  protected void applyMutation(Mutation uncastMutation) {
128959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Cast the Mutation to our AssociatedMutation, so we can access its fields.
129959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    AssociatedMutation mutation = (AssociatedMutation) uncastMutation;
130959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    MutatableCode mutatableCode = mutation.mutatableCode;
131959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
132959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    generateCachedConstInsns(mutatableCode);
133959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
134959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    MInsn constInsn = constInsns.get(mutation.constInsnIdx);
135959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
136959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    long oldConstant = ((ContainsConst)constInsn.insn.info.format).getConst(constInsn.insn);
137959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
138959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    Log.info("Changed constant value #" + oldConstant + " to #" + mutation.newConstant
139959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        + " in " + constInsn);
140959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
141959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    stats.incrementStat("Changed constant value");
142959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
143959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Set the new constant.
144959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    ((ContainsConst)constInsn.insn.info.format).setConst(constInsn.insn, mutation.newConstant);
145959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
146959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Clear cache.
147959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    constInsns = null;
148959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
149959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle}
150