diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /toolkit/xre/test/win | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'toolkit/xre/test/win')
-rw-r--r-- | toolkit/xre/test/win/Makefile.in | 14 | ||||
-rw-r--r-- | toolkit/xre/test/win/TestDllInterceptor.cpp | 237 | ||||
-rw-r--r-- | toolkit/xre/test/win/TestXREMakeCommandLineWin.cpp | 265 | ||||
-rw-r--r-- | toolkit/xre/test/win/TestXREMakeCommandLineWin.ini | 94 | ||||
-rw-r--r-- | toolkit/xre/test/win/moz.build | 30 |
5 files changed, 640 insertions, 0 deletions
diff --git a/toolkit/xre/test/win/Makefile.in b/toolkit/xre/test/win/Makefile.in new file mode 100644 index 000000000..331a8a4fd --- /dev/null +++ b/toolkit/xre/test/win/Makefile.in @@ -0,0 +1,14 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +MOZ_WINCONSOLE = 1 + +include $(topsrcdir)/config/rules.mk + +libs:: TestXREMakeCommandLineWin.ini + $(INSTALL) $^ $(FINAL_TARGET)/ + +check:: + @echo 'Running TestXREMakeCommandLineWin tests' + @$(RUN_TEST_PROGRAM) $(FINAL_TARGET)/TestXREMakeCommandLineWin.exe diff --git a/toolkit/xre/test/win/TestDllInterceptor.cpp b/toolkit/xre/test/win/TestDllInterceptor.cpp new file mode 100644 index 000000000..dff71817f --- /dev/null +++ b/toolkit/xre/test/win/TestDllInterceptor.cpp @@ -0,0 +1,237 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#if _WIN32_WINNT < 0x0600 +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0600 +#endif + +#include <shlobj.h> +#include <stdio.h> + +#include "mozilla/WindowsVersion.h" +#include "nsWindowsDllInterceptor.h" +#include "nsWindowsHelpers.h" + +using namespace mozilla; + +struct payload { + UINT64 a; + UINT64 b; + UINT64 c; + + bool operator==(const payload &other) const { + return (a == other.a && + b == other.b && + c == other.c); + } +}; + +extern "C" __declspec(dllexport) __declspec(noinline) payload rotatePayload(payload p) { + UINT64 tmp = p.a; + p.a = p.b; + p.b = p.c; + p.c = tmp; + return p; +} + +static bool patched_func_called = false; + +static payload (*orig_rotatePayload)(payload); + +static payload +patched_rotatePayload(payload p) +{ + patched_func_called = true; + return orig_rotatePayload(p); +} + +bool TestHook(const char *dll, const char *func) +{ + void *orig_func; + bool successful = false; + { + WindowsDllInterceptor TestIntercept; + TestIntercept.Init(dll); + successful = TestIntercept.AddHook(func, 0, &orig_func); + } + + if (successful) { + printf("TEST-PASS | WindowsDllInterceptor | Could hook %s from %s\n", func, dll); + return true; + } else { + printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to hook %s from %s\n", func, dll); + return false; + } +} + +bool TestDetour(const char *dll, const char *func) +{ + void *orig_func; + bool successful = false; + { + WindowsDllInterceptor TestIntercept; + TestIntercept.Init(dll); + successful = TestIntercept.AddDetour(func, 0, &orig_func); + } + + if (successful) { + printf("TEST-PASS | WindowsDllInterceptor | Could detour %s from %s\n", func, dll); + return true; + } else { + printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to detour %s from %s\n", func, dll); + return false; + } +} + +bool MaybeTestHook(const bool cond, const char* dll, const char* func) +{ + if (!cond) { + return true; + } + + return TestHook(dll, func); +} + +bool ShouldTestTipTsf() +{ +#if defined(_M_X64) + return false; +#else + if (!IsWin8OrLater()) { + return false; + } + + nsModuleHandle shell32(LoadLibraryW(L"shell32.dll")); + if (!shell32) { + return true; + } + + auto pSHGetKnownFolderPath = reinterpret_cast<decltype(&SHGetKnownFolderPath)>(GetProcAddress(shell32, "SHGetKnownFolderPath")); + if (!pSHGetKnownFolderPath) { + return true; + } + + PWSTR commonFilesPath = nullptr; + if (FAILED(pSHGetKnownFolderPath(FOLDERID_ProgramFilesCommon, 0, nullptr, + &commonFilesPath))) { + return true; + } + + wchar_t fullPath[MAX_PATH + 1] = {}; + wcscpy(fullPath, commonFilesPath); + wcscat(fullPath, L"\\Microsoft Shared\\Ink\\tiptsf.dll"); + CoTaskMemFree(commonFilesPath); + + if (!LoadLibraryW(fullPath)) { + return false; + } + + // Leak the module so that it's loaded for the interceptor test + return true; +#endif +} + +int main() +{ + payload initial = { 0x12345678, 0xfc4e9d31, 0x87654321 }; + payload p0, p1; + ZeroMemory(&p0, sizeof(p0)); + ZeroMemory(&p1, sizeof(p1)); + + p0 = rotatePayload(initial); + + { + WindowsDllInterceptor ExeIntercept; + ExeIntercept.Init("TestDllInterceptor.exe"); + if (ExeIntercept.AddHook("rotatePayload", reinterpret_cast<intptr_t>(patched_rotatePayload), (void**) &orig_rotatePayload)) { + printf("TEST-PASS | WindowsDllInterceptor | Hook added\n"); + } else { + printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to add hook\n"); + return 1; + } + + p1 = rotatePayload(initial); + + if (patched_func_called) { + printf("TEST-PASS | WindowsDllInterceptor | Hook called\n"); + } else { + printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Hook was not called\n"); + return 1; + } + + if (p0 == p1) { + printf("TEST-PASS | WindowsDllInterceptor | Hook works properly\n"); + } else { + printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Hook didn't return the right information\n"); + return 1; + } + } + + patched_func_called = false; + ZeroMemory(&p1, sizeof(p1)); + + p1 = rotatePayload(initial); + + if (!patched_func_called) { + printf("TEST-PASS | WindowsDllInterceptor | Hook was not called after unregistration\n"); + } else { + printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Hook was still called after unregistration\n"); + return 1; + } + + if (p0 == p1) { + printf("TEST-PASS | WindowsDllInterceptor | Original function worked properly\n"); + } else { + printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Original function didn't return the right information\n"); + return 1; + } + + if (TestHook("user32.dll", "GetWindowInfo") && +#ifdef _WIN64 + TestHook("user32.dll", "SetWindowLongPtrA") && + TestHook("user32.dll", "SetWindowLongPtrW") && +#else + TestHook("user32.dll", "SetWindowLongA") && + TestHook("user32.dll", "SetWindowLongW") && +#endif + TestHook("user32.dll", "TrackPopupMenu") && +#ifdef _M_IX86 + // We keep this test to hook complex code on x86. (Bug 850957) + TestHook("ntdll.dll", "NtFlushBuffersFile") && +#endif + TestHook("ntdll.dll", "NtCreateFile") && + TestHook("ntdll.dll", "NtReadFile") && + TestHook("ntdll.dll", "NtReadFileScatter") && + TestHook("ntdll.dll", "NtWriteFile") && + TestHook("ntdll.dll", "NtWriteFileGather") && + TestHook("ntdll.dll", "NtQueryFullAttributesFile") && + // Bug 733892: toolkit/crashreporter/nsExceptionHandler.cpp + TestHook("kernel32.dll", "SetUnhandledExceptionFilter") && +#ifdef _M_IX86 + // Bug 670967: xpcom/base/AvailableMemoryTracker.cpp + TestHook("kernel32.dll", "VirtualAlloc") && + TestHook("kernel32.dll", "MapViewOfFile") && + TestHook("gdi32.dll", "CreateDIBSection") && + TestHook("kernel32.dll", "CreateFileW") && +#endif + TestDetour("user32.dll", "CreateWindowExW") && + TestHook("user32.dll", "InSendMessageEx") && + TestHook("imm32.dll", "ImmGetContext") && + TestHook("imm32.dll", "ImmGetCompositionStringW") && + TestHook("imm32.dll", "ImmSetCandidateWindow") && +#ifdef _M_X64 + TestHook("user32.dll", "GetKeyState") && +#endif + MaybeTestHook(ShouldTestTipTsf(), "tiptsf.dll", "ProcessCaretEvents") && +#ifdef _M_IX86 + TestHook("user32.dll", "SendMessageTimeoutW") && +#endif + TestDetour("ntdll.dll", "LdrLoadDll")) { + printf("TEST-PASS | WindowsDllInterceptor | all checks passed\n"); + return 0; + } + + return 1; +} diff --git a/toolkit/xre/test/win/TestXREMakeCommandLineWin.cpp b/toolkit/xre/test/win/TestXREMakeCommandLineWin.cpp new file mode 100644 index 000000000..00d786aa2 --- /dev/null +++ b/toolkit/xre/test/win/TestXREMakeCommandLineWin.cpp @@ -0,0 +1,265 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <stdio.h> +#include <stdlib.h> +#include <windows.h> +// Support for _setmode +#include <fcntl.h> +#include <io.h> + +#include "nsWindowsRestart.cpp" + +// CommandLineToArgvW may return different values for argv[0] since it contains +// the path to the binary that was executed so we prepend an argument that is +// quoted with a space to prevent argv[1] being appended to argv[0]. +#define DUMMY_ARG1 L"\"arg 1\" " + +#ifndef MAXPATHLEN +# ifdef PATH_MAX +# define MAXPATHLEN PATH_MAX +# elif defined(MAX_PATH) +# define MAXPATHLEN MAX_PATH +# elif defined(_MAX_PATH) +# define MAXPATHLEN _MAX_PATH +# elif defined(CCHMAXPATH) +# define MAXPATHLEN CCHMAXPATH +# else +# define MAXPATHLEN 1024 +# endif +#endif + +#define TEST_NAME L"XRE MakeCommandLine" +#define MAX_TESTS 100 + +// Verbose output can be enabled by defining VERBOSE 1 +#define VERBOSE 0 + +// Compares compareCmdLine with the output of MakeCommandLine. This is +// accomplished by converting inCmdLine to an argument list with +// CommandLineToArgvW and converting it back to a command line with +// MakeCommandLine. +static int +verifyCmdLineCreation(wchar_t *inCmdLine, + wchar_t *compareCmdLine, + bool passes, int testNum) +{ + int rv = 0; + int i; + int inArgc; + int outArgc; + bool isEqual; + + // When debugging with command lines containing Unicode characters greater + // than 255 you can set the mode for stdout to Unicode so the console will + // receive the correct characters though it won't display them properly unless + // the console's font has been set to one that can display the characters. You + // can also redirect the console output to a file that has been saved as Unicode + // to view the characters. +// _setmode(_fileno(stdout), _O_WTEXT); + + // Prepend an additional argument to the command line. CommandLineToArgvW + // handles argv[0] differently than other arguments since argv[0] is the path + // to the binary being executed and MakeCommandLine only handles argv[1] and + // larger. + wchar_t *inCmdLineNew = (wchar_t *) malloc((wcslen(DUMMY_ARG1) + wcslen(inCmdLine) + 1) * sizeof(wchar_t)); + wcscpy(inCmdLineNew, DUMMY_ARG1); + wcscat(inCmdLineNew, inCmdLine); + LPWSTR *inArgv = CommandLineToArgvW(inCmdLineNew, &inArgc); + + wchar_t *outCmdLine = MakeCommandLine(inArgc - 1, inArgv + 1); + wchar_t *outCmdLineNew = (wchar_t *) malloc((wcslen(DUMMY_ARG1) + wcslen(outCmdLine) + 1) * sizeof(wchar_t)); + wcscpy(outCmdLineNew, DUMMY_ARG1); + wcscat(outCmdLineNew, outCmdLine); + LPWSTR *outArgv = CommandLineToArgvW(outCmdLineNew, &outArgc); + + if (VERBOSE) { + wprintf(L"\n"); + wprintf(L"Verbose Output\n"); + wprintf(L"--------------\n"); + wprintf(L"Input command line : >%s<\n", inCmdLine); + wprintf(L"MakeComandLine output: >%s<\n", outCmdLine); + wprintf(L"Expected command line: >%s<\n", compareCmdLine); + + wprintf(L"input argc : %d\n", inArgc - 1); + wprintf(L"output argc: %d\n", outArgc - 1); + + for (i = 1; i < inArgc; ++i) { + wprintf(L"input argv[%d] : >%s<\n", i - 1, inArgv[i]); + } + + for (i = 1; i < outArgc; ++i) { + wprintf(L"output argv[%d]: >%s<\n", i - 1, outArgv[i]); + } + wprintf(L"\n"); + } + + isEqual = (inArgc == outArgc); + if (!isEqual) { + wprintf(L"TEST-%s-FAIL | %s | ARGC Comparison (check %2d)\n", + passes ? L"UNEXPECTED" : L"KNOWN", TEST_NAME, testNum); + if (passes) { + rv = 1; + } + LocalFree(inArgv); + LocalFree(outArgv); + free(inCmdLineNew); + free(outCmdLineNew); + free(outCmdLine); + return rv; + } + + for (i = 1; i < inArgc; ++i) { + isEqual = (wcscmp(inArgv[i], outArgv[i]) == 0); + if (!isEqual) { + wprintf(L"TEST-%s-FAIL | %s | ARGV Comparison (check %2d)\n", + passes ? L"UNEXPECTED" : L"KNOWN", TEST_NAME, testNum); + if (passes) { + rv = 1; + } + LocalFree(inArgv); + LocalFree(outArgv); + free(inCmdLineNew); + free(outCmdLineNew); + free(outCmdLine); + return rv; + } + } + + isEqual = (wcscmp(outCmdLine, compareCmdLine) == 0); + if (!isEqual) { + wprintf(L"TEST-%s-FAIL | %s | Command Line Comparison (check %2d)\n", + passes ? L"UNEXPECTED" : L"KNOWN", TEST_NAME, testNum); + if (passes) { + rv = 1; + } + LocalFree(inArgv); + LocalFree(outArgv); + free(inCmdLineNew); + free(outCmdLineNew); + free(outCmdLine); + return rv; + } + + if (rv == 0) { + if (passes) { + wprintf(L"TEST-PASS | %s | check %2d\n", TEST_NAME, testNum); + } else { + wprintf(L"TEST-UNEXPECTED-PASS | %s | check %2d\n", TEST_NAME, testNum); + rv = 1; + } + } + + LocalFree(inArgv); + LocalFree(outArgv); + free(inCmdLineNew); + free(outCmdLineNew); + free(outCmdLine); + return rv; +} + +int wmain(int argc, wchar_t *argv[]) +{ + int i; + int rv = 0; + + if (argc > 1 && (_wcsicmp(argv[1], L"-check-one") != 0 || argc != 3)) { + fwprintf(stderr, L"Displays and validates output from MakeCommandLine.\n\n"); + fwprintf(stderr, L"Usage: %s -check-one <test number>\n\n", argv[0]); + fwprintf(stderr, L" <test number>\tSpecifies the test number to run from the\n"); + fwprintf(stderr, L"\t\tTestXREMakeCommandLineWin.ini file.\n"); + return 255; + } + + wchar_t inifile[MAXPATHLEN]; + if (!::GetModuleFileNameW(0, inifile, MAXPATHLEN)) { + wprintf(L"TEST-UNEXPECTED-FAIL | %s | GetModuleFileNameW\n", TEST_NAME); + return 2; + } + + WCHAR *slash = wcsrchr(inifile, '\\'); + if (!slash) { + wprintf(L"TEST-UNEXPECTED-FAIL | %s | wcsrchr\n", TEST_NAME); + return 3; + } + + wcscpy(slash + 1, L"TestXREMakeCommandLineWin.ini\0"); + + for (i = 0; i < MAX_TESTS; ++i) { + wchar_t sInputVal[MAXPATHLEN]; + wchar_t sOutputVal[MAXPATHLEN]; + wchar_t sPassesVal[MAXPATHLEN]; + wchar_t sInputKey[MAXPATHLEN]; + wchar_t sOutputKey[MAXPATHLEN]; + wchar_t sPassesKey[MAXPATHLEN]; + + if (argc > 2 && _wcsicmp(argv[1], L"-check-one") == 0 && argc == 3) { + i = _wtoi(argv[2]); + } + + _snwprintf(sInputKey, MAXPATHLEN, L"input_%d", i); + _snwprintf(sOutputKey, MAXPATHLEN, L"output_%d", i); + _snwprintf(sPassesKey, MAXPATHLEN, L"passes_%d", i); + + if (!GetPrivateProfileStringW(L"MakeCommandLineTests", sInputKey, nullptr, + sInputVal, MAXPATHLEN, inifile)) { + if (i == 0 || (argc > 2 && _wcsicmp(argv[1], L"-check-one") == 0)) { + wprintf(L"TEST-UNEXPECTED-FAIL | %s | see following explanation:\n", TEST_NAME); + wprintf(L"ERROR: Either the TestXREMakeCommandLineWin.ini file doesn't exist\n"); + if (argc > 1 && _wcsicmp(argv[1], L"-check-one") == 0 && argc == 3) { + wprintf(L"ERROR: or the test is not defined in the MakeCommandLineTests section.\n"); + } else { + wprintf(L"ERROR: or it has no tests defined in the MakeCommandLineTests section.\n"); + } + wprintf(L"ERROR: File: %s\n", inifile); + return 4; + } + break; + } + + GetPrivateProfileStringW(L"MakeCommandLineTests", sOutputKey, nullptr, + sOutputVal, MAXPATHLEN, inifile); + GetPrivateProfileStringW(L"MakeCommandLineTests", sPassesKey, nullptr, + sPassesVal, MAXPATHLEN, inifile); + + rv |= verifyCmdLineCreation(sInputVal, sOutputVal, + (_wcsicmp(sPassesVal, L"false") == 0) ? FALSE : TRUE, + i); + + if (argc > 2 && _wcsicmp(argv[1], L"-check-one") == 0) { + break; + } + } + + if (rv == 0) { + wprintf(L"TEST-PASS | %s | all checks passed\n", TEST_NAME); + } else { + wprintf(L"TEST-UNEXPECTED-FAIL | %s | some checks failed\n", TEST_NAME); + } + + return rv; +} + +#ifdef __MINGW32__ + +/* MingW currently does not implement a wide version of the + startup routines. Workaround is to implement something like + it ourselves. See bug 411826 */ + +#include <shellapi.h> + +int main(int argc, char **argv) +{ + LPWSTR commandLine = GetCommandLineW(); + int argcw = 0; + LPWSTR *argvw = CommandLineToArgvW(commandLine, &argcw); + if (!argvw) + return 127; + + int result = wmain(argcw, argvw); + LocalFree(argvw); + return result; +} +#endif /* __MINGW32__ */ diff --git a/toolkit/xre/test/win/TestXREMakeCommandLineWin.ini b/toolkit/xre/test/win/TestXREMakeCommandLineWin.ini new file mode 100644 index 000000000..dbb529d1b --- /dev/null +++ b/toolkit/xre/test/win/TestXREMakeCommandLineWin.ini @@ -0,0 +1,94 @@ +; A typical MakeCommandLine test will contain an input and an output name value +; pair. The value for input_xx is the input command line and the value for +; output_xx is the expected output command line. +; +; A test that is known to fail can be added as follows. If the passes_xx name +; value pair doesn't exist it defaults to true. +; input_99=yabadaba +; output_99=doo +; passes_99=false +; +; If a value starts and ends with single or double quotation marks then it must +; be enclosed in single or double quotation marks due to GetPrivateProfileString +; discarding the outmost quotation marks. See GetPrivateProfileString on MSDN +; for more information. +; http://msdn.microsoft.com/en-us/library/ms724353.aspx + +[MakeCommandLineTests] +input_0=a:\ +output_0=a:\ + +input_1=""a:\"" +output_1=a:\" + +input_2=""a:\b c"" +output_2=""a:\b c"" + +input_3=""a:\b c\"" +output_3=""a:\b c\""" + +input_4=""a:\b c\d e"" +output_4=""a:\b c\d e"" + +input_5=""a:\b c\d e\"" +output_5=""a:\b c\d e\""" + +input_6=""a:\\"" +output_6=a:\ + +input_7="a:\" "b:\c d" +output_7=a:\" "b:\c d" + +input_8="a "b:\" "c:\d e"" +output_8="a "b:\" c:\d" e" + +input_9="abc" d e +output_9=abc d e + +input_10="a b c" d e +output_10="a b c" d e + +input_11=a\\\b d"e f"g h +output_11=a\\\b "de fg" h + +input_12=a b +output_12=a b + +input_13=""a b"" +output_13=""a b"" + +input_14=a\\\"b c d +output_14=a\\\"b c d + +input_15=a\\\"b c" +output_15=a\\\"b c + +input_16=""a\\\b c" +output_16=""a\\\b c"" + +input_17=\"a +output_17=\"a + +input_18=\\"a +output_18=\a + +input_19=\\"\\\\"a +output_19=\\\a + +input_20=\\"\\\\\"a +output_20=\\\\\\\"a + +input_21="a\\\"b c\" d e +output_21=""a\\\"b c\" d e"" + +input_22=a\\\\\"b c" d e" +output_22=a\\\\\"b "c d e" + +input_23=a:\b c\アルファ オメガ\d +output_23=a:\b c\アルファ オメガ\d + +input_24=a:\b "c\アルファ オメガ\d" +output_24=a:\b "c\アルファ オメガ\d" + +input_25=アルファ オメガ +output_25=アルファ オメガ diff --git a/toolkit/xre/test/win/moz.build b/toolkit/xre/test/win/moz.build new file mode 100644 index 000000000..51ad0bcb3 --- /dev/null +++ b/toolkit/xre/test/win/moz.build @@ -0,0 +1,30 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +SimplePrograms([ + 'TestXREMakeCommandLineWin', +]) + +CppUnitTests([ + 'TestDllInterceptor', +]) + +DEFINES['NS_NO_XPCOM'] = True + +LOCAL_INCLUDES += [ + '/config', + '/toolkit/xre', +] + +DISABLE_STL_WRAPPING = True +USE_STATIC_LIBS = True + +OS_LIBS += [ + 'comctl32', + 'ole32', + 'shell32', + 'ws2_32', +] |