336 lines
12 KiB
C
336 lines
12 KiB
C
|
/* 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();
|
||
|
}
|
||
|
|