diff options
| -rw-r--r-- | runtime/fault_handler.cc | 14 | ||||
| -rw-r--r-- | test/305-other-fault-handler/expected.txt | 2 | ||||
| -rw-r--r-- | test/305-other-fault-handler/fault_handler.cc | 102 | ||||
| -rw-r--r-- | test/305-other-fault-handler/info.txt | 3 | ||||
| -rw-r--r-- | test/305-other-fault-handler/src/Main.java | 25 | ||||
| -rw-r--r-- | test/Android.bp | 1 |
6 files changed, 140 insertions, 7 deletions
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc index 49c2a15e86..9d6e5de803 100644 --- a/runtime/fault_handler.cc +++ b/runtime/fault_handler.cc @@ -201,13 +201,13 @@ bool FaultManager::HandleFault(int sig, siginfo_t* info, void* context) { return true; } } + } - // We hit a signal we didn't handle. This might be something for which - // we can give more information about so call all registered handlers to - // see if it is. - if (HandleFaultByOtherHandlers(sig, info, context)) { - return true; - } + // We hit a signal we didn't handle. This might be something for which + // we can give more information about so call all registered handlers to + // see if it is. + if (HandleFaultByOtherHandlers(sig, info, context)) { + return true; } // Set a breakpoint in this function to catch unhandled signals. @@ -232,7 +232,7 @@ void FaultManager::RemoveHandler(FaultHandler* handler) { } auto it2 = std::find(other_handlers_.begin(), other_handlers_.end(), handler); if (it2 != other_handlers_.end()) { - other_handlers_.erase(it); + other_handlers_.erase(it2); return; } LOG(FATAL) << "Attempted to remove non existent handler " << handler; diff --git a/test/305-other-fault-handler/expected.txt b/test/305-other-fault-handler/expected.txt new file mode 100644 index 0000000000..6221e8e853 --- /dev/null +++ b/test/305-other-fault-handler/expected.txt @@ -0,0 +1,2 @@ +JNI_OnLoad called +Passed! diff --git a/test/305-other-fault-handler/fault_handler.cc b/test/305-other-fault-handler/fault_handler.cc new file mode 100644 index 0000000000..f04832613b --- /dev/null +++ b/test/305-other-fault-handler/fault_handler.cc @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2018 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. + */ + + +#include <atomic> +#include <memory> + +#include <jni.h> +#include <signal.h> +#include <stdint.h> +#include <sys/mman.h> + +#include "fault_handler.h" +#include "globals.h" +#include "mem_map.h" + +namespace art { + +class TestFaultHandler FINAL : public FaultHandler { + public: + explicit TestFaultHandler(FaultManager* manager) + : FaultHandler(manager), + map_error_(""), + target_map_(MemMap::MapAnonymous("test-305-mmap", + /* addr */ nullptr, + /* byte_count */ kPageSize, + /* prot */ PROT_NONE, + /* low_4gb */ false, + /* reuse */ false, + /* error_msg */ &map_error_, + /* use_ashmem */ false)), + was_hit_(false) { + CHECK(target_map_ != nullptr) << "Unable to create segfault target address " << map_error_; + manager_->AddHandler(this, /*in_generated_code*/false); + } + + virtual ~TestFaultHandler() { + manager_->RemoveHandler(this); + } + + bool Action(int sig, siginfo_t* siginfo, void* context ATTRIBUTE_UNUSED) OVERRIDE { + CHECK_EQ(sig, SIGSEGV); + CHECK_EQ(reinterpret_cast<uint32_t*>(siginfo->si_addr), + GetTargetPointer()) << "Segfault on unexpected address!"; + CHECK(!was_hit_) << "Recursive signal!"; + was_hit_ = true; + + LOG(INFO) << "SEGV Caught. mprotecting map."; + CHECK(target_map_->Protect(PROT_READ | PROT_WRITE)) << "Failed to mprotect R/W"; + LOG(INFO) << "Setting value to be read."; + *GetTargetPointer() = kDataValue; + LOG(INFO) << "Changing prot to be read-only."; + CHECK(target_map_->Protect(PROT_READ)) << "Failed to mprotect R-only"; + return true; + } + + void CauseSegfault() { + CHECK_EQ(target_map_->GetProtect(), PROT_NONE); + + // This will segfault. The handler should deal with it though and we will get a value out of it. + uint32_t data = *GetTargetPointer(); + + // Prevent re-ordering around the *GetTargetPointer by the compiler + std::atomic_signal_fence(std::memory_order_seq_cst); + + CHECK(was_hit_); + CHECK_EQ(data, kDataValue) << "Unexpected read value from mmap"; + CHECK_EQ(target_map_->GetProtect(), PROT_READ); + LOG(INFO) << "Success!"; + } + + private: + uint32_t* GetTargetPointer() { + return reinterpret_cast<uint32_t*>(target_map_->Begin() + 8); + } + + static constexpr uint32_t kDataValue = 0xDEADBEEF; + + std::string map_error_; + std::unique_ptr<MemMap> target_map_; + bool was_hit_; +}; + +extern "C" JNIEXPORT void JNICALL Java_Main_runFaultHandlerTest(JNIEnv*, jclass) { + std::unique_ptr<TestFaultHandler> handler(new TestFaultHandler(&fault_manager)); + handler->CauseSegfault(); +} + +} // namespace art diff --git a/test/305-other-fault-handler/info.txt b/test/305-other-fault-handler/info.txt new file mode 100644 index 0000000000..656c8bd406 --- /dev/null +++ b/test/305-other-fault-handler/info.txt @@ -0,0 +1,3 @@ +Test that we correctly handle basic non-generated-code fault handlers + +Tests that we can use and remove these handlers and they can change mappings. diff --git a/test/305-other-fault-handler/src/Main.java b/test/305-other-fault-handler/src/Main.java new file mode 100644 index 0000000000..13a6fef730 --- /dev/null +++ b/test/305-other-fault-handler/src/Main.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2018 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. + */ + +public class Main { + public static void main(String[] args) throws Exception { + System.loadLibrary(args[0]); + runFaultHandlerTest(); + System.out.println("Passed!"); + } + + public static native void runFaultHandlerTest(); +} diff --git a/test/Android.bp b/test/Android.bp index f5ca2f0338..49a34a1246 100644 --- a/test/Android.bp +++ b/test/Android.bp @@ -369,6 +369,7 @@ cc_defaults { "154-gc-loop/heap_interface.cc", "167-visit-locks/visit_locks.cc", "203-multi-checkpoint/multi_checkpoint.cc", + "305-other-fault-handler/fault_handler.cc", "454-get-vreg/get_vreg_jni.cc", "457-regs/regs_jni.cc", "461-get-reference-vreg/get_reference_vreg_jni.cc", |