1 /*
2  * Copyright (C) 2017 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 import static art.Redefinition.doCommonClassRedefinition;
18 
19 import java.lang.reflect.Method;
20 import java.util.ArrayList;
21 import java.util.Base64;
22 import java.util.LinkedList;
23 
24 public class Main {
25 
26   // TODO We should make this run on the RI.
27   /**
28    * This test cannot be run on the RI.
29    */
30   private static final byte[] CLASS_BYTES = new byte[0];
31 
32   // TODO It might be a good idea to replace this hard-coded Object definition with a
33   // retransformation based test.
34   /**
35    * Base64 encoding of the following smali file.
36    *
37    *  .class public Ljava/lang/Object;
38    *  .source "Object.java"
39    *  # instance fields
40    *  .field private transient shadow$_klass_:Ljava/lang/Class;
41    *      .annotation system Ldalvik/annotation/Signature;
42    *          value = {
43    *              "Ljava/lang/Class",
44    *              "<*>;"
45    *          }
46    *      .end annotation
47    *  .end field
48    *
49    *  .field private transient shadow$_monitor_:I
50    *  # direct methods
51    *  .method public constructor <init>()V
52    *      .registers 1
53    *      .prologue
54    *      invoke-static {p0}, Lart/test/TestWatcher;->NotifyConstructed(Ljava/lang/Object;)V
55    *      return-void
56    *  .end method
57    *
58    *  .method static identityHashCode(Ljava/lang/Object;)I
59    *      .registers 7
60    *      .prologue
61    *      iget v0, p0, Ljava/lang/Object;->shadow$_monitor_:I
62    *      const/high16 v3, -0x40000000    # -2.0f
63    *      const/high16 v2, -0x80000000
64    *      const v1, 0xfffffff
65    *      const/high16 v4, -0x40000000    # -2.0f
66    *      and-int/2addr v4, v0
67    *      const/high16 v5, -0x80000000
68    *      if-ne v4, v5, :cond_15
69    *      const v4, 0xfffffff
70    *      and-int/2addr v4, v0
71    *      return v4
72    *      :cond_15
73    *      invoke-static {p0}, Ljava/lang/Object;->identityHashCodeNative(Ljava/lang/Object;)I
74    *      move-result v4
75    *      return v4
76    *  .end method
77    *
78    *  .method private static native identityHashCodeNative(Ljava/lang/Object;)I
79    *      .annotation build Ldalvik/annotation/optimization/FastNative;
80    *      .end annotation
81    *  .end method
82    *
83    *  .method private native internalClone()Ljava/lang/Object;
84    *      .annotation build Ldalvik/annotation/optimization/FastNative;
85    *      .end annotation
86    *  .end method
87    *
88    *
89    *  # virtual methods
90    *  .method protected clone()Ljava/lang/Object;
91    *      .registers 4
92    *      .annotation system Ldalvik/annotation/Throws;
93    *          value = {
94    *              Ljava/lang/CloneNotSupportedException;
95    *          }
96    *      .end annotation
97    *
98    *      .prologue
99    *      instance-of v0, p0, Ljava/lang/Cloneable;
100    *      if-nez v0, :cond_2d
101    *      new-instance v0, Ljava/lang/CloneNotSupportedException;
102    *      new-instance v1, Ljava/lang/StringBuilder;
103    *      invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V
104    *      const-string/jumbo v2, "Class "
105    *      invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
106    *      move-result-object v1
107    *      invoke-virtual {p0}, Ljava/lang/Object;->getClass()Ljava/lang/Class;
108    *      move-result-object v2
109    *      invoke-virtual {v2}, Ljava/lang/Class;->getName()Ljava/lang/String;
110    *      move-result-object v2
111    *      invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
112    *      move-result-object v1
113    *      const-string/jumbo v2, " doesn\'t implement Cloneable"
114    *      invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
115    *      move-result-object v1
116    *      invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
117    *      move-result-object v1
118    *      invoke-direct {v0, v1}, Ljava/lang/CloneNotSupportedException;-><init>(Ljava/lang/String;)V
119    *      throw v0
120    *      :cond_2d
121    *      invoke-direct {p0}, Ljava/lang/Object;->internalClone()Ljava/lang/Object;
122    *      move-result-object v0
123    *      return-object v0
124    *  .end method
125    *
126    *  .method public equals(Ljava/lang/Object;)Z
127    *      .registers 3
128    *      .prologue
129    *      if-ne p0, p1, :cond_4
130    *      const/4 v0, 0x1
131    *      :goto_3
132    *      return v0
133    *      :cond_4
134    *      const/4 v0, 0x0
135    *      goto :goto_3
136    *  .end method
137    *
138    *  .method protected finalize()V
139    *      .registers 1
140    *      .annotation system Ldalvik/annotation/Throws;
141    *          value = {
142    *              Ljava/lang/Throwable;
143    *          }
144    *      .end annotation
145    *      .prologue
146    *      return-void
147    *  .end method
148    *
149    *  .method public final getClass()Ljava/lang/Class;
150    *      .registers 2
151    *      .annotation system Ldalvik/annotation/Signature;
152    *          value = {
153    *              "()",
154    *              "Ljava/lang/Class",
155    *              "<*>;"
156    *          }
157    *      .end annotation
158    *      .prologue
159    *      iget-object v0, p0, Ljava/lang/Object;->shadow$_klass_:Ljava/lang/Class;
160    *      return-object v0
161    *  .end method
162    *
163    *  .method public hashCode()I
164    *      .registers 2
165    *      .prologue
166    *      invoke-static {p0}, Ljava/lang/Object;->identityHashCode(Ljava/lang/Object;)I
167    *      move-result v0
168    *      return v0
169    *  .end method
170    *
171    *  .method public final native notify()V
172    *      .annotation build Ldalvik/annotation/optimization/FastNative;
173    *      .end annotation
174    *  .end method
175    *
176    *  .method public final native notifyAll()V
177    *      .annotation build Ldalvik/annotation/optimization/FastNative;
178    *      .end annotation
179    *  .end method
180    *
181    *  .method public toString()Ljava/lang/String;
182    *      .registers 3
183    *      .prologue
184    *      new-instance v0, Ljava/lang/StringBuilder;
185    *      invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
186    *      invoke-virtual {p0}, Ljava/lang/Object;->getClass()Ljava/lang/Class;
187    *      move-result-object v1
188    *      invoke-virtual {v1}, Ljava/lang/Class;->getName()Ljava/lang/String;
189    *      move-result-object v1
190    *      invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
191    *      move-result-object v0
192    *      const-string/jumbo v1, "@"
193    *      invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
194    *      move-result-object v0
195    *      invoke-virtual {p0}, Ljava/lang/Object;->hashCode()I
196    *      move-result v1
197    *      invoke-static {v1}, Ljava/lang/Integer;->toHexString(I)Ljava/lang/String;
198    *      move-result-object v1
199    *      invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
200    *      move-result-object v0
201    *      invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
202    *      move-result-object v0
203    *      return-object v0
204    *  .end method
205    *
206    *  .method public final native wait()V
207    *      .annotation system Ldalvik/annotation/Throws;
208    *          value = {
209    *              Ljava/lang/InterruptedException;
210    *          }
211    *      .end annotation
212    *
213    *      .annotation build Ldalvik/annotation/optimization/FastNative;
214    *      .end annotation
215    *  .end method
216    *
217    *  .method public final wait(J)V
218    *      .registers 4
219    *      .annotation system Ldalvik/annotation/Throws;
220    *          value = {
221    *              Ljava/lang/InterruptedException;
222    *          }
223    *      .end annotation
224    *      .prologue
225    *      const/4 v0, 0x0
226    *      invoke-virtual {p0, p1, p2, v0}, Ljava/lang/Object;->wait(JI)V
227    *      return-void
228    *  .end method
229    *
230    *  .method public final native wait(JI)V
231    *      .annotation system Ldalvik/annotation/Throws;
232    *          value = {
233    *              Ljava/lang/InterruptedException;
234    *          }
235    *      .end annotation
236    *
237    *      .annotation build Ldalvik/annotation/optimization/FastNative;
238    *      .end annotation
239    *  .end method
240    */
241   private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
242       "ZGV4CjAzNQDUlMR9j03MYuOKekKs2p7zJzu2IfDb7RlMCgAAcAAAAHhWNBIAAAAAAAAAAIgJAAA6" +
243       "AAAAcAAAABEAAABYAQAADQAAAJwBAAACAAAAOAIAABYAAABIAgAAAQAAAPgCAAA0BwAAGAMAABgD" +
244       "AAA2AwAAOgMAAEADAABIAwAASwMAAFMDAABWAwAAWgMAAF0DAABgAwAAZAMAAGgDAACAAwAAnwMA" +
245       "ALsDAADoAwAA+gMAAA0EAAA1BAAATAQAAGEEAACDBAAAlwQAAKsEAADGBAAA3QQAAPAEAAD9BAAA" +
246       "AAUAAAQFAAAJBQAADQUAABAFAAAUBQAAHAUAACMFAAArBQAANQUAAD8FAABIBQAAUgUAAGQFAAB8" +
247       "BQAAiwUAAJUFAACnBQAAugUAAM0FAADVBQAA3QUAAOgFAADtBQAA/QUAAA8GAAAcBgAAJgYAAC0G" +
248       "AAAGAAAACAAAAAwAAAANAAAADgAAAA8AAAARAAAAEgAAABMAAAAUAAAAFQAAABYAAAAXAAAAGAAA" +
249       "ABkAAAAcAAAAIAAAAAYAAAAAAAAAAAAAAAcAAAAAAAAAPAYAAAkAAAAGAAAAAAAAAAkAAAALAAAA" +
250       "AAAAAAkAAAAMAAAAAAAAAAoAAAAMAAAARAYAAAsAAAANAAAAVAYAABwAAAAPAAAAAAAAAB0AAAAP" +
251       "AAAATAYAAB4AAAAPAAAANAYAAB8AAAAPAAAAPAYAAB8AAAAPAAAAVAYAACEAAAAQAAAAPAYAAAsA" +
252       "BgA0AAAACwAAADUAAAACAAoAGgAAAAYABAAnAAAABwALAAMAAAAJAAUANgAAAAsABwADAAAACwAD" +
253       "ACMAAAALAAwAJAAAAAsABwAlAAAACwACACYAAAALAAAAKAAAAAsAAQApAAAACwABACoAAAALAAMA" +
254       "KwAAAAsABwAxAAAACwAHADIAAAALAAQANwAAAAsABwA5AAAACwAIADkAAAALAAkAOQAAAA0ABwAD" +
255       "AAAADQAGACIAAAANAAQANwAAAAsAAAABAAAA/////wAAAAAbAAAA0AYAAD4JAAAAAAAAHCBkb2Vz" +
256       "bid0IGltcGxlbWVudCBDbG9uZWFibGUAAigpAAQ8Kj47AAY8aW5pdD4AAUAABkNsYXNzIAABSQAC" +
257       "SUwAAUoAAUwAAkxJAAJMTAAWTGFydC90ZXN0L1Rlc3RXYXRjaGVyOwAdTGRhbHZpay9hbm5vdGF0" +
258       "aW9uL1NpZ25hdHVyZTsAGkxkYWx2aWsvYW5ub3RhdGlvbi9UaHJvd3M7ACtMZGFsdmlrL2Fubm90" +
259       "YXRpb24vb3B0aW1pemF0aW9uL0Zhc3ROYXRpdmU7ABBMamF2YS9sYW5nL0NsYXNzABFMamF2YS9s" +
260       "YW5nL0NsYXNzOwAmTGphdmEvbGFuZy9DbG9uZU5vdFN1cHBvcnRlZEV4Y2VwdGlvbjsAFUxqYXZh" +
261       "L2xhbmcvQ2xvbmVhYmxlOwATTGphdmEvbGFuZy9JbnRlZ2VyOwAgTGphdmEvbGFuZy9JbnRlcnJ1" +
262       "cHRlZEV4Y2VwdGlvbjsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABlM" +
263       "amF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7ABVMamF2YS9sYW5nL1Rocm93YWJsZTsAEU5vdGlmeUNv" +
264       "bnN0cnVjdGVkAAtPYmplY3QuamF2YQABVgACVkoAA1ZKSQACVkwAAVoAAlpMAAZhcHBlbmQABWNs" +
265       "b25lAAZlcXVhbHMACGZpbmFsaXplAAhnZXRDbGFzcwAHZ2V0TmFtZQAIaGFzaENvZGUAEGlkZW50" +
266       "aXR5SGFzaENvZGUAFmlkZW50aXR5SGFzaENvZGVOYXRpdmUADWludGVybmFsQ2xvbmUACGxvY2tX" +
267       "b3JkABBsb2NrV29yZEhhc2hNYXNrABFsb2NrV29yZFN0YXRlSGFzaAARbG9ja1dvcmRTdGF0ZU1h" +
268       "c2sABm1pbGxpcwAGbm90aWZ5AAlub3RpZnlBbGwAA29iagAOc2hhZG93JF9rbGFzc18AEHNoYWRv" +
269       "dyRfbW9uaXRvcl8AC3RvSGV4U3RyaW5nAAh0b1N0cmluZwAFdmFsdWUABHdhaXQAAAIAAAABAAAA" +
270       "AQAAAAsAAAABAAAAAAAAAAEAAAABAAAAAQAAAAwAAgQBOBwBGAcCBAE4HAEYCgIDATgcAhcQFwIC" +
271       "BAE4HAEYDgAFAAIDATgcAxcBFxAXAgAAAAAAAAAAAAEAAABaBgAAAgAAAGIGAAB8BgAAAQAAAGIG" +
272       "AAABAAAAagYAAAEAAAB0BgAAAQAAAHwGAAABAAAAfwYAAAAAAAABAAAACgAAAAAAAAAAAAAAsAYA" +
273       "AAUAAACUBgAABwAAALgGAAAIAAAAyAYAAAsAAADABgAADAAAAMAGAAANAAAAwAYAAA4AAADABgAA" +
274       "EAAAAJwGAAARAAAAqAYAABIAAACcBgAAKAAHDgBwATQHDi0DAC0BLQMDMAEtAwIvATwDAS4BeFsA" +
275       "7AEABw5LARoPOsYArAEBNAcOAMUEAAcOAEEABw4AaAAHDgCRAgAHDgCmAwExBw5LAAAAAQABAAEA" +
276       "AAA4BwAABAAAAHEQAAAAAA4ABwABAAEAAAA9BwAAGgAAAFJgAQAVAwDAFQIAgBQB////DxUEAMC1" +
277       "BBUFAIAzVAcAFAT///8PtQQPBHEQCwAGAAoEDwQEAAEAAgAAAFkHAAAyAAAAIDAIADkAKwAiAAcA" +
278       "IgENAHAQEwABABsCBQAAAG4gFAAhAAwBbhAIAAMADAJuEAEAAgAMAm4gFAAhAAwBGwIAAAAAbiAU" +
279       "ACEADAFuEBUAAQAMAXAgAgAQACcAcBAMAAMADAARAAMAAgAAAAAAZQcAAAYAAAAzIQQAEhAPABIA" +
280       "KP4BAAEAAAAAAGwHAAABAAAADgAAAAIAAQAAAAAAcgcAAAMAAABUEAAAEQAAAAIAAQABAAAAdwcA" +
281       "AAUAAABxEAoAAQAKAA8AAAADAAEAAgAAAHwHAAApAAAAIgANAHAQEwAAAG4QCAACAAwBbhABAAEA" +
282       "DAFuIBQAEAAMABsBBAAAAG4gFAAQAAwAbhAJAAIACgFxEAMAAQAMAW4gFAAQAAwAbhAVAAAADAAR" +
283       "AAAABAADAAQAAACCBwAABQAAABIAbkASACEDDgAAAgQLAIIBAYIBBIGABIwPBgikDwGKAgABggIA" +
284       "BQToDwEB3BABBPgQARGMEQEBpBEEkQIAAZECAAEBwBEBkQIAARGkEgGRAgAAABAAAAAAAAAAAQAA" +
285       "AAAAAAABAAAAOgAAAHAAAAACAAAAEQAAAFgBAAADAAAADQAAAJwBAAAEAAAAAgAAADgCAAAFAAAA" +
286       "FgAAAEgCAAAGAAAAAQAAAPgCAAACIAAAOgAAABgDAAABEAAABQAAADQGAAAEIAAABgAAAFoGAAAD" +
287       "EAAACQAAAIwGAAAGIAAAAQAAANAGAAADIAAACQAAADgHAAABIAAACQAAAIwHAAAAIAAAAQAAAD4J" +
288       "AAAAEAAAAQAAAIgJAAA=");
289 
290   private static final String LISTENER_LOCATION =
291       System.getenv("DEX_LOCATION") + "/980-redefine-object-ex.jar";
292 
293   private static Method doEnableReporting;
294   private static Method doDisableReporting;
295 
DisableReporting()296   private static void DisableReporting() {
297     if (doDisableReporting == null) {
298       return;
299     }
300     try {
301       doDisableReporting.invoke(null);
302     } catch (Exception e) {
303       throw new Error("Unable to disable reporting!");
304     }
305   }
306 
EnableReporting()307   private static void EnableReporting() {
308     if (doEnableReporting == null) {
309       return;
310     }
311     try {
312       doEnableReporting.invoke(null);
313     } catch (Exception e) {
314       throw new Error("Unable to enable reporting!");
315     }
316   }
317 
main(String[] args)318   public static void main(String[] args) {
319     doTest();
320   }
321 
ensureTestWatcherInitialized()322   private static void ensureTestWatcherInitialized() {
323     try {
324       // Make sure the TestWatcher class can be found from the Object <init> function.
325       addToBootClassLoader(LISTENER_LOCATION);
326       // Load TestWatcher from the bootclassloader and make sure it is initialized.
327       Class<?> testwatcher_class = Class.forName("art.test.TestWatcher", true, null);
328       doEnableReporting = testwatcher_class.getDeclaredMethod("EnableReporting");
329       doDisableReporting = testwatcher_class.getDeclaredMethod("DisableReporting");
330     } catch (Exception e) {
331       throw new Error("Exception while making testwatcher", e);
332     }
333   }
334 
335   // NB This function will cause 2 objects of type "Ljava/nio/HeapCharBuffer;" and
336   // "Ljava/nio/HeapCharBuffer;" to be allocated each time it is called.
safePrintln(Object o)337   private static void safePrintln(Object o) {
338     DisableReporting();
339     System.out.println("\t" + o);
340     EnableReporting();
341   }
342 
throwFrom(int depth)343   private static void throwFrom(int depth) throws Exception {
344     if (depth <= 0) {
345       throw new Exception("Throwing the exception");
346     } else {
347       throwFrom(depth - 1);
348     }
349   }
350 
doTest()351   public static void doTest() {
352     safePrintln("Initializing and loading the TestWatcher class that will (eventually) be " +
353                 "notified of object allocations");
354     // Make sure the TestWatcher class is initialized before we do anything else.
355     ensureTestWatcherInitialized();
356     safePrintln("Allocating an j.l.Object before redefining Object class");
357     // Make sure these aren't shown.
358     Object o = new Object();
359     safePrintln("Allocating a Transform before redefining Object class");
360     Transform t = new Transform();
361 
362     // Redefine the Object Class.
363     safePrintln("Redefining the Object class to add a hook into the <init> method");
364     doCommonClassRedefinition(Object.class, CLASS_BYTES, DEX_BYTES);
365 
366     safePrintln("Allocating an j.l.Object after redefining Object class");
367     Object o2 = new Object();
368     safePrintln("Allocating a Transform after redefining Object class");
369     Transform t2 = new Transform();
370 
371     // This shouldn't cause the Object constructor to be run.
372     safePrintln("Allocating an int[] after redefining Object class");
373     int[] abc = new int[12];
374 
375     // Try adding stuff to an array list.
376     safePrintln("Allocating an array list");
377     ArrayList<Object> al = new ArrayList<>();
378     safePrintln("Adding a bunch of stuff to the array list");
379     al.add(new Object());
380     al.add(new Object());
381     al.add(o2);
382     al.add(o);
383     al.add(t);
384     al.add(t2);
385     al.add(new Transform());
386 
387     // Try adding stuff to a LinkedList
388     safePrintln("Allocating a linked list");
389     LinkedList<Object> ll = new LinkedList<>();
390     safePrintln("Adding a bunch of stuff to the linked list");
391     ll.add(new Object());
392     ll.add(new Object());
393     ll.add(o2);
394     ll.add(o);
395     ll.add(t);
396     ll.add(t2);
397     ll.add(new Transform());
398 
399     // Try making an exception.
400     safePrintln("Throwing from down 4 stack frames");
401     try {
402       throwFrom(4);
403     } catch (Exception e) {
404       safePrintln("Exception caught.");
405     }
406 
407     safePrintln("Finishing test!");
408   }
409 
addToBootClassLoader(String s)410   private static native void addToBootClassLoader(String s);
411 }
412