diff --git a/CMakeLists.txt b/CMakeLists.txt index 7612868f..fc7e64ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,109 +1,109 @@ -cmake_minimum_required(VERSION 3.16) - -# Read version from version.txt (single source of truth) -file(READ "${CMAKE_CURRENT_SOURCE_DIR}/version.txt" VLD_VERSION_RAW) -string(STRIP "${VLD_VERSION_RAW}" VLD_VERSION_STRING) - -project(VLD - VERSION ${VLD_VERSION_STRING} - DESCRIPTION "Visual Leak Detector for Visual C++" - LANGUAGES CXX C -) - -# Generate version.h from version.txt -set(VLD_VERSION_COMMA "${PROJECT_VERSION_MAJOR},${PROJECT_VERSION_MINOR},${PROJECT_VERSION_PATCH},0") -configure_file( - "${CMAKE_CURRENT_SOURCE_DIR}/setup/version.h.in" - "${CMAKE_CURRENT_SOURCE_DIR}/setup/version.h" - @ONLY -) - -# Set C++ standard -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -# Option to enable/disable MFC support -option(VLD_USE_MFC "Build with MFC support (includes MFC test projects)" OFF) - -# Configure output directories -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) - -# Per-configuration output directories -foreach(CONFIG_TYPE ${CMAKE_CONFIGURATION_TYPES}) - string(TOUPPER ${CONFIG_TYPE} CONFIG_TYPE_UPPER) - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CONFIG_TYPE_UPPER} ${CMAKE_BINARY_DIR}/lib/${CONFIG_TYPE}) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CONFIG_TYPE_UPPER} ${CMAKE_BINARY_DIR}/bin/${CONFIG_TYPE}) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CONFIG_TYPE_UPPER} ${CMAKE_BINARY_DIR}/bin/${CONFIG_TYPE}) -endforeach() - -# Platform detection -# Use CMAKE_VS_PLATFORM_NAME for reliable ARM64 detection in Visual Studio generator -# NOTE: This requires Visual Studio generators. For other generators (Ninja, NMake, etc.), -# you would need to detect platform using CMAKE_SYSTEM_PROCESSOR and CMAKE_SIZEOF_VOID_P: -# - Check CMAKE_SYSTEM_PROCESSOR for "ARM64" or "aarch64" -# - Fall back to CMAKE_SIZEOF_VOID_P to distinguish x64 (8 bytes) from Win32 (4 bytes) -if(DEFINED CMAKE_VS_PLATFORM_NAME) - if(CMAKE_VS_PLATFORM_NAME STREQUAL "ARM64") - set(VLD_PLATFORM "ARM64") - set(VLD_PLATFORM_DEFINE "WIN64") - elseif(CMAKE_VS_PLATFORM_NAME STREQUAL "x64") - set(VLD_PLATFORM "x64") - set(VLD_PLATFORM_DEFINE "WIN64") - else() - set(VLD_PLATFORM "Win32") - set(VLD_PLATFORM_DEFINE "WIN32") - endif() -else() - message(FATAL_ERROR "VLD requires Visual Studio generator. CMAKE_VS_PLATFORM_NAME is not defined.") -endif() - -# MSVC specific settings -if(MSVC) - # Default to DLL runtime for tests (they need it for GetProcAddress tests) - # VLD core library overrides this to use static runtime - set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") - - # Common compile options - use highest warning level and treat warnings as errors - add_compile_options(/W4 /WX) - add_link_options(/WX) - - add_compile_definitions( - _CRT_SECURE_NO_WARNINGS - _VARIADIC_MAX=10 - $<$:_DEBUG> - $<$>:NDEBUG> - ) -endif() - -# Status messages -message(STATUS "Configuring Visual Leak Detector v${PROJECT_VERSION}") -message(STATUS "Platform: ${VLD_PLATFORM}") -message(STATUS "MFC Support: ${VLD_USE_MFC}") - -# Enable testing -enable_testing() - -# Google Test configuration - use DLL runtime to match tests -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) -set(BUILD_GMOCK OFF CACHE BOOL "" FORCE) -set(INSTALL_GTEST OFF CACHE BOOL "" FORCE) - -# Add subdirectories -add_subdirectory(lib/gtest) -add_subdirectory(lib/cppformat) -add_subdirectory(src) -add_subdirectory(src/tests) - -# Third-party libraries: don't treat warnings as errors and use static runtime -if(MSVC) - target_compile_options(fmt PRIVATE /W3 /WX-) - set_property(TARGET fmt PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") -endif() - -# IDE folder organization -set_property(GLOBAL PROPERTY USE_FOLDERS ON) -set_target_properties(gtest PROPERTIES FOLDER "Libraries") -set_target_properties(fmt PROPERTIES FOLDER "Libraries") -set_target_properties(vld PROPERTIES FOLDER "VLD") +cmake_minimum_required(VERSION 3.16) + +# Read version from version.txt (single source of truth) +file(READ "${CMAKE_CURRENT_SOURCE_DIR}/version.txt" VLD_VERSION_RAW) +string(STRIP "${VLD_VERSION_RAW}" VLD_VERSION_STRING) + +project(VLD + VERSION ${VLD_VERSION_STRING} + DESCRIPTION "Visual Leak Detector for Visual C++" + LANGUAGES CXX C +) + +# Generate version.h from version.txt +set(VLD_VERSION_COMMA "${PROJECT_VERSION_MAJOR},${PROJECT_VERSION_MINOR},${PROJECT_VERSION_PATCH},0") +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/setup/version.h.in" + "${CMAKE_CURRENT_SOURCE_DIR}/setup/version.h" + @ONLY +) + +# Set C++ standard +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# Option to enable/disable MFC support +option(VLD_USE_MFC "Build with MFC support (includes MFC test projects)" OFF) + +# Configure output directories +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + +# Per-configuration output directories +foreach(CONFIG_TYPE ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER ${CONFIG_TYPE} CONFIG_TYPE_UPPER) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CONFIG_TYPE_UPPER} ${CMAKE_BINARY_DIR}/lib/${CONFIG_TYPE}) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CONFIG_TYPE_UPPER} ${CMAKE_BINARY_DIR}/bin/${CONFIG_TYPE}) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CONFIG_TYPE_UPPER} ${CMAKE_BINARY_DIR}/bin/${CONFIG_TYPE}) +endforeach() + +# Platform detection +# Use CMAKE_VS_PLATFORM_NAME for reliable ARM64 detection in Visual Studio generator +# NOTE: This requires Visual Studio generators. For other generators (Ninja, NMake, etc.), +# you would need to detect platform using CMAKE_SYSTEM_PROCESSOR and CMAKE_SIZEOF_VOID_P: +# - Check CMAKE_SYSTEM_PROCESSOR for "ARM64" or "aarch64" +# - Fall back to CMAKE_SIZEOF_VOID_P to distinguish x64 (8 bytes) from Win32 (4 bytes) +if(DEFINED CMAKE_VS_PLATFORM_NAME) + if(CMAKE_VS_PLATFORM_NAME STREQUAL "ARM64") + set(VLD_PLATFORM "ARM64") + set(VLD_PLATFORM_DEFINE "WIN64") + elseif(CMAKE_VS_PLATFORM_NAME STREQUAL "x64") + set(VLD_PLATFORM "x64") + set(VLD_PLATFORM_DEFINE "WIN64") + else() + set(VLD_PLATFORM "Win32") + set(VLD_PLATFORM_DEFINE "WIN32") + endif() +else() + message(FATAL_ERROR "VLD requires Visual Studio generator. CMAKE_VS_PLATFORM_NAME is not defined.") +endif() + +# MSVC specific settings +if(MSVC) + # Default to DLL runtime for tests (they need it for GetProcAddress tests) + # VLD core library overrides this to use static runtime + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") + + # Common compile options - use highest warning level and treat warnings as errors + add_compile_options(/W4 /WX) + add_link_options(/WX) + + add_compile_definitions( + _CRT_SECURE_NO_WARNINGS + _VARIADIC_MAX=10 + $<$:_DEBUG> + $<$>:NDEBUG> + ) +endif() + +# Status messages +message(STATUS "Configuring Visual Leak Detector v${PROJECT_VERSION}") +message(STATUS "Platform: ${VLD_PLATFORM}") +message(STATUS "MFC Support: ${VLD_USE_MFC}") + +# Enable testing +enable_testing() + +# Google Test configuration - use DLL runtime to match tests +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +set(BUILD_GMOCK OFF CACHE BOOL "" FORCE) +set(INSTALL_GTEST OFF CACHE BOOL "" FORCE) + +# Add subdirectories +add_subdirectory(lib/gtest) +add_subdirectory(lib/cppformat) +add_subdirectory(src) +add_subdirectory(src/tests) + +# Third-party libraries: don't treat warnings as errors and use static runtime +if(MSVC) + target_compile_options(fmt PRIVATE /W3 /WX-) + set_property(TARGET fmt PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") +endif() + +# IDE folder organization +set_property(GLOBAL PROPERTY USE_FOLDERS ON) +set_target_properties(gtest PROPERTIES FOLDER "Libraries") +set_target_properties(fmt PROPERTIES FOLDER "Libraries") +set_target_properties(vld PROPERTIES FOLDER "VLD") diff --git a/COPYING.txt b/COPYING.txt index 073dd57f..658d53eb 100644 --- a/COPYING.txt +++ b/COPYING.txt @@ -55,7 +55,7 @@ modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. - + Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a @@ -111,7 +111,7 @@ modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. - + GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION @@ -146,7 +146,7 @@ such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. - + 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an @@ -158,7 +158,7 @@ Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. - + 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 @@ -216,7 +216,7 @@ instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. - + Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. @@ -267,7 +267,7 @@ Library will still fall under Section 6.) distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. - + 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work @@ -329,7 +329,7 @@ restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. - + 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined @@ -370,7 +370,7 @@ subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. - + 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or @@ -422,7 +422,7 @@ conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. - + 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b8e89936..8272a8ad 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -96,21 +96,21 @@ target_compile_definitions(vld PRIVATE if(MSVC) # VLD core uses static runtime (different from tests which use DLL runtime) set_property(TARGET vld PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") - + # Precompiled header target_precompile_headers(vld PRIVATE stdafx.h) - + # Compiler options - disable inlining in Release/RelWithDebInfo to avoid issues with # __forceinline functions that have their body in .cpp files (bug in source) target_compile_options(vld PRIVATE $<$,$>:/Ob0> # Disable inlining ) - + # Disable C4244 warning for x86 builds (fmt library triggers this with 64-bit to 32-bit conversions) if(VLD_PLATFORM STREQUAL "Win32") target_compile_options(vld PRIVATE /wd4244) endif() - + # Linker settings if(VLD_PLATFORM STREQUAL "ARM64" OR VLD_PLATFORM STREQUAL "x64") # ARM64 and x64 require base address >= 4GB for ASLR optimization @@ -125,7 +125,7 @@ if(MSVC) /BASE:0x03200000 ) endif() - + # Additional Windows libraries target_link_libraries(vld PRIVATE kernel32 diff --git a/src/map.h b/src/map.h index 1c8f456d..6e0b4982 100644 --- a/src/map.h +++ b/src/map.h @@ -156,7 +156,7 @@ class Map { // Return Value: // // Returns the Iterator after it has been incremented. - // + // Iterator& operator ++ (int) { m_node = m_tree->next(m_node); @@ -177,7 +177,7 @@ class Map { // Return Value: // // Returns the Iterator before it has been incremented. - // + // Iterator operator ++ () { typename Tree >::node_t *cur = m_node; diff --git a/src/resource.h b/src/resource.h index c210abbb..2fbdf0f6 100644 --- a/src/resource.h +++ b/src/resource.h @@ -3,7 +3,7 @@ // Used by vld.rc // Next default values for new objects -// +// #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 101 diff --git a/src/set.h b/src/set.h index c3a03865..445ef048 100644 --- a/src/set.h +++ b/src/set.h @@ -106,7 +106,7 @@ class Set { // Return Value: // // Returns the Iterator after it has been incremented. - // + // Iterator& operator ++ (int) { m_node = m_tree->next(m_node); @@ -127,7 +127,7 @@ class Set { // Return Value: // // Returns the Iterator before it has been incremented. - // + // Iterator operator ++ () { typename Tree::node_t *cur = m_node; diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 1b08903d..e9b019bd 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -1,555 +1,555 @@ -# VLD Test Projects -cmake_minimum_required(VERSION 3.16) - -# Common include directories for all tests -set(VLD_TEST_INCLUDE_DIRS - ${CMAKE_SOURCE_DIR}/src - ${CMAKE_SOURCE_DIR}/lib/gtest/googletest/include -) - -# Common function to set up VLD test targets -function(add_vld_test TARGET_NAME) - cmake_parse_arguments(ARG "IS_DLL;USE_MFC;HAS_PCH;NO_UNICODE;NO_TEST;USE_STATIC_CRT;NO_VLD_LINK" "PCH_HEADER" "SOURCES;HEADERS;DEPENDS;DEFINITIONS" ${ARGN}) - - if(ARG_IS_DLL) - add_library(${TARGET_NAME} SHARED ${ARG_SOURCES} ${ARG_HEADERS}) - else() - add_executable(${TARGET_NAME} ${ARG_SOURCES} ${ARG_HEADERS}) - endif() - - target_include_directories(${TARGET_NAME} PRIVATE ${VLD_TEST_INCLUDE_DIRS}) - - # Link to vld (unless NO_VLD_LINK is specified) - if(NOT ARG_NO_VLD_LINK) - target_link_libraries(${TARGET_NAME} PRIVATE vld) - endif() - - # Additional dependencies - if(ARG_DEPENDS) - target_link_libraries(${TARGET_NAME} PRIVATE ${ARG_DEPENDS}) - endif() - - # Definitions - target_compile_definitions(${TARGET_NAME} PRIVATE - _VARIADIC_MAX=10 - $<$:_DEBUG> - $<$>:NDEBUG> - $<$>:VLD_FORCE_ENABLE> - ) - - # Unicode support (most tests need it) - if(NOT ARG_NO_UNICODE) - target_compile_definitions(${TARGET_NAME} PRIVATE UNICODE _UNICODE) - endif() - - if(ARG_DEFINITIONS) - target_compile_definitions(${TARGET_NAME} PRIVATE ${ARG_DEFINITIONS}) - endif() - - target_compile_definitions(${TARGET_NAME} PRIVATE ${VLD_PLATFORM_DEFINE}) - - # MFC support - if(ARG_USE_MFC AND VLD_USE_MFC) - set_target_properties(${TARGET_NAME} PROPERTIES - MFC_FLAG 2 # Use MFC as a shared DLL - ) - target_compile_definitions(${TARGET_NAME} PRIVATE _AFXDLL) - endif() - - # MSVC settings - DLL runtime is set as default in root CMakeLists.txt - if(MSVC) - target_compile_options(${TARGET_NAME} PRIVATE /W3) - - # Override to static CRT if requested (needed for some DLLs like vld_dll1/vld_dll2) - if(ARG_USE_STATIC_CRT) - set_property(TARGET ${TARGET_NAME} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") - endif() - - if(ARG_IS_DLL) - target_link_options(${TARGET_NAME} PRIVATE /SUBSYSTEM:WINDOWS) - else() - target_link_options(${TARGET_NAME} PRIVATE /SUBSYSTEM:CONSOLE) - endif() - endif() - - # Precompiled headers - if(ARG_HAS_PCH AND ARG_PCH_HEADER) - target_precompile_headers(${TARGET_NAME} PRIVATE ${ARG_PCH_HEADER}) - endif() - - # Add to tests folder in IDE - set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests") - - # Register with CTest if it's an executable (not a DLL) and not a helper program - if(NOT ARG_IS_DLL AND NOT ARG_NO_TEST) - add_test( - NAME ${TARGET_NAME} - COMMAND ${TARGET_NAME} - WORKING_DIRECTORY $ - ) - endif() -endfunction() - -# ============================================================================ -# test_basics - Basic VLD tests -# ============================================================================ -add_vld_test(test_basics - SOURCES - basics/Allocs.cpp - basics/basics.cpp - basics/basics_disabled.cpp - basics/stdafx.cpp - HEADERS - basics/Allocs.h - basics/stdafx.h - basics/targetver.h - DEPENDS gtest - HAS_PCH - PCH_HEADER basics/stdafx.h -) - -# ============================================================================ -# testsuite - Main test suite (ANSI build - CharacterSet=NotSet in original) -# ============================================================================ -add_vld_test(testsuite - NO_UNICODE - SOURCES - suite/testsuite.cpp - DEPENDS gtest -) - -# ============================================================================ -# dynamic - Dynamic library for testing (does NOT link VLD - test uses VLDEnableModule) -# ============================================================================ -add_vld_test(dynamic - IS_DLL - NO_VLD_LINK - SOURCES - dynamic_dll/dynamic.cpp - dynamic_dll/stdafx.cpp - basics/Allocs.cpp - HEADERS - dynamic_dll/dynamic.h - dynamic_dll/stdafx.h - dynamic_dll/targetver.h - basics/Allocs.h - DEPENDS gtest - DEFINITIONS DYNAMIC_EXPORTS - HAS_PCH - PCH_HEADER dynamic_dll/stdafx.h -) - -# ============================================================================ -# dynamic_app - Application that uses dynamic DLL -# ============================================================================ -add_vld_test(dynamic_app - SOURCES - dynamic_app/dynamic_app.cpp - dynamic_app/LoadTests.cpp - dynamic_app/ThreadTest.cpp - dynamic_app/stdafx.cpp - HEADERS - dynamic_app/stdafx.h - dynamic_app/targetver.h - DEPENDS dynamic gtest - HAS_PCH - PCH_HEADER dynamic_app/stdafx.h -) - -# Add dependency on test_mfc if MFC is enabled (runtime LoadLibrary dependency) -if(VLD_USE_MFC AND TARGET test_mfc) - add_dependencies(dynamic_app test_mfc) - target_compile_definitions(dynamic_app PRIVATE VLD_MFC_TESTS) -endif() - -# ============================================================================ -# corruption - Memory corruption tests -# ============================================================================ -add_vld_test(corruption - SOURCES - corruption/corruption.cpp - corruption/Tests.cpp - corruption/stdafx.cpp - HEADERS - corruption/stdafx.h - corruption/targetver.h - DEPENDS gtest - HAS_PCH - PCH_HEADER corruption/stdafx.h -) - -# ============================================================================ -# vld_main - Helper program spawned by vld_main_test (not a test itself) -# ============================================================================ -add_vld_test(vld_main - SOURCES - vld_main/vld_main.cpp - vld_main/stdafx.cpp - HEADERS - vld_main/stdafx.h - vld_main/targetver.h - HAS_PCH - PCH_HEADER vld_main/stdafx.h - NO_TEST # This is a helper program, not a standalone test -) - -# ============================================================================ -# tls_init_test - Multi-threaded TLS initialization stress test -# ============================================================================ -add_vld_test(tls_init_test - SOURCES - tls_init_test/tls_init_test.cpp -) - -# ============================================================================ -# vld_main_test - Main VLD test with gtest -# ============================================================================ -add_vld_test(vld_main_test - SOURCES - vld_main_test/vld_main_test.cpp - vld_main_test/stdafx.cpp - HEADERS - vld_main_test/stdafx.h - vld_main_test/targetver.h - DEPENDS gtest - HAS_PCH - PCH_HEADER vld_main_test/stdafx.h -) -# vld_main_test spawns vld_main.exe - ensure it's built first -add_dependencies(vld_main_test vld_main) - -# ============================================================================ -# MFC Tests (only when VLD_USE_MFC is ON) -# ============================================================================ -if(VLD_USE_MFC) - # test_mfc - MFC DLL test - add_vld_test(test_mfc - IS_DLL - USE_MFC - SOURCES - mfc_dll/mfc.cpp - mfc_dll/stdafx.cpp - HEADERS - mfc_dll/mfc.h - mfc_dll/stdafx.h - mfc_dll/targetver.h - mfc_dll/resource.h - HAS_PCH - PCH_HEADER mfc_dll/stdafx.h - ) - - set_target_properties(test_mfc PROPERTIES - VS_MFC_FLAG 2 - ) - - # Module definition file for MFC DLL - if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/mfc_dll/mfc.def) - target_sources(test_mfc PRIVATE mfc_dll/mfc.def) - endif() - - # vldmfc - MFC Application test - add_executable(vldmfc WIN32 - mfc/vldmfc.cpp - mfc/vldmfcdlg.cpp - mfc/StdAfx.cpp - mfc/vldmfc.rc - mfc/vldmfc.h - mfc/vldmfcdlg.h - mfc/resource.h - mfc/StdAfx.h - ) - - target_include_directories(vldmfc PRIVATE ${VLD_TEST_INCLUDE_DIRS}) - target_link_libraries(vldmfc PRIVATE vld) - - target_compile_definitions(vldmfc PRIVATE - VLD_FORCE_ENABLE - _WINDOWS - _AFXDLL - UNICODE - _UNICODE - $<$:_DEBUG> - $<$>:NDEBUG> - ) - - target_compile_definitions(vldmfc PRIVATE ${VLD_PLATFORM_DEFINE}) - - # MFC settings - UseOfMfc=Dynamic corresponds to CMAKE_MFC_FLAG=2 - set_target_properties(vldmfc PROPERTIES - FOLDER "Tests" - VS_GLOBAL_KEYWORD "MFCProj" - ) - # CMake's MFC support requires setting this variable before add_executable - # But since we already added it, we need a workaround using VS generator expression - set_property(TARGET vldmfc PROPERTY VS_GLOBAL_UseOfMfc "Dynamic") - - # MFC requires DLL runtime - set_property(TARGET vldmfc PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") - - target_compile_options(vldmfc PRIVATE /W3) - - # MFC uses its own entry point - just set subsystem - target_link_options(vldmfc PRIVATE /SUBSYSTEM:WINDOWS) - - target_precompile_headers(vldmfc PRIVATE mfc/StdAfx.h) -endif() - -# ============================================================================ -# Console test (optional, simpler test) -# ============================================================================ -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/console/main.cpp) - add_vld_test(vldconsole - SOURCES - console/main.cpp - ) -endif() - -# ============================================================================ -# Static string test -# ============================================================================ -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/static_string_test/static_string_test.cpp) - file(GLOB STATIC_STRING_TEST_SOURCES static_string_test/*.cpp) - file(GLOB STATIC_STRING_TEST_HEADERS static_string_test/*.h) - add_vld_test(static_string_test - SOURCES ${STATIC_STRING_TEST_SOURCES} - HEADERS ${STATIC_STRING_TEST_HEADERS} - DEPENDS gtest - ) -endif() - -# ============================================================================ -# Ignore functions test -# ============================================================================ -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/ignore_functions_test/ignore_functions_test.cpp) - file(GLOB IGNORE_FUNCTIONS_TEST_SOURCES ignore_functions_test/*.cpp) - file(GLOB IGNORE_FUNCTIONS_TEST_HEADERS ignore_functions_test/*.h) - add_vld_test(ignore_functions_test - SOURCES ${IGNORE_FUNCTIONS_TEST_SOURCES} - HEADERS ${IGNORE_FUNCTIONS_TEST_HEADERS} - DEPENDS gtest - ) - - # This test needs its own output subdirectory to avoid vld.ini conflicts with other tests - set_target_properties(ignore_functions_test PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/$/ignore_functions_test" - RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/bin/Debug/ignore_functions_test" - RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/bin/Release/ignore_functions_test" - RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}/bin/RelWithDebInfo/ignore_functions_test" - RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_BINARY_DIR}/bin/MinSizeRel/ignore_functions_test" - ) - - # This test requires its own vld.ini with IgnoreFunctionsList - # Determine dbghelp architecture for copying - if(VLD_PLATFORM STREQUAL "ARM64") - set(DBGHELP_ARCH "arm64") - elseif(VLD_PLATFORM STREQUAL "x64") - set(DBGHELP_ARCH "x64") - else() - set(DBGHELP_ARCH "x86") - endif() - - add_custom_command(TARGET ignore_functions_test POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - "${CMAKE_CURRENT_SOURCE_DIR}/ignore_functions_test/vld.ini" - "$/vld.ini" - COMMAND ${CMAKE_COMMAND} -E copy_if_different - "$" - "$/$" - COMMAND ${CMAKE_COMMAND} -E copy_if_different - "${CMAKE_SOURCE_DIR}/setup/dbghelp/${DBGHELP_ARCH}/dbghelp.dll" - "$/dbghelp.dll" - COMMENT "Copying ignore_functions_test vld.ini, VLD DLL, and dbghelp.dll" - ) -endif() - -# ============================================================================ -# Deep Callstack Test - Tests for excessively long stack traces (PR #37) -# ============================================================================ -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/deep_callstack_test/deep_callstack_test.cpp) - add_vld_test(deep_callstack_test - SOURCES - deep_callstack_test/deep_callstack_test.cpp - ) -endif() - -# ============================================================================ -# VLD DLLs for unload testing -# ============================================================================ -# vld_dll1 -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/vld_dll1) - file(GLOB VLD_DLL1_SOURCES vld_dll1/*.cpp) - file(GLOB VLD_DLL1_HEADERS vld_dll1/*.h) - if(VLD_DLL1_SOURCES) - add_vld_test(vld_dll1 - IS_DLL - SOURCES ${VLD_DLL1_SOURCES} - HEADERS ${VLD_DLL1_HEADERS} - ) - endif() -endif() - -# vld_dll2 -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/vld_dll2) - file(GLOB VLD_DLL2_SOURCES vld_dll2/*.cpp) - file(GLOB VLD_DLL2_HEADERS vld_dll2/*.h) - if(VLD_DLL2_SOURCES) - add_vld_test(vld_dll2 - IS_DLL - SOURCES ${VLD_DLL2_SOURCES} - HEADERS ${VLD_DLL2_HEADERS} - ) - endif() -endif() - -# vld_unload - Uses LoadLibrary at runtime, no link-time dependency on dll1/dll2 -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/vld_unload) - file(GLOB VLD_UNLOAD_SOURCES vld_unload/*.cpp) - file(GLOB VLD_UNLOAD_HEADERS vld_unload/*.h) - if(VLD_UNLOAD_SOURCES) - add_vld_test(vld_unload - SOURCES ${VLD_UNLOAD_SOURCES} - HEADERS ${VLD_UNLOAD_HEADERS} - DEPENDS gtest - ) - # Ensure dll1 and dll2 are built before vld_unload (runtime dependency) - if(TARGET vld_dll1) - add_dependencies(vld_unload vld_dll1) - endif() - if(TARGET vld_dll2) - add_dependencies(vld_unload vld_dll2) - endif() - endif() -endif() - -# ============================================================================ -# COM Test - MFC/ATL COM DLL with IDL compilation -# ============================================================================ -if(VLD_USE_MFC AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/vld_ComTest/ComTest.idl) - # Find MIDL compiler - find_program(MIDL_EXECUTABLE midl) - - if(MIDL_EXECUTABLE) - set(COMTEST_IDL ${CMAKE_CURRENT_SOURCE_DIR}/vld_ComTest/ComTest.idl) - set(COMTEST_GENERATED_DIR ${CMAKE_CURRENT_BINARY_DIR}/vld_ComTest) - - # Generated files from MIDL - set(COMTEST_GENERATED_H ${COMTEST_GENERATED_DIR}/ComTest_i.h) - set(COMTEST_GENERATED_C ${COMTEST_GENERATED_DIR}/ComTest_i.c) - set(COMTEST_GENERATED_P ${COMTEST_GENERATED_DIR}/ComTest_p.c) - set(COMTEST_GENERATED_TLB ${COMTEST_GENERATED_DIR}/ComTest.tlb) - - # Create output directory - file(MAKE_DIRECTORY ${COMTEST_GENERATED_DIR}) - - # Determine target environment for MIDL - if(VLD_PLATFORM STREQUAL "ARM64") - set(MIDL_ENV "arm64") - elseif(VLD_PLATFORM STREQUAL "x64") - set(MIDL_ENV "x64") - else() - set(MIDL_ENV "win32") - endif() - - # Custom command to run MIDL compiler - add_custom_command( - OUTPUT ${COMTEST_GENERATED_H} ${COMTEST_GENERATED_C} ${COMTEST_GENERATED_P} ${COMTEST_GENERATED_TLB} - COMMAND ${MIDL_EXECUTABLE} - /nologo - /env ${MIDL_ENV} - /h ComTest_i.h - /iid ComTest_i.c - /proxy ComTest_p.c - /tlb ComTest.tlb - /Oicf - /out ${COMTEST_GENERATED_DIR} - ${COMTEST_IDL} - DEPENDS ${COMTEST_IDL} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/vld_ComTest - COMMENT "Compiling IDL file: ComTest.idl" - VERBATIM - ) - - # Custom target for IDL compilation - add_custom_target(ComTest_idl DEPENDS - ${COMTEST_GENERATED_H} - ${COMTEST_GENERATED_C} - ) - - # C++ source files (use PCH) - set(COMTEST_CPP_SOURCES - vld_ComTest/ComTest.cpp - vld_ComTest/dllmain.cpp - vld_ComTest/MyMath.cpp - vld_ComTest/stdafx.cpp - ) - - # C source files (no PCH - they're RPC/proxy stubs) - # Note: xdlldata.c includes dlldata.c conditionally via _MERGE_PROXYSTUB - # We only need xdlldata.c and the generated ComTest_i.c - set(COMTEST_C_SOURCES - vld_ComTest/xdlldata.c - ${COMTEST_GENERATED_C} - ) - - # COM Test DLL - add_library(ComTest SHARED - ${COMTEST_CPP_SOURCES} - ${COMTEST_C_SOURCES} - vld_ComTest/ComTest.rc - vld_ComTest/ComTest.def - ) - - # Exclude C files from precompiled header - set_source_files_properties(${COMTEST_C_SOURCES} PROPERTIES - SKIP_PRECOMPILE_HEADERS ON - ) - - # Ensure IDL is compiled before ComTest - add_dependencies(ComTest ComTest_idl) - - target_include_directories(ComTest PRIVATE - ${VLD_TEST_INCLUDE_DIRS} - ${COMTEST_GENERATED_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/vld_ComTest - ) - - target_link_libraries(ComTest PRIVATE vld) - - # Basic definitions - ATL macros are already in stdafx.h - target_compile_definitions(ComTest PRIVATE - _WINDOWS - _USRDLL - _AFXDLL - UNICODE - _UNICODE - $<$:_DEBUG> - $<$>:NDEBUG> - ) - - target_compile_definitions(ComTest PRIVATE ${VLD_PLATFORM_DEFINE}) - - # MFC settings - set_target_properties(ComTest PROPERTIES - FOLDER "Tests" - VS_GLOBAL_KEYWORD "MFCProj" - ) - set_property(TARGET ComTest PROPERTY VS_GLOBAL_UseOfMfc "Dynamic") - - # MFC requires DLL runtime - set_property(TARGET ComTest PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") - - target_compile_options(ComTest PRIVATE /W3) - target_link_options(ComTest PRIVATE /SUBSYSTEM:WINDOWS) - - # Precompiled header for C++ files only - target_precompile_headers(ComTest PRIVATE - "$<$:${CMAKE_CURRENT_SOURCE_DIR}/vld_ComTest/stdafx.h>" - ) - - message(STATUS "COM Test enabled - MIDL found at: ${MIDL_EXECUTABLE}") - else() - message(WARNING "COM Test skipped - MIDL compiler not found") - endif() -endif() - - +# VLD Test Projects +cmake_minimum_required(VERSION 3.16) + +# Common include directories for all tests +set(VLD_TEST_INCLUDE_DIRS + ${CMAKE_SOURCE_DIR}/src + ${CMAKE_SOURCE_DIR}/lib/gtest/googletest/include +) + +# Common function to set up VLD test targets +function(add_vld_test TARGET_NAME) + cmake_parse_arguments(ARG "IS_DLL;USE_MFC;HAS_PCH;NO_UNICODE;NO_TEST;USE_STATIC_CRT;NO_VLD_LINK" "PCH_HEADER" "SOURCES;HEADERS;DEPENDS;DEFINITIONS" ${ARGN}) + + if(ARG_IS_DLL) + add_library(${TARGET_NAME} SHARED ${ARG_SOURCES} ${ARG_HEADERS}) + else() + add_executable(${TARGET_NAME} ${ARG_SOURCES} ${ARG_HEADERS}) + endif() + + target_include_directories(${TARGET_NAME} PRIVATE ${VLD_TEST_INCLUDE_DIRS}) + + # Link to vld (unless NO_VLD_LINK is specified) + if(NOT ARG_NO_VLD_LINK) + target_link_libraries(${TARGET_NAME} PRIVATE vld) + endif() + + # Additional dependencies + if(ARG_DEPENDS) + target_link_libraries(${TARGET_NAME} PRIVATE ${ARG_DEPENDS}) + endif() + + # Definitions + target_compile_definitions(${TARGET_NAME} PRIVATE + _VARIADIC_MAX=10 + $<$:_DEBUG> + $<$>:NDEBUG> + $<$>:VLD_FORCE_ENABLE> + ) + + # Unicode support (most tests need it) + if(NOT ARG_NO_UNICODE) + target_compile_definitions(${TARGET_NAME} PRIVATE UNICODE _UNICODE) + endif() + + if(ARG_DEFINITIONS) + target_compile_definitions(${TARGET_NAME} PRIVATE ${ARG_DEFINITIONS}) + endif() + + target_compile_definitions(${TARGET_NAME} PRIVATE ${VLD_PLATFORM_DEFINE}) + + # MFC support + if(ARG_USE_MFC AND VLD_USE_MFC) + set_target_properties(${TARGET_NAME} PROPERTIES + MFC_FLAG 2 # Use MFC as a shared DLL + ) + target_compile_definitions(${TARGET_NAME} PRIVATE _AFXDLL) + endif() + + # MSVC settings - DLL runtime is set as default in root CMakeLists.txt + if(MSVC) + target_compile_options(${TARGET_NAME} PRIVATE /W3) + + # Override to static CRT if requested (needed for some DLLs like vld_dll1/vld_dll2) + if(ARG_USE_STATIC_CRT) + set_property(TARGET ${TARGET_NAME} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + endif() + + if(ARG_IS_DLL) + target_link_options(${TARGET_NAME} PRIVATE /SUBSYSTEM:WINDOWS) + else() + target_link_options(${TARGET_NAME} PRIVATE /SUBSYSTEM:CONSOLE) + endif() + endif() + + # Precompiled headers + if(ARG_HAS_PCH AND ARG_PCH_HEADER) + target_precompile_headers(${TARGET_NAME} PRIVATE ${ARG_PCH_HEADER}) + endif() + + # Add to tests folder in IDE + set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests") + + # Register with CTest if it's an executable (not a DLL) and not a helper program + if(NOT ARG_IS_DLL AND NOT ARG_NO_TEST) + add_test( + NAME ${TARGET_NAME} + COMMAND ${TARGET_NAME} + WORKING_DIRECTORY $ + ) + endif() +endfunction() + +# ============================================================================ +# test_basics - Basic VLD tests +# ============================================================================ +add_vld_test(test_basics + SOURCES + basics/Allocs.cpp + basics/basics.cpp + basics/basics_disabled.cpp + basics/stdafx.cpp + HEADERS + basics/Allocs.h + basics/stdafx.h + basics/targetver.h + DEPENDS gtest + HAS_PCH + PCH_HEADER basics/stdafx.h +) + +# ============================================================================ +# testsuite - Main test suite (ANSI build - CharacterSet=NotSet in original) +# ============================================================================ +add_vld_test(testsuite + NO_UNICODE + SOURCES + suite/testsuite.cpp + DEPENDS gtest +) + +# ============================================================================ +# dynamic - Dynamic library for testing (does NOT link VLD - test uses VLDEnableModule) +# ============================================================================ +add_vld_test(dynamic + IS_DLL + NO_VLD_LINK + SOURCES + dynamic_dll/dynamic.cpp + dynamic_dll/stdafx.cpp + basics/Allocs.cpp + HEADERS + dynamic_dll/dynamic.h + dynamic_dll/stdafx.h + dynamic_dll/targetver.h + basics/Allocs.h + DEPENDS gtest + DEFINITIONS DYNAMIC_EXPORTS + HAS_PCH + PCH_HEADER dynamic_dll/stdafx.h +) + +# ============================================================================ +# dynamic_app - Application that uses dynamic DLL +# ============================================================================ +add_vld_test(dynamic_app + SOURCES + dynamic_app/dynamic_app.cpp + dynamic_app/LoadTests.cpp + dynamic_app/ThreadTest.cpp + dynamic_app/stdafx.cpp + HEADERS + dynamic_app/stdafx.h + dynamic_app/targetver.h + DEPENDS dynamic gtest + HAS_PCH + PCH_HEADER dynamic_app/stdafx.h +) + +# Add dependency on test_mfc if MFC is enabled (runtime LoadLibrary dependency) +if(VLD_USE_MFC AND TARGET test_mfc) + add_dependencies(dynamic_app test_mfc) + target_compile_definitions(dynamic_app PRIVATE VLD_MFC_TESTS) +endif() + +# ============================================================================ +# corruption - Memory corruption tests +# ============================================================================ +add_vld_test(corruption + SOURCES + corruption/corruption.cpp + corruption/Tests.cpp + corruption/stdafx.cpp + HEADERS + corruption/stdafx.h + corruption/targetver.h + DEPENDS gtest + HAS_PCH + PCH_HEADER corruption/stdafx.h +) + +# ============================================================================ +# vld_main - Helper program spawned by vld_main_test (not a test itself) +# ============================================================================ +add_vld_test(vld_main + SOURCES + vld_main/vld_main.cpp + vld_main/stdafx.cpp + HEADERS + vld_main/stdafx.h + vld_main/targetver.h + HAS_PCH + PCH_HEADER vld_main/stdafx.h + NO_TEST # This is a helper program, not a standalone test +) + +# ============================================================================ +# tls_init_test - Multi-threaded TLS initialization stress test +# ============================================================================ +add_vld_test(tls_init_test + SOURCES + tls_init_test/tls_init_test.cpp +) + +# ============================================================================ +# vld_main_test - Main VLD test with gtest +# ============================================================================ +add_vld_test(vld_main_test + SOURCES + vld_main_test/vld_main_test.cpp + vld_main_test/stdafx.cpp + HEADERS + vld_main_test/stdafx.h + vld_main_test/targetver.h + DEPENDS gtest + HAS_PCH + PCH_HEADER vld_main_test/stdafx.h +) +# vld_main_test spawns vld_main.exe - ensure it's built first +add_dependencies(vld_main_test vld_main) + +# ============================================================================ +# MFC Tests (only when VLD_USE_MFC is ON) +# ============================================================================ +if(VLD_USE_MFC) + # test_mfc - MFC DLL test + add_vld_test(test_mfc + IS_DLL + USE_MFC + SOURCES + mfc_dll/mfc.cpp + mfc_dll/stdafx.cpp + HEADERS + mfc_dll/mfc.h + mfc_dll/stdafx.h + mfc_dll/targetver.h + mfc_dll/resource.h + HAS_PCH + PCH_HEADER mfc_dll/stdafx.h + ) + + set_target_properties(test_mfc PROPERTIES + VS_MFC_FLAG 2 + ) + + # Module definition file for MFC DLL + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/mfc_dll/mfc.def) + target_sources(test_mfc PRIVATE mfc_dll/mfc.def) + endif() + + # vldmfc - MFC Application test + add_executable(vldmfc WIN32 + mfc/vldmfc.cpp + mfc/vldmfcdlg.cpp + mfc/StdAfx.cpp + mfc/vldmfc.rc + mfc/vldmfc.h + mfc/vldmfcdlg.h + mfc/resource.h + mfc/StdAfx.h + ) + + target_include_directories(vldmfc PRIVATE ${VLD_TEST_INCLUDE_DIRS}) + target_link_libraries(vldmfc PRIVATE vld) + + target_compile_definitions(vldmfc PRIVATE + VLD_FORCE_ENABLE + _WINDOWS + _AFXDLL + UNICODE + _UNICODE + $<$:_DEBUG> + $<$>:NDEBUG> + ) + + target_compile_definitions(vldmfc PRIVATE ${VLD_PLATFORM_DEFINE}) + + # MFC settings - UseOfMfc=Dynamic corresponds to CMAKE_MFC_FLAG=2 + set_target_properties(vldmfc PROPERTIES + FOLDER "Tests" + VS_GLOBAL_KEYWORD "MFCProj" + ) + # CMake's MFC support requires setting this variable before add_executable + # But since we already added it, we need a workaround using VS generator expression + set_property(TARGET vldmfc PROPERTY VS_GLOBAL_UseOfMfc "Dynamic") + + # MFC requires DLL runtime + set_property(TARGET vldmfc PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") + + target_compile_options(vldmfc PRIVATE /W3) + + # MFC uses its own entry point - just set subsystem + target_link_options(vldmfc PRIVATE /SUBSYSTEM:WINDOWS) + + target_precompile_headers(vldmfc PRIVATE mfc/StdAfx.h) +endif() + +# ============================================================================ +# Console test (optional, simpler test) +# ============================================================================ +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/console/main.cpp) + add_vld_test(vldconsole + SOURCES + console/main.cpp + ) +endif() + +# ============================================================================ +# Static string test +# ============================================================================ +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/static_string_test/static_string_test.cpp) + file(GLOB STATIC_STRING_TEST_SOURCES static_string_test/*.cpp) + file(GLOB STATIC_STRING_TEST_HEADERS static_string_test/*.h) + add_vld_test(static_string_test + SOURCES ${STATIC_STRING_TEST_SOURCES} + HEADERS ${STATIC_STRING_TEST_HEADERS} + DEPENDS gtest + ) +endif() + +# ============================================================================ +# Ignore functions test +# ============================================================================ +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/ignore_functions_test/ignore_functions_test.cpp) + file(GLOB IGNORE_FUNCTIONS_TEST_SOURCES ignore_functions_test/*.cpp) + file(GLOB IGNORE_FUNCTIONS_TEST_HEADERS ignore_functions_test/*.h) + add_vld_test(ignore_functions_test + SOURCES ${IGNORE_FUNCTIONS_TEST_SOURCES} + HEADERS ${IGNORE_FUNCTIONS_TEST_HEADERS} + DEPENDS gtest + ) + + # This test needs its own output subdirectory to avoid vld.ini conflicts with other tests + set_target_properties(ignore_functions_test PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/$/ignore_functions_test" + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/bin/Debug/ignore_functions_test" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/bin/Release/ignore_functions_test" + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}/bin/RelWithDebInfo/ignore_functions_test" + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_BINARY_DIR}/bin/MinSizeRel/ignore_functions_test" + ) + + # This test requires its own vld.ini with IgnoreFunctionsList + # Determine dbghelp architecture for copying + if(VLD_PLATFORM STREQUAL "ARM64") + set(DBGHELP_ARCH "arm64") + elseif(VLD_PLATFORM STREQUAL "x64") + set(DBGHELP_ARCH "x64") + else() + set(DBGHELP_ARCH "x86") + endif() + + add_custom_command(TARGET ignore_functions_test POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${CMAKE_CURRENT_SOURCE_DIR}/ignore_functions_test/vld.ini" + "$/vld.ini" + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "$" + "$/$" + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${CMAKE_SOURCE_DIR}/setup/dbghelp/${DBGHELP_ARCH}/dbghelp.dll" + "$/dbghelp.dll" + COMMENT "Copying ignore_functions_test vld.ini, VLD DLL, and dbghelp.dll" + ) +endif() + +# ============================================================================ +# Deep Callstack Test - Tests for excessively long stack traces (PR #37) +# ============================================================================ +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/deep_callstack_test/deep_callstack_test.cpp) + add_vld_test(deep_callstack_test + SOURCES + deep_callstack_test/deep_callstack_test.cpp + ) +endif() + +# ============================================================================ +# VLD DLLs for unload testing +# ============================================================================ +# vld_dll1 +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/vld_dll1) + file(GLOB VLD_DLL1_SOURCES vld_dll1/*.cpp) + file(GLOB VLD_DLL1_HEADERS vld_dll1/*.h) + if(VLD_DLL1_SOURCES) + add_vld_test(vld_dll1 + IS_DLL + SOURCES ${VLD_DLL1_SOURCES} + HEADERS ${VLD_DLL1_HEADERS} + ) + endif() +endif() + +# vld_dll2 +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/vld_dll2) + file(GLOB VLD_DLL2_SOURCES vld_dll2/*.cpp) + file(GLOB VLD_DLL2_HEADERS vld_dll2/*.h) + if(VLD_DLL2_SOURCES) + add_vld_test(vld_dll2 + IS_DLL + SOURCES ${VLD_DLL2_SOURCES} + HEADERS ${VLD_DLL2_HEADERS} + ) + endif() +endif() + +# vld_unload - Uses LoadLibrary at runtime, no link-time dependency on dll1/dll2 +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/vld_unload) + file(GLOB VLD_UNLOAD_SOURCES vld_unload/*.cpp) + file(GLOB VLD_UNLOAD_HEADERS vld_unload/*.h) + if(VLD_UNLOAD_SOURCES) + add_vld_test(vld_unload + SOURCES ${VLD_UNLOAD_SOURCES} + HEADERS ${VLD_UNLOAD_HEADERS} + DEPENDS gtest + ) + # Ensure dll1 and dll2 are built before vld_unload (runtime dependency) + if(TARGET vld_dll1) + add_dependencies(vld_unload vld_dll1) + endif() + if(TARGET vld_dll2) + add_dependencies(vld_unload vld_dll2) + endif() + endif() +endif() + +# ============================================================================ +# COM Test - MFC/ATL COM DLL with IDL compilation +# ============================================================================ +if(VLD_USE_MFC AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/vld_ComTest/ComTest.idl) + # Find MIDL compiler + find_program(MIDL_EXECUTABLE midl) + + if(MIDL_EXECUTABLE) + set(COMTEST_IDL ${CMAKE_CURRENT_SOURCE_DIR}/vld_ComTest/ComTest.idl) + set(COMTEST_GENERATED_DIR ${CMAKE_CURRENT_BINARY_DIR}/vld_ComTest) + + # Generated files from MIDL + set(COMTEST_GENERATED_H ${COMTEST_GENERATED_DIR}/ComTest_i.h) + set(COMTEST_GENERATED_C ${COMTEST_GENERATED_DIR}/ComTest_i.c) + set(COMTEST_GENERATED_P ${COMTEST_GENERATED_DIR}/ComTest_p.c) + set(COMTEST_GENERATED_TLB ${COMTEST_GENERATED_DIR}/ComTest.tlb) + + # Create output directory + file(MAKE_DIRECTORY ${COMTEST_GENERATED_DIR}) + + # Determine target environment for MIDL + if(VLD_PLATFORM STREQUAL "ARM64") + set(MIDL_ENV "arm64") + elseif(VLD_PLATFORM STREQUAL "x64") + set(MIDL_ENV "x64") + else() + set(MIDL_ENV "win32") + endif() + + # Custom command to run MIDL compiler + add_custom_command( + OUTPUT ${COMTEST_GENERATED_H} ${COMTEST_GENERATED_C} ${COMTEST_GENERATED_P} ${COMTEST_GENERATED_TLB} + COMMAND ${MIDL_EXECUTABLE} + /nologo + /env ${MIDL_ENV} + /h ComTest_i.h + /iid ComTest_i.c + /proxy ComTest_p.c + /tlb ComTest.tlb + /Oicf + /out ${COMTEST_GENERATED_DIR} + ${COMTEST_IDL} + DEPENDS ${COMTEST_IDL} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/vld_ComTest + COMMENT "Compiling IDL file: ComTest.idl" + VERBATIM + ) + + # Custom target for IDL compilation + add_custom_target(ComTest_idl DEPENDS + ${COMTEST_GENERATED_H} + ${COMTEST_GENERATED_C} + ) + + # C++ source files (use PCH) + set(COMTEST_CPP_SOURCES + vld_ComTest/ComTest.cpp + vld_ComTest/dllmain.cpp + vld_ComTest/MyMath.cpp + vld_ComTest/stdafx.cpp + ) + + # C source files (no PCH - they're RPC/proxy stubs) + # Note: xdlldata.c includes dlldata.c conditionally via _MERGE_PROXYSTUB + # We only need xdlldata.c and the generated ComTest_i.c + set(COMTEST_C_SOURCES + vld_ComTest/xdlldata.c + ${COMTEST_GENERATED_C} + ) + + # COM Test DLL + add_library(ComTest SHARED + ${COMTEST_CPP_SOURCES} + ${COMTEST_C_SOURCES} + vld_ComTest/ComTest.rc + vld_ComTest/ComTest.def + ) + + # Exclude C files from precompiled header + set_source_files_properties(${COMTEST_C_SOURCES} PROPERTIES + SKIP_PRECOMPILE_HEADERS ON + ) + + # Ensure IDL is compiled before ComTest + add_dependencies(ComTest ComTest_idl) + + target_include_directories(ComTest PRIVATE + ${VLD_TEST_INCLUDE_DIRS} + ${COMTEST_GENERATED_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/vld_ComTest + ) + + target_link_libraries(ComTest PRIVATE vld) + + # Basic definitions - ATL macros are already in stdafx.h + target_compile_definitions(ComTest PRIVATE + _WINDOWS + _USRDLL + _AFXDLL + UNICODE + _UNICODE + $<$:_DEBUG> + $<$>:NDEBUG> + ) + + target_compile_definitions(ComTest PRIVATE ${VLD_PLATFORM_DEFINE}) + + # MFC settings + set_target_properties(ComTest PROPERTIES + FOLDER "Tests" + VS_GLOBAL_KEYWORD "MFCProj" + ) + set_property(TARGET ComTest PROPERTY VS_GLOBAL_UseOfMfc "Dynamic") + + # MFC requires DLL runtime + set_property(TARGET ComTest PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") + + target_compile_options(ComTest PRIVATE /W3) + target_link_options(ComTest PRIVATE /SUBSYSTEM:WINDOWS) + + # Precompiled header for C++ files only + target_precompile_headers(ComTest PRIVATE + "$<$:${CMAKE_CURRENT_SOURCE_DIR}/vld_ComTest/stdafx.h>" + ) + + message(STATUS "COM Test enabled - MIDL found at: ${MIDL_EXECUTABLE}") + else() + message(WARNING "COM Test skipped - MIDL compiler not found") + endif() +endif() + + diff --git a/src/tests/basics/Allocs.cpp b/src/tests/basics/Allocs.cpp index 736f91a1..5d43d853 100644 --- a/src/tests/basics/Allocs.cpp +++ b/src/tests/basics/Allocs.cpp @@ -103,11 +103,11 @@ ::testing::AssertionResult AssertCompareCallStacks(const char* actual_expr, // Convert wide string to UTF-8 using Windows API std::string actualLine; if (!wactualLine.empty()) { - int size_needed = WideCharToMultiByte(CP_UTF8, 0, wactualLine.c_str(), + int size_needed = WideCharToMultiByte(CP_UTF8, 0, wactualLine.c_str(), static_cast(wactualLine.size()), nullptr, 0, nullptr, nullptr); if (size_needed > 0) { actualLine.resize(size_needed); - WideCharToMultiByte(CP_UTF8, 0, wactualLine.c_str(), + WideCharToMultiByte(CP_UTF8, 0, wactualLine.c_str(), static_cast(wactualLine.size()), &actualLine[0], size_needed, nullptr, nullptr); } } diff --git a/src/tests/corruption/Tests.cpp b/src/tests/corruption/Tests.cpp index d43a4d81..2fd55f90 100644 --- a/src/tests/corruption/Tests.cpp +++ b/src/tests/corruption/Tests.cpp @@ -34,7 +34,7 @@ void TestAllocationMismatch_newVec_free() void TestHeapMismatch() { - HANDLE test_heap = HeapCreate(HEAP_GENERATE_EXCEPTIONS | HEAP_CREATE_ENABLE_EXECUTE, + HANDLE test_heap = HeapCreate(HEAP_GENERATE_EXCEPTIONS | HEAP_CREATE_ENABLE_EXECUTE, 0, // initialize reserved size; 0); // maximum size can grow HeapSetInformation(test_heap, HeapEnableTerminationOnCorruption, NULL, 0); @@ -47,6 +47,6 @@ void TestHeapMismatch() void* vptr = HeapAlloc(test_heap, 0, 56); // Free this using the WRONG heap! HeapFree( default_heap, 0, vptr); - + HeapDestroy(test_heap); } diff --git a/src/tests/deep_callstack_test/deep_callstack_test.cpp b/src/tests/deep_callstack_test/deep_callstack_test.cpp index f739f359..a9c7cb32 100644 --- a/src/tests/deep_callstack_test/deep_callstack_test.cpp +++ b/src/tests/deep_callstack_test/deep_callstack_test.cpp @@ -1,173 +1,173 @@ -// deep_callstack_test.cpp -// Test to expose crash caused by excessively long stack traces (PR #37) -// -// PROBLEM: -// VLD's Print() function in utility.cpp uses wcstombs_s() with _TRUNCATE to -// convert Unicode messages to ANSI. The output buffer is MAXMESSAGELENGTH=5119 -// bytes. When the message exceeds this size, wcstombs_s() returns STRUNCATE -// (not 0) to indicate successful truncation. The old code treated STRUNCATE -// as an error and called assert(err == 0), causing a crash. -// -// TEST STRATEGY: -// This test creates deeply nested function calls to generate long call stacks, -// then triggers a memory leak to force VLD to print the full stack trace. -// -// BUFFER SIZE CALCULATION: -// - MAXMESSAGELENGTH = 5119 bytes (defined in utility.cpp line ~896) -// - Each stack frame prints approximately: -// " recursive_func_15() + 0x42 (File: deep_callstack_test.cpp, Line: 78)\n" -// which is roughly 70-80 characters per frame -// - 300 frames × ~70 chars = ~21,000 characters (about 4× the 5119 byte buffer) -// - This provides comfortable margin to reliably trigger truncation -// -// NOTE: This is an empirical estimate, not a programmatic check. The test uses -// 300 frames as a "definitely big enough" depth based on the calculation above. -// -// SUCCESS CRITERIA: -// The test completes and prints "Test completed successfully!" without crashing. -// If the STRUNCATE bug exists, this test will crash with an assertion failure. - -#include -#include -#include - -// VLD_FORCE_ENABLE is defined via CMake for non-Debug builds -#include - -// Use volatile to prevent compiler from optimizing away the recursion -volatile int g_depth = 0; -volatile void* g_leak = nullptr; - -// Forward declarations for the recursive chain -// We use multiple functions to create unique stack frames with different names -// This makes the stack trace output longer (each frame has a different function name) - -#define DECLARE_RECURSIVE_FUNC(N) \ - __declspec(noinline) void recursive_func_##N(int depth); - -#define DEFINE_RECURSIVE_FUNC(N, NEXT) \ - __declspec(noinline) void recursive_func_##N(int depth) { \ - volatile char local_buffer[64] = {0}; \ - local_buffer[0] = (char)depth; \ - g_depth = depth; \ - if (depth > 0) { \ - recursive_func_##NEXT(depth - 1); \ - } else { \ - /* At the bottom of the recursion, allocate memory and leak it */ \ - g_leak = malloc(42); \ - printf("Leaked memory at depth %d, address: %p\n", g_depth, g_leak); \ - } \ - } - -// Declare 20 different recursive functions to create varied stack frames -DECLARE_RECURSIVE_FUNC(0) -DECLARE_RECURSIVE_FUNC(1) -DECLARE_RECURSIVE_FUNC(2) -DECLARE_RECURSIVE_FUNC(3) -DECLARE_RECURSIVE_FUNC(4) -DECLARE_RECURSIVE_FUNC(5) -DECLARE_RECURSIVE_FUNC(6) -DECLARE_RECURSIVE_FUNC(7) -DECLARE_RECURSIVE_FUNC(8) -DECLARE_RECURSIVE_FUNC(9) -DECLARE_RECURSIVE_FUNC(10) -DECLARE_RECURSIVE_FUNC(11) -DECLARE_RECURSIVE_FUNC(12) -DECLARE_RECURSIVE_FUNC(13) -DECLARE_RECURSIVE_FUNC(14) -DECLARE_RECURSIVE_FUNC(15) -DECLARE_RECURSIVE_FUNC(16) -DECLARE_RECURSIVE_FUNC(17) -DECLARE_RECURSIVE_FUNC(18) -DECLARE_RECURSIVE_FUNC(19) - -// Define the recursive chain - each function calls the next -DEFINE_RECURSIVE_FUNC(0, 1) -DEFINE_RECURSIVE_FUNC(1, 2) -DEFINE_RECURSIVE_FUNC(2, 3) -DEFINE_RECURSIVE_FUNC(3, 4) -DEFINE_RECURSIVE_FUNC(4, 5) -DEFINE_RECURSIVE_FUNC(5, 6) -DEFINE_RECURSIVE_FUNC(6, 7) -DEFINE_RECURSIVE_FUNC(7, 8) -DEFINE_RECURSIVE_FUNC(8, 9) -DEFINE_RECURSIVE_FUNC(9, 10) -DEFINE_RECURSIVE_FUNC(10, 11) -DEFINE_RECURSIVE_FUNC(11, 12) -DEFINE_RECURSIVE_FUNC(12, 13) -DEFINE_RECURSIVE_FUNC(13, 14) -DEFINE_RECURSIVE_FUNC(14, 15) -DEFINE_RECURSIVE_FUNC(15, 16) -DEFINE_RECURSIVE_FUNC(16, 17) -DEFINE_RECURSIVE_FUNC(17, 18) -DEFINE_RECURSIVE_FUNC(18, 19) - -// Last function in the chain - allocates the leak -__declspec(noinline) void recursive_func_19(int depth) { - volatile char local_buffer[64] = {0}; - local_buffer[0] = (char)depth; - g_depth = depth; - if (depth > 0) { - // Loop back to the first function to continue recursion - recursive_func_0(depth - 1); - } else { - // At the bottom of the recursion, allocate memory and leak it - g_leak = malloc(42); - printf("Leaked memory at final depth, address: %p\n", g_leak); - } -} - -// Test with configurable recursion depth -// Each "cycle" through the 20 functions adds 20 stack frames -// depth=300 means 300 total frames (15 cycles through the 20 functions) -// -// Why 300? See calculation in file header: -// - 300 frames × ~70 chars/frame = ~21KB output -// - MAXMESSAGELENGTH = 5119 bytes -// - 21KB >> 5KB, so truncation is guaranteed -void test_deep_callstack(int total_depth) { - printf("Testing with call stack depth: %d\n", total_depth); - printf("This will generate a stack trace with ~%d frames\n", total_depth); - - // Configure VLD to capture all frames - // MaxTraceFrames is the key - set it high to capture deep stacks - VLDSetOptions(VLD_OPT_TRACE_INTERNAL_FRAMES, (UINT)total_depth + 50, 64); - - // Start the recursive chain - recursive_func_0(total_depth); - - // Force VLD to report the leak now - printf("\n=== Forcing VLD leak report (this may crash if bug exists) ===\n"); - fflush(stdout); - - int leaks = (int)VLDGetLeaksCount(); - printf("VLD reports %d leak(s)\n", leaks); - - VLDReportLeaks(); - - printf("=== VLD report complete (no crash!) ===\n"); -} - -int main(int argc, char* argv[]) { - // Default depth: 300 stack frames - // This generates ~21KB of output, well exceeding MAXMESSAGELENGTH (5119 bytes) - // See file header for detailed calculation - int depth = 300; - - if (argc > 1) { - depth = atoi(argv[1]); - if (depth < 10) depth = 10; - if (depth > 1000) depth = 1000; // Cap to avoid actual stack overflow - } - - printf("Deep Call Stack Test for VLD\n"); - printf("=============================\n"); - printf("This test creates deeply nested function calls to stress-test\n"); - printf("VLD's Print() function with excessively long stack trace messages.\n"); - printf("If PR #37's bug exists, this test will crash.\n\n"); - - test_deep_callstack(depth); - - printf("\nTest completed successfully!\n"); - return 0; // Return 0 = success (VLD handled long stack trace without crash) -} +// deep_callstack_test.cpp +// Test to expose crash caused by excessively long stack traces (PR #37) +// +// PROBLEM: +// VLD's Print() function in utility.cpp uses wcstombs_s() with _TRUNCATE to +// convert Unicode messages to ANSI. The output buffer is MAXMESSAGELENGTH=5119 +// bytes. When the message exceeds this size, wcstombs_s() returns STRUNCATE +// (not 0) to indicate successful truncation. The old code treated STRUNCATE +// as an error and called assert(err == 0), causing a crash. +// +// TEST STRATEGY: +// This test creates deeply nested function calls to generate long call stacks, +// then triggers a memory leak to force VLD to print the full stack trace. +// +// BUFFER SIZE CALCULATION: +// - MAXMESSAGELENGTH = 5119 bytes (defined in utility.cpp line ~896) +// - Each stack frame prints approximately: +// " recursive_func_15() + 0x42 (File: deep_callstack_test.cpp, Line: 78)\n" +// which is roughly 70-80 characters per frame +// - 300 frames × ~70 chars = ~21,000 characters (about 4× the 5119 byte buffer) +// - This provides comfortable margin to reliably trigger truncation +// +// NOTE: This is an empirical estimate, not a programmatic check. The test uses +// 300 frames as a "definitely big enough" depth based on the calculation above. +// +// SUCCESS CRITERIA: +// The test completes and prints "Test completed successfully!" without crashing. +// If the STRUNCATE bug exists, this test will crash with an assertion failure. + +#include +#include +#include + +// VLD_FORCE_ENABLE is defined via CMake for non-Debug builds +#include + +// Use volatile to prevent compiler from optimizing away the recursion +volatile int g_depth = 0; +volatile void* g_leak = nullptr; + +// Forward declarations for the recursive chain +// We use multiple functions to create unique stack frames with different names +// This makes the stack trace output longer (each frame has a different function name) + +#define DECLARE_RECURSIVE_FUNC(N) \ + __declspec(noinline) void recursive_func_##N(int depth); + +#define DEFINE_RECURSIVE_FUNC(N, NEXT) \ + __declspec(noinline) void recursive_func_##N(int depth) { \ + volatile char local_buffer[64] = {0}; \ + local_buffer[0] = (char)depth; \ + g_depth = depth; \ + if (depth > 0) { \ + recursive_func_##NEXT(depth - 1); \ + } else { \ + /* At the bottom of the recursion, allocate memory and leak it */ \ + g_leak = malloc(42); \ + printf("Leaked memory at depth %d, address: %p\n", g_depth, g_leak); \ + } \ + } + +// Declare 20 different recursive functions to create varied stack frames +DECLARE_RECURSIVE_FUNC(0) +DECLARE_RECURSIVE_FUNC(1) +DECLARE_RECURSIVE_FUNC(2) +DECLARE_RECURSIVE_FUNC(3) +DECLARE_RECURSIVE_FUNC(4) +DECLARE_RECURSIVE_FUNC(5) +DECLARE_RECURSIVE_FUNC(6) +DECLARE_RECURSIVE_FUNC(7) +DECLARE_RECURSIVE_FUNC(8) +DECLARE_RECURSIVE_FUNC(9) +DECLARE_RECURSIVE_FUNC(10) +DECLARE_RECURSIVE_FUNC(11) +DECLARE_RECURSIVE_FUNC(12) +DECLARE_RECURSIVE_FUNC(13) +DECLARE_RECURSIVE_FUNC(14) +DECLARE_RECURSIVE_FUNC(15) +DECLARE_RECURSIVE_FUNC(16) +DECLARE_RECURSIVE_FUNC(17) +DECLARE_RECURSIVE_FUNC(18) +DECLARE_RECURSIVE_FUNC(19) + +// Define the recursive chain - each function calls the next +DEFINE_RECURSIVE_FUNC(0, 1) +DEFINE_RECURSIVE_FUNC(1, 2) +DEFINE_RECURSIVE_FUNC(2, 3) +DEFINE_RECURSIVE_FUNC(3, 4) +DEFINE_RECURSIVE_FUNC(4, 5) +DEFINE_RECURSIVE_FUNC(5, 6) +DEFINE_RECURSIVE_FUNC(6, 7) +DEFINE_RECURSIVE_FUNC(7, 8) +DEFINE_RECURSIVE_FUNC(8, 9) +DEFINE_RECURSIVE_FUNC(9, 10) +DEFINE_RECURSIVE_FUNC(10, 11) +DEFINE_RECURSIVE_FUNC(11, 12) +DEFINE_RECURSIVE_FUNC(12, 13) +DEFINE_RECURSIVE_FUNC(13, 14) +DEFINE_RECURSIVE_FUNC(14, 15) +DEFINE_RECURSIVE_FUNC(15, 16) +DEFINE_RECURSIVE_FUNC(16, 17) +DEFINE_RECURSIVE_FUNC(17, 18) +DEFINE_RECURSIVE_FUNC(18, 19) + +// Last function in the chain - allocates the leak +__declspec(noinline) void recursive_func_19(int depth) { + volatile char local_buffer[64] = {0}; + local_buffer[0] = (char)depth; + g_depth = depth; + if (depth > 0) { + // Loop back to the first function to continue recursion + recursive_func_0(depth - 1); + } else { + // At the bottom of the recursion, allocate memory and leak it + g_leak = malloc(42); + printf("Leaked memory at final depth, address: %p\n", g_leak); + } +} + +// Test with configurable recursion depth +// Each "cycle" through the 20 functions adds 20 stack frames +// depth=300 means 300 total frames (15 cycles through the 20 functions) +// +// Why 300? See calculation in file header: +// - 300 frames × ~70 chars/frame = ~21KB output +// - MAXMESSAGELENGTH = 5119 bytes +// - 21KB >> 5KB, so truncation is guaranteed +void test_deep_callstack(int total_depth) { + printf("Testing with call stack depth: %d\n", total_depth); + printf("This will generate a stack trace with ~%d frames\n", total_depth); + + // Configure VLD to capture all frames + // MaxTraceFrames is the key - set it high to capture deep stacks + VLDSetOptions(VLD_OPT_TRACE_INTERNAL_FRAMES, (UINT)total_depth + 50, 64); + + // Start the recursive chain + recursive_func_0(total_depth); + + // Force VLD to report the leak now + printf("\n=== Forcing VLD leak report (this may crash if bug exists) ===\n"); + fflush(stdout); + + int leaks = (int)VLDGetLeaksCount(); + printf("VLD reports %d leak(s)\n", leaks); + + VLDReportLeaks(); + + printf("=== VLD report complete (no crash!) ===\n"); +} + +int main(int argc, char* argv[]) { + // Default depth: 300 stack frames + // This generates ~21KB of output, well exceeding MAXMESSAGELENGTH (5119 bytes) + // See file header for detailed calculation + int depth = 300; + + if (argc > 1) { + depth = atoi(argv[1]); + if (depth < 10) depth = 10; + if (depth > 1000) depth = 1000; // Cap to avoid actual stack overflow + } + + printf("Deep Call Stack Test for VLD\n"); + printf("=============================\n"); + printf("This test creates deeply nested function calls to stress-test\n"); + printf("VLD's Print() function with excessively long stack trace messages.\n"); + printf("If PR #37's bug exists, this test will crash.\n\n"); + + test_deep_callstack(depth); + + printf("\nTest completed successfully!\n"); + return 0; // Return 0 = success (VLD handled long stack trace without crash) +} diff --git a/src/tests/dynamic_dll/dynamic.h b/src/tests/dynamic_dll/dynamic.h index 5de4861b..95237366 100644 --- a/src/tests/dynamic_dll/dynamic.h +++ b/src/tests/dynamic_dll/dynamic.h @@ -1,7 +1,7 @@ -// The following ifdef block is the standard way of creating macros which make exporting +// The following ifdef block is the standard way of creating macros which make exporting // from a DLL simpler. All files within this DLL are compiled with the DYNAMIC_EXPORTS // symbol defined on the command line. This symbol should not be defined on any project -// that uses this DLL. This way any other project whose source files include this file see +// that uses this DLL. This way any other project whose source files include this file see // DYNAMIC_API functions as being imported from a DLL, whereas this DLL sees symbols // defined with this macro as being exported. #ifdef DYNAMIC_EXPORTS diff --git a/src/tests/ignore_functions_test/ignore_functions_test.cpp b/src/tests/ignore_functions_test/ignore_functions_test.cpp index b875475a..2487afe8 100644 --- a/src/tests/ignore_functions_test/ignore_functions_test.cpp +++ b/src/tests/ignore_functions_test/ignore_functions_test.cpp @@ -34,32 +34,32 @@ class TestIgnoreFunctions : public ::testing::Test // these function names in the call stack, so they won't match the IgnoreFunctionsList. // Disabling optimization ensures proper stack frames are created. #pragma optimize("", off) -void* GetOSVersion() +void* GetOSVersion() { void* ptr = new char[32]; // 1 allocation return ptr; } -void* SomeOtherString() +void* SomeOtherString() { void* ptr = new char[32]; // 1 allocation return ptr; } -void* abcdefg() +void* abcdefg() { void* ptr = new char[32]; // 1 allocation return ptr; } -void* testOtherString() +void* testOtherString() { void* ptr = new char[32]; // 1 allocation return ptr; } // This function is NOT in IgnoreFunctionsList -void* NotInTheList() +void* NotInTheList() { void* ptr = new char[32]; // 1 allocation - should be detected as leak return ptr; diff --git a/src/tests/ignore_functions_test/vld.ini b/src/tests/ignore_functions_test/vld.ini index d12b8dcb..69505b38 100644 --- a/src/tests/ignore_functions_test/vld.ini +++ b/src/tests/ignore_functions_test/vld.ini @@ -55,7 +55,7 @@ AggregateDuplicates = no ; Valid Values: Any list containing module names (i.e. names of EXEs or DLLs) ; Default: None. ; -ForceIncludeModules = +ForceIncludeModules = ; Maximum number of data bytes to display for each leaked block. If zero, then ; the data dump is completely suppressed and only call stacks are shown. @@ -65,7 +65,7 @@ ForceIncludeModules = ; Value Values: 0 - 4294967295 ; Default: 256 ; -MaxDataDump = +MaxDataDump = ; Maximum number of call stack frames to trace back during leak detection. ; Limiting this to a low number can reduce the CPU utilization overhead imposed @@ -75,7 +75,7 @@ MaxDataDump = ; Valid Values: 1 - 4294967295 ; Default: 64 ; -MaxTraceFrames = +MaxTraceFrames = ; Sets the type of encoding to use for the generated memory leak report. This ; option is really only useful in conjuction with sending the report to a file. @@ -96,7 +96,7 @@ ReportEncoding = ascii ; Valid Values: Any valid path and filename. ; Default: .\memory_leak_report.txt ; -ReportFile = +ReportFile = ; Sets the report destination to either a file, the debugger, or both. If ; reporting to file is enabled, the report is sent to the file specified by the @@ -126,7 +126,7 @@ SelfTest = off ; ; Valid Values: fast, safe ; Default: fast -; +; StackWalkMethod = fast ; Determines whether memory leak detection should be initially enabled for all @@ -171,7 +171,7 @@ SkipHeapFreeLeaks = no SkipCrtStartupLeaks = yes ; Lists any specific functions to be ignored in memory leak detection. This can -; be useful for false positive functions that report memory leaks especially +; be useful for false positive functions that report memory leaks especially ; when the code is maintained by 3rd party libraries. This option should be ; used only if absolutely necessary and only if you really know what you are ; doing. diff --git a/src/tests/mfc/StdAfx.cpp b/src/tests/mfc/StdAfx.cpp index 52f38aae..107139f1 100644 --- a/src/tests/mfc/StdAfx.cpp +++ b/src/tests/mfc/StdAfx.cpp @@ -3,6 +3,3 @@ // stdafx.obj will contain the pre-compiled type information #include "stdafx.h" - - - diff --git a/src/tests/mfc/resource.h b/src/tests/mfc/resource.h index 016c8c5d..4231b124 100644 --- a/src/tests/mfc/resource.h +++ b/src/tests/mfc/resource.h @@ -10,7 +10,7 @@ #define IDC_CHECK_LEAK 1002 // Next default values for new objects -// +// #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 129 diff --git a/src/tests/mfc/vldmfcdlg.cpp b/src/tests/mfc/vldmfcdlg.cpp index d2cfd03f..085923e4 100644 --- a/src/tests/mfc/vldmfcdlg.cpp +++ b/src/tests/mfc/vldmfcdlg.cpp @@ -111,11 +111,11 @@ BOOL CMFCExampleDlg::OnInitDialog() // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon - + // TODO: Add extra initialization here m_bLeak = TRUE; UpdateData(FALSE); - + return TRUE; // return TRUE unless you set the focus to a control } @@ -136,7 +136,7 @@ void CMFCExampleDlg::OnSysCommand(UINT nID, LPARAM lParam) // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. -void CMFCExampleDlg::OnPaint() +void CMFCExampleDlg::OnPaint() { if (IsIconic()) { diff --git a/src/tests/mfc_dll/mfc.cpp b/src/tests/mfc_dll/mfc.cpp index d8dfaadd..28c9c8b5 100644 --- a/src/tests/mfc_dll/mfc.cpp +++ b/src/tests/mfc_dll/mfc.cpp @@ -24,7 +24,7 @@ // // It is very important that this macro appear in each // function, prior to any calls into MFC. This means that -// it must appear as the first statement within the +// it must appear as the first statement within the // function, even before any object variable declarations // as their constructors may generate calls into the MFC // DLL. @@ -58,7 +58,7 @@ CmfcApp theApp; BOOL CmfcApp::InitInstance() { CWinApp::InitInstance(); - + return TRUE; } @@ -75,7 +75,7 @@ int CmfcApp::ExitInstance() extern "C" void __declspec(dllexport) MFC_LeakSimple() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - + // Attempt to allocate and leak some form of memory CString* str_a = new CString(_T("I am a string in MFC")); CString* str_b = new CString(_T("Another string in MFC")); @@ -87,7 +87,7 @@ extern "C" void __declspec(dllexport) MFC_LeakSimple() extern "C" void __declspec(dllexport) MFC_LeakArray() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); - + // Attempt to allocate and leak an array of CStrings CString* mystr = new CString[3]; diff --git a/src/tests/static_string_test/static_string.h b/src/tests/static_string_test/static_string.h index e93c6d62..c0948039 100644 --- a/src/tests/static_string_test/static_string.h +++ b/src/tests/static_string_test/static_string.h @@ -1,10 +1,10 @@ -#pragma once - -#include - -namespace my_string -{ - const std::string the_string("foobar"); -} - +#pragma once + +#include + +namespace my_string +{ + const std::string the_string("foobar"); +} + const std::string string_global("xyz1234567"); \ No newline at end of file diff --git a/src/tests/static_string_test/static_string_test.cpp b/src/tests/static_string_test/static_string_test.cpp index 41ff6890..0dd75e46 100644 --- a/src/tests/static_string_test/static_string_test.cpp +++ b/src/tests/static_string_test/static_string_test.cpp @@ -4,9 +4,9 @@ #include "stdafx.h" #include "vld.h" #include "static_string.h" - -#include - + +#include + class StaticStringTest : public ::testing::Test { virtual void SetUp() @@ -18,34 +18,34 @@ class StaticStringTest : public ::testing::Test // Check that callstack resolved without unresolved functions (required symbols for all dll's) EXPECT_EQ(0, VLDResolveCallstacks()); } -}; - -void access_strings() -{ - // Just do something with the string so it isn't optimized away +}; + +void access_strings() +{ + // Just do something with the string so it isn't optimized away std::string copied_string = my_string::the_string; - printf("Copied string %s\n", copied_string.c_str()); - + printf("Copied string %s\n", copied_string.c_str()); + std::string copied_string2 = string_global; - printf("Copied string %s\n", copied_string2.c_str()); -} - + printf("Copied string %s\n", copied_string2.c_str()); +} + TEST_F(StaticStringTest, StaticStringsSuccess) -{ +{ int leaks = static_cast(VLDGetLeaksCount()); - ASSERT_EQ(0, leaks); - - access_strings(); - - leaks = static_cast(VLDGetLeaksCount()); - ASSERT_EQ(0, leaks); - -} - -int main(int argc, char **argv) -{ - ::testing::InitGoogleTest(&argc, argv); - int res = RUN_ALL_TESTS(); - VLDMarkAllLeaksAsReported(); + ASSERT_EQ(0, leaks); + + access_strings(); + + leaks = static_cast(VLDGetLeaksCount()); + ASSERT_EQ(0, leaks); + +} + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + int res = RUN_ALL_TESTS(); + VLDMarkAllLeaksAsReported(); return res; } diff --git a/src/tests/tls_init_test/tls_init_test.cpp b/src/tests/tls_init_test/tls_init_test.cpp index 9d6756dc..2acd76c8 100644 --- a/src/tests/tls_init_test/tls_init_test.cpp +++ b/src/tests/tls_init_test/tls_init_test.cpp @@ -1,113 +1,113 @@ -// Multi-threaded TLS initialization stress test -// -// This test spawns multiple threads that simultaneously perform their first -// allocations, stressing VLD's per-thread TLS (Thread Local Storage) initialization. -// -// What it tests: -// - Multiple threads calling getTls() concurrently -// - VLD's CriticalSection protection during TLS map operations -// - First allocation in each thread triggers TLS structure creation -// - Recursive CriticalSection behavior (same thread can re-acquire) -// -// Thread flow: -// 1. Thread calls malloc() -> _RtlAllocateHeap hook -// 2. Hook calls getTls() to get thread-local state -// 3. If first time: getTls() takes m_tlsLock, calls new tls_t -// 4. new tls_t may trigger _RtlAllocateHeap again (recursive) -// 5. Recursive call also calls getTls() -// 6. Windows CriticalSection is recursive - same thread can re-acquire -// 7. Second getTls() finds TLS already in map (inserted by first call) -// 8. Both calls complete successfully -// -// This test verifies VLD handles concurrent TLS initialization across threads -// and recursive calls within a single thread during TLS initialization. - -#include -#include -#include - -// Number of threads to spawn - more threads = more likely to hit the race -#define NUM_THREADS 50 - -// Simple barrier to make all threads start at once -volatile LONG g_readyCount = 0; -volatile LONG g_goFlag = 0; - -DWORD WINAPI ThreadFunc(LPVOID param) -{ - int threadId = (int)(INT_PTR)param; - - // Signal we're ready - InterlockedIncrement(&g_readyCount); - - // Wait for all threads to be ready - while (g_goFlag == 0) { - Sleep(0); - } - - // This is the first allocation in this thread - // Tests VLD's handling of concurrent TLS initialization - void* ptr = malloc(100); - - // Do more allocations to stress test - for (int i = 0; i < 10; i++) { - void* temp = malloc(i * 10 + 1); - free(temp); - } - - free(ptr); - - return 0; -} - -int main() -{ - printf("TLS Initialization Stress Test\n"); - printf("===============================\n"); - printf("Testing VLD's handling of concurrent TLS initialization.\n"); - printf("Creating %d threads that will all allocate simultaneously...\n\n", NUM_THREADS); - - HANDLE threads[NUM_THREADS]; - - // Create all threads (they'll wait at barrier) - for (int i = 0; i < NUM_THREADS; i++) { - threads[i] = CreateThread(NULL, 0, ThreadFunc, (LPVOID)(INT_PTR)i, 0, NULL); - if (threads[i] == NULL) { - printf("Failed to create thread %d\n", i); - return 1; - } - } - - // Wait for all threads to be ready - while (g_readyCount < NUM_THREADS) { - Sleep(1); - } - - printf("All threads ready, releasing them simultaneously...\n"); - - // Release all threads at once to maximize race condition - g_goFlag = 1; - - // Wait for all threads to complete - DWORD result = WaitForMultipleObjects(NUM_THREADS, threads, TRUE, 30000); // 30 second timeout - - if (result == WAIT_TIMEOUT) { - printf("\nFAILED: Threads deadlocked or hung (likely infinite recursion)\n"); - printf("This indicates the TLS initialization bug is present.\n"); - return 1; - } else if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + NUM_THREADS) { - printf("SUCCESS: All threads completed without crashing\n"); - printf("The s_inVldCall reentrancy protection is working correctly.\n"); - } else { - printf("FAILED: WaitForMultipleObjects returned unexpected result: 0x%X\n", result); - return 1; - } - - // Clean up - for (int i = 0; i < NUM_THREADS; i++) { - CloseHandle(threads[i]); - } - - printf("\nTest PASSED: TLS initialization is properly protected from reentrancy\n"); - return 0; -} +// Multi-threaded TLS initialization stress test +// +// This test spawns multiple threads that simultaneously perform their first +// allocations, stressing VLD's per-thread TLS (Thread Local Storage) initialization. +// +// What it tests: +// - Multiple threads calling getTls() concurrently +// - VLD's CriticalSection protection during TLS map operations +// - First allocation in each thread triggers TLS structure creation +// - Recursive CriticalSection behavior (same thread can re-acquire) +// +// Thread flow: +// 1. Thread calls malloc() -> _RtlAllocateHeap hook +// 2. Hook calls getTls() to get thread-local state +// 3. If first time: getTls() takes m_tlsLock, calls new tls_t +// 4. new tls_t may trigger _RtlAllocateHeap again (recursive) +// 5. Recursive call also calls getTls() +// 6. Windows CriticalSection is recursive - same thread can re-acquire +// 7. Second getTls() finds TLS already in map (inserted by first call) +// 8. Both calls complete successfully +// +// This test verifies VLD handles concurrent TLS initialization across threads +// and recursive calls within a single thread during TLS initialization. + +#include +#include +#include + +// Number of threads to spawn - more threads = more likely to hit the race +#define NUM_THREADS 50 + +// Simple barrier to make all threads start at once +volatile LONG g_readyCount = 0; +volatile LONG g_goFlag = 0; + +DWORD WINAPI ThreadFunc(LPVOID param) +{ + int threadId = (int)(INT_PTR)param; + + // Signal we're ready + InterlockedIncrement(&g_readyCount); + + // Wait for all threads to be ready + while (g_goFlag == 0) { + Sleep(0); + } + + // This is the first allocation in this thread + // Tests VLD's handling of concurrent TLS initialization + void* ptr = malloc(100); + + // Do more allocations to stress test + for (int i = 0; i < 10; i++) { + void* temp = malloc(i * 10 + 1); + free(temp); + } + + free(ptr); + + return 0; +} + +int main() +{ + printf("TLS Initialization Stress Test\n"); + printf("===============================\n"); + printf("Testing VLD's handling of concurrent TLS initialization.\n"); + printf("Creating %d threads that will all allocate simultaneously...\n\n", NUM_THREADS); + + HANDLE threads[NUM_THREADS]; + + // Create all threads (they'll wait at barrier) + for (int i = 0; i < NUM_THREADS; i++) { + threads[i] = CreateThread(NULL, 0, ThreadFunc, (LPVOID)(INT_PTR)i, 0, NULL); + if (threads[i] == NULL) { + printf("Failed to create thread %d\n", i); + return 1; + } + } + + // Wait for all threads to be ready + while (g_readyCount < NUM_THREADS) { + Sleep(1); + } + + printf("All threads ready, releasing them simultaneously...\n"); + + // Release all threads at once to maximize race condition + g_goFlag = 1; + + // Wait for all threads to complete + DWORD result = WaitForMultipleObjects(NUM_THREADS, threads, TRUE, 30000); // 30 second timeout + + if (result == WAIT_TIMEOUT) { + printf("\nFAILED: Threads deadlocked or hung (likely infinite recursion)\n"); + printf("This indicates the TLS initialization bug is present.\n"); + return 1; + } else if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + NUM_THREADS) { + printf("SUCCESS: All threads completed without crashing\n"); + printf("The s_inVldCall reentrancy protection is working correctly.\n"); + } else { + printf("FAILED: WaitForMultipleObjects returned unexpected result: 0x%X\n", result); + return 1; + } + + // Clean up + for (int i = 0; i < NUM_THREADS; i++) { + CloseHandle(threads[i]); + } + + printf("\nTest PASSED: TLS initialization is properly protected from reentrancy\n"); + return 0; +} diff --git a/src/tests/vld_ComTest/ComTest.aps b/src/tests/vld_ComTest/ComTest.aps deleted file mode 100644 index eeb1b0db..00000000 Binary files a/src/tests/vld_ComTest/ComTest.aps and /dev/null differ diff --git a/src/tests/vld_ComTest/ComTest.cpp b/src/tests/vld_ComTest/ComTest.cpp index 47df2d73..e87c5fd3 100644 --- a/src/tests/vld_ComTest/ComTest.cpp +++ b/src/tests/vld_ComTest/ComTest.cpp @@ -1,81 +1,81 @@ -#include "stdafx.h" -#include "resource.h" -#include "ComTest_i.h" -#include "dllmain.h" -#include "xdlldata.h" - - -STDAPI DllCanUnloadNow(void) -{ - #ifdef _MERGE_PROXYSTUB - HRESULT hr = PrxDllCanUnloadNow(); - if (hr != S_OK) - return hr; -#endif - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - return (AfxDllCanUnloadNow()==S_OK && _AtlModule.GetLockCount()==0) ? S_OK : S_FALSE; -} - -STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) -{ - #ifdef _MERGE_PROXYSTUB - if (PrxDllGetClassObject(rclsid, riid, ppv) == S_OK) - return S_OK; -#endif - return _AtlModule.DllGetClassObject(rclsid, riid, ppv); -} - -STDAPI DllRegisterServer(void) -{ - //MessageBox(NULL, L"df", L"df", NULL); - HRESULT hr = _AtlModule.DllRegisterServer(); - #ifdef _MERGE_PROXYSTUB - if (FAILED(hr)) - return hr; - hr = PrxDllRegisterServer(); -#endif - return hr; -} - -STDAPI DllUnregisterServer(void) -{ - HRESULT hr = _AtlModule.DllUnregisterServer(); - #ifdef _MERGE_PROXYSTUB - if (FAILED(hr)) - return hr; - hr = PrxDllRegisterServer(); - if (FAILED(hr)) - return hr; - hr = PrxDllUnregisterServer(); -#endif - return hr; -} - -STDAPI DllInstall(BOOL bInstall, LPCWSTR pszCmdLine) -{ - HRESULT hr = E_FAIL; - static const wchar_t szUserSwitch[] = L"user"; - - if (pszCmdLine != NULL) - { - if (_wcsnicmp(pszCmdLine, szUserSwitch, _countof(szUserSwitch)) == 0) - { - ATL::AtlSetPerUserRegistration(true); - } - } - - if (bInstall) - { - hr = DllRegisterServer(); - if (FAILED(hr)) - { - DllUnregisterServer(); - } - } - else - { - hr = DllUnregisterServer(); - } - - return hr; -} +#include "stdafx.h" +#include "resource.h" +#include "ComTest_i.h" +#include "dllmain.h" +#include "xdlldata.h" + + +STDAPI DllCanUnloadNow(void) +{ + #ifdef _MERGE_PROXYSTUB + HRESULT hr = PrxDllCanUnloadNow(); + if (hr != S_OK) + return hr; +#endif + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + return (AfxDllCanUnloadNow()==S_OK && _AtlModule.GetLockCount()==0) ? S_OK : S_FALSE; +} + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) +{ + #ifdef _MERGE_PROXYSTUB + if (PrxDllGetClassObject(rclsid, riid, ppv) == S_OK) + return S_OK; +#endif + return _AtlModule.DllGetClassObject(rclsid, riid, ppv); +} + +STDAPI DllRegisterServer(void) +{ + //MessageBox(NULL, L"df", L"df", NULL); + HRESULT hr = _AtlModule.DllRegisterServer(); + #ifdef _MERGE_PROXYSTUB + if (FAILED(hr)) + return hr; + hr = PrxDllRegisterServer(); +#endif + return hr; +} + +STDAPI DllUnregisterServer(void) +{ + HRESULT hr = _AtlModule.DllUnregisterServer(); + #ifdef _MERGE_PROXYSTUB + if (FAILED(hr)) + return hr; + hr = PrxDllRegisterServer(); + if (FAILED(hr)) + return hr; + hr = PrxDllUnregisterServer(); +#endif + return hr; +} + +STDAPI DllInstall(BOOL bInstall, LPCWSTR pszCmdLine) +{ + HRESULT hr = E_FAIL; + static const wchar_t szUserSwitch[] = L"user"; + + if (pszCmdLine != NULL) + { + if (_wcsnicmp(pszCmdLine, szUserSwitch, _countof(szUserSwitch)) == 0) + { + ATL::AtlSetPerUserRegistration(true); + } + } + + if (bInstall) + { + hr = DllRegisterServer(); + if (FAILED(hr)) + { + DllUnregisterServer(); + } + } + else + { + hr = DllUnregisterServer(); + } + + return hr; +} diff --git a/src/tests/vld_ComTest/ComTest.idl b/src/tests/vld_ComTest/ComTest.idl index 5952778f..6ef974b3 100644 --- a/src/tests/vld_ComTest/ComTest.idl +++ b/src/tests/vld_ComTest/ComTest.idl @@ -17,7 +17,7 @@ library ComTestLib { importlib("stdole2.tlb"); [ - uuid(B379BB26-80E6-4DCB-AD82-8F46BA81BBCF) + uuid(B379BB26-80E6-4DCB-AD82-8F46BA81BBCF) ] coclass MyMath { diff --git a/src/tests/vld_ComTest/ComTest.rc b/src/tests/vld_ComTest/ComTest.rc index 31a00ea7..a03c5f5a 100644 Binary files a/src/tests/vld_ComTest/ComTest.rc and b/src/tests/vld_ComTest/ComTest.rc differ diff --git a/src/tests/vld_ComTest/MyMath.cpp b/src/tests/vld_ComTest/MyMath.cpp index 0aa55b2f..3f430e0d 100644 --- a/src/tests/vld_ComTest/MyMath.cpp +++ b/src/tests/vld_ComTest/MyMath.cpp @@ -1,11 +1,11 @@ -#include "stdafx.h" -#include "MyMath.h" - -// CMyMath - -STDMETHODIMP CMyMath::Test(void) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - - return S_OK; -} +#include "stdafx.h" +#include "MyMath.h" + +// CMyMath + +STDMETHODIMP CMyMath::Test(void) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + return S_OK; +} diff --git a/src/tests/vld_ComTest/MyMath.h b/src/tests/vld_ComTest/MyMath.h index 493ab7b4..f3da8576 100644 --- a/src/tests/vld_ComTest/MyMath.h +++ b/src/tests/vld_ComTest/MyMath.h @@ -1,41 +1,41 @@ -#pragma once -#include "resource.h" - -#include "ComTest_i.h" - -using namespace ATL; - -// CMyMath - -class ATL_NO_VTABLE CMyMath : - public CComObjectRootEx, - public CComCoClass, - public IMyMath -{ -public: - CMyMath() - { - } - -DECLARE_REGISTRY_RESOURCEID(IDR_MYMATH) - -BEGIN_COM_MAP(CMyMath) - COM_INTERFACE_ENTRY(IMyMath) -END_COM_MAP() - - DECLARE_PROTECT_FINAL_CONSTRUCT() - - HRESULT FinalConstruct() - { - return S_OK; - } - - void FinalRelease() - { - } - -public: - STDMETHOD(Test)(void); -}; - -OBJECT_ENTRY_AUTO(__uuidof(MyMath), CMyMath) +#pragma once +#include "resource.h" + +#include "ComTest_i.h" + +using namespace ATL; + +// CMyMath + +class ATL_NO_VTABLE CMyMath : + public CComObjectRootEx, + public CComCoClass, + public IMyMath +{ +public: + CMyMath() + { + } + +DECLARE_REGISTRY_RESOURCEID(IDR_MYMATH) + +BEGIN_COM_MAP(CMyMath) + COM_INTERFACE_ENTRY(IMyMath) +END_COM_MAP() + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + HRESULT FinalConstruct() + { + return S_OK; + } + + void FinalRelease() + { + } + +public: + STDMETHOD(Test)(void); +}; + +OBJECT_ENTRY_AUTO(__uuidof(MyMath), CMyMath) diff --git a/src/tests/vld_ComTest/Resource.h b/src/tests/vld_ComTest/Resource.h index 86dc9607..1e37007c 100644 --- a/src/tests/vld_ComTest/Resource.h +++ b/src/tests/vld_ComTest/Resource.h @@ -1,18 +1,18 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by ComTest.rc -// -#define IDS_PROJNAME 100 -#define IDR_COMTEST 101 -#define IDR_MYMATH 106 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 201 -#define _APS_NEXT_COMMAND_VALUE 32768 -#define _APS_NEXT_CONTROL_VALUE 201 -#define _APS_NEXT_SYMED_VALUE 107 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ComTest.rc +// +#define IDS_PROJNAME 100 +#define IDR_COMTEST 101 +#define IDR_MYMATH 106 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 201 +#define _APS_NEXT_COMMAND_VALUE 32768 +#define _APS_NEXT_CONTROL_VALUE 201 +#define _APS_NEXT_SYMED_VALUE 107 +#endif +#endif diff --git a/src/tests/vld_ComTest/dlldata.c b/src/tests/vld_ComTest/dlldata.c index b9c83e82..f234833d 100644 --- a/src/tests/vld_ComTest/dlldata.c +++ b/src/tests/vld_ComTest/dlldata.c @@ -1,37 +1,37 @@ -/********************************************************* - DllData file -- generated by MIDL compiler - - DO NOT ALTER THIS FILE - - This file is regenerated by MIDL on every IDL file compile. - - To completely reconstruct this file, delete it and rerun MIDL - on all the IDL files in this DLL, specifying this file for the - /dlldata command line option - -*********************************************************/ - - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -EXTERN_PROXY_FILE( ComTest ) - - -PROXYFILE_LIST_START -/* Start of list */ - REFERENCE_PROXY_FILE( ComTest ), -/* End of list */ -PROXYFILE_LIST_END - - -DLLDATA_ROUTINES( aProxyFileList, GET_DLL_CLSID ) - -#ifdef __cplusplus -} /*extern "C" */ -#endif - -/* end of generated dlldata file */ +/********************************************************* + DllData file -- generated by MIDL compiler + + DO NOT ALTER THIS FILE + + This file is regenerated by MIDL on every IDL file compile. + + To completely reconstruct this file, delete it and rerun MIDL + on all the IDL files in this DLL, specifying this file for the + /dlldata command line option + +*********************************************************/ + + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +EXTERN_PROXY_FILE( ComTest ) + + +PROXYFILE_LIST_START +/* Start of list */ + REFERENCE_PROXY_FILE( ComTest ), +/* End of list */ +PROXYFILE_LIST_END + + +DLLDATA_ROUTINES( aProxyFileList, GET_DLL_CLSID ) + +#ifdef __cplusplus +} /*extern "C" */ +#endif + +/* end of generated dlldata file */ diff --git a/src/tests/vld_ComTest/dllmain.cpp b/src/tests/vld_ComTest/dllmain.cpp index ce5045a9..5f6c4c6b 100644 --- a/src/tests/vld_ComTest/dllmain.cpp +++ b/src/tests/vld_ComTest/dllmain.cpp @@ -1,35 +1,35 @@ -#include "stdafx.h" -#include "resource.h" -#include "ComTest_i.h" -#include "dllmain.h" -#include "xdlldata.h" - -CComTestModule _AtlModule; - -class CComTestApp : public CWinApp -{ -public: - virtual BOOL InitInstance(); - virtual int ExitInstance(); - - DECLARE_MESSAGE_MAP() -}; - -BEGIN_MESSAGE_MAP(CComTestApp, CWinApp) -END_MESSAGE_MAP() - -CComTestApp theApp; - -BOOL CComTestApp::InitInstance() -{ -#ifdef _MERGE_PROXYSTUB - if (!PrxDllMain(m_hInstance, DLL_PROCESS_ATTACH, NULL)) - return FALSE; -#endif - return CWinApp::InitInstance(); -} - -int CComTestApp::ExitInstance() -{ - return CWinApp::ExitInstance(); -} +#include "stdafx.h" +#include "resource.h" +#include "ComTest_i.h" +#include "dllmain.h" +#include "xdlldata.h" + +CComTestModule _AtlModule; + +class CComTestApp : public CWinApp +{ +public: + virtual BOOL InitInstance(); + virtual int ExitInstance(); + + DECLARE_MESSAGE_MAP() +}; + +BEGIN_MESSAGE_MAP(CComTestApp, CWinApp) +END_MESSAGE_MAP() + +CComTestApp theApp; + +BOOL CComTestApp::InitInstance() +{ +#ifdef _MERGE_PROXYSTUB + if (!PrxDllMain(m_hInstance, DLL_PROCESS_ATTACH, NULL)) + return FALSE; +#endif + return CWinApp::InitInstance(); +} + +int CComTestApp::ExitInstance() +{ + return CWinApp::ExitInstance(); +} diff --git a/src/tests/vld_ComTest/dllmain.h b/src/tests/vld_ComTest/dllmain.h index f2978954..7db66452 100644 --- a/src/tests/vld_ComTest/dllmain.h +++ b/src/tests/vld_ComTest/dllmain.h @@ -1,8 +1,8 @@ -class CComTestModule : public ATL::CAtlDllModuleT< CComTestModule > -{ -public : - DECLARE_LIBID(LIBID_ComTestLib) - DECLARE_REGISTRY_APPID_RESOURCEID(IDR_COMTEST, "{06DD8E8C-4587-41A0-8D5A-B3A87883B158}") -}; - -extern class CComTestModule _AtlModule; +class CComTestModule : public ATL::CAtlDllModuleT< CComTestModule > +{ +public : + DECLARE_LIBID(LIBID_ComTestLib) + DECLARE_REGISTRY_APPID_RESOURCEID(IDR_COMTEST, "{06DD8E8C-4587-41A0-8D5A-B3A87883B158}") +}; + +extern class CComTestModule _AtlModule; diff --git a/src/tests/vld_ComTest/stdafx.cpp b/src/tests/vld_ComTest/stdafx.cpp index a27b824d..fd4f341c 100644 --- a/src/tests/vld_ComTest/stdafx.cpp +++ b/src/tests/vld_ComTest/stdafx.cpp @@ -1 +1 @@ -#include "stdafx.h" +#include "stdafx.h" diff --git a/src/tests/vld_ComTest/stdafx.h b/src/tests/vld_ComTest/stdafx.h index 979ad7bd..27e73c3e 100644 --- a/src/tests/vld_ComTest/stdafx.h +++ b/src/tests/vld_ComTest/stdafx.h @@ -1,39 +1,39 @@ -#pragma once - -#ifndef STRICT -#define STRICT -#endif - -#include "targetver.h" - -//#define DISABLE_VLD -//#define OVERRIDE_DISABLE_VLD -#include - -#define _ATL_APARTMENT_THREADED - -#define _ATL_NO_AUTOMATIC_NAMESPACE - -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef _AFX_NO_OLE_SUPPORT -#include -#endif // _AFX_NO_OLE_SUPPORT - -#define ATL_NO_ASSERT_ON_DESTROY_NONEXISTENT_WINDOW - -#include "resource.h" -#include -#include -#include +#pragma once + +#ifndef STRICT +#define STRICT +#endif + +#include "targetver.h" + +//#define DISABLE_VLD +//#define OVERRIDE_DISABLE_VLD +#include + +#define _ATL_APARTMENT_THREADED + +#define _ATL_NO_AUTOMATIC_NAMESPACE + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef _AFX_NO_OLE_SUPPORT +#include +#endif // _AFX_NO_OLE_SUPPORT + +#define ATL_NO_ASSERT_ON_DESTROY_NONEXISTENT_WINDOW + +#include "resource.h" +#include +#include +#include diff --git a/src/tests/vld_ComTest/targetver.h b/src/tests/vld_ComTest/targetver.h index 2b26ce28..05ba7d4c 100644 --- a/src/tests/vld_ComTest/targetver.h +++ b/src/tests/vld_ComTest/targetver.h @@ -1,3 +1,3 @@ -#pragma once - -#include +#pragma once + +#include diff --git a/src/tests/vld_ComTest/xdlldata.c b/src/tests/vld_ComTest/xdlldata.c index 599daa7d..cc74dad2 100644 Binary files a/src/tests/vld_ComTest/xdlldata.c and b/src/tests/vld_ComTest/xdlldata.c differ diff --git a/src/tests/vld_ComTest/xdlldata.h b/src/tests/vld_ComTest/xdlldata.h index 89313c5c..461a2f6c 100644 --- a/src/tests/vld_ComTest/xdlldata.h +++ b/src/tests/vld_ComTest/xdlldata.h @@ -2,9 +2,9 @@ #ifdef _MERGE_PROXYSTUB -extern "C" +extern "C" { -BOOL WINAPI PrxDllMain(HINSTANCE hInstance, DWORD dwReason, +BOOL WINAPI PrxDllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved); STDAPI PrxDllCanUnloadNow(void); STDAPI PrxDllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv); diff --git a/src/tests/vld_dll1/dllmain.cpp b/src/tests/vld_dll1/dllmain.cpp index 7158e09d..d975430e 100644 --- a/src/tests/vld_dll1/dllmain.cpp +++ b/src/tests/vld_dll1/dllmain.cpp @@ -2,12 +2,12 @@ #include "stdafx.h" #include #include - -#include - -// Here we static initialize a string within the DLL -// Previous versions of VLD would flag this as a leak, make sure it does not -static std::string my_string("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); + +#include + +// Here we static initialize a string within the DLL +// Previous versions of VLD would flag this as a leak, make sure it does not +static std::string my_string("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, diff --git a/src/tests/vld_main/vld_main.cpp b/src/tests/vld_main/vld_main.cpp index 100fa525..6a0cdcd7 100644 --- a/src/tests/vld_main/vld_main.cpp +++ b/src/tests/vld_main/vld_main.cpp @@ -10,7 +10,7 @@ // VLD_FORCE_ENABLE is defined via CMake for non-Debug builds #include -static std::string str("my_string"); // 10 +static std::string str("my_string"); // 10 class MemoryLeak { public: @@ -49,20 +49,20 @@ int Test() // debug CRT allocation header. std::cout << "Test: cout"; //std::cerr << "Test: cerr"; - - // NOTE: This test is a bit weird due to the fix we made in callstack.cpp - // All allocations that happen before main (anything static or global allocated in its initialization) - // will be ignored. - // This means that 2 leaks will be reported (8,9 above) - - // Really, we should report all leaks except 4,5,10 (which have known destructors that we have to assume will "do the right thing") - // Which means we would want the leak count to be reported as 7 - + + // NOTE: This test is a bit weird due to the fix we made in callstack.cpp + // All allocations that happen before main (anything static or global allocated in its initialization) + // will be ignored. + // This means that 2 leaks will be reported (8,9 above) + + // Really, we should report all leaks except 4,5,10 (which have known destructors that we have to assume will "do the right thing") + // Which means we would want the leak count to be reported as 7 + // The note below is old (but relevant for historical purposes): // At this point VLDGetLeaksCount() and VLDReportLeaks() should report 9 leaks // including a leak for ml which has not been freed yet. ml will be freed after // _tmain exits but before VLDReportLeaks() is called internally by VLD and - // therefore correctly report 8 leaks. + // therefore correctly report 8 leaks. int leaks = VLDGetLeaksCount(); VLDReportLeaks(); // at this point should report 9 leaks; diff --git a/src/tests/vld_unload/vld_unload.cpp b/src/tests/vld_unload/vld_unload.cpp index 91b16400..7eb1f1ba 100644 --- a/src/tests/vld_unload/vld_unload.cpp +++ b/src/tests/vld_unload/vld_unload.cpp @@ -45,16 +45,16 @@ UINT VLDReportLeaks() } } return -1; -} - -void ExpectLeakCount(int expected, int actual) -{ - if (expected != actual) - { - VLDReportLeaks(); - } - EXPECT_EQ(expected, actual); -} +} + +void ExpectLeakCount(int expected, int actual) +{ + if (expected != actual) + { + VLDReportLeaks(); + } + EXPECT_EQ(expected, actual); +} HMODULE GetModuleFromAddress(LPCVOID pAddress) { diff --git a/src/vld.cpp b/src/vld.cpp index dca162af..e3547b54 100644 --- a/src/vld.cpp +++ b/src/vld.cpp @@ -3088,10 +3088,10 @@ BOOL CaptureContext::IsExcludedModule() { PVOID frames[32]; ULONG hash; USHORT frameCount = RtlCaptureStackBackTrace(0, maxframes, frames, &hash); - + for (USHORT i = 0; i < frameCount; i++) { HMODULE frameModule = GetCallingModule((UINT_PTR)frames[i]); - if (frameModule != NULL && + if (frameModule != NULL && frameModule != hModule && // Skip the CRT module we already checked frameModule != g_vld.m_dbghlpBase && frameModule != g_vld.m_vldBase) { diff --git a/src/vld_def.h b/src/vld_def.h index c4e49dfc..c44a0518 100644 --- a/src/vld_def.h +++ b/src/vld_def.h @@ -42,7 +42,7 @@ #define VLD_OPT_SKIP_HEAPFREE_LEAKS 0x1000 // If set, VLD skip HeapFree memory leaks. #define VLD_OPT_VALIDATE_HEAPFREE 0x2000 // If set, VLD verifies and reports heap consistency for HeapFree calls. #define VLD_OPT_SKIP_CRTSTARTUP_LEAKS 0x4000 // If set, VLD skip crt srtartup memory leaks. -#define VLD_OPT_IGNORE_FUNCTIONS 0x8000 // If set, VLD skips the defined functions in IgnoreFunctionsList. +#define VLD_OPT_IGNORE_FUNCTIONS 0x8000 // If set, VLD skips the defined functions in IgnoreFunctionsList. #define VLD_RPTHOOK_INSTALL 0 #define VLD_RPTHOOK_REMOVE 1 diff --git a/vld.ini b/vld.ini index 4c613141..7ef83f12 100644 --- a/vld.ini +++ b/vld.ini @@ -55,7 +55,7 @@ AggregateDuplicates = no ; Valid Values: Any list containing module names (i.e. names of EXEs or DLLs) ; Default: None. ; -ForceIncludeModules = +ForceIncludeModules = ; Maximum number of data bytes to display for each leaked block. If zero, then ; the data dump is completely suppressed and only call stacks are shown. @@ -65,7 +65,7 @@ ForceIncludeModules = ; Value Values: 0 - 4294967295 ; Default: 256 ; -MaxDataDump = +MaxDataDump = ; Maximum number of call stack frames to trace back during leak detection. ; Limiting this to a low number can reduce the CPU utilization overhead imposed @@ -75,7 +75,7 @@ MaxDataDump = ; Valid Values: 1 - 4294967295 ; Default: 64 ; -MaxTraceFrames = +MaxTraceFrames = ; Sets the type of encoding to use for the generated memory leak report. This ; option is really only useful in conjuction with sending the report to a file. @@ -96,7 +96,7 @@ ReportEncoding = ascii ; Valid Values: Any valid path and filename. ; Default: .\memory_leak_report.txt ; -ReportFile = +ReportFile = ; Sets the report destination to either a file, the debugger, or both. If ; reporting to file is enabled, the report is sent to the file specified by the @@ -126,7 +126,7 @@ SelfTest = off ; ; Valid Values: fast, safe ; Default: fast -; +; StackWalkMethod = fast ; Determines whether memory leak detection should be initially enabled for all @@ -171,7 +171,7 @@ SkipHeapFreeLeaks = no SkipCrtStartupLeaks = yes ; Lists any specific functions to be ignored in memory leak detection. This can -; be useful for false positive functions that report memory leaks especially +; be useful for false positive functions that report memory leaks especially ; when the code is maintained by 3rd party libraries. This option should be ; used only if absolutely necessary and only if you really know what you are ; doing. @@ -181,4 +181,4 @@ SkipCrtStartupLeaks = yes ; Valid Values: Functions names as strings separated by comma. Strings are case sensitive. ; Default: None. ; -IgnoreFunctionsList = \ No newline at end of file +IgnoreFunctionsList = \ No newline at end of file