1 /*
2  * Copyright (C) 2009 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 
20 public class Main {
21     static class ArrayMemEater {
22         static boolean sawOome;
23 
blowup(char[][] holder)24         static void blowup(char[][] holder) {
25             try {
26                 for (int i = 0; i < holder.length; ++i) {
27                     holder[i] = new char[1024 * 1024];
28                 }
29             } catch (OutOfMemoryError oome) {
30                 ArrayMemEater.sawOome = true;
31             }
32         }
33     }
34 
35     static class InstanceMemEater {
36         static boolean sawOome;
37         static InstanceMemEater hook;
38 
39         InstanceMemEater next;
40         double d1, d2, d3, d4, d5, d6, d7, d8; // Bloat this object so we fill the heap faster.
41 
allocate()42         static InstanceMemEater allocate() {
43             try {
44                 return new InstanceMemEater();
45             } catch (OutOfMemoryError e) {
46                 InstanceMemEater.sawOome = true;
47                 return null;
48             }
49         }
50 
confuseCompilerOptimization(InstanceMemEater instance)51         static void confuseCompilerOptimization(InstanceMemEater instance) {
52           hook = instance;
53         }
54     }
55 
eatAllMemory()56     public static Object eatAllMemory() {
57         Object[] result = null;
58         int size = 1000000;
59         while (result == null && size != 0) {
60             try {
61                 result = new Object[size];
62             } catch (OutOfMemoryError oome) {
63                 size /= 2;
64             }
65         }
66         if (result != null) {
67             int index = 0;
68             while (index != result.length && size != 0) {
69                 try {
70                     result[index] = new byte[size];
71                     ++index;
72                 } catch (OutOfMemoryError oome) {
73                     size /= 2;
74                 }
75             }
76         }
77         return result;
78     }
79 
triggerArrayOOM()80     static boolean triggerArrayOOM() {
81         ArrayMemEater.blowup(new char[128 * 1024][]);
82         return ArrayMemEater.sawOome;
83     }
84 
triggerInstanceOOM()85     static boolean triggerInstanceOOM() {
86         InstanceMemEater memEater = InstanceMemEater.allocate();
87         InstanceMemEater lastMemEater = memEater;
88         do {
89             lastMemEater.next = InstanceMemEater.allocate();
90             lastMemEater = lastMemEater.next;
91         } while (lastMemEater != null);
92         memEater.confuseCompilerOptimization(memEater);
93         InstanceMemEater.hook = null;
94         return InstanceMemEater.sawOome;
95     }
96 
main(String[] args)97     public static void main(String[] args) {
98         if (triggerReflectionOOM()) {
99             System.out.println("Test reflection correctly threw");
100         }
101         if (triggerReflectionOOM2()) {
102             System.out.println("Test reflection2 correctly threw");
103         }
104 
105         if (triggerArrayOOM()) {
106             System.out.println("NEW_ARRAY correctly threw OOME");
107         }
108 
109         if (triggerInstanceOOM()) {
110             System.out.println("NEW_INSTANCE correctly threw OOME");
111         }
112     }
113 
114     static Object[] holder;
115 
blowup()116     public static void blowup() throws Exception {
117         int size = 2 * 1024 * 1024;
118         for (int i = 0; i < holder.length; ) {
119             try {
120                 holder[i] = new char[size];
121                 i++;
122             } catch (OutOfMemoryError oome) {
123                 size = size / 16;
124                 if (size == 0) {
125                      break;
126                 }
127             }
128         }
129         holder[0] = new char[100000];
130     }
131 
triggerReflectionOOM()132     static boolean triggerReflectionOOM() {
133         try {
134             Class<?> c = Main.class;
135             Method m = c.getMethod("blowup");
136             holder = new Object[1000000];
137             m.invoke(null);
138             holder = null;
139             System.out.println("Didn't throw from blowup");
140         } catch (OutOfMemoryError e) {
141             holder = null;
142         } catch (InvocationTargetException e) {
143             holder = null;
144             if (!(e.getCause() instanceof OutOfMemoryError)) {
145                 System.out.println("InvocationTargetException cause not OOME " + e.getCause());
146                 return false;
147             }
148         } catch (Exception e) {
149             holder = null;
150             System.out.println("Unexpected exception " + e);
151             return false;
152         }
153         return true;
154     }
155 
triggerReflectionOOM2()156     static boolean triggerReflectionOOM2() {
157         Object memory = eatAllMemory();
158         boolean result = false;
159         try {
160             Main.class.getDeclaredMethods();
161         } catch (OutOfMemoryError e) {
162             result = true;
163         }
164         if (!result) {
165             boolean memoryWasAllocated = (memory != null);
166             memory = null;
167             System.out.println("memoryWasAllocated = " + memoryWasAllocated);
168         }
169         return result;
170     }
171 }
172