Skip to content

Commit

Permalink
Add file handle leak test (#693)
Browse files Browse the repository at this point in the history
* Add file handle leak test

Add test to check for leaked file handles when installing a module without properly formatted zip data

Signed-off-by: The MathWorks, Inc. <jdicleme@mathworks.com>

* Fix -Werror=missing-field-initializers warning

Signed-off-by: The MathWorks, Inc. <jdicleme@mathworks.com>

* Update OpenFileHandleTest.cpp

Signed-off-by: The MathWorks, Inc. <jdicleme@mathworks.com>
  • Loading branch information
jeffdiclemente committed Jun 24, 2022
1 parent 51ad86a commit 954936f
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 0 deletions.
2 changes: 2 additions & 0 deletions framework/test/bundles/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,5 @@ add_subdirectory(largeBundle)

add_subdirectory(libStartBundleA)
add_subdirectory(libStopBundleA)

add_subdirectory(libTestModuleWithEmbeddedZip)
36 changes: 36 additions & 0 deletions framework/test/bundles/libTestModuleWithEmbeddedZip/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

# This cmake module builds a very specific test module; one with embedded zip data
# that contains NO directories within the zip. This test module is used
# for test cases involving malformed/invalid bundles.
project(TestModuleWithEmbeddedZip)

set(resource_files
test.xml
)

set(_srcs foo.cpp)

add_library(${PROJECT_NAME} ${_srcs})

if(CMAKE_CROSSCOMPILING)
# Cross-compiled builds need to use the imported host version of usResourceCompiler
include(${IMPORT_EXECUTABLES})
set(resource_compiler native-${US_RCC_EXECUTABLE_TARGET})
else()
set(resource_compiler ${US_RCC_EXECUTABLE})
if(TARGET ${US_RCC_EXECUTABLE_TARGET})
set(resource_compiler ${US_RCC_EXECUTABLE_TARGET})
elseif(NOT resource_compiler)
message(FATAL_ERROR "The CppMicroServices resource compiler was not found. Check the US_RCC_EXECUTABLE CMake variable.")
endif()
endif()

add_custom_command(
TARGET ${PROJECT_NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E tar "cf" "${CMAKE_CURRENT_BINARY_DIR}/data.zip" --format=zip -- ${resource_files}
COMMAND ${resource_compiler} -V -b $<TARGET_FILE:${PROJECT_NAME}> -z ${CMAKE_CURRENT_BINARY_DIR}/data.zip
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${resource_compiler}
COMMENT "Embedding zip file into ${PROJECT_NAME}"
VERBATIM)
4 changes: 4 additions & 0 deletions framework/test/bundles/libTestModuleWithEmbeddedZip/foo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

class foo final {
~foo() = default;
};
3 changes: 3 additions & 0 deletions framework/test/bundles/libTestModuleWithEmbeddedZip/test.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>

<foo id="bar">hi</foo>
74 changes: 74 additions & 0 deletions framework/test/gtest/OpenFileHandleTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ limitations under the License.

#include "TestUtilBundleListener.h"
#include "TestUtils.h"
#include "TestingConfig.h"
#include "cppmicroservices/Bundle.h"
#include "cppmicroservices/BundleContext.h"
#include "cppmicroservices/BundleEvent.h"
Expand All @@ -34,6 +35,8 @@ limitations under the License.
#include "cppmicroservices/util/FileSystem.h"
#include "gtest/gtest.h"

#include "miniz.h"

#if defined(US_PLATFORM_WINDOWS)
# include "windows.h"
#elif defined(US_PLATFORM_POSIX)
Expand Down Expand Up @@ -99,6 +102,77 @@ TEST(OpenFileHandleTest, InstallBundle)
<< "The handle counts before and after installing a bundle should not "
"differ.";

f.Stop();
f.WaitForStop(std::chrono::seconds::zero());
}

// Test that file handles do not leak when a bundle fails to install.
TEST(OpenFileHandleTest, InstallBundleFailure)
{
auto f = FrameworkFactory().NewFramework();
ASSERT_TRUE(f);
ASSERT_NO_THROW(f.Start());
auto context = f.GetBundleContext();

auto baselineHandleCount = GetHandleCountForCurrentProcess();

// Test that bogus bundle installs throw the appropriate exception and don't
// leak file handles.
EXPECT_THROW(context.InstallBundles(std::string{}), std::runtime_error);

auto newHandleCounter = GetHandleCountForCurrentProcess();
EXPECT_EQ(baselineHandleCount, newHandleCounter);

EXPECT_THROW(context.InstallBundles(
std::string("\\path\\which\\won't\\exist\\phantom_bundle")),
std::runtime_error);

newHandleCounter = GetHandleCountForCurrentProcess();
EXPECT_EQ(baselineHandleCount, newHandleCounter);

#if defined(US_BUILD_SHARED_LIBS)

// Using miniz APIs to qualify that the test module has the correct
// embedded zip file.
mz_zip_archive zipArchive;
memset(&zipArchive, 0, sizeof(mz_zip_archive));

std::string testModulePath =
cppmicroservices::testing::LIB_PATH + util::DIR_SEP + US_LIB_PREFIX +
"TestModuleWithEmbeddedZip" + US_LIB_POSTFIX + US_LIB_EXT;
EXPECT_TRUE(
mz_zip_reader_init_file(&zipArchive, testModulePath.c_str(), 0));

mz_uint numFiles =
mz_zip_reader_get_num_files(const_cast<mz_zip_archive*>(&zipArchive));
EXPECT_EQ(numFiles, 1) << "Wrong # of files in the zip found.";
for (mz_uint fileIndex = 0; fileIndex < numFiles; ++fileIndex) {
char fileName[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE];
if (mz_zip_reader_get_filename(&zipArchive,
fileIndex,
fileName,
MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE)) {
std::string strFileName{ fileName };
std::size_t pos = strFileName.find_first_of('/');
EXPECT_EQ(pos, std::string::npos)
<< "Found a directory in the zip file where one should not exist.";
}
}

mz_zip_reader_end(&zipArchive);

// Test that a shared library which contains zip formatted data not in
// the format CppMicroServices expects fails correctly and does not leak
// file handles.
EXPECT_THROW(cppmicroservices::testing::InstallLib(
f.GetBundleContext(), "TestModuleWithEmbeddedZip");
, std::runtime_error);

newHandleCounter = GetHandleCountForCurrentProcess();
EXPECT_EQ(baselineHandleCount, newHandleCounter);
#endif

f.Stop();
f.WaitForStop(std::chrono::seconds::zero());
}

0 comments on commit 954936f

Please sign in to comment.