runtime: Add -Xverify:softfail and ART_TEST_INTERPRETER_ACCESS_CHECKS
Use ART_TEST_INTERPRETER_ACCESS_CHECKS=true to run all the tests through
the interpreter with access checks enabled. The normal interpreter tests
do not currently enable access checks, which means that a large part of
the interpreter codebase is untested.
The verifier will force every class into a soft fail mode if
-Xverify:softfail is used, thereby ensuring that if used along with the
interpreter (-Xint) that the interpret is always in access checks mode.
This is used alongside with --compile-filter=verify-at-runtime to
prevent the AOT compiler from putting down any code.
Change-Id: I35a10ed8c43d76fa96133cf01fdad497da387200
diff --git a/build/Android.common_test.mk b/build/Android.common_test.mk
index 45b6490..2f43f5f 100644
--- a/build/Android.common_test.mk
+++ b/build/Android.common_test.mk
@@ -45,6 +45,7 @@
# Do you want interpreter tests run?
ART_TEST_INTERPRETER ?= $(ART_TEST_FULL)
+ART_TEST_INTERPRETER_ACCESS_CHECKS ?= $(ART_TEST_FULL)
# Do you want JIT tests run?
ART_TEST_JIT ?= $(ART_TEST_FULL)
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index 728469c..c70e12d 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -31,7 +31,7 @@
endif
# Use dex2oat debug version for better error reporting
-# $(1): compiler - default, optimizing, jit or interpreter.
+# $(1): compiler - default, optimizing, jit, interpreter or interpreter-access-checks.
# $(2): pic/no-pic
# $(3): 2ND_ or undefined, 2ND_ for 32-bit host builds.
# $(4): wrapper, e.g., valgrind.
@@ -64,12 +64,16 @@
core_compile_options += --compiler-filter=interpret-only
core_infix := -interpreter
endif
+ ifeq ($(1),interpreter-access-checks)
+ core_compile_options += --compiler-filter=verify-at-runtime --runtime-arg -Xverify:softfail
+ core_infix := -interpreter-access-checks
+ endif
ifeq ($(1),default)
# Default has no infix, no compile options.
endif
- ifneq ($(filter-out default interpreter jit optimizing,$(1)),)
+ ifneq ($(filter-out default interpreter interpreter-access-checks jit optimizing,$(1)),)
#Technically this test is not precise, but hopefully good enough.
- $$(error found $(1) expected default, interpreter, jit or optimizing)
+ $$(error found $(1) expected default, interpreter, interpreter-access-checks, jit or optimizing)
endif
ifeq ($(2),pic)
@@ -127,7 +131,7 @@
core_pic_infix :=
endef # create-core-oat-host-rules
-# $(1): compiler - default, optimizing, jit or interpreter.
+# $(1): compiler - default, optimizing, jit, interpreter or interpreter-access-checks.
# $(2): wrapper.
# $(3): dex2oat suffix.
define create-core-oat-host-rule-combination
@@ -143,12 +147,14 @@
$(eval $(call create-core-oat-host-rule-combination,default,,))
$(eval $(call create-core-oat-host-rule-combination,optimizing,,))
$(eval $(call create-core-oat-host-rule-combination,interpreter,,))
+$(eval $(call create-core-oat-host-rule-combination,interpreter-access-checks,,))
valgrindHOST_CORE_IMG_OUTS :=
valgrindHOST_CORE_OAT_OUTS :=
$(eval $(call create-core-oat-host-rule-combination,default,valgrind,32))
$(eval $(call create-core-oat-host-rule-combination,optimizing,valgrind,32))
$(eval $(call create-core-oat-host-rule-combination,interpreter,valgrind,32))
+$(eval $(call create-core-oat-host-rule-combination,interpreter-access-checks,valgrind,32))
valgrind-test-art-host-dex2oat-host: $(valgrindHOST_CORE_IMG_OUTS)
@@ -178,12 +184,16 @@
core_compile_options += --compiler-filter=interpret-only
core_infix := -interpreter
endif
+ ifeq ($(1),interpreter-access-checks)
+ core_compile_options += --compiler-filter=verify-at-runtime --runtime-arg -Xverify:softfail
+ core_infix := -interpreter-access-checks
+ endif
ifeq ($(1),default)
# Default has no infix, no compile options.
endif
- ifneq ($(filter-out default interpreter jit optimizing,$(1)),)
+ ifneq ($(filter-out default interpreter interpreter-access-checks jit optimizing,$(1)),)
# Technically this test is not precise, but hopefully good enough.
- $$(error found $(1) expected default, interpreter, jit or optimizing)
+ $$(error found $(1) expected default, interpreter, interpreter-access-checks, jit or optimizing)
endif
ifeq ($(2),pic)
@@ -246,7 +256,7 @@
core_pic_infix :=
endef # create-core-oat-target-rules
-# $(1): compiler - default, optimizing, jit or interpreter.
+# $(1): compiler - default, optimizing, jit, interpreter or interpreter-access-checks.
# $(2): wrapper.
# $(3): dex2oat suffix.
define create-core-oat-target-rule-combination
@@ -262,12 +272,14 @@
$(eval $(call create-core-oat-target-rule-combination,default,,))
$(eval $(call create-core-oat-target-rule-combination,optimizing,,))
$(eval $(call create-core-oat-target-rule-combination,interpreter,,))
+$(eval $(call create-core-oat-target-rule-combination,interpreter-access-checks,,))
valgrindTARGET_CORE_IMG_OUTS :=
valgrindTARGET_CORE_OAT_OUTS :=
$(eval $(call create-core-oat-target-rule-combination,default,valgrind,32))
$(eval $(call create-core-oat-target-rule-combination,optimizing,valgrind,32))
$(eval $(call create-core-oat-target-rule-combination,interpreter,valgrind,32))
+$(eval $(call create-core-oat-target-rule-combination,interpreter-access-checks,valgrind,32))
valgrind-test-art-host-dex2oat-target: $(valgrindTARGET_CORE_IMG_OUTS)
diff --git a/cmdline/cmdline_parser_test.cc b/cmdline/cmdline_parser_test.cc
index 98fd327..52df7de 100644
--- a/cmdline/cmdline_parser_test.cc
+++ b/cmdline/cmdline_parser_test.cc
@@ -216,9 +216,6 @@
EXPECT_SINGLE_PARSE_EXISTS("-Xzygote", M::Zygote);
EXPECT_SINGLE_PARSE_VALUE_STR("/hello/world", "-Xbootclasspath:/hello/world", M::BootClassPath);
EXPECT_SINGLE_PARSE_VALUE("/hello/world", "-Xbootclasspath:/hello/world", M::BootClassPath);
- EXPECT_SINGLE_PARSE_VALUE(false, "-Xverify:none", M::Verify);
- EXPECT_SINGLE_PARSE_VALUE(true, "-Xverify:remote", M::Verify);
- EXPECT_SINGLE_PARSE_VALUE(true, "-Xverify:all", M::Verify);
EXPECT_SINGLE_PARSE_VALUE(Memory<1>(234), "-Xss234", M::StackSize);
EXPECT_SINGLE_PARSE_VALUE(MemoryKiB(1234*MB), "-Xms1234m", M::MemoryInitialSize);
EXPECT_SINGLE_PARSE_VALUE(true, "-XX:EnableHSpaceCompactForOOM", M::EnableHSpaceCompactForOOM);
@@ -550,6 +547,14 @@
M::ExperimentalLambdas);
}
+// -Xverify:_
+TEST_F(CmdlineParserTest, TestVerify) {
+ EXPECT_SINGLE_PARSE_VALUE(verifier::VerifyMode::kNone, "-Xverify:none", M::Verify);
+ EXPECT_SINGLE_PARSE_VALUE(verifier::VerifyMode::kEnable, "-Xverify:remote", M::Verify);
+ EXPECT_SINGLE_PARSE_VALUE(verifier::VerifyMode::kEnable, "-Xverify:all", M::Verify);
+ EXPECT_SINGLE_PARSE_VALUE(verifier::VerifyMode::kSoftFail, "-Xverify:softfail", M::Verify);
+}
+
TEST_F(CmdlineParserTest, TestIgnoreUnrecognized) {
RuntimeParser::Builder parserBuilder;
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index e0d7708..9325454 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -1950,9 +1950,12 @@
}
state->stats_.managed_code_bytes_ignoring_deduplication += quick_oat_code_size;
+ uint32_t method_access_flags = method->GetAccessFlags();
+
indent_os << StringPrintf("OAT CODE: %p-%p\n", quick_oat_code_begin, quick_oat_code_end);
- indent_os << StringPrintf("SIZE: Dex Instructions=%zd GC=%zd Mapping=%zd\n",
- dex_instruction_bytes, gc_map_bytes, pc_mapping_table_bytes);
+ indent_os << StringPrintf("SIZE: Dex Instructions=%zd GC=%zd Mapping=%zd AccessFlags=0x%x\n",
+ dex_instruction_bytes, gc_map_bytes, pc_mapping_table_bytes,
+ method_access_flags);
size_t total_size = dex_instruction_bytes + gc_map_bytes + pc_mapping_table_bytes +
vmap_table_bytes + quick_oat_code_size + ArtMethod::ObjectSize(image_pointer_size);
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 5798c04..8f7862a 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -3040,6 +3040,18 @@
mirror::Class::SetStatus(klass, mirror::Class::kStatusVerifyingAtRuntime, self);
}
+ // Skip verification if we are forcing a soft fail.
+ // This has to be before the normal verification enabled check,
+ // since technically verification is disabled in this mode.
+ if (UNLIKELY(Runtime::Current()->IsVerificationSoftFail())) {
+ // Force verification to be a 'soft failure'.
+ mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self);
+ // As this is a fake verified status, make sure the methods are _not_ marked preverified
+ // later.
+ klass->SetPreverified();
+ return;
+ }
+
// Skip verification if disabled.
if (!Runtime::Current()->IsVerificationEnabled()) {
mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self);
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index d08af71..7772354 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -244,10 +244,11 @@
.AppendValues()
.IntoKey(M::ImageCompilerOptions)
.Define("-Xverify:_")
- .WithType<bool>()
- .WithValueMap({{"none", false},
- {"remote", true},
- {"all", true}})
+ .WithType<verifier::VerifyMode>()
+ .WithValueMap({{"none", verifier::VerifyMode::kNone},
+ {"remote", verifier::VerifyMode::kEnable},
+ {"all", verifier::VerifyMode::kEnable},
+ {"softfail", verifier::VerifyMode::kSoftFail}})
.IntoKey(M::Verify)
.Define("-XX:NativeBridge=_")
.WithType<std::string>()
@@ -686,7 +687,7 @@
UsageMessage(stream, " -esa\n");
UsageMessage(stream, " -dsa\n");
UsageMessage(stream, " (-enablesystemassertions, -disablesystemassertions)\n");
- UsageMessage(stream, " -Xverify:{none,remote,all}\n");
+ UsageMessage(stream, " -Xverify:{none,remote,all,softfail}\n");
UsageMessage(stream, " -Xrs\n");
UsageMessage(stream, " -Xint:portable, -Xint:fast, -Xint:jit\n");
UsageMessage(stream, " -Xdexopt:{none,verified,all,full}\n");
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 3b0ca9e..c5aece5 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -185,7 +185,7 @@
system_class_loader_(nullptr),
dump_gc_performance_on_shutdown_(false),
preinitialization_transaction_(nullptr),
- verify_(false),
+ verify_(verifier::VerifyMode::kNone),
allow_dex_file_fallback_(true),
target_sdk_version_(0),
implicit_null_checks_(false),
@@ -1757,4 +1757,12 @@
imt_unimplemented_method_ = method;
}
+bool Runtime::IsVerificationEnabled() const {
+ return verify_ == verifier::VerifyMode::kEnable;
+}
+
+bool Runtime::IsVerificationSoftFail() const {
+ return verify_ == verifier::VerifyMode::kSoftFail;
+}
+
} // namespace art
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 9ee96a3..806292f 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -64,6 +64,7 @@
} // namespace mirror
namespace verifier {
class MethodVerifier;
+ enum class VerifyMode : int8_t;
} // namespace verifier
class ArenaPool;
class ArtMethod;
@@ -500,9 +501,8 @@
return !implicit_so_checks_;
}
- bool IsVerificationEnabled() const {
- return verify_;
- }
+ bool IsVerificationEnabled() const;
+ bool IsVerificationSoftFail() const;
bool IsDexFileFallbackEnabled() const {
return allow_dex_file_fallback_;
@@ -700,8 +700,8 @@
// Transaction used for pre-initializing classes at compilation time.
Transaction* preinitialization_transaction_;
- // If false, verification is disabled. True by default.
- bool verify_;
+ // If kNone, verification is disabled. kEnable by default.
+ verifier::VerifyMode verify_;
// If true, the runtime may use dex files directly with the interpreter if an oat file is not
// available/usable.
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index dc4c0c7..9922c5f 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -106,7 +106,8 @@
CompilerOptions) // -Xcompiler-option ...
RUNTIME_OPTIONS_KEY (std::vector<std::string>, \
ImageCompilerOptions) // -Ximage-compiler-option ...
-RUNTIME_OPTIONS_KEY (bool, Verify, true)
+RUNTIME_OPTIONS_KEY (verifier::VerifyMode, \
+ Verify, verifier::VerifyMode::kEnable)
RUNTIME_OPTIONS_KEY (std::string, NativeBridge)
RUNTIME_OPTIONS_KEY (unsigned int, ZygoteMaxFailedBoots, 10)
RUNTIME_OPTIONS_KEY (Unit, NoDexFileFallback)
diff --git a/runtime/runtime_options.h b/runtime/runtime_options.h
index 7e59000..88ac00a 100644
--- a/runtime/runtime_options.h
+++ b/runtime/runtime_options.h
@@ -32,6 +32,7 @@
#include "gc/space/large_object_space.h"
#include "profiler_options.h"
#include "arch/instruction_set.h"
+#include "verifier/verify_mode.h"
#include <stdio.h>
#include <stdarg.h>
diff --git a/runtime/verifier/verify_mode.h b/runtime/verifier/verify_mode.h
new file mode 100644
index 0000000..bea4378
--- /dev/null
+++ b/runtime/verifier/verify_mode.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef ART_RUNTIME_VERIFIER_VERIFY_MODE_H_
+#define ART_RUNTIME_VERIFIER_VERIFY_MODE_H_
+
+#include <stdint.h>
+
+namespace art {
+namespace verifier {
+
+// The mode that the verifier should run as.
+enum class VerifyMode : int8_t {
+ kNone, // Everything is assumed verified.
+ kEnable, // Standard verification, try pre-verifying at compile-time.
+ kSoftFail, // Force a soft fail, punting to the interpreter with access checks.
+};
+
+} // namespace verifier
+} // namespace art
+
+#endif // ART_RUNTIME_VERIFIER_VERIFY_MODE_H_
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 65ddf8d..3d5c483 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -112,6 +112,9 @@
ifeq ($(ART_TEST_DEFAULT_COMPILER),true)
COMPILER_TYPES += default
endif
+ifeq ($(ART_TEST_INTERPRETER_ACCESS_CHECKS),true)
+ COMPILER_TYPES += interpreter-access-checks
+endif
ifeq ($(ART_TEST_INTERPRETER),true)
COMPILER_TYPES += interpreter
endif
@@ -260,6 +263,28 @@
TEST_ART_BROKEN_NO_RELOCATE_TESTS :=
+# Temporarily disable some broken tests when forcing access checks in interpreter b/22414682
+TEST_ART_BROKEN_INTERPRETER_ACCESS_CHECK_TESTS := \
+ 004-JniTest \
+ 005-annotations \
+ 044-proxy \
+ 073-mismatched-field \
+ 088-monitor-verification \
+ 135-MirandaDispatch \
+ 137-cfi \
+ 412-new-array \
+ 471-uninitialized-locals \
+ 506-verify-aput \
+ 800-smali
+
+ifneq (,$(filter interpreter-access-checks,$(COMPILER_TYPES)))
+ ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
+ interpreter-access-checks,$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
+ $(IMAGE_TYPES), $(PICTEST_TYPES), $(DEBUGGABLE_TYPES), $(TEST_ART_BROKEN_INTERPRETER_ACCESS_CHECK_TESTS), $(ALL_ADDRESS_SIZES))
+endif
+
+TEST_ART_BROKEN_INTERPRETER_ACCESS_CHECK_TESTS :=
+
# Tests that are broken with GC stress.
# 137-cfi needs to unwind a second forked process. We're using a primitive sleep to wait till we
# hope the second process got into the expected state. The slowness of gcstress makes this bad.
@@ -604,7 +629,8 @@
# Create a rule to build and run a tests following the form:
# test-art-{1: host or target}-run-test-{2: debug ndebug}-{3: prebuild no-prebuild no-dex2oat}-
-# {4: interpreter default optimizing jit}-{5: relocate nrelocate relocate-npatchoat}-
+# {4: interpreter default optimizing jit interpreter-access-checks}-
+# {5: relocate nrelocate relocate-npatchoat}-
# {6: trace or ntrace}-{7: gcstress gcverify cms}-{8: forcecopy checkjni jni}-
# {9: no-image image picimage}-{10: pictest npictest}-
# {11: ndebuggable debuggable}-{12: test name}{13: 32 or 64}
@@ -674,6 +700,9 @@
ifeq ($(4),interpreter)
test_groups += ART_RUN_TEST_$$(uc_host_or_target)_INTERPRETER_RULES
run_test_options += --interpreter
+ else ifeq ($(4),interpreter-access-checks)
+ test_groups += ART_RUN_TEST_$$(uc_host_or_target)_INTERPRETER_ACCESS_CHECKS_RULES
+ run_test_options += --interpreter --verify-soft-fail
else
ifeq ($(4),default)
test_groups += ART_RUN_TEST_$$(uc_host_or_target)_DEFAULT_RULES
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 842d87e..db64b77 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -42,7 +42,7 @@
TIME_OUT_VALUE=10
USE_GDB="n"
USE_JVM="n"
-VERIFY="y"
+VERIFY="y" # y=yes,n=no,s=softfail
ZYGOTE=""
DEX_VERIFY=""
USE_DEX2OAT_AND_PATCHOAT="y"
@@ -149,6 +149,9 @@
elif [ "x$1" = "x--no-verify" ]; then
VERIFY="n"
shift
+ elif [ "x$1" = "x--verify-soft-fail" ]; then
+ VERIFY="s"
+ shift
elif [ "x$1" = "x--no-optimize" ]; then
OPTIMIZE="n"
shift
@@ -201,7 +204,11 @@
if [ "$VERIFY" = "y" ]; then
JVM_VERIFY_ARG="-Xverify:all"
msg "Performing verification"
- else
+ elif [ "$VERIFY" = "s" ]; then
+ JVM_VERIFY_ARG="Xverify:all"
+ DEX_VERIFY="-Xverify:softfail"
+ msg "Forcing verification to be soft fail"
+ else # VERIFY = "n"
DEX_VERIFY="-Xverify:none"
JVM_VERIFY_ARG="-Xverify:none"
msg "Skipping verification"
@@ -263,7 +270,10 @@
INT_OPTS="-Xint"
if [ "$VERIFY" = "y" ] ; then
COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=interpret-only"
- else
+ elif [ "$VERIFY" = "s" ]; then
+ COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=verify-at-runtime"
+ DEX_VERIFY="${DEX_VERIFY} -Xverify:softfail"
+ else # VERIFY = "n"
COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=verify-none"
DEX_VERIFY="${DEX_VERIFY} -Xverify:none"
fi
diff --git a/test/run-test b/test/run-test
index bdf680b..eabbab3 100755
--- a/test/run-test
+++ b/test/run-test
@@ -262,6 +262,10 @@
elif [ "x$1" = "x--no-verify" ]; then
run_args="${run_args} --no-verify"
shift
+ elif [ "x$1" = "x--verify-soft-fail" ]; then
+ run_args="${run_args} --verify-soft-fail"
+ image_suffix="-interpreter-access-checks"
+ shift
elif [ "x$1" = "x--no-optimize" ]; then
run_args="${run_args} --no-optimize"
shift
@@ -520,6 +524,9 @@
echo " --optimizing Enable optimizing compiler (default)."
echo " --quick Use Quick compiler (off by default)."
echo " --no-verify Turn off verification (on by default)."
+ echo " --verify-soft-fail Force soft fail verification (off by default)."
+ echo " Verification is enabled if neither --no-verify"
+ echo " nor --verify-soft-fail is specified."
echo " --no-optimize Turn off optimization (on by default)."
echo " --no-precise Turn off precise GC (on by default)."
echo " --zygote Spawn the process from the Zygote." \