From b2ca4ae08f2b8b0acb514226c31c731b3c358c7e Mon Sep 17 00:00:00 2001 From: Aaron Jomy Date: Wed, 4 Nov 2026 13:04:27 +0100 Subject: [PATCH] [cppinterop] Delete each test's interpreters when it ends CppInterOpTests kept every interpreter alive for the whole run, about 250 by the end. On a 32-bit Windows build the newest of them sit near the 2 GB address-space limit when the run crashes in a late test. Three tests relied on an interpreter left behind by an earlier test and now create their own. --- .../unittests/CppInterOp/InterpreterTest.cpp | 4 +++- .../unittests/CppInterOp/ScopeReflectionTest.cpp | 1 + .../CppInterOp/unittests/CppInterOp/Utils.cpp | 16 ++++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/interpreter/CppInterOp/unittests/CppInterOp/InterpreterTest.cpp b/interpreter/CppInterOp/unittests/CppInterOp/InterpreterTest.cpp index eb08cbf816efd..ed906a49cd5f4 100644 --- a/interpreter/CppInterOp/unittests/CppInterOp/InterpreterTest.cpp +++ b/interpreter/CppInterOp/unittests/CppInterOp/InterpreterTest.cpp @@ -853,6 +853,7 @@ TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_DetectSystemCompilerIncludePaths) { TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_IncludePaths) { if (TypeParam::isOutOfProcess) GTEST_SKIP() << "Test fails for OOP JIT builds"; + TestFixture::CreateInterpreter(); std::vector includes; Cpp::GetIncludePaths(includes); EXPECT_FALSE(includes.empty()); @@ -955,7 +956,8 @@ TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_GetLanguageStandardGNU) { } TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_ExternalInterpreter) { - + // UseExternalInterpreter must refuse while an interpreter is registered. + TestFixture::CreateInterpreter(); #ifndef CPPINTEROP_USE_CLING llvm::ExitOnError ExitOnErr; diff --git a/interpreter/CppInterOp/unittests/CppInterOp/ScopeReflectionTest.cpp b/interpreter/CppInterOp/unittests/CppInterOp/ScopeReflectionTest.cpp index 749b6eba053c3..2fc5fdc38ef8e 100644 --- a/interpreter/CppInterOp/unittests/CppInterOp/ScopeReflectionTest.cpp +++ b/interpreter/CppInterOp/unittests/CppInterOp/ScopeReflectionTest.cpp @@ -781,6 +781,7 @@ TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_GetUsingNamespaces) { } TYPED_TEST(CPPINTEROP_TEST_MODE, ScopeReflection_GetGlobalScope) { + TestFixture::CreateInterpreter(); EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetGlobalScope()), ""); EXPECT_EQ(Cpp::GetName(Cpp::GetGlobalScope()), ""); } diff --git a/interpreter/CppInterOp/unittests/CppInterOp/Utils.cpp b/interpreter/CppInterOp/unittests/CppInterOp/Utils.cpp index 2192dd4a69d03..885b961f119d0 100644 --- a/interpreter/CppInterOp/unittests/CppInterOp/Utils.cpp +++ b/interpreter/CppInterOp/unittests/CppInterOp/Utils.cpp @@ -44,6 +44,22 @@ bool HasRuntimeModulemaps() { } } +namespace { +// Interpreters do not outlive the test that created them: kept alive, they +// pile up for the whole run and exhaust a 32-bit address space. +class DeleteInterpretersOnTestEnd : public ::testing::EmptyTestEventListener { + void OnTestEnd(const ::testing::TestInfo& /*info*/) override { + while (Cpp::DeleteInterpreter()) + ; + } +}; +[[maybe_unused]] const bool kDeleteInterpretersOnTestEnd = [] { + ::testing::UnitTest::GetInstance()->listeners().Append( + new DeleteInterpretersOnTestEnd); + return true; +}(); +} // namespace + void TestUtils::GetAllTopLevelDecls( const std::string& code, std::vector& Decls, bool filter_implicitGenerated /* = false */,