1 /* 2 * Copyright 2016, Google Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 package org.jf.smali;import com.google.common.collect.Lists; 33 import com.google.common.collect.Maps; 34 import junit.framework.Assert; 35 import org.antlr.runtime.RecognitionException; 36 import org.jf.dexlib2.Opcode; 37 import org.jf.dexlib2.ValueType; 38 import org.jf.dexlib2.iface.ClassDef; 39 import org.jf.dexlib2.iface.Field; 40 import org.jf.dexlib2.iface.Method; 41 import org.jf.dexlib2.iface.MethodImplementation; 42 import org.jf.dexlib2.iface.instruction.Instruction; 43 import org.jf.dexlib2.iface.instruction.formats.Instruction21c; 44 import org.jf.dexlib2.iface.instruction.formats.Instruction35c; 45 import org.jf.dexlib2.iface.reference.FieldReference; 46 import org.jf.dexlib2.iface.reference.MethodReference; 47 import org.jf.dexlib2.iface.value.FieldEncodedValue; 48 import org.jf.dexlib2.iface.value.MethodEncodedValue; 49 import org.jf.dexlib2.iface.value.TypeEncodedValue; 50 import org.jf.smali.SmaliTestUtils; 51 import org.junit.Test; 52 53 import java.io.IOException; 54 import java.util.List; 55 import java.util.Map; 56 57 /** 58 * Tests for method/field references that use an implicit type 59 */ 60 public class ImplicitReferenceTest extends SmaliTestUtils { 61 @Test 62 public void testImplicitMethodReference() throws RecognitionException, IOException { 63 ClassDef classDef = SmaliTestUtils.compileSmali("" + 64 ".class public LHelloWorld;\n" + 65 ".super Ljava/lang/Object;\n" + 66 ".method public static main([Ljava/lang/String;)V\n" + 67 " .registers 1\n" + 68 " invoke-static {p0}, toString()V\n" + 69 " invoke-static {p0}, V()V\n" + 70 " invoke-static {p0}, I()V\n" + 71 " return-void\n" + 72 ".end method"); 73 74 Method mainMethod = null; 75 for (Method method: classDef.getMethods()) { 76 if (method.getName().equals("main")) { 77 mainMethod = method; 78 } 79 } 80 Assert.assertNotNull(mainMethod); 81 82 MethodImplementation methodImpl = mainMethod.getImplementation(); 83 Assert.assertNotNull(methodImpl); 84 85 List<Instruction> instructions = Lists.newArrayList(methodImpl.getInstructions()); 86 87 Instruction35c instruction = (Instruction35c)instructions.get(0); 88 Assert.assertNotNull(instruction); 89 Assert.assertEquals(Opcode.INVOKE_STATIC, instruction.getOpcode()); 90 MethodReference method = (MethodReference)instruction.getReference(); 91 Assert.assertEquals(classDef.getType(), method.getDefiningClass()); 92 Assert.assertEquals("toString", method.getName()); 93 94 instruction = (Instruction35c)instructions.get(1); 95 Assert.assertNotNull(instruction); 96 Assert.assertEquals(Opcode.INVOKE_STATIC, instruction.getOpcode()); 97 method = (MethodReference)instruction.getReference(); 98 Assert.assertEquals(classDef.getType(), method.getDefiningClass()); 99 Assert.assertEquals("V", method.getName()); 100 101 instruction = (Instruction35c)instructions.get(2); 102 Assert.assertNotNull(instruction); 103 Assert.assertEquals(Opcode.INVOKE_STATIC, instruction.getOpcode()); 104 method = (MethodReference)instruction.getReference(); 105 Assert.assertEquals(classDef.getType(), method.getDefiningClass()); 106 Assert.assertEquals("I", method.getName()); 107 } 108 109 @Test 110 public void testImplicitMethodLiteral() throws RecognitionException, IOException { 111 ClassDef classDef = SmaliTestUtils.compileSmali("" + 112 ".class public LHelloWorld;\n" + 113 ".super Ljava/lang/Object;\n" + 114 ".field public static field1:Ljava/lang/reflect/Method; = toString()V\n" + 115 ".field public static field2:Ljava/lang/reflect/Method; = V()V\n" + 116 ".field public static field3:Ljava/lang/reflect/Method; = I()V\n" + 117 ".field public static field4:Ljava/lang/Class; = I"); 118 119 Map<String, Field> fields = Maps.newHashMap(); 120 for (Field field: classDef.getFields()) { 121 fields.put(field.getName(), field); 122 } 123 124 Field field = fields.get("field1"); 125 Assert.assertNotNull(field); 126 Assert.assertNotNull(field.getInitialValue()); 127 Assert.assertEquals(ValueType.METHOD, field.getInitialValue().getValueType()); 128 MethodEncodedValue methodEncodedValue = (MethodEncodedValue)field.getInitialValue(); 129 Assert.assertEquals(classDef.getType(), methodEncodedValue.getValue().getDefiningClass()); 130 Assert.assertEquals("toString", methodEncodedValue.getValue().getName()); 131 132 field = fields.get("field2"); 133 Assert.assertNotNull(field); 134 Assert.assertNotNull(field.getInitialValue()); 135 Assert.assertEquals(ValueType.METHOD, field.getInitialValue().getValueType()); 136 methodEncodedValue = (MethodEncodedValue)field.getInitialValue(); 137 Assert.assertEquals(classDef.getType(), methodEncodedValue.getValue().getDefiningClass()); 138 Assert.assertEquals("V", methodEncodedValue.getValue().getName()); 139 140 field = fields.get("field3"); 141 Assert.assertNotNull(field); 142 Assert.assertNotNull(field.getInitialValue()); 143 Assert.assertEquals(ValueType.METHOD, field.getInitialValue().getValueType()); 144 methodEncodedValue = (MethodEncodedValue)field.getInitialValue(); 145 Assert.assertEquals(classDef.getType(), methodEncodedValue.getValue().getDefiningClass()); 146 Assert.assertEquals("I", methodEncodedValue.getValue().getName()); 147 148 field = fields.get("field4"); 149 Assert.assertNotNull(field); 150 Assert.assertNotNull(field.getInitialValue()); 151 Assert.assertEquals(ValueType.TYPE, field.getInitialValue().getValueType()); 152 TypeEncodedValue typeEncodedValue = (TypeEncodedValue)field.getInitialValue(); 153 Assert.assertEquals("I", typeEncodedValue.getValue()); 154 } 155 156 @Test 157 public void testImplicitFieldReference() throws RecognitionException, IOException { 158 ClassDef classDef = SmaliTestUtils.compileSmali("" + 159 ".class public LHelloWorld;\n" + 160 ".super Ljava/lang/Object;\n" + 161 ".method public static main([Ljava/lang/String;)V\n" + 162 " .registers 1\n" + 163 " sget-object v0, someField:I\n" + 164 " sget-object v0, V:I\n" + 165 " sget-object v0, I:I\n" + 166 " return-void\n" + 167 ".end method"); 168 169 Method mainMethod = null; 170 for (Method method: classDef.getMethods()) { 171 if (method.getName().equals("main")) { 172 mainMethod = method; 173 } 174 } 175 Assert.assertNotNull(mainMethod); 176 177 MethodImplementation methodImpl = mainMethod.getImplementation(); 178 Assert.assertNotNull(methodImpl); 179 180 List<Instruction> instructions = Lists.newArrayList(methodImpl.getInstructions()); 181 182 Instruction21c instruction = (Instruction21c)instructions.get(0); 183 Assert.assertNotNull(instruction); 184 Assert.assertEquals(Opcode.SGET_OBJECT, instruction.getOpcode()); 185 FieldReference field = (FieldReference)instruction.getReference(); 186 Assert.assertEquals(classDef.getType(), field.getDefiningClass()); 187 Assert.assertEquals("someField", field.getName()); 188 189 instruction = (Instruction21c)instructions.get(1); 190 Assert.assertNotNull(instruction); 191 Assert.assertEquals(Opcode.SGET_OBJECT, instruction.getOpcode()); 192 field = (FieldReference)instruction.getReference(); 193 Assert.assertEquals(classDef.getType(), field.getDefiningClass()); 194 Assert.assertEquals("V", field.getName()); 195 196 instruction = (Instruction21c)instructions.get(2); 197 Assert.assertNotNull(instruction); 198 Assert.assertEquals(Opcode.SGET_OBJECT, instruction.getOpcode()); 199 field = (FieldReference)instruction.getReference(); 200 Assert.assertEquals(classDef.getType(), field.getDefiningClass()); 201 Assert.assertEquals("I", field.getName()); 202 } 203 204 @Test 205 public void testImplicitFieldLiteral() throws RecognitionException, IOException { 206 ClassDef classDef = SmaliTestUtils.compileSmali("" + 207 ".class public LHelloWorld;\n" + 208 ".super Ljava/lang/Object;\n" + 209 ".field public static field1:Ljava/lang/reflect/Field; = someField:I\n" + 210 ".field public static field2:Ljava/lang/reflect/Field; = V:I\n" + 211 ".field public static field3:Ljava/lang/reflect/Field; = I:I\n"); 212 213 Map<String, Field> fields = Maps.newHashMap(); 214 for (Field field: classDef.getFields()) { 215 fields.put(field.getName(), field); 216 } 217 218 Field field = fields.get("field1"); 219 Assert.assertNotNull(field); 220 Assert.assertNotNull(field.getInitialValue()); 221 Assert.assertEquals(ValueType.FIELD, field.getInitialValue().getValueType()); 222 FieldEncodedValue fieldEncodedValue = (FieldEncodedValue)field.getInitialValue(); 223 Assert.assertEquals(classDef.getType(), fieldEncodedValue.getValue().getDefiningClass()); 224 Assert.assertEquals("someField", fieldEncodedValue.getValue().getName()); 225 226 field = fields.get("field2"); 227 Assert.assertNotNull(field); 228 Assert.assertNotNull(field.getInitialValue()); 229 Assert.assertEquals(ValueType.FIELD, field.getInitialValue().getValueType()); 230 fieldEncodedValue = (FieldEncodedValue)field.getInitialValue(); 231 Assert.assertEquals(classDef.getType(), fieldEncodedValue.getValue().getDefiningClass()); 232 Assert.assertEquals("V", fieldEncodedValue.getValue().getName()); 233 234 field = fields.get("field3"); 235 Assert.assertNotNull(field); 236 Assert.assertNotNull(field.getInitialValue()); 237 Assert.assertEquals(ValueType.FIELD, field.getInitialValue().getValueType()); 238 fieldEncodedValue = (FieldEncodedValue)field.getInitialValue(); 239 Assert.assertEquals(classDef.getType(), fieldEncodedValue.getValue().getDefiningClass()); 240 Assert.assertEquals("I", fieldEncodedValue.getValue().getName()); 241 } 242 } 243