// Copyright 2014 The Crashpad Authors // // 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 "util/misc/capture_context.h" #include #include #include "build/build_config.h" #include "gtest/gtest.h" #include "util/misc/address_sanitizer.h" #include "util/misc/capture_context_test_util.h" #include "util/misc/memory_sanitizer.h" namespace crashpad { namespace test { namespace { #if BUILDFLAG(IS_FUCHSIA) // Fuchsia uses -fsanitize=safe-stack by default, which splits local variables // and the call stack into separate regions (see // https://clang.llvm.org/docs/SafeStack.html). Because this test would like to // find an approximately valid stack pointer by comparing locals to the // captured one, disable safe-stack for this function. __attribute__((no_sanitize("safe-stack"))) #endif // BUILDFLAG(IS_FUCHSIA) #if defined(MEMORY_SANITIZER) // CaptureContext() calls inline assembly and is incompatible with MSan. __attribute__((no_sanitize("memory"))) #endif // defined(MEMORY_SANITIZER) void TestCaptureContext() { NativeCPUContext context_1; CaptureContext(&context_1); { SCOPED_TRACE("context_1"); ASSERT_NO_FATAL_FAILURE(SanityCheckContext(context_1)); } // The program counter reference value is this function’s address. The // captured program counter should be slightly greater than or equal to the // reference program counter. uintptr_t pc = ProgramCounterFromContext(context_1); #if !defined(ADDRESS_SANITIZER) && !defined(ARCH_CPU_MIPS_FAMILY) && \ !defined(MEMORY_SANITIZER) // Sanitizers can cause enough code bloat that the “nearby” check would // likely fail. const uintptr_t kReferencePC = reinterpret_cast(TestCaptureContext); EXPECT_PRED2([](uintptr_t actual, uintptr_t reference) { return actual - reference < 128u; }, pc, kReferencePC); #endif const uintptr_t sp = StackPointerFromContext(context_1); // Declare context_2 here because all local variables need to be declared // before computing the stack pointer reference value, so that the reference // value can be the lowest value possible. NativeCPUContext context_2; // AddressSanitizer with use-after-return detection causes stack variables to // be allocated on the heap. #if !defined(ADDRESS_SANITIZER) // The stack pointer reference value is the lowest address of a local variable // in this function. The captured program counter will be slightly less than // or equal to the reference stack pointer. const uintptr_t kReferenceSP = std::min(std::min(reinterpret_cast(&context_1), reinterpret_cast(&context_2)), std::min(reinterpret_cast(&pc), reinterpret_cast(&sp))); EXPECT_PRED2([](uintptr_t actual, uintptr_t reference) { return reference - actual < 768u; }, sp, kReferenceSP); #endif // !defined(ADDRESS_SANITIZER) // Capture the context again, expecting that the stack pointer stays the same // and the program counter increases. Strictly speaking, there’s no guarantee // that these conditions will hold, although they do for known compilers even // under typical optimization. CaptureContext(&context_2); { SCOPED_TRACE("context_2"); ASSERT_NO_FATAL_FAILURE(SanityCheckContext(context_2)); } EXPECT_EQ(StackPointerFromContext(context_2), sp); EXPECT_GT(ProgramCounterFromContext(context_2), pc); } TEST(CaptureContext, CaptureContext) { ASSERT_NO_FATAL_FAILURE(TestCaptureContext()); } } // namespace } // namespace test } // namespace crashpad