unittests/VMRuntime/NativeFrameTest.cpp (50 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #include "TestHelpers.h" using namespace hermes::hbc; using namespace hermes::vm; namespace { // Count the number of native stack frames we can make before it reports // overflow. Also verify that our stack descends down. static unsigned makeFramesUntilOverflow( Runtime &runtime, ScopedNativeCallFrame *prev) { ScopedNativeCallFrame frame{ runtime, 0, HermesValue::encodeUndefinedValue(), HermesValue::encodeUndefinedValue(), HermesValue::encodeUndefinedValue()}; if (frame.overflowed()) return 0; EXPECT_TRUE(!prev || (*prev)->ptr() < frame->ptr()); return 1 + makeFramesUntilOverflow(runtime, &frame); } using NativeFrameTest = RuntimeTestFixture; TEST_F(NativeFrameTest, OverflowTest) { unsigned maxDepth = makeFramesUntilOverflow(runtime, nullptr); // Save into a local variable in order to avoid linker errors when passed // to gtest. auto expectedMaxDepth = Runtime::MAX_NATIVE_CALL_FRAME_DEPTH; EXPECT_EQ(maxDepth, expectedMaxDepth); } #if HERMES_SLOW_DEBUG TEST(NativeFrameDeathTest, PoisonedStackTest) { auto fn = [] { auto rt = Runtime::create({}); auto &runtime = *rt; // Verify that stack frames are poisoned. ScopedNativeCallFrame frame{ runtime, 0, HermesValue::encodeUndefinedValue(), HermesValue::encodeUndefinedValue(), HermesValue::encodeUndefinedValue()}; ASSERT_FALSE(frame.overflowed()); // We should not die after this because there were no arguments. runtime.collect("test"); // Now make a frame with arguments. ScopedNativeCallFrame frame2{ runtime, 1, HermesValue::encodeUndefinedValue(), HermesValue::encodeUndefinedValue(), HermesValue::encodeUndefinedValue()}; ASSERT_FALSE(frame2.overflowed()); // The frame should be poisoned; ensure we die after a GC. runtime.collect("test"); }; EXPECT_DEATH_IF_SUPPORTED(fn(), "Invalid"); } #endif } // namespace