Author: akhaldi Date: Tue Jul 12 21:10:24 2016 New Revision: 71910 URL: http://svn.reactos.org/svn/reactos?rev=71910&view=rev Log: [KERNEL32_WINETEST] Sync with Wine Staging 1.9.14 except thread tests. CORE-11511
Modified: trunk/rostests/winetests/kernel32/codepage.c trunk/rostests/winetests/kernel32/comm.c trunk/rostests/winetests/kernel32/console.c trunk/rostests/winetests/kernel32/directory.c trunk/rostests/winetests/kernel32/file.c trunk/rostests/winetests/kernel32/loader.c trunk/rostests/winetests/kernel32/locale.c trunk/rostests/winetests/kernel32/path.c trunk/rostests/winetests/kernel32/pipe.c trunk/rostests/winetests/kernel32/process.c trunk/rostests/winetests/kernel32/sync.c trunk/rostests/winetests/kernel32/virtual.c Modified: trunk/rostests/winetests/kernel32/codepage.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/kernel32/codepage.c?rev=71910&r1=71909&r2=71910&view=diff ============================================================================== --- trunk/rostests/winetests/kernel32/codepage.c [iso-8859-1] (original) +++ trunk/rostests/winetests/kernel32/codepage.c [iso-8859-1] Tue Jul 12 21:10:24 2016 @@ -1139,8 +1139,8 @@ static void test_dbcs_to_widechar(void) { int i, count, count2; - WCHAR wbuf[2]; - unsigned char buf[] = {0xbf, 0xb4, 0xc7}; + WCHAR wbuf[5]; + unsigned char buf[] = {0xbf, 0xb4, 0xc7, '\0', 'x'}; static const DWORD flags[] = { MB_PRECOMPOSED, MB_COMPOSITE, @@ -1157,8 +1157,7 @@ for (i = 0; i < sizeof(flags)/sizeof(DWORD); ++i) { - wbuf[0] = 0xffff; - wbuf[1] = 0xffff; + memset(wbuf, 0xff, sizeof(wbuf)); count = MultiByteToWideChar(936, flags[i], (char*)&buf[0], 2, NULL, 0); count2 = MultiByteToWideChar(936, flags[i], (char*)&buf[0], 2, wbuf, count); @@ -1170,8 +1169,7 @@ for (i = 0; i < sizeof(flags)/sizeof(DWORD); ++i) { - wbuf[0] = 0xffff; - wbuf[1] = 0xffff; + memset(wbuf, 0xff, sizeof(wbuf)); count = MultiByteToWideChar(936, flags[i], (char*)&buf[0], 3, NULL, 0); SetLastError( 0xdeadbeef ); count2 = MultiByteToWideChar(936, flags[i], (char*)&buf[0], 3, wbuf, count); @@ -1190,6 +1188,65 @@ ok(wbuf[0] == 0x770b, "%04x: returned %04x (expected 770b)\n", flags[i], wbuf[0]); ok(wbuf[1] == 0x003f || broken(wbuf[1] == 0), /*windows xp*/ "%04x: wrong wide char: %04x\n", flags[i], wbuf[1]); + ok(wbuf[2] == 0xffff, "%04x: returned %04x (expected ffff)\n", flags[i], wbuf[2]); + } + } + + /* src ends with null character */ + for (i = 0; i < sizeof(flags)/sizeof(DWORD); ++i) + { + memset(wbuf, 0xff, sizeof(wbuf)); + count = MultiByteToWideChar(936, flags[i], (char*)&buf[0], 4, NULL, 0); + SetLastError( 0xdeadbeef ); + count2 = MultiByteToWideChar(936, flags[i], (char*)&buf[0], 4, wbuf, count); + ok(count == count2, "%04x: returned %d (expected %d)\n", flags[i], count2, count); + + if (flags[i] & MB_ERR_INVALID_CHARS) + { + ok(count == 0, "%04x: returned %d (expected 0)\n", flags[i], count); + ok(GetLastError() == ERROR_NO_UNICODE_TRANSLATION, "%04x: returned %d (expected %d)\n", + flags[i], GetLastError(), ERROR_NO_UNICODE_TRANSLATION); + } + else + { + WCHAR wbuf_ok[] = { 0x770b, 0x003f, '\0', 0xffff }; + WCHAR wbuf_broken[] = { 0x770b, '\0', 0xffff, 0xffff }; + ok(count == 3 || broken(count == 2 /*windows xp*/), + "%04x: returned %d (expected 3)\n", flags[i], count); + ok(!memcmp(wbuf, wbuf_ok, sizeof(wbuf_ok)) + || broken(!memcmp(wbuf, wbuf_broken, sizeof(wbuf_broken))), + "%04x: returned %04x %04x %04x %04x (expected %04x %04x %04x %04x)\n", + flags[i], wbuf[0], wbuf[1], wbuf[2], wbuf[3], + wbuf_ok[0], wbuf_ok[1], wbuf_ok[2], wbuf_ok[3]); + } + } + + /* src has null character, but not ends with it */ + for (i = 0; i < sizeof(flags)/sizeof(DWORD); ++i) + { + memset(wbuf, 0xff, sizeof(wbuf)); + count = MultiByteToWideChar(936, flags[i], (char*)&buf[0], 5, NULL, 0); + SetLastError( 0xdeadbeef ); + count2 = MultiByteToWideChar(936, flags[i], (char*)&buf[0], 5, wbuf, count); + ok(count == count2, "%04x: returned %d (expected %d)\n", flags[i], count2, count); + + if (flags[i] & MB_ERR_INVALID_CHARS) + { + ok(count == 0, "%04x: returned %d (expected 0)\n", flags[i], count); + ok(GetLastError() == ERROR_NO_UNICODE_TRANSLATION, "%04x: returned %d (expected %d)\n", + flags[i], GetLastError(), ERROR_NO_UNICODE_TRANSLATION); + } + else + { + WCHAR wbuf_ok[] = { 0x770b, 0x003f, '\0', 'x', 0xffff }; + WCHAR wbuf_broken[] = { 0x770b, '\0', 'x', 0xffff, 0xffff }; + ok(count == 4 || broken(count == 3), + "%04x: returned %d (expected 4)\n", flags[i], count); + ok(!memcmp(wbuf, wbuf_ok, sizeof(wbuf_ok)) + || broken(!memcmp(wbuf, wbuf_broken, sizeof(wbuf_broken))), + "%04x: returned %04x %04x %04x %04x %04x (expected %04x %04x %04x %04x %04x)\n", + flags[i], wbuf[0], wbuf[1], wbuf[2], wbuf[3], wbuf[4], + wbuf_ok[0], wbuf_ok[1], wbuf_ok[2], wbuf_ok[3], wbuf_ok[4]); } } } Modified: trunk/rostests/winetests/kernel32/comm.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/kernel32/comm.c?rev=71910&r1=71909&r2=71910&view=diff ============================================================================== --- trunk/rostests/winetests/kernel32/comm.c [iso-8859-1] (original) +++ trunk/rostests/winetests/kernel32/comm.c [iso-8859-1] Tue Jul 12 21:10:24 2016 @@ -2151,13 +2151,9 @@ iob.Information = -1; offset.QuadPart = (LONGLONG)i; status = pNtReadFile(hcom, 0, NULL, NULL, &iob, buf, 0, &offset, NULL); - /* FIXME: Remove once Wine is fixed */ - if (status == STATUS_PENDING) WaitForSingleObject(hcom, TIMEOUT); if (i >= 0) { -todo_wine ok(status == STATUS_SUCCESS, "%d: expected STATUS_SUCCESS, got %#x\n", i, status); -todo_wine ok(U(iob).Status == STATUS_SUCCESS, "%d: expected STATUS_SUCCESS, got %#x\n", i, U(iob).Status); ok(iob.Information == 0, "%d: expected 0, got %lu\n", i, iob.Information); } Modified: trunk/rostests/winetests/kernel32/console.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/kernel32/console.c?rev=71910&r1=71909&r2=71910&view=diff ============================================================================== --- trunk/rostests/winetests/kernel32/console.c [iso-8859-1] (original) +++ trunk/rostests/winetests/kernel32/console.c [iso-8859-1] Tue Jul 12 21:10:24 2016 @@ -2779,6 +2779,165 @@ pSetConsoleFont(std_output, index); /* restore original font size */ } +static void test_GetConsoleFontInfo(HANDLE std_output) +{ + HANDLE hmod; + BOOL (WINAPI *pGetConsoleFontInfo)(HANDLE, BOOL, DWORD, CONSOLE_FONT_INFO *); + DWORD (WINAPI *pGetNumberOfConsoleFonts)(void); + DWORD num_fonts, index, i; + int memsize, win_width, win_height, tmp_w, tmp_h; + CONSOLE_FONT_INFO *cfi; + BOOL ret; + CONSOLE_SCREEN_BUFFER_INFO csbi; + COORD orig_sb_size, tmp_sb_size, orig_font, tmp_font; + + hmod = GetModuleHandleA("kernel32.dll"); + pGetConsoleFontInfo = (void *)GetProcAddress(hmod, "GetConsoleFontInfo"); + if (!pGetConsoleFontInfo) + { + win_skip("GetConsoleFontInfo is not available\n"); + return; + } + + pGetNumberOfConsoleFonts = (void *)GetProcAddress(hmod, "GetNumberOfConsoleFonts"); + if (!pGetNumberOfConsoleFonts) + { + win_skip("GetNumberOfConsoleFonts is not available\n"); + return; + } + + num_fonts = pGetNumberOfConsoleFonts(); + memsize = num_fonts * sizeof(CONSOLE_FONT_INFO); + cfi = HeapAlloc(GetProcessHeap(), 0, memsize); + memset(cfi, 0, memsize); + + GetConsoleScreenBufferInfo(std_output, &csbi); + orig_sb_size = csbi.dwSize; + tmp_sb_size.X = csbi.dwSize.X + 3; + tmp_sb_size.Y = csbi.dwSize.Y + 5; + SetConsoleScreenBufferSize(std_output, tmp_sb_size); + + SetLastError(0xdeadbeef); + ret = pGetConsoleFontInfo(NULL, FALSE, 0, cfi); + ok(!ret, "got %d, expected zero\n", ret); + todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = pGetConsoleFontInfo(GetStdHandle(STD_INPUT_HANDLE), FALSE, 0, cfi); + ok(!ret, "got %d, expected zero\n", ret); + todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = pGetConsoleFontInfo(std_output, FALSE, 0, cfi); + ok(!ret, "got %d, expected zero\n", ret); + todo_wine ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError()); + + GetConsoleScreenBufferInfo(std_output, &csbi); + win_width = csbi.srWindow.Right - csbi.srWindow.Left + 1; + win_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; + + GetCurrentConsoleFont(std_output, FALSE, &cfi[0]); + index = cfi[0].nFont; + orig_font = GetConsoleFontSize(std_output, index); + + memset(cfi, 0, memsize); + ret = pGetConsoleFontInfo(std_output, FALSE, num_fonts, cfi); + todo_wine ok(ret, "got %d, expected non-zero\n", ret); + + todo_wine ok(cfi[index].dwFontSize.X == win_width, "got %d, expected %d\n", + cfi[index].dwFontSize.X, win_width); + todo_wine ok(cfi[index].dwFontSize.Y == win_height, "got %d, expected %d\n", + cfi[index].dwFontSize.Y, win_height); + + for (i = 0; i < num_fonts; i++) + { + ok(cfi[i].nFont == i, "element out of order, got nFont %d, expected %d\n", cfi[i].nFont, i); + tmp_font = GetConsoleFontSize(std_output, cfi[i].nFont); + tmp_w = (double)orig_font.X / tmp_font.X * win_width; + tmp_h = (double)orig_font.Y / tmp_font.Y * win_height; + todo_wine ok(cfi[i].dwFontSize.X == tmp_w, "got %d, expected %d\n", cfi[i].dwFontSize.X, tmp_w); + todo_wine ok(cfi[i].dwFontSize.Y == tmp_h, "got %d, expected %d\n", cfi[i].dwFontSize.Y, tmp_h); + } + + SetLastError(0xdeadbeef); + ret = pGetConsoleFontInfo(NULL, TRUE, 0, cfi); + ok(!ret, "got %d, expected zero\n", ret); + todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = pGetConsoleFontInfo(GetStdHandle(STD_INPUT_HANDLE), TRUE, 0, cfi); + ok(!ret, "got %d, expected zero\n", ret); + todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = pGetConsoleFontInfo(std_output, TRUE, 0, cfi); + ok(!ret, "got %d, expected zero\n", ret); + todo_wine ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError()); + + memset(cfi, 0, memsize); + ret = pGetConsoleFontInfo(std_output, TRUE, num_fonts, cfi); + todo_wine ok(ret, "got %d, expected non-zero\n", ret); + + todo_wine ok(cfi[index].dwFontSize.X == csbi.dwMaximumWindowSize.X, "got %d, expected %d\n", + cfi[index].dwFontSize.X, csbi.dwMaximumWindowSize.X); + todo_wine ok(cfi[index].dwFontSize.Y == csbi.dwMaximumWindowSize.Y, "got %d, expected %d\n", + cfi[index].dwFontSize.Y, csbi.dwMaximumWindowSize.Y); + + for (i = 0; i < num_fonts; i++) + { + ok(cfi[i].nFont == i, "element out of order, got nFont %d, expected %d\n", cfi[i].nFont, i); + tmp_font = GetConsoleFontSize(std_output, cfi[i].nFont); + tmp_w = (double)orig_font.X / tmp_font.X * csbi.dwMaximumWindowSize.X; + tmp_h = (double)orig_font.Y / tmp_font.Y * csbi.dwMaximumWindowSize.Y; + todo_wine ok(cfi[i].dwFontSize.X == tmp_w, "got %d, expected %d\n", cfi[i].dwFontSize.X, tmp_w); + todo_wine ok(cfi[i].dwFontSize.Y == tmp_h, "got %d, expected %d\n", cfi[i].dwFontSize.Y, tmp_h); + } + + HeapFree(GetProcessHeap(), 0, cfi); + SetConsoleScreenBufferSize(std_output, orig_sb_size); +} + +static void test_SetConsoleFont(HANDLE std_output) +{ + HANDLE hmod; + BOOL (WINAPI *pSetConsoleFont)(HANDLE, DWORD); + BOOL ret; + DWORD (WINAPI *pGetNumberOfConsoleFonts)(void); + DWORD num_fonts; + + hmod = GetModuleHandleA("kernel32.dll"); + pSetConsoleFont = (void *)GetProcAddress(hmod, "SetConsoleFont"); + if (!pSetConsoleFont) + { + win_skip("SetConsoleFont is not available\n"); + return; + } + + SetLastError(0xdeadbeef); + ret = pSetConsoleFont(NULL, 0); + ok(!ret, "got %d, expected zero\n", ret); + todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = pSetConsoleFont(GetStdHandle(STD_INPUT_HANDLE), 0); + ok(!ret, "got %d, expected zero\n", ret); + todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError()); + + pGetNumberOfConsoleFonts = (void *)GetProcAddress(hmod, "GetNumberOfConsoleFonts"); + if (!pGetNumberOfConsoleFonts) + { + win_skip("GetNumberOfConsoleFonts is not available\n"); + return; + } + + num_fonts = pGetNumberOfConsoleFonts(); + + SetLastError(0xdeadbeef); + ret = pSetConsoleFont(std_output, num_fonts); + ok(!ret, "got %d, expected zero\n", ret); + todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError()); +} + START_TEST(console) { static const char font_name[] = "Lucida Console"; @@ -2925,4 +3084,6 @@ test_GetCurrentConsoleFont(hConOut); test_GetConsoleFontSize(hConOut); test_GetLargestConsoleWindowSize(hConOut); -} + test_GetConsoleFontInfo(hConOut); + test_SetConsoleFont(hConOut); +} Modified: trunk/rostests/winetests/kernel32/directory.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/kernel32/directory.c?rev=71910&r1=71909&r2=71910&view=diff ============================================================================== --- trunk/rostests/winetests/kernel32/directory.c [iso-8859-1] (original) +++ trunk/rostests/winetests/kernel32/directory.c [iso-8859-1] Tue Jul 12 21:10:24 2016 @@ -157,6 +157,7 @@ static void test_CreateDirectoryA(void) { char tmpdir[MAX_PATH]; + WCHAR curdir[MAX_PATH]; BOOL ret; ret = CreateDirectoryA(NULL, NULL); @@ -172,6 +173,7 @@ ret = GetSystemDirectoryA(tmpdir, MAX_PATH); ok(ret < MAX_PATH, "System directory should fit into MAX_PATH\n"); + GetCurrentDirectoryW(MAX_PATH, curdir); ret = SetCurrentDirectoryA(tmpdir); ok(ret == TRUE, "could not chdir to the System directory\n"); @@ -329,6 +331,7 @@ ret = RemoveDirectoryA(tmpdir); ok(ret == TRUE, "RemoveDirectoryA(%s) failed err=%d\n", tmpdir, GetLastError()); + SetCurrentDirectoryW(curdir); } static void test_CreateDirectoryW(void) @@ -341,6 +344,7 @@ static const WCHAR slashW[] = {'/',0}; static const WCHAR dotdotW[] = {'.','.',0}; static const WCHAR questionW[] = {'?',0}; + WCHAR curdir[MAX_PATH]; ret = CreateDirectoryW(NULL, NULL); if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) @@ -358,6 +362,7 @@ ret = GetSystemDirectoryW(tmpdir, MAX_PATH); ok(ret < MAX_PATH, "System directory should fit into MAX_PATH\n"); + GetCurrentDirectoryW(MAX_PATH, curdir); ret = SetCurrentDirectoryW(tmpdir); ok(ret == TRUE, "could not chdir to the System directory ret %u err %u\n", ret, GetLastError()); @@ -413,6 +418,8 @@ ret, GetLastError()); ret = RemoveDirectoryW(tmpdir); ok(ret == FALSE, "RemoveDirectoryW should have failed\n"); + + SetCurrentDirectoryW(curdir); } static void test_RemoveDirectoryA(void) Modified: trunk/rostests/winetests/kernel32/file.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/kernel32/file.c?rev=71910&r1=71909&r2=71910&view=diff ============================================================================== --- trunk/rostests/winetests/kernel32/file.c [iso-8859-1] (original) +++ trunk/rostests/winetests/kernel32/file.c [iso-8859-1] Tue Jul 12 21:10:24 2016 @@ -1214,6 +1214,7 @@ {NULL, 0, -1, 0, FALSE} }; BY_HANDLE_FILE_INFORMATION Finfo; + WCHAR curdir[MAX_PATH]; ret = GetTempPathA(MAX_PATH, temp_path); ok(ret != 0, "GetTempPathA error %d\n", GetLastError()); @@ -1278,6 +1279,7 @@ ret = CreateDirectoryA(dirname, NULL); ok( ret, "Createdirectory failed, gle=%d\n", GetLastError() ); /* set current drive & directory to known location */ + GetCurrentDirectoryW( MAX_PATH, curdir); SetCurrentDirectoryA( temp_path ); i = 0; while (p[i].file) @@ -1332,7 +1334,7 @@ } ret = RemoveDirectoryA(dirname); ok(ret, "RemoveDirectoryA: error %d\n", GetLastError()); - + SetCurrentDirectoryW(curdir); /* test opening directory as a directory */ hFile = CreateFileA( temp_path, GENERIC_READ, @@ -3450,6 +3452,11 @@ "wrong error %u\n", GetLastError() ); ok( r == FALSE, "should return false\n"); + r = GetOverlappedResult( 0, &ov, &result, TRUE ); + ok( r == TRUE, "should return TRUE\n" ); + ok( result == 0xabcd, "wrong result %u\n", result ); + ok( ov.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %08lx\n", ov.Internal ); + ResetEvent( ov.hEvent ); SetLastError( 0xb00 ); @@ -3845,17 +3852,13 @@ if (i == 0 || i == 5) { /* FIXME: remove once Wine is fixed */ -if (i == 5) todo_wine - ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError()); -else +todo_wine_if (i == 5) ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError()); } else { /* FIXME: remove once Wine is fixed */ -if (i == 1) todo_wine - ok(GetLastError() == ERROR_ACCESS_DENIED, "%d: expected ERROR_ACCESS_DENIED, got %d\n", i, GetLastError()); -else +todo_wine_if (i == 1) ok(GetLastError() == ERROR_ACCESS_DENIED, "%d: expected ERROR_ACCESS_DENIED, got %d\n", i, GetLastError()); } @@ -3867,9 +3870,7 @@ else { /* FIXME: remove once Wine is fixed */ -if (i == 1) todo_wine - ok(GetLastError() == ERROR_ACCESS_DENIED, "%d: expected ERROR_ACCESS_DENIED, got %d\n", i, GetLastError()); -else +todo_wine_if (i == 1) ok(GetLastError() == ERROR_ACCESS_DENIED, "%d: expected ERROR_ACCESS_DENIED, got %d\n", i, GetLastError()); } } @@ -4543,9 +4544,28 @@ strcpy(dos_path, dos_prefix); strcat(dos_path, long_path); + count = pGetFinalPathNameByHandleA(INVALID_HANDLE_VALUE, NULL, 0, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); + ok(count == 0, "Expected length 0, got %u\n", count); + ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %u\n", GetLastError()); + file = CreateFileA(test_path, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, 0); ok(file != INVALID_HANDLE_VALUE, "CreateFileA error %u\n", GetLastError()); + + if (0) { + /* Windows crashes on NULL path */ + count = pGetFinalPathNameByHandleA(file, NULL, MAX_PATH, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); + ok(count == 0, "Expected length 0, got %u\n", count); + ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %u\n", GetLastError()); + } + + /* Test 0-length path */ + count = pGetFinalPathNameByHandleA(file, result_path, 0, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); + ok(count == strlen(dos_path), "Expected length %u, got %u\n", lstrlenA(dos_path), count); + + /* Test 0 and NULL path */ + count = pGetFinalPathNameByHandleA(file, NULL, 0, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); + ok(count == strlen(dos_path), "Expected length %u, got %u\n", lstrlenA(dos_path), count); /* Test VOLUME_NAME_DOS with sufficient buffer size */ memset(result_path, 0x11, sizeof(result_path)); @@ -4608,6 +4628,10 @@ ok(count == 0, "Expected length 0, got %u\n", count); ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %u\n", GetLastError()); + count = pGetFinalPathNameByHandleW(INVALID_HANDLE_VALUE, NULL, 0, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); + ok(count == 0, "Expected length 0, got %u\n", count); + ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %u\n", GetLastError()); + count = GetTempPathW(MAX_PATH, temp_path); ok(count, "Failed to get temp path, error %u\n", GetLastError()); ret = GetTempFileNameW(temp_path, prefix, 0, test_path); @@ -4620,6 +4644,23 @@ file = CreateFileW(test_path, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, 0); ok(file != INVALID_HANDLE_VALUE, "CreateFileW error %u\n", GetLastError()); + + if (0) { + /* Windows crashes on NULL path */ + count = pGetFinalPathNameByHandleW(file, NULL, MAX_PATH, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); + ok(count == 0, "Expected length 0, got %u\n", count); + ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %u\n", GetLastError()); + } + + /* Test 0-length path */ + count = pGetFinalPathNameByHandleW(file, result_path, 0, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); + ok(count == lstrlenW(dos_path) + 1 || + broken(count == lstrlenW(dos_path) + 2), "Expected length %u, got %u\n", lstrlenW(dos_path) + 1, count); + + /* Test 0 and NULL path */ + count = pGetFinalPathNameByHandleW(file, NULL, 0, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); + ok(count == lstrlenW(dos_path) + 1 || + broken(count == lstrlenW(dos_path) + 2), "Expected length %u, got %u\n", lstrlenW(dos_path) + 1, count); /* Test VOLUME_NAME_DOS with sufficient buffer size */ memset(result_path, 0x11, sizeof(result_path)); Modified: trunk/rostests/winetests/kernel32/loader.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/kernel32/loader.c?rev=71910&r1=71909&r2=71910&view=diff ============================================================================== --- trunk/rostests/winetests/kernel32/loader.c [iso-8859-1] (original) +++ trunk/rostests/winetests/kernel32/loader.c [iso-8859-1] Tue Jul 12 21:10:24 2016 @@ -2750,6 +2750,24 @@ DeleteFileA(dll_name); } +static void test_InMemoryOrderModuleList(void) +{ + LIST_ENTRY *entry1, *mark1 = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList; + LIST_ENTRY *entry2, *mark2 = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList; + LDR_MODULE *module1, *module2; + + for (entry1 = mark1->Flink, entry2 = mark2->Flink; + entry1 != mark1 && entry2 != mark2; + entry1 = entry1->Flink, entry2 = entry2->Flink) + { + module1 = CONTAINING_RECORD(entry1, LDR_MODULE, InLoadOrderModuleList); + module2 = CONTAINING_RECORD(entry2, LDR_MODULE, InMemoryOrderModuleList); + ok(module1 == module2, "expected module1 == module2, got %p and %p\n", module1, module2); + } + ok(entry1 == mark1, "expected entry1 == mark1, got %p and %p\n", entry1, mark1); + ok(entry2 == mark2, "expected entry2 == mark2, got %p and %p\n", entry2, mark2); +} + START_TEST(loader) { int argc; @@ -2804,4 +2822,5 @@ test_section_access(); test_import_resolution(); test_ExitProcess(); + test_InMemoryOrderModuleList(); } Modified: trunk/rostests/winetests/kernel32/locale.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/kernel32/locale.c?rev=71910&r1=71909&r2=71910&view=diff ============================================================================== --- trunk/rostests/winetests/kernel32/locale.c [iso-8859-1] (original) +++ trunk/rostests/winetests/kernel32/locale.c [iso-8859-1] Tue Jul 12 21:10:24 2016 @@ -74,7 +74,6 @@ } /* Some functions are only in later versions of kernel32.dll */ -static HMODULE hKernel32; static WORD enumCount; static INT (WINAPI *pGetTimeFormatEx)(LPCWSTR, DWORD, const SYSTEMTIME *, LPCWSTR, LPWSTR, INT); @@ -101,12 +100,14 @@ static INT (WINAPI *pGetGeoInfoW)(GEOID, GEOTYPE, LPWSTR, INT, LANGID); static BOOL (WINAPI *pEnumSystemGeoID)(GEOCLASS, GEOID, GEO_ENUMPROC); static BOOL (WINAPI *pGetSystemPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*); +static BOOL (WINAPI *pGetThreadPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*); +static WCHAR (WINAPI *pRtlUpcaseUnicodeChar)(WCHAR); static void InitFunctionPointers(void) { - hKernel32 = GetModuleHandleA("kernel32"); - -#define X(f) p##f = (void*)GetProcAddress(hKernel32, #f) + HMODULE mod = GetModuleHandleA("kernel32"); + +#define X(f) p##f = (void*)GetProcAddress(mod, #f) X(GetTimeFormatEx); X(GetDateFormatEx); X(EnumSystemLanguageGroupsA); @@ -130,6 +131,10 @@ X(GetGeoInfoW); X(EnumSystemGeoID); X(GetSystemPreferredUILanguages); + X(GetThreadPreferredUILanguages); + + mod = GetModuleHandleA("ntdll"); + X(RtlUpcaseUnicodeChar); #undef X } @@ -2458,7 +2463,7 @@ SetLastError(0xdeadbeef); lcid = pLocaleNameToLCID(fooW, 0); ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected lcid == 0, got got %08x, error %d\n", lcid, GetLastError()); + "Expected lcid == 0, got %08x, error %d\n", lcid, GetLastError()); /* english neutral name */ lcid = pLocaleNameToLCID(enW, 0); @@ -3767,6 +3772,18 @@ GetStringTypeW(CT_CTYPE1, ch, 2, types); ok(types[0] == (C1_DEFINED|C1_SPACE), "got %x\n", types[0]); ok(types[1] == (C1_DEFINED|C1_SPACE), "got %x\n", types[1]); + + /* check Arabic range for kashida flag */ + for (ch[0] = 0x600; ch[0] <= 0x6ff; ch[0] += 1) + { + types[0] = 0; + ret = GetStringTypeW(CT_CTYPE3, ch, 1, types); + ok(ret, "%#x: failed %d\n", ch[0], ret); + if (ch[0] == 0x640) /* ARABIC TATWEEL (Kashida) */ + ok(types[0] & C3_KASHIDA, "%#x: type %#x\n", ch[0], types[0]); + else + ok(!(types[0] & C3_KASHIDA), "%#x: type %#x\n", ch[0], types[0]); + } } static void test_IdnToNameprepUnicode(void) @@ -4180,6 +4197,8 @@ ok(!ret, "IsValidLocaleName should have failed\n"); ret = pIsValidLocaleName(LOCALE_NAME_INVARIANT); ok(ret, "IsValidLocaleName failed\n"); + ret = pIsValidLocaleName(NULL); + ok(!ret, "IsValidLocaleName should have failed\n"); } static void test_CompareStringOrdinal(void) @@ -4196,6 +4215,7 @@ WCHAR coop2[] = { 'c','o','o','p',0 }; WCHAR nonascii1[] = { 0x0102,0 }; WCHAR nonascii2[] = { 0x0201,0 }; + WCHAR ch1, ch2; if (!pCompareStringOrdinal) { @@ -4252,6 +4272,21 @@ ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN); ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, TRUE); ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN); + + for (ch1 = 0; ch1 < 512; ch1++) + { + for (ch2 = 0; ch2 < 1024; ch2++) + { + int diff = ch1 - ch2; + ret = pCompareStringOrdinal( &ch1, 1, &ch2, 1, FALSE ); + ok( ret == (diff > 0 ? CSTR_GREATER_THAN : diff < 0 ? CSTR_LESS_THAN : CSTR_EQUAL), + "wrong result %d %04x %04x\n", ret, ch1, ch2 ); + diff = pRtlUpcaseUnicodeChar( ch1 ) - pRtlUpcaseUnicodeChar( ch2 ); + ret = pCompareStringOrdinal( &ch1, 1, &ch2, 1, TRUE ); + ok( ret == (diff > 0 ? CSTR_GREATER_THAN : diff < 0 ? CSTR_LESS_THAN : CSTR_EQUAL), + "wrong result %d %04x %04x\n", ret, ch1, ch2 ); + } + } } static void test_GetGeoInfo(void) @@ -4685,7 +4720,7 @@ size_buffer = max(size_id, size_name); if(!size_buffer) { - skip("No vaild buffer size\n"); + skip("No valid buffer size\n"); return; } @@ -4771,6 +4806,34 @@ ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n"); ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(), "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); + + HeapFree(GetProcessHeap(), 0, buffer); +} + +static void test_GetThreadPreferredUILanguages(void) +{ + BOOL ret; + ULONG count, size; + WCHAR *buf; + + if (!pGetThreadPreferredUILanguages) + { + win_skip("GetThreadPreferredUILanguages is not available.\n"); + return; + } + + size = count = 0; + ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID|MUI_UI_FALLBACK, &count, NULL, &size); + ok(ret, "got %u\n", GetLastError()); + ok(count, "expected count > 0\n"); + ok(size, "expected size > 0\n"); + + count = 0; + buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size * sizeof(WCHAR)); + ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID|MUI_UI_FALLBACK, &count, buf, &size); + ok(ret, "got %u\n", GetLastError()); + ok(count, "expected count > 0\n"); + HeapFree(GetProcessHeap(), 0, buf); } START_TEST(locale) @@ -4816,5 +4879,6 @@ test_EnumSystemGeoID(); test_invariant(); test_GetSystemPreferredUILanguages(); + test_GetThreadPreferredUILanguages(); test_sorting(); } Modified: trunk/rostests/winetests/kernel32/path.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/kernel32/path.c?rev=71910&r1=71909&r2=71910&view=diff ============================================================================== --- trunk/rostests/winetests/kernel32/path.c [iso-8859-1] (original) +++ trunk/rostests/winetests/kernel32/path.c [iso-8859-1] Tue Jul 12 21:10:24 2016 @@ -1116,10 +1116,9 @@ { char save_TMP[MAX_PATH]; char windir[MAX_PATH]; - char origdir[MAX_PATH]; char buf[MAX_PATH]; - - GetCurrentDirectoryA(sizeof(origdir), origdir); + WCHAR curdir[MAX_PATH]; + if (!GetEnvironmentVariableA("TMP", save_TMP, sizeof(save_TMP))) save_TMP[0] = 0; /* test default configuration */ @@ -1151,6 +1150,7 @@ test_GetTempPathA(windir); test_GetTempPathW(windir); + GetCurrentDirectoryW(MAX_PATH, curdir); /* TMP=C: i.e. use current working directory of the specified drive */ GetWindowsDirectoryA(windir, sizeof(windir)); SetCurrentDirectoryA(windir); @@ -1164,13 +1164,13 @@ test_GetTempPathW(windir); SetEnvironmentVariableA("TMP", save_TMP); - SetCurrentDirectoryA(origdir); + SetCurrentDirectoryW(curdir); } static void test_GetLongPathNameA(void) { DWORD length, explength, hostsize; - char tempfile[MAX_PATH]; + char tempfile[MAX_PATH], *name; char longpath[MAX_PATH]; char unc_prefix[MAX_PATH]; char unc_short[MAX_PATH], unc_long[MAX_PATH]; @@ -1181,7 +1181,15 @@ return; GetTempPathA(MAX_PATH, tempfile); - lstrcatA(tempfile, "longfilename.longext"); + name = tempfile + strlen(tempfile); + + strcpy(name, "*"); + SetLastError(0xdeadbeef); + length = pGetLongPathNameA(tempfile, temppath, MAX_PATH); + ok(!length, "GetLongPathNameA should fail\n"); + ok(GetLastError() == ERROR_INVALID_NAME, "wrong error %d\n", GetLastError()); + + strcpy(name, "longfilename.longext"); file = CreateFileA(tempfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); CloseHandle(file); @@ -1385,6 +1393,7 @@ static const WCHAR name[] = { 't', 'e', 's', 't', 0 }; static const WCHAR backSlash[] = { '\\', 0 }; static const WCHAR a_bcdeW[] = {'a','.','b','c','d','e',0}; + static const WCHAR wildW[] = { '*',0 }; WCHAR path[MAX_PATH], tmppath[MAX_PATH], *ptr; WCHAR short_path[MAX_PATH]; DWORD length; @@ -1447,6 +1456,13 @@ length = GetShortPathNameW( path, short_path, sizeof(short_path)/sizeof(*short_path) ); ok( length, "GetShortPathNameW failed: %u.\n", GetLastError() ); + lstrcpyW(ptr, wildW); + SetLastError(0xdeadbeef); + length = GetShortPathNameW( path, short_path, sizeof(short_path)/sizeof(*short_path) ); + ok(!length, "GetShortPathNameW should fail\n"); + ok(GetLastError() == ERROR_INVALID_NAME, "wrong error %d\n", GetLastError()); + + lstrcpyW(ptr, a_bcdeW); ret = DeleteFileW( path ); ok( ret, "Cannot delete file.\n" ); *ptr = 0; @@ -2142,9 +2158,11 @@ char path[MAX_PATH], buf[MAX_PATH]; HANDLE file; int ret; + WCHAR curdir[MAX_PATH]; if (!pGetLongPathNameA) return; + GetCurrentDirectoryW(MAX_PATH, curdir); GetTempPathA(MAX_PATH, path); ret = SetCurrentDirectoryA(path); ok(ret, "SetCurrentDirectory error %d\n", GetLastError()); @@ -2202,6 +2220,7 @@ DeleteFileA("foo\\file"); RemoveDirectoryA("foo"); RemoveDirectoryA("bar"); + SetCurrentDirectoryW(curdir); } static void test_CheckNameLegalDOS8Dot3(void) Modified: trunk/rostests/winetests/kernel32/pipe.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/kernel32/pipe.c?rev=71910&r1=71909&r2=71910&view=diff ============================================================================== --- trunk/rostests/winetests/kernel32/pipe.c [iso-8859-1] (original) +++ trunk/rostests/winetests/kernel32/pipe.c [iso-8859-1] Tue Jul 12 21:10:24 2016 @@ -2571,6 +2571,64 @@ CloseHandle(thread); } +static void test_overlapped_error(void) +{ + HANDLE pipe, file, event; + DWORD err, numbytes; + OVERLAPPED overlapped; + BOOL ret; + + event = CreateEventA(NULL, TRUE, FALSE, NULL); + ok(event != NULL, "CreateEventA failed with %u\n", GetLastError()); + + pipe = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + 1, 1024, 1024, NMPWAIT_WAIT_FOREVER, NULL); + ok(pipe != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with %u\n", GetLastError()); + + memset(&overlapped, 0, sizeof(overlapped)); + overlapped.hEvent = event; + ret = ConnectNamedPipe(pipe, &overlapped); + err = GetLastError(); + ok(ret == FALSE, "ConnectNamedPipe succeeded\n"); + ok(err == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %u\n", err); + + file = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); + ok(file != INVALID_HANDLE_VALUE, "CreateFile failed with %u\n", GetLastError()); + + numbytes = 0xdeadbeef; + ret = GetOverlappedResult(pipe, &overlapped, &numbytes, TRUE); + ok(ret == TRUE, "GetOverlappedResult failed\n"); + ok(numbytes == 0, "expected 0, got %u\n", numbytes); + ok(overlapped.Internal == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08lx\n", overlapped.Internal); + + CloseHandle(file); + CloseHandle(pipe); + + pipe = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + 1, 1024, 1024, NMPWAIT_WAIT_FOREVER, NULL); + ok(pipe != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with %u\n", GetLastError()); + + file = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); + ok(file != INVALID_HANDLE_VALUE, "CreateFile failed with %u\n", GetLastError()); + + memset(&overlapped, 0, sizeof(overlapped)); + overlapped.hEvent = event; + ret = ConnectNamedPipe(pipe, &overlapped); + err = GetLastError(); + ok(ret == FALSE, "ConnectNamedPipe succeeded\n"); + ok(err == ERROR_PIPE_CONNECTED, "expected ERROR_PIPE_CONNECTED, got %u\n", err); + ok(overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %08lx\n", overlapped.Internal); + + CloseHandle(file); + CloseHandle(pipe); + + CloseHandle(event); +} + static void test_nowait(int pipemode) { HANDLE hnp; @@ -3400,6 +3458,7 @@ test_CloseHandle(); test_impersonation(); test_overlapped(); + test_overlapped_error(); test_nowait(PIPE_TYPE_BYTE); test_nowait(PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE); test_NamedPipeHandleState(); Modified: trunk/rostests/winetests/kernel32/process.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/kernel32/process.c?rev=71910&r1=71909&r2=71910&view=diff ============================================================================== --- trunk/rostests/winetests/kernel32/process.c [iso-8859-1] (original) +++ trunk/rostests/winetests/kernel32/process.c [iso-8859-1] Tue Jul 12 21:10:24 2016 @@ -88,6 +88,7 @@ static BOOL (WINAPI *pThread32First)(HANDLE, THREADENTRY32*); static BOOL (WINAPI *pThread32Next)(HANDLE, THREADENTRY32*); static BOOL (WINAPI *pGetLogicalProcessorInformationEx)(LOGICAL_PROCESSOR_RELATIONSHIP,SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*,DWORD*); +static SIZE_T (WINAPI *pGetLargePageMinimum)(void); /* ############################### */ static char base[MAX_PATH]; @@ -252,6 +253,7 @@ pThread32First = (void *)GetProcAddress(hkernel32, "Thread32First"); pThread32Next = (void *)GetProcAddress(hkernel32, "Thread32Next"); pGetLogicalProcessorInformationEx = (void *)GetProcAddress(hkernel32, "GetLogicalProcessorInformationEx"); + pGetLargePageMinimum = (void *)GetProcAddress(hkernel32, "GetLargePageMinimum"); return TRUE; } @@ -2991,7 +2993,7 @@ sizeof(buf) /* ProcessHandleTracing */, sizeof(ULONG) /* ProcessIoPriority */, sizeof(ULONG) /* ProcessExecuteFlags */, -#if 0 /* FIXME: Add remaning classes */ +#if 0 /* FIXME: Add remaining classes */ ProcessResourceManagement, sizeof(ULONG) /* ProcessCookie */, sizeof(SECTION_IMAGE_INFORMATION) /* ProcessImageInformation */, @@ -3138,6 +3140,19 @@ HeapFree(GetProcessHeap(), 0, info); } +static void test_largepages(void) +{ + SIZE_T size; + + if (!pGetLargePageMinimum) { + skip("No GetLargePageMinimum support.\n"); + return; + } + size = pGetLargePageMinimum(); + + ok((size == 0) || (size == 2*1024*1024) || (size == 4*1024*1024), "GetLargePageMinimum reports %ld size\n", size); +} + START_TEST(process) { HANDLE job; @@ -3210,6 +3225,7 @@ test_GetNumaProcessorNode(); test_session_info(); test_GetLogicalProcessorInformationEx(); + test_largepages(); /* things that can be tested: * lookup: check the way program to be executed is searched Modified: trunk/rostests/winetests/kernel32/sync.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/kernel32/sync.c?rev=71910&r1=71909&r2=71910&view=diff ============================================================================== --- trunk/rostests/winetests/kernel32/sync.c [iso-8859-1] (original) +++ trunk/rostests/winetests/kernel32/sync.c [iso-8859-1] Tue Jul 12 21:10:24 2016 @@ -1740,9 +1740,9 @@ /* Sequence of wake/sleep to check boundary conditions: * 0: init - * 1: producer emits a WakeConditionVaribale without consumer waiting. + * 1: producer emits a WakeConditionVariable without consumer waiting. * 2: consumer sleeps without a wake expecting timeout - * 3: producer emits a WakeAllConditionVaribale without consumer waiting. + * 3: producer emits a WakeAllConditionVariable without consumer waiting. * 4: consumer sleeps without a wake expecting timeout * 5: a wake is handed to a SleepConditionVariableCS * 6: a wakeall is handed to a SleepConditionVariableCS Modified: trunk/rostests/winetests/kernel32/virtual.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/kernel32/virtual.c?rev=71910&r1=71909&r2=71910&view=diff ============================================================================== --- trunk/rostests/winetests/kernel32/virtual.c [iso-8859-1] (original) +++ trunk/rostests/winetests/kernel32/virtual.c [iso-8859-1] Tue Jul 12 21:10:24 2016 @@ -43,7 +43,6 @@ static NTSTATUS (WINAPI *pNtAreMappedFilesTheSame)(PVOID,PVOID); static NTSTATUS (WINAPI *pNtMapViewOfSection)(HANDLE, HANDLE, PVOID *, ULONG, SIZE_T, const LARGE_INTEGER *, SIZE_T *, ULONG, ULONG, ULONG); static DWORD (WINAPI *pNtUnmapViewOfSection)(HANDLE, PVOID); -static struct _TEB * (WINAPI *pNtCurrentTeb)(void); static PVOID (WINAPI *pRtlAddVectoredExceptionHandler)(ULONG, PVECTORED_EXCEPTION_HANDLER); static ULONG (WINAPI *pRtlRemoveVectoredExceptionHandler)(PVOID); static BOOL (WINAPI *pGetProcessDEPPolicy)(HANDLE, LPDWORD, PBOOL); @@ -454,7 +453,7 @@ SetLastError(0xdeadbeef); file = CreateFileA( testfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 ); ok( file != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() ); - SetFilePointer( file, 4096, NULL, FILE_BEGIN ); + SetFilePointer( file, 12288, NULL, FILE_BEGIN ); SetEndOfFile( file ); /* read/write mapping */ @@ -1013,6 +1012,31 @@ ok(info.State == MEM_FREE, "%#x != MEM_FREE\n", info.State); ok(info.Type == 0, "%#x != 0\n", info.Type); + mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 12288, NULL ); + ok( mapping != 0, "CreateFileMappingA failed with error %u\n", GetLastError() ); + + ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 12288 ); + ok( ptr != NULL, "MapViewOfFile failed with error %u\n", GetLastError() ); + + ret = UnmapViewOfFile( (char *)ptr + 100 ); + ok( ret, "UnmapViewOfFile failed with error %u\n", GetLastError() ); + if (!ret) UnmapViewOfFile( ptr ); + + ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 12288 ); + ok( ptr != NULL, "MapViewOfFile failed with error %u\n", GetLastError() ); + + ret = UnmapViewOfFile( (char *)ptr + 4096 ); + ok( ret, "UnmapViewOfFile failed with error %u\n", GetLastError() ); + if (!ret) UnmapViewOfFile( ptr ); + + ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 12288 ); + ok( ptr != NULL, "MapViewOfFile failed with error %u\n", GetLastError() ); + + ret = UnmapViewOfFile( (char *)ptr + 4096 + 100 ); + ok( ret, "UnmapViewOfFile failed with error %u\n", GetLastError() ); + if (!ret) UnmapViewOfFile( ptr ); + + CloseHandle(mapping); CloseHandle(file); DeleteFileA(testfile); } @@ -1824,263 +1848,14 @@ VirtualFree( base, 0, MEM_RELEASE ); } -#ifdef __i386__ - -static DWORD num_guard_page_calls; - -static DWORD guard_page_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, - CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) -{ - trace( "exception: %08x flags:%x addr:%p\n", - rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress ); - - ok( rec->NumberParameters == 2, "NumberParameters is %d instead of 2\n", rec->NumberParameters ); - ok( rec->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION, "ExceptionCode is %08x instead of %08x\n", - rec->ExceptionCode, STATUS_GUARD_PAGE_VIOLATION ); - - num_guard_page_calls++; - *(int *)rec->ExceptionInformation[1] += 0x100; - - return ExceptionContinueExecution; -} - -static void test_guard_page(void) -{ - EXCEPTION_REGISTRATION_RECORD frame; - MEMORY_BASIC_INFORMATION info; - DWORD ret, size, old_prot; - int *value, old_value; - void *results[64]; - ULONG_PTR count; - ULONG pagesize; - BOOL success; - char *base; - - if (!pNtCurrentTeb) - { - win_skip( "NtCurrentTeb not supported\n" ); - return; - } - - size = 0x1000; - base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE | PAGE_GUARD ); - ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() ); - value = (int *)base; - - /* verify info structure */ - ret = VirtualQuery( base, &info, sizeof(info) ); - ok( ret, "VirtualQuery failed %u\n", GetLastError()); - ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base ); - ok( info.AllocationProtect == (PAGE_READWRITE | PAGE_GUARD), "wrong AllocationProtect %x\n", info.AllocationProtect ); - ok( info.RegionSize == size, "wrong RegionSize 0x%lx\n", info.RegionSize ); - ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State ); - ok( info.Protect == (PAGE_READWRITE | PAGE_GUARD), "wrong Protect 0x%x\n", info.Protect ); - ok( info.Type == MEM_PRIVATE, "wrong Type 0x%x\n", info.Type ); - - /* put some initial value into the memory */ - success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); - ok( old_prot == (PAGE_READWRITE | PAGE_GUARD), "wrong old prot %x\n", old_prot ); - - *value = 1; - *(value + 1) = 2; - - success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); - ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot ); - - /* test behaviour of VirtualLock - first attempt should fail */ - SetLastError( 0xdeadbeef ); - success = VirtualLock( base, size ); - ok( !success, "VirtualLock unexpectedly succeeded\n" ); - todo_wine - ok( GetLastError() == STATUS_GUARD_PAGE_VIOLATION, "wrong error %u\n", GetLastError() ); - - success = VirtualLock( base, size ); - todo_wine - ok( success, "VirtualLock failed %u\n", GetLastError() ); - if (success) - { - ok( *value == 1, "memory block contains wrong value, expected 1, got 0x%x\n", *value ); - success = VirtualUnlock( base, size ); - ok( success, "VirtualUnlock failed %u\n", GetLastError() ); - } - - /* check info structure again, PAGE_GUARD should be removed now */ - ret = VirtualQuery( base, &info, sizeof(info) ); - ok( ret, "VirtualQuery failed %u\n", GetLastError()); - ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base ); - ok( info.AllocationProtect == (PAGE_READWRITE | PAGE_GUARD), "wrong AllocationProtect %x\n", info.AllocationProtect ); - ok( info.RegionSize == size, "wrong RegionSize 0x%lx\n", info.RegionSize ); - ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State ); - todo_wine - ok( info.Protect == PAGE_READWRITE, "wrong Protect 0x%x\n", info.Protect ); - ok( info.Type == MEM_PRIVATE, "wrong Type 0x%x\n", info.Type ); - - success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); - todo_wine - ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot ); - - /* test directly accessing the memory - we need to setup an exception handler first */ - frame.Handler = guard_page_handler; - frame.Prev = pNtCurrentTeb()->Tib.ExceptionList; - pNtCurrentTeb()->Tib.ExceptionList = &frame; - - num_guard_page_calls = 0; - old_value = *value; /* exception handler increments value by 0x100 */ - *value = 2; - ok( old_value == 0x101, "memory block contains wrong value, expected 0x101, got 0x%x\n", old_value ); - ok( num_guard_page_calls == 1, "expected one callback of guard page handler, got %d calls\n", num_guard_page_calls ); - - pNtCurrentTeb()->Tib.ExceptionList = frame.Prev; - - /* check info structure again, PAGE_GUARD should be removed now */ - ret = VirtualQuery( base, &info, sizeof(info) ); - ok( ret, "VirtualQuery failed %u\n", GetLastError()); - ok( info.Protect == PAGE_READWRITE, "wrong Protect 0x%x\n", info.Protect ); - - success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); - ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot ); - - /* test accessing second integer in memory */ - frame.Handler = guard_page_handler; - frame.Prev = pNtCurrentTeb()->Tib.ExceptionList; - pNtCurrentTeb()->Tib.ExceptionList = &frame; - - num_guard_page_calls = 0; - old_value = *(value + 1); - ok( old_value == 0x102, "memory block contains wrong value, expected 0x102, got 0x%x\n", old_value ); - ok( *value == 2, "memory block contains wrong value, expected 2, got 0x%x\n", *value ); - ok( num_guard_page_calls == 1, "expected one callback of guard page handler, got %d calls\n", num_guard_page_calls ); - - pNtCurrentTeb()->Tib.ExceptionList = frame.Prev; - - success = VirtualLock( base, size ); - ok( success, "VirtualLock failed %u\n", GetLastError() ); - if (success) - { - ok( *value == 2, "memory block contains wrong value, expected 2, got 0x%x\n", *value ); - success = VirtualUnlock( base, size ); - ok( success, "VirtualUnlock failed %u\n", GetLastError() ); - } - - VirtualFree( base, 0, MEM_RELEASE ); - - /* combined guard page / write watch tests */ - if (!pGetWriteWatch || !pResetWriteWatch) - { - win_skip( "GetWriteWatch not supported, skipping combined guard page / write watch tests\n" ); - return; - } - - base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_COMMIT | MEM_WRITE_WATCH, PAGE_READWRITE | PAGE_GUARD ); - if (!base && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_NOT_SUPPORTED)) - { - win_skip( "MEM_WRITE_WATCH not supported\n" ); - return; - } - ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() ); - value = (int *)base; - - ret = VirtualQuery( base, &info, sizeof(info) ); - ok( ret, "VirtualQuery failed %u\n", GetLastError() ); - ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base ); - ok( info.AllocationProtect == (PAGE_READWRITE | PAGE_GUARD), "wrong AllocationProtect %x\n", info.AllocationProtect ); - ok( info.RegionSize == size, "wrong RegionSize 0x%lx\n", info.RegionSize ); - ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State ); - ok( info.Protect == (PAGE_READWRITE | PAGE_GUARD), "wrong Protect 0x%x\n", info.Protect ); - ok( info.Type == MEM_PRIVATE, "wrong Type 0x%x\n", info.Type ); - - count = 64; - ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); - ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); - ok( count == 0, "wrong count %lu\n", count ); - - /* writing to a page should trigger should trigger guard page, even if write watch is set */ - frame.Handler = guard_page_handler; - frame.Prev = pNtCurrentTeb()->Tib.ExceptionList; - pNtCurrentTeb()->Tib.ExceptionList = &frame; - - num_guard_page_calls = 0; - *value = 1; - *(value + 1) = 2; - ok( num_guard_page_calls == 1, "expected one callback of guard page handler, got %d calls\n", num_guard_page_calls ); - - pNtCurrentTeb()->Tib.ExceptionList = frame.Prev; - - count = 64; - ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); - ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); - ok( count == 1, "wrong count %lu\n", count ); - ok( results[0] == base, "wrong result %p\n", results[0] ); - - success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); - - /* write watch is triggered from inside of the guard page handler */ - frame.Handler = guard_page_handler; - frame.Prev = pNtCurrentTeb()->Tib.ExceptionList; - pNtCurrentTeb()->Tib.ExceptionList = &frame; - - num_guard_page_calls = 0; - old_value = *(value + 1); /* doesn't trigger write watch */ - ok( old_value == 0x102, "memory block contains wrong value, expected 0x102, got 0x%x\n", old_value ); - ok( *value == 1, "memory block contains wrong value, expected 1, got 0x%x\n", *value ); - ok( num_guard_page_calls == 1, "expected one callback of guard page handler, got %d calls\n", num_guard_page_calls ); - - pNtCurrentTeb()->Tib.ExceptionList = frame.Prev; - - count = 64; - ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); - ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); - ok( count == 1, "wrong count %lu\n", count ); - ok( results[0] == base, "wrong result %p\n", results[0] ); - - success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); - - /* test behaviour of VirtualLock - first attempt should fail without triggering write watches */ - SetLastError( 0xdeadbeef ); - success = VirtualLock( base, size ); - ok( !success, "VirtualLock unexpectedly succeeded\n" ); - todo_wine - ok( GetLastError() == STATUS_GUARD_PAGE_VIOLATION, "wrong error %u\n", GetLastError() ); - - count = 64; - ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); - ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); - ok( count == 0, "wrong count %lu\n", count ); - - success = VirtualLock( base, size ); - todo_wine - ok( success, "VirtualLock failed %u\n", GetLastError() ); - if (success) - { - ok( *value == 1, "memory block contains wrong value, expected 1, got 0x%x\n", *value ); - success = VirtualUnlock( base, size ); - ok( success, "VirtualUnlock failed %u\n", GetLastError() ); - } - - count = 64; - results[0] = (void *)0xdeadbeef; - ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); - ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); - todo_wine - ok( count == 1 || broken(count == 0) /* Windows 8 */, "wrong count %lu\n", count ); - todo_wine - ok( results[0] == base || broken(results[0] == (void *)0xdeadbeef) /* Windows 8 */, "wrong result %p\n", results[0] ); - - VirtualFree( base, 0, MEM_RELEASE ); -} +#if defined(__i386__) || defined(__x86_64__) static DWORD WINAPI stack_commit_func( void *arg ) { volatile char *p = (char *)&p; /* trigger all guard pages, to ensure that the pages are committed */ - while (p >= (char *)pNtCurrentTeb()->DeallocationStack + 3 * 0x1000) + while (p >= (char *)NtCurrentTeb()->DeallocationStack + 4 * 0x1000) { p[0] |= 0; p -= 0x1000; @@ -2092,6 +1867,7 @@ static void test_stack_commit(void) { +#ifdef __i386__ static const char code_call_on_stack[] = { 0x55, /* pushl %ebp */ 0x56, /* pushl %esi */ @@ -2109,17 +1885,24 @@ 0x5e, /* popl %esi */ 0x5d, /* popl %ebp */ 0xc2, 0x0c, 0x00 }; /* ret $12 */ - +#else + static const char code_call_on_stack[] = { + 0x55, /* pushq %rbp */ + 0x48, 0x89, 0xe5, /* movq %rsp,%rbp */ + /* %rcx - func, %rdx - arg, %r8 - stack */ + 0x48, 0x87, 0xca, /* xchgq %rcx,%rdx */ + 0x49, 0x83, 0xe0, 0xf0, /* andq $~15,%r8 */ + 0x49, 0x83, 0xe8, 0x20, /* subq $0x20,%r8 */ + 0x4c, 0x89, 0xc4, /* movq %r8,%rsp */ + 0xff, 0xd2, /* callq *%rdx */ + 0x48, 0x89, 0xec, /* movq %rbp,%rsp */ + 0x5d, /* popq %rbp */ + 0xc3 }; /* ret */ +#endif DWORD (WINAPI *call_on_stack)( DWORD (WINAPI *func)(void *), void *arg, void *stack ); void *old_stack, *old_stack_base, *old_stack_limit; void *new_stack, *new_stack_base; DWORD result; - - if (!pNtCurrentTeb) - { - win_skip( "NtCurrentTeb not supported\n" ); - return; - } call_on_stack = VirtualAlloc( 0, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE ); ok( call_on_stack != NULL, "VirtualAlloc failed %u\n", GetLastError() ); @@ -2131,26 +1914,273 @@ new_stack_base = (char *)new_stack + 0x400000; VirtualAlloc( (char *)new_stack_base - 0x1000, 0x1000, MEM_COMMIT, PAGE_READWRITE | PAGE_GUARD ); - old_stack = pNtCurrentTeb()->DeallocationStack; - old_stack_base = pNtCurrentTeb()->Tib.StackBase; - old_stack_limit = pNtCurrentTeb()->Tib.StackLimit; - - pNtCurrentTeb()->DeallocationStack = new_stack; - pNtCurrentTeb()->Tib.StackBase = new_stack_base; - pNtCurrentTeb()->Tib.StackLimit = new_stack_base; + old_stack = NtCurrentTeb()->DeallocationStack; + old_stack_base = NtCurrentTeb()->Tib.StackBase; + old_stack_limit = NtCurrentTeb()->Tib.StackLimit; + + NtCurrentTeb()->DeallocationStack = new_stack; + NtCurrentTeb()->Tib.StackBase = new_stack_base; + NtCurrentTeb()->Tib.StackLimit = new_stack_base; result = call_on_stack( stack_commit_func, (void *)0xdeadbeef, new_stack_base ); + + NtCurrentTeb()->DeallocationStack = old_stack; + NtCurrentTeb()->Tib.StackBase = old_stack_base; + NtCurrentTeb()->Tib.StackLimit = old_stack_limit; + ok( result == 42, "expected 42, got %u\n", result ); - - pNtCurrentTeb()->DeallocationStack = old_stack; - pNtCurrentTeb()->Tib.StackBase = old_stack_base; - pNtCurrentTeb()->Tib.StackLimit = old_stack_limit; VirtualFree( new_stack, 0, MEM_RELEASE ); VirtualFree( call_on_stack, 0, MEM_RELEASE ); } -DWORD num_execute_fault_calls; +#endif /* defined(__i386__) || defined(__x86_64__) */ +#ifdef __i386__ + +static LONG num_guard_page_calls; + +static DWORD guard_page_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, + CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) +{ + trace( "exception: %08x flags:%x addr:%p\n", + rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress ); + + ok( rec->NumberParameters == 2, "NumberParameters is %d instead of 2\n", rec->NumberParameters ); + ok( rec->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION, "ExceptionCode is %08x instead of %08x\n", + rec->ExceptionCode, STATUS_GUARD_PAGE_VIOLATION ); + + InterlockedIncrement( &num_guard_page_calls ); + *(int *)rec->ExceptionInformation[1] += 0x100; + + return ExceptionContinueExecution; +} + +static void test_guard_page(void) +{ + EXCEPTION_REGISTRATION_RECORD frame; + MEMORY_BASIC_INFORMATION info; + DWORD ret, size, old_prot; + int *value, old_value; + void *results[64]; + ULONG_PTR count; + ULONG pagesize; + BOOL success; + char *base; + + size = 0x1000; + base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE | PAGE_GUARD ); + ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() ); + value = (int *)base; + + /* verify info structure */ + ret = VirtualQuery( base, &info, sizeof(info) ); + ok( ret, "VirtualQuery failed %u\n", GetLastError()); + ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base ); + ok( info.AllocationProtect == (PAGE_READWRITE | PAGE_GUARD), "wrong AllocationProtect %x\n", info.AllocationProtect ); + ok( info.RegionSize == size, "wrong RegionSize 0x%lx\n", info.RegionSize ); + ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State ); + ok( info.Protect == (PAGE_READWRITE | PAGE_GUARD), "wrong Protect 0x%x\n", info.Protect ); + ok( info.Type == MEM_PRIVATE, "wrong Type 0x%x\n", info.Type ); + + /* put some initial value into the memory */ + success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot ); + ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( old_prot == (PAGE_READWRITE | PAGE_GUARD), "wrong old prot %x\n", old_prot ); + + *value = 1; + *(value + 1) = 2; + + success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot ); + ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot ); + + /* test behaviour of VirtualLock - first attempt should fail */ + SetLastError( 0xdeadbeef ); + success = VirtualLock( base, size ); + ok( !success, "VirtualLock unexpectedly succeeded\n" ); + todo_wine + ok( GetLastError() == STATUS_GUARD_PAGE_VIOLATION, "wrong error %u\n", GetLastError() ); + + success = VirtualLock( base, size ); + todo_wine + ok( success, "VirtualLock failed %u\n", GetLastError() ); + if (success) + { + ok( *value == 1, "memory block contains wrong value, expected 1, got 0x%x\n", *value ); + success = VirtualUnlock( base, size ); + ok( success, "VirtualUnlock failed %u\n", GetLastError() ); + } + + /* check info structure again, PAGE_GUARD should be removed now */ + ret = VirtualQuery( base, &info, sizeof(info) ); + ok( ret, "VirtualQuery failed %u\n", GetLastError()); + ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base ); + ok( info.AllocationProtect == (PAGE_READWRITE | PAGE_GUARD), "wrong AllocationProtect %x\n", info.AllocationProtect ); + ok( info.RegionSize == size, "wrong RegionSize 0x%lx\n", info.RegionSize ); + ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State ); + todo_wine + ok( info.Protect == PAGE_READWRITE, "wrong Protect 0x%x\n", info.Protect ); + ok( info.Type == MEM_PRIVATE, "wrong Type 0x%x\n", info.Type ); + + success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot ); + ok( success, "VirtualProtect failed %u\n", GetLastError() ); + todo_wine + ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot ); + + /* test directly accessing the memory - we need to setup an exception handler first */ + frame.Handler = guard_page_handler; + frame.Prev = NtCurrentTeb()->Tib.ExceptionList; + NtCurrentTeb()->Tib.ExceptionList = &frame; + + InterlockedExchange( &num_guard_page_calls, 0 ); + InterlockedExchange( &old_value, *value ); /* exception handler increments value by 0x100 */ + *value = 2; + ok( old_value == 0x101, "memory block contains wrong value, expected 0x101, got 0x%x\n", old_value ); + ok( num_guard_page_calls == 1, "expected one callback of guard page handler, got %d calls\n", num_guard_page_calls ); + + NtCurrentTeb()->Tib.ExceptionList = frame.Prev; + + /* check info structure again, PAGE_GUARD should be removed now */ + ret = VirtualQuery( base, &info, sizeof(info) ); + ok( ret, "VirtualQuery failed %u\n", GetLastError()); + ok( info.Protect == PAGE_READWRITE, "wrong Protect 0x%x\n", info.Protect ); + + success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot ); + ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot ); + + /* test accessing second integer in memory */ + frame.Handler = guard_page_handler; + frame.Prev = NtCurrentTeb()->Tib.ExceptionList; + NtCurrentTeb()->Tib.ExceptionList = &frame; + + InterlockedExchange( &num_guard_page_calls, 0 ); + old_value = *(value + 1); + ok( old_value == 0x102, "memory block contains wrong value, expected 0x102, got 0x%x\n", old_value ); + ok( *value == 2, "memory block contains wrong value, expected 2, got 0x%x\n", *value ); + ok( num_guard_page_calls == 1, "expected one callback of guard page handler, got %d calls\n", num_guard_page_calls ); + + NtCurrentTeb()->Tib.ExceptionList = frame.Prev; + + success = VirtualLock( base, size ); + ok( success, "VirtualLock failed %u\n", GetLastError() ); + if (success) + { + ok( *value == 2, "memory block contains wrong value, expected 2, got 0x%x\n", *value ); + success = VirtualUnlock( base, size ); + ok( success, "VirtualUnlock failed %u\n", GetLastError() ); + } + + VirtualFree( base, 0, MEM_RELEASE ); + + /* combined guard page / write watch tests */ + if (!pGetWriteWatch || !pResetWriteWatch) + { + win_skip( "GetWriteWatch not supported, skipping combined guard page / write watch tests\n" ); + return; + } + + base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_COMMIT | MEM_WRITE_WATCH, PAGE_READWRITE | PAGE_GUARD ); + if (!base && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_NOT_SUPPORTED)) + { + win_skip( "MEM_WRITE_WATCH not supported\n" ); + return; + } + ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() ); + value = (int *)base; + + ret = VirtualQuery( base, &info, sizeof(info) ); + ok( ret, "VirtualQuery failed %u\n", GetLastError() ); + ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base ); + ok( info.AllocationProtect == (PAGE_READWRITE | PAGE_GUARD), "wrong AllocationProtect %x\n", info.AllocationProtect ); + ok( info.RegionSize == size, "wrong RegionSize 0x%lx\n", info.RegionSize ); + ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State ); + ok( info.Protect == (PAGE_READWRITE | PAGE_GUARD), "wrong Protect 0x%x\n", info.Protect ); + ok( info.Type == MEM_PRIVATE, "wrong Type 0x%x\n", info.Type ); + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 0, "wrong count %lu\n", count ); + + /* writing to a page should trigger should trigger guard page, even if write watch is set */ + frame.Handler = guard_page_handler; + frame.Prev = NtCurrentTeb()->Tib.ExceptionList; + NtCurrentTeb()->Tib.ExceptionList = &frame; + + InterlockedExchange( &num_guard_page_calls, 0 ); + *value = 1; + *(value + 1) = 2; + ok( num_guard_page_calls == 1, "expected one callback of guard page handler, got %d calls\n", num_guard_page_calls ); + + NtCurrentTeb()->Tib.ExceptionList = frame.Prev; + + count = 64; + ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 1, "wrong count %lu\n", count ); + ok( results[0] == base, "wrong result %p\n", results[0] ); + + success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot ); + ok( success, "VirtualProtect failed %u\n", GetLastError() ); + + /* write watch is triggered from inside of the guard page handler */ + frame.Handler = guard_page_handler; + frame.Prev = NtCurrentTeb()->Tib.ExceptionList; + NtCurrentTeb()->Tib.ExceptionList = &frame; + + InterlockedExchange( &num_guard_page_calls, 0 ); + old_value = *(value + 1); /* doesn't trigger write watch */ + ok( old_value == 0x102, "memory block contains wrong value, expected 0x102, got 0x%x\n", old_value ); + ok( *value == 1, "memory block contains wrong value, expected 1, got 0x%x\n", *value ); + ok( num_guard_page_calls == 1, "expected one callback of guard page handler, got %d calls\n", num_guard_page_calls ); + + NtCurrentTeb()->Tib.ExceptionList = frame.Prev; + + count = 64; + ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 1, "wrong count %lu\n", count ); + ok( results[0] == base, "wrong result %p\n", results[0] ); + + success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot ); + ok( success, "VirtualProtect failed %u\n", GetLastError() ); + + /* test behaviour of VirtualLock - first attempt should fail without triggering write watches */ + SetLastError( 0xdeadbeef ); + success = VirtualLock( base, size ); + ok( !success, "VirtualLock unexpectedly succeeded\n" ); + todo_wine + ok( GetLastError() == STATUS_GUARD_PAGE_VIOLATION, "wrong error %u\n", GetLastError() ); + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 0, "wrong count %lu\n", count ); + + success = VirtualLock( base, size ); + todo_wine + ok( success, "VirtualLock failed %u\n", GetLastError() ); + if (success) + { + ok( *value == 1, "memory block contains wrong value, expected 1, got 0x%x\n", *value ); + success = VirtualUnlock( base, size ); + ok( success, "VirtualUnlock failed %u\n", GetLastError() ); + } + + count = 64; + results[0] = (void *)0xdeadbeef; + ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + todo_wine + ok( count == 1 || broken(count == 0) /* Windows 8 */, "wrong count %lu\n", count ); + todo_wine + ok( results[0] == base || broken(results[0] == (void *)0xdeadbeef) /* Windows 8 */, "wrong result %p\n", results[0] ); + + VirtualFree( base, 0, MEM_RELEASE ); +} + +static LONG num_execute_fault_calls; static DWORD execute_fault_seh_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) @@ -2175,7 +2205,7 @@ ok( rec->ExceptionInformation[0] == err, "ExceptionInformation[0] is %d instead of %d\n", (DWORD)rec->ExceptionInformation[0], err ); - num_guard_page_calls++; + InterlockedIncrement( &num_guard_page_calls ); } else if (rec->ExceptionCode == STATUS_ACCESS_VIOLATION) { @@ -2190,7 +2220,7 @@ ok( success, "VirtualProtect failed %u\n", GetLastError() ); ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot ); - num_execute_fault_calls++; + InterlockedIncrement( &num_execute_fault_calls ); } return ExceptionContinueExecution; @@ -2211,7 +2241,7 @@ "ExceptionCode is %08x instead of STATUS_ACCESS_VIOLATION\n", rec->ExceptionCode ); if (rec->ExceptionCode == STATUS_ACCESS_VIOLATION) - num_execute_fault_calls++; + InterlockedIncrement( &num_execute_fault_calls ); if (rec->ExceptionInformation[0] == EXCEPTION_READ_FAULT) return EXCEPTION_CONTINUE_SEARCH; @@ -2229,13 +2259,14 @@ DWORD ret; frame.Handler = execute_fault_seh_handler; - frame.Prev = pNtCurrentTeb()->Tib.ExceptionList; - pNtCurrentTeb()->Tib.ExceptionList = &frame; - - num_guard_page_calls = num_execute_fault_calls = 0; + frame.Prev = NtCurrentTeb()->Tib.ExceptionList; + NtCurrentTeb()->Tib.ExceptionList = &frame; + + InterlockedExchange( &num_guard_page_calls, 0 ); + InterlockedExchange( &num_execute_fault_calls, 0 ); ret = SendMessageA( hWnd, uMsg, wParam, lParam ); - pNtCurrentTeb()->Tib.ExceptionList = frame.Prev; + NtCurrentTeb()->Tib.ExceptionList = frame.Prev; return ret; } @@ -2246,13 +2277,14 @@ DWORD ret; frame.Handler = execute_fault_seh_handler; - frame.Prev = pNtCurrentTeb()->Tib.ExceptionList; - pNtCurrentTeb()->Tib.ExceptionList = &frame; - - num_guard_page_calls = num_execute_fault_calls = 0; + frame.Prev = NtCurrentTeb()->Tib.ExceptionList; + NtCurrentTeb()->Tib.ExceptionList = &frame; + + InterlockedExchange( &num_guard_page_calls, 0 ); + InterlockedExchange( &num_execute_fault_calls, 0 ); ret = code( arg ); - pNtCurrentTeb()->Tib.ExceptionList = frame.Prev; + NtCurrentTeb()->Tib.ExceptionList = frame.Prev; return ret; } @@ -2299,12 +2331,6 @@ char *base; HWND hWnd; - if (!pNtCurrentTeb) - { - win_skip( "NtCurrentTeb not supported\n" ); - return; - } - trace( "Running DEP tests with ProcessExecuteFlags = %d\n", dep_flags ); NtQueryInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &old_flags, sizeof(old_flags), NULL ); @@ -2608,7 +2634,7 @@ ok( count == 1, "wrong count %lu\n", count ); ok( results[0] == base, "wrong result %p\n", results[0] ); - /* Create a new window class and associcated Window (see above) */ + /* Create a new window class and associated Window (see above) */ success = VirtualProtect( base, size, PAGE_EXECUTE_READWRITE, &old_prot ); ok( success, "VirtualProtect failed %u\n", GetLastError() ); @@ -3296,7 +3322,9 @@ SetLastError(0xdeadbeef); ret = VirtualQuery(base, &info, sizeof(info)); ok(ret, "VirtualQuery failed %d\n", GetLastError()); - ok(info.Protect == td[i].prot_after_write, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot_after_write); + /* FIXME: remove the condition below once Wine is fixed */ + todo_wine_if (td[i].prot == PAGE_WRITECOPY || td[i].prot == PAGE_EXECUTE_WRITECOPY) + ok(info.Protect == td[i].prot_after_write, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot_after_write); } } else @@ -3310,7 +3338,9 @@ SetLastError(0xdeadbeef); ret = VirtualProtect(base, si.dwPageSize, PAGE_NOACCESS, &old_prot); ok(ret, "%d: VirtualProtect error %d\n", i, GetLastError()); - ok(old_prot == td[i].prot_after_write, "%d: got %#x != expected %#x\n", i, old_prot, td[i].prot_after_write); + /* FIXME: remove the condition below once Wine is fixed */ + todo_wine_if (td[i].prot == PAGE_WRITECOPY || td[i].prot == PAGE_EXECUTE_WRITECOPY) + ok(old_prot == td[i].prot_after_write, "%d: got %#x != expected %#x\n", i, old_prot, td[i].prot_after_write); } UnmapViewOfFile(base); @@ -3840,7 +3870,6 @@ ok(info.basic.BaseAddress == NULL, "expected NULL, got %p\n", info.basic.BaseAddress); todo_wine ok(info.basic.Attributes == SEC_FILE, "expected SEC_FILE, got %#x\n", info.basic.Attributes); -todo_wine ok(info.basic.Size.QuadPart == fsize, "expected %#lx, got %#x/%08x\n", fsize, info.basic.Size.HighPart, info.basic.Size.LowPart); status = pNtQuerySection(mapping, SectionImageInformation, &info, sizeof(info.basic), &ret); @@ -3864,7 +3893,6 @@ ok(info.basic.BaseAddress == NULL, "expected NULL, got %p\n", info.basic.BaseAddress); todo_wine ok(info.basic.Attributes == SEC_FILE, "expected SEC_FILE, got %#x\n", info.basic.Attributes); -todo_wine ok(info.basic.Size.QuadPart == fsize, "expected %#lx, got %#x/%08x\n", fsize, info.basic.Size.HighPart, info.basic.Size.LowPart); UnmapViewOfFile(p); @@ -3950,16 +3978,13 @@ ok(info.basic.BaseAddress == NULL, "expected NULL, got %p\n", info.basic.BaseAddress); todo_wine ok(info.basic.Attributes == SEC_FILE, "expected SEC_FILE, got %#x\n", info.basic.Attributes); -todo_wine ok(info.basic.Size.QuadPart == fsize, "expected %#lx, got %#x/%08x\n", fsize, info.basic.Size.HighPart, info.basic.Size.LowPart); CloseHandle(mapping); SetLastError(0xdeadbef); mapping = CreateFileMappingA(file, NULL, PAGE_READONLY|SEC_RESERVE, 0, 0, NULL); -todo_wine ok(mapping != 0, "CreateFileMapping error %u\n", GetLastError()); - if (!mapping) goto skip1; memset(&info, 0x55, sizeof(info)); ret = 0xdeadbeef; @@ -3967,11 +3992,11 @@ ok(status == STATUS_SUCCESS, "NtQuerySection error %#x\n", status); ok(ret == sizeof(info.basic), "wrong returned size %u\n", ret); ok(info.basic.BaseAddress == NULL, "expected NULL, got %p\n", info.basic.BaseAddress); +todo_wine ok(info.basic.Attributes == SEC_FILE, "expected SEC_FILE, got %#x\n", info.basic.Attributes); ok(info.basic.Size.QuadPart == fsize, "expected %#lx, got %#x/%08x\n", fsize, info.basic.Size.HighPart, info.basic.Size.LowPart); CloseHandle(mapping); -skip1: CloseHandle(file); SetLastError(0xdeadbef); @@ -4076,7 +4101,6 @@ pNtAreMappedFilesTheSame = (void *)GetProcAddress( hntdll, "NtAreMappedFilesTheSame" ); pNtMapViewOfSection = (void *)GetProcAddress( hntdll, "NtMapViewOfSection" ); pNtUnmapViewOfSection = (void *)GetProcAddress( hntdll, "NtUnmapViewOfSection" ); - pNtCurrentTeb = (void *)GetProcAddress( hntdll, "NtCurrentTeb" ); pRtlAddVectoredExceptionHandler = (void *)GetProcAddress( hntdll, "RtlAddVectoredExceptionHandler" ); pRtlRemoveVectoredExceptionHandler = (void *)GetProcAddress( hntdll, "RtlRemoveVectoredExceptionHandler" ); pNtQuerySection = (void *)GetProcAddress( hntdll, "NtQuerySection" ); @@ -4103,7 +4127,9 @@ test_IsBadWritePtr(); test_IsBadCodePtr(); test_write_watch(); +#if defined(__i386__) || defined(__x86_64__) test_stack_commit(); +#endif #ifdef __i386__ if (!winetest_interactive) {