Add a test for new sun.misc.Cleaner timeout
This is a slightly modified clone of 030-bad-finalizer.
Includes minor fixes for 030-bad-finalizer, in order to keep these
more consistent.
Bug: Bug: 197500807
Test: art/test/run-test --host 2041-bad-cleaner
Change-Id: I801216819154e31a911be48ca79619270f69c8af
diff --git a/test/030-bad-finalizer/expected-stdout.txt b/test/030-bad-finalizer/expected-stdout.txt
index 0aca6f2..a0ae9ab 100644
--- a/test/030-bad-finalizer/expected-stdout.txt
+++ b/test/030-bad-finalizer/expected-stdout.txt
@@ -1,5 +1,5 @@
About to null reference.
-Finalizer started and spinning...
-Finalizer done spinning.
+Finalizer started and sleeping briefly...
+Finalizer done snoozing.
Finalizer sleeping forever now.
exit status: 2
diff --git a/test/030-bad-finalizer/src/Main.java b/test/030-bad-finalizer/src/Main.java
index a912f7d..f33b3aa 100644
--- a/test/030-bad-finalizer/src/Main.java
+++ b/test/030-bad-finalizer/src/Main.java
@@ -54,6 +54,7 @@
try {
args.wait(remainingWait);
} catch (Exception e) {
+ System.out.println("UNEXPECTED EXCEPTION");
}
}
remainingWait = timeout - (System.currentTimeMillis() - waitStart);
@@ -92,14 +93,13 @@
protected void finalize() {
finalizerWait.countDown();
- System.out.println("Finalizer started and spinning...");
+ System.out.println("Finalizer started and sleeping briefly...");
- /* spin for a bit */
long start, end;
start = System.nanoTime();
snooze(2000);
end = System.nanoTime();
- System.out.println("Finalizer done spinning.");
+ System.out.println("Finalizer done snoozing.");
System.out.println("Finalizer sleeping forever now.");
while (true) {
diff --git a/test/2041-bad-cleaner/Android.bp b/test/2041-bad-cleaner/Android.bp
new file mode 100644
index 0000000..e8b779c
--- /dev/null
+++ b/test/2041-bad-cleaner/Android.bp
@@ -0,0 +1,40 @@
+// Generated by `regen-test-files`. Do not edit manually.
+
+// Build rules for ART run-test `2041-bad-cleaner`.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "art_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["art_license"],
+}
+
+// Test's Dex code.
+java_test {
+ name: "art-run-test-2041-bad-cleaner",
+ defaults: ["art-run-test-defaults"],
+ test_config_template: ":art-run-test-target-no-test-suite-tag-template",
+ srcs: ["src/**/*.java"],
+ data: [
+ ":art-run-test-2041-bad-cleaner-expected-stdout",
+ ":art-run-test-2041-bad-cleaner-expected-stderr",
+ ],
+}
+
+// Test's expected standard output.
+genrule {
+ name: "art-run-test-2041-bad-cleaner-expected-stdout",
+ out: ["art-run-test-2041-bad-cleaner-expected-stdout.txt"],
+ srcs: ["expected-stdout.txt"],
+ cmd: "cp -f $(in) $(out)",
+}
+
+// Test's expected standard error.
+genrule {
+ name: "art-run-test-2041-bad-cleaner-expected-stderr",
+ out: ["art-run-test-2041-bad-cleaner-expected-stderr.txt"],
+ srcs: ["expected-stderr.txt"],
+ cmd: "cp -f $(in) $(out)",
+}
diff --git a/test/2041-bad-cleaner/expected-stderr.txt b/test/2041-bad-cleaner/expected-stderr.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/2041-bad-cleaner/expected-stderr.txt
diff --git a/test/2041-bad-cleaner/expected-stdout.txt b/test/2041-bad-cleaner/expected-stdout.txt
new file mode 100644
index 0000000..848a352
--- /dev/null
+++ b/test/2041-bad-cleaner/expected-stdout.txt
@@ -0,0 +1,5 @@
+About to null reference.
+Cleaner started and sleeping briefly...
+Cleaner done snoozing.
+Cleaner sleeping forever now.
+exit status: 2
diff --git a/test/2041-bad-cleaner/info.txt b/test/2041-bad-cleaner/info.txt
new file mode 100644
index 0000000..bb3286d
--- /dev/null
+++ b/test/2041-bad-cleaner/info.txt
@@ -0,0 +1,5 @@
+This is an adaptation of 030-bad-finalizers to Java 8 Cleaners, which
+run directly in the ReferenceQueueDaemon. The Cleaner never finishes.
+ART is expected to detect this situation and abort the VM (so you should
+see a message to that effect in the log output).
+
diff --git a/test/2041-bad-cleaner/run b/test/2041-bad-cleaner/run
new file mode 100755
index 0000000..54747ee
--- /dev/null
+++ b/test/2041-bad-cleaner/run
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# Copyright 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# The test logs error messages which is expected, discard them.
+export ANDROID_LOG_TAGS='*:f'
+
+# Squash the exit status and put it in expected
+./default-run --external-log-tags "${@}"
+echo "exit status:" $?
diff --git a/test/2041-bad-cleaner/src/Main.java b/test/2041-bad-cleaner/src/Main.java
new file mode 100644
index 0000000..72cb5aa
--- /dev/null
+++ b/test/2041-bad-cleaner/src/Main.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import dalvik.system.VMRuntime;
+import sun.misc.Cleaner;
+import java.util.concurrent.CountDownLatch;
+import static java.util.concurrent.TimeUnit.MINUTES;
+
+/**
+ * Test a class with a bad finalizer.
+ *
+ * This test is inherently flaky. It assumes that the system will schedule the finalizer daemon
+ * and finalizer watchdog daemon enough to reach the timeout and throwing the fatal exception.
+ */
+public class Main {
+ public static void main(String[] args) throws Exception {
+ CountDownLatch finalizerWait = new CountDownLatch(1);
+
+ // A separate method to ensure no dex register keeps the object alive.
+ createBadCleanable(finalizerWait);
+
+ // Should have at least two iterations to trigger finalization, but just to make sure run
+ // some more.
+ for (int i = 0; i < 5; i++) {
+ Runtime.getRuntime().gc();
+ }
+
+ // Now wait for the finalizer to start running. Give it a minute.
+ finalizerWait.await(1, MINUTES);
+
+ // Now fall asleep with a timeout. The timeout is large enough that we expect the
+ // finalizer daemon to have killed the process before the deadline elapses.
+ // The timeout is also large enough to cover the extra 5 seconds we wait
+ // to dump threads, plus potentially substantial gcstress overhead.
+ // Note: the timeout is here (instead of an infinite sleep) to protect the test
+ // environment (e.g., in case this is run without a timeout wrapper).
+ final long timeout = 100 * 1000 + VMRuntime.getRuntime().getFinalizerTimeoutMs();
+ long remainingWait = timeout;
+ final long waitStart = System.currentTimeMillis();
+ while (remainingWait > 0) {
+ synchronized (args) { // Just use an already existing object for simplicity...
+ try {
+ args.wait(remainingWait);
+ } catch (Exception e) {
+ System.out.println("UNEXPECTED EXCEPTION");
+ }
+ }
+ remainingWait = timeout - (System.currentTimeMillis() - waitStart);
+ }
+
+ // We should not get here.
+ System.out.println("UNREACHABLE");
+ System.exit(0);
+ }
+
+ private static void createBadCleanable(CountDownLatch finalizerWait) {
+ Object badCleanable = new Object();
+ Runnable badRunnable = new Runnable() {
+ public void run () {
+ finalizerWait.countDown();
+
+ System.out.println("Cleaner started and sleeping briefly...");
+
+ snooze(2000);
+ System.out.println("Cleaner done snoozing.");
+
+ System.out.println("Cleaner sleeping forever now.");
+ while (true) {
+ snooze(500000);
+ }
+ }
+ };
+ final Cleaner badCleaner = Cleaner.create(badCleanable, badRunnable);
+
+ System.out.println("About to null reference.");
+ badCleanable = null; // Not that this would make a difference, could be eliminated earlier.
+ }
+
+ public static void snooze(int ms) {
+ try {
+ Thread.sleep(ms);
+ } catch (InterruptedException ie) {
+ }
+ }
+
+}
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 76b02c3..b828ea4 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -372,7 +372,8 @@
"530-checker-lse2",
"030-bad-finalizer",
"080-oom-throw",
- "1336-short-finalizer-timeout"],
+ "1336-short-finalizer-timeout",
+ "2041-bad-cleaner"],
"bug": "http://b/36377828",
"variant": "interp-ac"
},
@@ -1083,6 +1084,7 @@
"1945-proxy-method-arguments",
"1946-list-descriptors",
"1947-breakpoint-redefine-deopt",
+ "2041-bad-cleaner",
"2230-profile-save-hotness"
],
"variant": "jvm",
diff --git a/test/utils/regen-test-files b/test/utils/regen-test-files
index c98b0f4..5195a43 100755
--- a/test/utils/regen-test-files
+++ b/test/utils/regen-test-files
@@ -213,6 +213,7 @@
# at Main.main(Main.java:56)
#
"2040-huge-native-alloc",
+ "2041-bad-cleaner",
"203-multi-checkpoint",
"2031-zygote-compiled-frame-deopt",
"2033-shutdown-mechanics",