ART: Add option to behave fatally on unmarked kThrow
Add a runtime option that makes the verifier abort when a runtime
exception is signaled for an instruction that isn't marked as such.
Bug: 121245951
Test: m test-art-host
Change-Id: Id953fa25fbcc12c1e6a7d74b30b28b81df57e427
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index afcf40d..fb1e6b7 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -371,6 +371,10 @@
.WithType<bool>()
.WithValueMap({{"true", true}, {"false", false}})
.IntoKey(M::OpaqueJniIds)
+ .Define("-XX:VerifierMissingKThrowFatal=_")
+ .WithType<bool>()
+ .WithValueMap({{"false", false}, {"true", true}})
+ .IntoKey(M::VerifierMissingKThrowFatal)
.Ignore({
"-ea", "-da", "-enableassertions", "-disableassertions", "--runtime-arg", "-esa",
"-dsa", "-enablesystemassertions", "-disablesystemassertions", "-Xrs", "-Xint:_",
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index fe64b8c..8d3fc4e 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -294,7 +294,8 @@
// Initially assume we perceive jank in case the process state is never updated.
process_state_(kProcessStateJankPerceptible),
zygote_no_threads_(false),
- verifier_logging_threshold_ms_(100) {
+ verifier_logging_threshold_ms_(100),
+ verifier_missing_kthrow_fatal_(false) {
static_assert(Runtime::kCalleeSaveSize ==
static_cast<uint32_t>(CalleeSaveType::kLastCalleeSaveType), "Unexpected size");
CheckConstants();
@@ -1149,6 +1150,8 @@
MemMap::Init();
+ verifier_missing_kthrow_fatal_ = runtime_options.GetOrDefault(Opt::VerifierMissingKThrowFatal);
+
// Try to reserve a dedicated fault page. This is allocated for clobbered registers and sentinels.
// If we cannot reserve it, log a warning.
// Note: We allocate this first to have a good chance of grabbing the page. The address (0xebad..)
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 0b880c9..82f7d57 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -895,6 +895,10 @@
return image_space_loading_order_;
}
+ bool IsVerifierMissingKThrowFatal() const {
+ return verifier_missing_kthrow_fatal_;
+ }
+
private:
static void InitPlatformSignalHandlers();
@@ -1240,6 +1244,8 @@
gc::space::ImageSpaceLoadingOrder image_space_loading_order_ =
gc::space::ImageSpaceLoadingOrder::kSystemFirst;
+ bool verifier_missing_kthrow_fatal_;
+
// Note: See comments on GetFaultMessage.
friend std::string GetFaultMessageForAbortLogging();
friend class ScopedThreadPoolUsage;
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index d2594b2..a00bb14 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -169,5 +169,6 @@
gc::space::ImageSpaceLoadingOrder::kSystemFirst)
RUNTIME_OPTIONS_KEY (bool, FastClassNotFoundException, true)
+RUNTIME_OPTIONS_KEY (bool, VerifierMissingKThrowFatal, false)
#undef RUNTIME_OPTIONS_KEY
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 744dc27..26de306 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -5570,6 +5570,10 @@
if ((Instruction::FlagsOf(opcode) & Instruction::kThrow) == 0 &&
!impl::IsCompatThrow(opcode) &&
GetInstructionFlags(work_insn_idx_).IsInTry()) {
+ if (Runtime::Current()->IsVerifierMissingKThrowFatal()) {
+ LOG(FATAL) << "Unexpected throw: " << std::hex << work_insn_idx_ << " " << opcode;
+ UNREACHABLE();
+ }
// We need to save the work_line if the instruction wasn't throwing before. Otherwise
// we'll try to merge garbage.
// Note: this assumes that Fail is called before we do any work_line modifications.