Skip to content

Instantly share code, notes, and snippets.

@jefgen
Created May 25, 2019 02:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jefgen/560077b80c64a833495e0d6c657f2b3d to your computer and use it in GitHub Desktop.
Save jefgen/560077b80c64a833495e0d6c657f2b3d to your computer and use it in GitHub Desktop.
Testing ICU DLL unload for leaking OS Critical Sections
// This is a simple test program to verify that ICU doesn't leak critical
// sections when the ICU library DLLs are dynamically loaded and unloaded
// from a running process.
//
// Compile and run this program under a debugger with AppVerifier enabled
// to see the output (either leaks or no leaks).
//
// Note: You need to add the path to the ICU DLL to your PATH first.
//
#include <stdio.h>
#include <stdint.h>
#include <Windows.h>
// U_STABLE const char* U_EXPORT2 uloc_getDefault(void);
typedef const char* (__cdecl* pfn_uloc_getDefault)(void);
// U_STABLE void U_EXPORT2 u_cleanup(void);
typedef void(__cdecl* pfn_u_cleanup)(void);
// U_STABLE int32_t U_EXPORT2 ucal_getDefaultTimeZone(UChar* result, int32_t resultCapacity, UErrorCode* ec);
typedef int32_t (__cdecl* pfn_ucal_getDefaultTimeZone)(char16_t*, int32_t, int32_t*);
int main()
{
wprintf(L"Testing ICU for leaking Critical Sections.\n");
HINSTANCE hIcuCommonLib = nullptr;
HINSTANCE hIcuI18nLib = nullptr;
pfn_uloc_getDefault func_uloc_getDefault = nullptr;
pfn_ucal_getDefaultTimeZone func_ucal_getDefaultTimeZone = nullptr;
pfn_u_cleanup func_u_cleanup = nullptr;
// Change the version number for the version of ICU you are testing, then rebuild.
hIcuCommonLib = LoadLibraryW(L"icuuc64.dll");
hIcuI18nLib = LoadLibraryW(L"icuin64.dll");
if ((hIcuCommonLib != nullptr) && (hIcuI18nLib != nullptr))
{
func_uloc_getDefault = (pfn_uloc_getDefault)GetProcAddress(hIcuCommonLib, "uloc_getDefault_64");
func_u_cleanup = (pfn_u_cleanup)GetProcAddress(hIcuCommonLib, "u_cleanup_64");
func_ucal_getDefaultTimeZone = (pfn_ucal_getDefaultTimeZone)GetProcAddress(hIcuI18nLib, "ucal_getDefaultTimeZone_64");
if ((func_uloc_getDefault != nullptr) && (func_u_cleanup != nullptr) && (func_ucal_getDefaultTimeZone != nullptr))
{
const char* locale = func_uloc_getDefault();
wprintf(L" ICU default locale = '%hs'\n", locale);
int32_t error = 0;
char16_t timezone[100] = {0};
func_ucal_getDefaultTimeZone(timezone, 100, &error);
if (error == 0)
{
wprintf(L" ICU default timezone = '%s'\n", timezone);
}
// Tell ICU to clean up. This should also free up any OS Critical Sections.
func_u_cleanup();
}
else
{
wprintf(L"ERROR: Failed to get the function addresses.\n");
}
// Unloading the DLLs shouldn't trigger any AppVerifier leaks.
if (FreeLibrary(hIcuI18nLib))
{
wprintf(L"ERROR: Failed to unload the DLL. GetLastError = 0x%08x \n", GetLastError());
}
if (FreeLibrary(hIcuCommonLib))
{
wprintf(L"ERROR: Failed to unload the DLL. GetLastError = 0x%08x \n", GetLastError());
}
}
else
{
wprintf(L"ERROR: Failed to load the DLL. (Are the ICU DLLs in your PATH ?). \n");
}
wprintf(L"End.\n");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment