| /* Unit test suite for Rtl* API functions |
| * |
| * Copyright 2003 Thomas Mertes |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| * |
| * NOTES |
| * We use function pointers here as there is no import library for NTDLL on |
| * windows. |
| */ |
| |
| #include <stdlib.h> |
| |
| #include "winbase.h" |
| #include "wine/test.h" |
| #include "winnt.h" |
| #include "winnls.h" |
| #include "winternl.h" |
| |
| /* Function ptrs for ntdll calls */ |
| static HMODULE hntdll = 0; |
| static SIZE_T (WINAPI *pRtlCompareMemoryUlong)(PULONG, SIZE_T, ULONG); |
| static ULONG (WINAPI *pRtlUniform)(PULONG); |
| |
| |
| static void InitFunctionPtrs(void) |
| { |
| hntdll = LoadLibraryA("ntdll.dll"); |
| ok(hntdll != 0, "LoadLibrary failed"); |
| if (hntdll) { |
| pRtlCompareMemoryUlong = (void *)GetProcAddress(hntdll, "RtlCompareMemoryUlong"); |
| pRtlUniform = (void *)GetProcAddress(hntdll, "RtlUniform"); |
| } /* if */ |
| } |
| |
| |
| static void test_RtlCompareMemoryUlong(void) |
| { |
| ULONG a[10]; |
| ULONG result; |
| |
| a[0]= 0x0123; |
| a[1]= 0x4567; |
| a[2]= 0x89ab; |
| a[3]= 0xcdef; |
| result = pRtlCompareMemoryUlong(a, 0, 0x0123); |
| ok(result == 0, "RtlCompareMemoryUlong(%p, 0, 0x0123) returns %lu, expected 0\n", a, result); |
| result = pRtlCompareMemoryUlong(a, 3, 0x0123); |
| ok(result == 0, "RtlCompareMemoryUlong(%p, 3, 0x0123) returns %lu, expected 0\n", a, result); |
| result = pRtlCompareMemoryUlong(a, 4, 0x0123); |
| ok(result == 4, "RtlCompareMemoryUlong(%p, 4, 0x0123) returns %lu, expected 4\n", a, result); |
| result = pRtlCompareMemoryUlong(a, 5, 0x0123); |
| ok(result == 4, "RtlCompareMemoryUlong(%p, 5, 0x0123) returns %lu, expected 4\n", a, result); |
| result = pRtlCompareMemoryUlong(a, 7, 0x0123); |
| ok(result == 4, "RtlCompareMemoryUlong(%p, 7, 0x0123) returns %lu, expected 4\n", a, result); |
| result = pRtlCompareMemoryUlong(a, 8, 0x0123); |
| ok(result == 4, "RtlCompareMemoryUlong(%p, 8, 0x0123) returns %lu, expected 4\n", a, result); |
| result = pRtlCompareMemoryUlong(a, 9, 0x0123); |
| ok(result == 4, "RtlCompareMemoryUlong(%p, 9, 0x0123) returns %lu, expected 4\n", a, result); |
| result = pRtlCompareMemoryUlong(a, 4, 0x0127); |
| ok(result == 0, "RtlCompareMemoryUlong(%p, 4, 0x0127) returns %lu, expected 0\n", a, result); |
| result = pRtlCompareMemoryUlong(a, 4, 0x7123); |
| ok(result == 0, "RtlCompareMemoryUlong(%p, 4, 0x7123) returns %lu, expected 0\n", a, result); |
| result = pRtlCompareMemoryUlong(a, 16, 0x4567); |
| ok(result == 0, "RtlCompareMemoryUlong(%p, 16, 0x4567) returns %lu, expected 0\n", a, result); |
| |
| a[1]= 0x0123; |
| result = pRtlCompareMemoryUlong(a, 3, 0x0123); |
| ok(result == 0, "RtlCompareMemoryUlong(%p, 3, 0x0123) returns %lu, expected 0\n", a, result); |
| result = pRtlCompareMemoryUlong(a, 4, 0x0123); |
| ok(result == 4, "RtlCompareMemoryUlong(%p, 4, 0x0123) returns %lu, expected 4\n", a, result); |
| result = pRtlCompareMemoryUlong(a, 5, 0x0123); |
| ok(result == 4, "RtlCompareMemoryUlong(%p, 5, 0x0123) returns %lu, expected 4\n", a, result); |
| result = pRtlCompareMemoryUlong(a, 7, 0x0123); |
| ok(result == 4, "RtlCompareMemoryUlong(%p, 7, 0x0123) returns %lu, expected 4\n", a, result); |
| result = pRtlCompareMemoryUlong(a, 8, 0x0123); |
| ok(result == 8, "RtlCompareMemoryUlong(%p, 8, 0x0123) returns %lu, expected 8\n", a, result); |
| result = pRtlCompareMemoryUlong(a, 9, 0x0123); |
| ok(result == 8, "RtlCompareMemoryUlong(%p, 9, 0x0123) returns %lu, expected 8\n", a, result); |
| } |
| |
| |
| static void test_RtlUniform(void) |
| { |
| ULONGLONG num; |
| ULONG seed; |
| ULONG seed_bak; |
| ULONG expected; |
| ULONG result; |
| |
| /* |
| * According to the documentation RtlUniform is using D.H. Lehmer's 1948 |
| * algorithm. This algorithm is: |
| * |
| * seed = (seed * const_1 + const_2) % const_3; |
| * |
| * According to the documentation the random number is distributed over |
| * [0..MAXLONG]. Therefore const_3 is MAXLONG + 1: |
| * |
| * seed = (seed * const_1 + const_2) % (MAXLONG + 1); |
| * |
| * Because MAXLONG is 0xfffffff (which is 0x10000000 - 1) the algorithm |
| * can be expressed as: |
| * |
| * seed = (seed * const_1 + const_2) & MAXLONG; |
| * |
| * To find out const_2 we just call RtlUniform with seed set to 0: |
| */ |
| seed = 0; |
| expected = 0x7fffffc3; |
| result = pRtlUniform(&seed); |
| ok(result == expected, |
| "RtlUniform(&seed (seed == 0)) returns %lx, expected %lx", |
| result, expected); |
| /* |
| * The algorithm is now: |
| * |
| * seed = (seed * const_1 + 0x7fffffc3) & MAXLONG; |
| * |
| * To find out const_1 we can use: |
| * |
| * const_1 = RtlUniform(1) - 0x7fffffc3; |
| * |
| * If that does not work a search loop can try all possible values of |
| * const_1 and compare to the result to RtlUniform(1). |
| * This way we find out that const_1 is 0xffffffed. |
| * |
| * For seed = 1 the const_2 is 0x7fffffc4: |
| */ |
| seed = 1; |
| expected = seed * 0xffffffed + 0x7fffffc3 + 1; |
| result = pRtlUniform(&seed); |
| ok(result == expected, |
| "RtlUniform(&seed (seed == 1)) returns %lx, expected %lx", |
| result, expected); |
| /* |
| * For seed = 2 the const_2 is 0x7fffffc3: |
| */ |
| seed = 2; |
| expected = seed * 0xffffffed + 0x7fffffc3; |
| result = pRtlUniform(&seed); |
| ok(result == expected, |
| "RtlUniform(&seed (seed == 2)) returns %lx, expected %lx", |
| result, expected); |
| /* |
| * More tests show that if seed is odd the result must be incremented by 1: |
| */ |
| seed = 3; |
| expected = seed * 0xffffffed + 0x7fffffc3 + (seed & 1); |
| result = pRtlUniform(&seed); |
| ok(result == expected, |
| "RtlUniform(&seed (seed == 2)) returns %lx, expected %lx", |
| result, expected); |
| |
| seed = 0x6bca1aa; |
| expected = seed * 0xffffffed + 0x7fffffc3; |
| result = pRtlUniform(&seed); |
| ok(result == expected, |
| "RtlUniform(&seed (seed == 0x6bca1aa)) returns %lx, expected %lx", |
| result, expected); |
| |
| seed = 0x6bca1ab; |
| expected = seed * 0xffffffed + 0x7fffffc3 + 1; |
| result = pRtlUniform(&seed); |
| ok(result == expected, |
| "RtlUniform(&seed (seed == 0x6bca1ab)) returns %lx, expected %lx", |
| result, expected); |
| /* |
| * When seed is 0x6bca1ac there is an exception: |
| */ |
| seed = 0x6bca1ac; |
| expected = seed * 0xffffffed + 0x7fffffc3 + 2; |
| result = pRtlUniform(&seed); |
| ok(result == expected, |
| "RtlUniform(&seed (seed == 0x6bca1ac)) returns %lx, expected %lx", |
| result, expected); |
| /* |
| * Note that up to here const_3 is not used |
| * (the highest bit of the result is not set). |
| * |
| * Starting with 0x6bca1ad: If seed is even the result must be incremented by 1: |
| */ |
| seed = 0x6bca1ad; |
| expected = (seed * 0xffffffed + 0x7fffffc3) & MAXLONG; |
| result = pRtlUniform(&seed); |
| ok(result == expected, |
| "RtlUniform(&seed (seed == 0x6bca1ad)) returns %lx, expected %lx", |
| result, expected); |
| |
| seed = 0x6bca1ae; |
| expected = (seed * 0xffffffed + 0x7fffffc3 + 1) & MAXLONG; |
| result = pRtlUniform(&seed); |
| ok(result == expected, |
| "RtlUniform(&seed (seed == 0x6bca1ae)) returns %lx, expected %lx", |
| result, expected); |
| /* |
| * There are several ranges where for odd or even seed the result must be |
| * incremented by 1. You can see this ranges in the following test. |
| * |
| * For a full test use one of the following loop heads: |
| * |
| * for (num = 0; num <= 0xffffffff; num++) { |
| * seed = num; |
| * ... |
| * |
| * seed = 0; |
| * for (num = 0; num <= 0xffffffff; num++) { |
| * ... |
| */ |
| seed = 0; |
| for (num = 0; num <= 100000; num++) { |
| |
| expected = seed * 0xffffffed + 0x7fffffc3; |
| if (seed < 0x6bca1ac) { |
| expected = expected + (seed & 1); |
| } else if (seed == 0x6bca1ac) { |
| expected = (expected + 2) & MAXLONG; |
| } else if (seed < 0xd79435c) { |
| expected = (expected + (~seed & 1)) & MAXLONG; |
| } else if (seed < 0x1435e50b) { |
| expected = expected + (seed & 1); |
| } else if (seed < 0x1af286ba) { |
| expected = (expected + (~seed & 1)) & MAXLONG; |
| } else if (seed < 0x21af2869) { |
| expected = expected + (seed & 1); |
| } else if (seed < 0x286bca18) { |
| expected = (expected + (~seed & 1)) & MAXLONG; |
| } else if (seed < 0x2f286bc7) { |
| expected = expected + (seed & 1); |
| } else if (seed < 0x35e50d77) { |
| expected = (expected + (~seed & 1)) & MAXLONG; |
| } else if (seed < 0x3ca1af26) { |
| expected = expected + (seed & 1); |
| } else if (seed < 0x435e50d5) { |
| expected = (expected + (~seed & 1)) & MAXLONG; |
| } else if (seed < 0x4a1af284) { |
| expected = expected + (seed & 1); |
| } else if (seed < 0x50d79433) { |
| expected = (expected + (~seed & 1)) & MAXLONG; |
| } else if (seed < 0x579435e2) { |
| expected = expected + (seed & 1); |
| } else if (seed < 0x5e50d792) { |
| expected = (expected + (~seed & 1)) & MAXLONG; |
| } else if (seed < 0x650d7941) { |
| expected = expected + (seed & 1); |
| } else if (seed < 0x6bca1af0) { |
| expected = (expected + (~seed & 1)) & MAXLONG; |
| } else if (seed < 0x7286bc9f) { |
| expected = expected + (seed & 1); |
| } else if (seed < 0x79435e4e) { |
| expected = (expected + (~seed & 1)) & MAXLONG; |
| } else if (seed < 0x7ffffffd) { |
| expected = expected + (seed & 1); |
| } else if (seed < 0x86bca1ac) { |
| expected = (expected + (~seed & 1)) & MAXLONG; |
| } else if (seed == 0x86bca1ac) { |
| expected = (expected + 1) & MAXLONG; |
| } else if (seed < 0x8d79435c) { |
| expected = expected + (seed & 1); |
| } else if (seed < 0x9435e50b) { |
| expected = (expected + (~seed & 1)) & MAXLONG; |
| } else if (seed < 0x9af286ba) { |
| expected = expected + (seed & 1); |
| } else if (seed < 0xa1af2869) { |
| expected = (expected + (~seed & 1)) & MAXLONG; |
| } else if (seed < 0xa86bca18) { |
| expected = expected + (seed & 1); |
| } else if (seed < 0xaf286bc7) { |
| expected = (expected + (~seed & 1)) & MAXLONG; |
| } else if (seed == 0xaf286bc7) { |
| expected = (expected + 2) & MAXLONG; |
| } else if (seed < 0xb5e50d77) { |
| expected = expected + (seed & 1); |
| } else if (seed < 0xbca1af26) { |
| expected = (expected + (~seed & 1)) & MAXLONG; |
| } else if (seed < 0xc35e50d5) { |
| expected = expected + (seed & 1); |
| } else if (seed < 0xca1af284) { |
| expected = (expected + (~seed & 1)) & MAXLONG; |
| } else if (seed < 0xd0d79433) { |
| expected = expected + (seed & 1); |
| } else if (seed < 0xd79435e2) { |
| expected = (expected + (~seed & 1)) & MAXLONG; |
| } else if (seed < 0xde50d792) { |
| expected = expected + (seed & 1); |
| } else if (seed < 0xe50d7941) { |
| expected = (expected + (~seed & 1)) & MAXLONG; |
| } else if (seed < 0xebca1af0) { |
| expected = expected + (seed & 1); |
| } else if (seed < 0xf286bc9f) { |
| expected = (expected + (~seed & 1)) & MAXLONG; |
| } else if (seed < 0xf9435e4e) { |
| expected = expected + (seed & 1); |
| } else if (seed < 0xfffffffd) { |
| expected = (expected + (~seed & 1)) & MAXLONG; |
| } else { |
| expected = expected + (seed & 1); |
| } /* if */ |
| seed_bak = seed; |
| result = pRtlUniform(&seed); |
| ok(result == expected, |
| "test: %llu RtlUniform(&seed (seed == %lx)) returns %lx, expected %lx", |
| num, seed_bak, result, expected); |
| ok(seed == expected, |
| "test: %llu RtlUniform(&seed (seed == %lx)) sets seed to %lx, expected %lx", |
| num, seed_bak, seed, expected); |
| } /* for */ |
| /* |
| * Further investigation shows: In the different regions the highest bit |
| * is set or cleared when even or odd seeds need an increment by 1. |
| * This leads to the simplified RtlUniform of wine (see dlls/ntdll/rtl.c). |
| */ |
| } |
| |
| |
| START_TEST(rtl) |
| { |
| InitFunctionPtrs(); |
| |
| test_RtlCompareMemoryUlong(); |
| test_RtlUniform(); |
| } |
| |