1 /*
2  * Copyright (C) 2010 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 java.lang.reflect.InvocationTargetException;
18 import java.lang.reflect.Method;
19 import java.lang.reflect.Modifier;
20 
21 /*
22  * Entry point and tests that are expected to succeed.
23  */
24 public class Main {
25     /**
26      * Drives tests.
27      */
main(String[] args)28     public static void main(String[] args) {
29         System.loadLibrary(args[0]);
30         if (!hasOatFile() || runtimeIsSoftFail() || isInterpreted()) {
31             // Some tests ensure that the verifier was able to guarantee balanced locking by
32             // asserting that the test function is running as compiled code. But skip this now,
33             // as this seems to be a non-compiled code test configuration.
34             disableStackFrameAsserts();
35         }
36 
37         Main m = new Main();
38 
39         m.recursiveSync(0);
40 
41         m.nestedMayThrow(false);
42         try {
43             m.nestedMayThrow(true);
44             System.err.println("nestedThrow(true) did not throw");
45         } catch (MyException me) {}
46         System.out.println("nestedMayThrow ok");
47 
48         m.constantLock();
49         System.out.println("constantLock ok");
50 
51         m.notExcessiveNesting();
52 
53         m.notNested();
54         System.out.println("notNested ok");
55 
56         Object obj1 = new Object();
57         Object obj2 = new Object();
58 
59         TwoPath.twoPath(obj1, obj2, 0);
60         System.out.println("twoPath ok");
61 
62         m.triplet(obj1, obj2, 0);
63         System.out.println("triplet ok");
64 
65         runSmaliTests();
66     }
67 
68     /**
69      * Recursive synchronized method.
70      */
recursiveSync(int iter)71     synchronized void recursiveSync(int iter) {
72         assertIsManaged();
73         if (iter < 40) {
74             recursiveSync(iter+1);
75         } else {
76             System.out.println("recursiveSync ok");
77         }
78     }
79 
80     /**
81      * Tests simple nesting, with and without a throw.
82      */
nestedMayThrow(boolean doThrow)83     void nestedMayThrow(boolean doThrow) {
84         assertIsManaged();
85         synchronized (this) {
86             synchronized (Main.class) {
87                 synchronized (new Object()) {
88                     synchronized(Class.class) {
89                         if (doThrow) {
90                             throw new MyException();
91                         }
92                     }
93                 }
94             }
95         }
96     }
97 
98     /**
99      * Exercises bug 3215458.
100      */
constantLock()101     void constantLock() {
102         assertIsManaged();
103         Class<?> thing = Thread.class;
104         synchronized (Thread.class) {}
105     }
106 
107     /**
108      * Confirms that we can have 32 nested monitors on one method.
109      */
notExcessiveNesting()110     void notExcessiveNesting() {
111         assertIsManaged();
112         synchronized (this) {   // 1
113         synchronized (this) {   // 2
114         synchronized (this) {   // 3
115         synchronized (this) {   // 4
116         synchronized (this) {   // 5
117         synchronized (this) {   // 6
118         synchronized (this) {   // 7
119         synchronized (this) {   // 8
120         synchronized (this) {   // 9
121         synchronized (this) {   // 10
122         synchronized (this) {   // 11
123         synchronized (this) {   // 12
124         synchronized (this) {   // 13
125         synchronized (this) {   // 14
126         synchronized (this) {   // 15
127         synchronized (this) {   // 16
128         synchronized (this) {   // 17
129         synchronized (this) {   // 18
130         synchronized (this) {   // 19
131         synchronized (this) {   // 20
132         synchronized (this) {   // 21
133         synchronized (this) {   // 22
134         synchronized (this) {   // 23
135         synchronized (this) {   // 24
136         synchronized (this) {   // 25
137         synchronized (this) {   // 26
138         synchronized (this) {   // 27
139         synchronized (this) {   // 28
140         synchronized (this) {   // 29
141         synchronized (this) {   // 30
142         synchronized (this) {   // 31
143         synchronized (this) {   // 32
144         }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
145     }
146 
147     /**
148      * Confirms that we can have more than 32 non-nested monitors in one
149      * method.
150      */
notNested()151     void notNested() {
152         assertIsManaged();
153         synchronized (this) {}  // 1
154         synchronized (this) {}  // 2
155         synchronized (this) {}  // 3
156         synchronized (this) {}  // 4
157         synchronized (this) {}  // 5
158         synchronized (this) {}  // 6
159         synchronized (this) {}  // 7
160         synchronized (this) {}  // 8
161         synchronized (this) {}  // 9
162         synchronized (this) {}  // 10
163         synchronized (this) {}  // 11
164         synchronized (this) {}  // 12
165         synchronized (this) {}  // 13
166         synchronized (this) {}  // 14
167         synchronized (this) {}  // 15
168         synchronized (this) {}  // 16
169         synchronized (this) {}  // 17
170         synchronized (this) {}  // 18
171         synchronized (this) {}  // 19
172         synchronized (this) {}  // 20
173         synchronized (this) {}  // 21
174         synchronized (this) {}  // 22
175         synchronized (this) {}  // 23
176         synchronized (this) {}  // 24
177         synchronized (this) {}  // 25
178         synchronized (this) {}  // 26
179         synchronized (this) {}  // 27
180         synchronized (this) {}  // 28
181         synchronized (this) {}  // 29
182         synchronized (this) {}  // 30
183         synchronized (this) {}  // 31
184         synchronized (this) {}  // 32
185         synchronized (this) {}  // 33
186         synchronized (this) {}  // 34
187     }
188 
189     /* does nothing but ensure that the compiler doesn't discard an object */
doNothing(Object obj)190     private void doNothing(Object obj) {}
191 
192     /**
193      * Lock the monitor two or three times, and make use of the locked or
194      * unlocked object.
195      */
triplet(Object obj1, Object obj2, int x)196     public void triplet(Object obj1, Object obj2, int x) {
197         Object localObj;
198 
199         synchronized (obj1) {
200             synchronized(obj1) {
201                 if (x == 0) {
202                     synchronized(obj1) {
203                         localObj = obj2;
204                     }
205                 } else {
206                     localObj = obj1;
207                 }
208             }
209         }
210 
211         doNothing(localObj);
212     }
213 
214     // Smali testing code.
runSmaliTests()215     private static void runSmaliTests() {
216         runTest("OK", new Object[] { new Object(), new Object() }, null);
217         runTest("TooDeep", new Object[] { new Object() }, null);
218         runTest("NotStructuredOverUnlock", new Object[] { new Object() },
219                 IllegalMonitorStateException.class);
220         runTest("NotStructuredUnderUnlock", new Object[] { new Object() },
221                 IllegalMonitorStateException.class);
222         runTest("UnbalancedJoin", new Object[] { new Object(), new Object() }, null);
223         runTest("UnbalancedStraight", new Object[] { new Object(), new Object() }, null);
224         runTest("NullLocks", new Object[] { false }, null);
225         runTest("NullLocks", new Object[] { true }, NullPointerException.class);
226     }
227 
runTest(String className, Object[] parameters, Class<?> excType)228     private static void runTest(String className, Object[] parameters, Class<?> excType) {
229         try {
230             Class<?> c = Class.forName(className);
231 
232             Method[] methods = c.getDeclaredMethods();
233 
234             // For simplicity we assume that test methods are not overloaded. So searching by name
235             // will give us the method we need to run.
236             Method method = null;
237             for (Method m : methods) {
238                 if (m.getName().equals("run")) {
239                     method = m;
240                     break;
241                 }
242             }
243 
244             if (method == null) {
245                 System.out.println("Could not find test method for " + className);
246             } else if (!Modifier.isStatic(method.getModifiers())) {
247                 System.out.println("Test method for " + className + " is not static.");
248             } else {
249                 method.invoke(null, parameters);
250                 if (excType != null) {
251                     System.out.println("Expected an exception in " + className);
252                 }
253             }
254         } catch (Throwable exc) {
255             if (excType == null) {
256                 System.out.println("Did not expect exception " + exc + " for " + className);
257                 exc.printStackTrace(System.out);
258             } else if (exc instanceof InvocationTargetException && exc.getCause() != null &&
259                        exc.getCause().getClass().equals(excType)) {
260                 // Expected exception is wrapped in InvocationTargetException.
261             } else if (!excType.equals(exc.getClass())) {
262                 System.out.println("Expected " + excType.getName() + ", but got " + exc.getClass());
263             } else {
264               // Expected exception, do nothing.
265             }
266         }
267     }
268 
269     // Helpers for the smali code.
assertIsInterpreted()270     public static native void assertIsInterpreted();
assertIsManaged()271     public static native void assertIsManaged();
hasOatFile()272     public static native boolean hasOatFile();
runtimeIsSoftFail()273     public static native boolean runtimeIsSoftFail();
isInterpreted()274     public static native boolean isInterpreted();
disableStackFrameAsserts()275     public static native void disableStackFrameAsserts();
276 }
277