summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathieu Chartier <mathieuc@google.com>2015-04-23 16:32:54 -0700
committerMathieu Chartier <mathieuc@google.com>2015-04-23 17:21:26 -0700
commita61894d88fabe45677f491c9f6bde30059a49026 (patch)
treeb9d8b09e5f90792867b6720a1fb4ab5c76cdfa5f
parent4ceed922d44b68c3fa7cbe670014c9e2e003b92b (diff)
downloadart-a61894d88fabe45677f491c9f6bde30059a49026.zip
art-a61894d88fabe45677f491c9f6bde30059a49026.tar.gz
art-a61894d88fabe45677f491c9f6bde30059a49026.tar.bz2
Fix reflection handling and test flakiness
Fixed reflection invoke to handle exceptions which occur from FindClass or NewObject by throwing these instead of the expected InvocationTargetException. Added test case to 080 for this reflection invoke. Fixed println throwing OOM in 104-growth-limit. Change-Id: I65766e7c3478e299da06fdc3a521fe3f3e8fdba9
-rw-r--r--runtime/reflection.cc12
-rw-r--r--runtime/thread.cc11
-rw-r--r--runtime/thread.h1
-rw-r--r--runtime/well_known_classes.cc2
-rw-r--r--runtime/well_known_classes.h1
-rw-r--r--test/080-oom-throw/expected.txt1
-rw-r--r--test/080-oom-throw/src/Main.java49
-rw-r--r--test/104-growth-limit/src/Main.java6
-rwxr-xr-xtest/etc/run-test-jar3
9 files changed, 79 insertions, 7 deletions
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index e546738..3099094 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -615,11 +615,21 @@ jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject javaM
// Wrap any exception with "Ljava/lang/reflect/InvocationTargetException;" and return early.
if (soa.Self()->IsExceptionPending()) {
+ // If we get another exception when we are trying to wrap, then just use that instead.
jthrowable th = soa.Env()->ExceptionOccurred();
- soa.Env()->ExceptionClear();
+ soa.Self()->ClearException();
jclass exception_class = soa.Env()->FindClass("java/lang/reflect/InvocationTargetException");
+ if (exception_class == nullptr) {
+ soa.Self()->AssertPendingOOMException();
+ return nullptr;
+ }
jmethodID mid = soa.Env()->GetMethodID(exception_class, "<init>", "(Ljava/lang/Throwable;)V");
+ CHECK(mid != nullptr);
jobject exception_instance = soa.Env()->NewObject(exception_class, mid, th);
+ if (exception_instance == nullptr) {
+ soa.Self()->AssertPendingOOMException();
+ return nullptr;
+ }
soa.Env()->Throw(reinterpret_cast<jthrowable>(exception_instance));
return nullptr;
}
diff --git a/runtime/thread.cc b/runtime/thread.cc
index fa65bce..b27ad4a 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1171,9 +1171,14 @@ bool Thread::IsStillStarting() const {
}
void Thread::AssertPendingException() const {
- if (UNLIKELY(!IsExceptionPending())) {
- LOG(FATAL) << "Pending exception expected.";
- }
+ CHECK(IsExceptionPending()) << "Pending exception expected.";
+}
+
+void Thread::AssertPendingOOMException() const {
+ AssertPendingException();
+ auto* e = GetException();
+ CHECK_EQ(e->GetClass(), DecodeJObject(WellKnownClasses::java_lang_OutOfMemoryError)->AsClass())
+ << e->Dump();
}
void Thread::AssertNoPendingException() const {
diff --git a/runtime/thread.h b/runtime/thread.h
index dd9e734..35b785d 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -336,6 +336,7 @@ class Thread {
}
void AssertPendingException() const;
+ void AssertPendingOOMException() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void AssertNoPendingException() const;
void AssertNoPendingExceptionForNewException(const char* msg) const;
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index a803df8..a2d0427 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -39,6 +39,7 @@ jclass WellKnownClasses::java_lang_ClassNotFoundException;
jclass WellKnownClasses::java_lang_Daemons;
jclass WellKnownClasses::java_lang_Error;
jclass WellKnownClasses::java_lang_Object;
+jclass WellKnownClasses::java_lang_OutOfMemoryError;
jclass WellKnownClasses::java_lang_reflect_AbstractMethod;
jclass WellKnownClasses::java_lang_reflect_ArtMethod;
jclass WellKnownClasses::java_lang_reflect_Constructor;
@@ -176,6 +177,7 @@ void WellKnownClasses::Init(JNIEnv* env) {
java_lang_ClassNotFoundException = CacheClass(env, "java/lang/ClassNotFoundException");
java_lang_Daemons = CacheClass(env, "java/lang/Daemons");
java_lang_Object = CacheClass(env, "java/lang/Object");
+ java_lang_OutOfMemoryError = CacheClass(env, "java/lang/OutOfMemoryError");
java_lang_Error = CacheClass(env, "java/lang/Error");
java_lang_reflect_AbstractMethod = CacheClass(env, "java/lang/reflect/AbstractMethod");
java_lang_reflect_ArtMethod = CacheClass(env, "java/lang/reflect/ArtMethod");
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index 2df1c0e..cef9d55 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -50,6 +50,7 @@ struct WellKnownClasses {
static jclass java_lang_Daemons;
static jclass java_lang_Error;
static jclass java_lang_Object;
+ static jclass java_lang_OutOfMemoryError;
static jclass java_lang_reflect_AbstractMethod;
static jclass java_lang_reflect_ArtMethod;
static jclass java_lang_reflect_Constructor;
diff --git a/test/080-oom-throw/expected.txt b/test/080-oom-throw/expected.txt
index 73cc0d8..904393b 100644
--- a/test/080-oom-throw/expected.txt
+++ b/test/080-oom-throw/expected.txt
@@ -1,2 +1,3 @@
+Test reflection correctly threw
NEW_ARRAY correctly threw OOME
NEW_INSTANCE correctly threw OOME
diff --git a/test/080-oom-throw/src/Main.java b/test/080-oom-throw/src/Main.java
index c93f8bb..f007b25 100644
--- a/test/080-oom-throw/src/Main.java
+++ b/test/080-oom-throw/src/Main.java
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
public class Main {
static class ArrayMemEater {
static boolean sawOome;
@@ -68,6 +71,10 @@ public class Main {
}
public static void main(String[] args) {
+ if (triggerReflectionOOM()) {
+ System.out.println("Test reflection correctly threw");
+ }
+
if (triggerArrayOOM()) {
System.out.println("NEW_ARRAY correctly threw OOME");
}
@@ -76,4 +83,46 @@ public class Main {
System.out.println("NEW_INSTANCE correctly threw OOME");
}
}
+
+ static Object[] holder;
+
+ public static void blowup() throws Exception {
+ int size = 32 * 1024 * 1024;
+ for (int i = 0; i < holder.length; ) {
+ try {
+ holder[i] = new char[size];
+ i++;
+ } catch (OutOfMemoryError oome) {
+ size = size / 2;
+ if (size == 0) {
+ break;
+ }
+ }
+ }
+ holder[0] = new char[100000];
+ }
+
+ static boolean triggerReflectionOOM() {
+ try {
+ Class<?> c = Main.class;
+ Method m = c.getMethod("blowup", (Class[]) null);
+ holder = new Object[1000000];
+ m.invoke(null);
+ holder = null;
+ System.out.println("Didn't throw from blowup");
+ } catch (OutOfMemoryError e) {
+ holder = null;
+ } catch (InvocationTargetException e) {
+ holder = null;
+ if (!(e.getCause() instanceof OutOfMemoryError)) {
+ System.out.println("InvocationTargetException cause not OOME " + e.getCause());
+ return false;
+ }
+ } catch (Exception e) {
+ holder = null;
+ System.out.println("Unexpected exception " + e);
+ return false;
+ }
+ return true;
+ }
}
diff --git a/test/104-growth-limit/src/Main.java b/test/104-growth-limit/src/Main.java
index d666377..d31cbf1 100644
--- a/test/104-growth-limit/src/Main.java
+++ b/test/104-growth-limit/src/Main.java
@@ -29,26 +29,28 @@ public class Main {
final Method get_runtime = vm_runtime.getDeclaredMethod("getRuntime");
final Object runtime = get_runtime.invoke(null);
final Method clear_growth_limit = vm_runtime.getDeclaredMethod("clearGrowthLimit");
+ List<byte[]> l = new ArrayList<byte[]>();
try {
- List<byte[]> l = new ArrayList<byte[]>();
while (true) {
// Allocate a MB at a time
l.add(new byte[1048576]);
alloc1++;
}
} catch (OutOfMemoryError e) {
+ l = null;
}
// Expand the heap to the maximum size.
clear_growth_limit.invoke(runtime);
int alloc2 = 1;
+ l = new ArrayList<byte[]>();
try {
- List<byte[]> l = new ArrayList<byte[]>();
while (true) {
// Allocate a MB at a time
l.add(new byte[1048576]);
alloc2++;
}
} catch (OutOfMemoryError e2) {
+ l = null;
if (alloc1 > alloc2) {
System.out.println("ERROR: Allocated less memory after growth" +
"limit cleared (" + alloc1 + " MBs > " + alloc2 + " MBs");
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 414e4df..8dd7573 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -225,7 +225,8 @@ if [ "$DEBUGGER" = "y" ]; then
fi
if [ "$USE_JVM" = "y" ]; then
- ${JAVA} ${DEBUGGER_OPTS} ${JVM_VERIFY_ARG} -classpath classes $MAIN "$@"
+ # Xmx is necessary since we don't pass down the ART flags to JVM.
+ ${JAVA} ${DEBUGGER_OPTS} ${JVM_VERIFY_ARG} -Xmx256m -classpath classes $MAIN "$@"
exit
fi