From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/ntdll/tests/rtl.c | 119 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+)
diff --git a/dlls/ntdll/tests/rtl.c b/dlls/ntdll/tests/rtl.c index 05a27ec6b2c..9d1c5ec7497 100644 --- a/dlls/ntdll/tests/rtl.c +++ b/dlls/ntdll/tests/rtl.c @@ -91,6 +91,7 @@ __ASM_STDCALL_FUNC( wrap_fastcall_func1, 8, static HMODULE hntdll = 0; static PRTL_SPLAY_LINKS (WINAPI *pRtlDelete)(PRTL_SPLAY_LINKS); static void (WINAPI *pRtlDeleteNoSplay)(PRTL_SPLAY_LINKS, PRTL_SPLAY_LINKS *); +static BOOLEAN (WINAPI *pRtlDeleteElementGenericTable)(PRTL_GENERIC_TABLE,PVOID); static VOID (WINAPI *pRtlMoveMemory)(LPVOID,LPCVOID,SIZE_T); static VOID (WINAPI *pRtlFillMemory)(LPVOID,SIZE_T,BYTE); static VOID (WINAPI *pRtlFillMemoryUlong)(LPVOID,SIZE_T,ULONG); @@ -100,6 +101,7 @@ static ULONG (FASTCALL *pRtlUlongByteSwap)(ULONG source); static ULONGLONG (FASTCALL *pRtlUlonglongByteSwap)(ULONGLONG source); static DWORD (WINAPI *pRtlGetThreadErrorMode)(void); static NTSTATUS (WINAPI *pRtlSetThreadErrorMode)(DWORD, LPDWORD); +static PVOID (WINAPI *pRtlInsertElementGenericTable)(PRTL_GENERIC_TABLE, PVOID, CLONG, PBOOLEAN); static NTSTATUS (WINAPI *pRtlIpv4AddressToStringExA)(const IN_ADDR *, USHORT, LPSTR, PULONG); static NTSTATUS (WINAPI *pRtlIpv4StringToAddressExA)(PCSTR, BOOLEAN, IN_ADDR *, PUSHORT); static NTSTATUS (WINAPI *pRtlIpv6AddressToStringExA)(struct in6_addr *, ULONG, USHORT, PCHAR, PULONG); @@ -156,6 +158,7 @@ static void InitFunctionPtrs(void) ok(hntdll != 0, "LoadLibrary failed\n"); if (hntdll) { pRtlDelete = (void *)GetProcAddress(hntdll, "RtlDelete"); + pRtlDeleteElementGenericTable = (void *)GetProcAddress(hntdll, "RtlDeleteElementGenericTable"); pRtlDeleteNoSplay = (void *)GetProcAddress(hntdll, "RtlDeleteNoSplay"); pRtlMoveMemory = (void *)GetProcAddress(hntdll, "RtlMoveMemory"); pRtlFillMemory = (void *)GetProcAddress(hntdll, "RtlFillMemory"); @@ -166,6 +169,7 @@ static void InitFunctionPtrs(void) pRtlUlonglongByteSwap = (void *)GetProcAddress(hntdll, "RtlUlonglongByteSwap"); pRtlGetThreadErrorMode = (void *)GetProcAddress(hntdll, "RtlGetThreadErrorMode"); pRtlSetThreadErrorMode = (void *)GetProcAddress(hntdll, "RtlSetThreadErrorMode"); + pRtlInsertElementGenericTable = (void *)GetProcAddress(hntdll, "RtlInsertElementGenericTable"); pRtlIpv4AddressToStringExA = (void *)GetProcAddress(hntdll, "RtlIpv4AddressToStringExA"); pRtlIpv4StringToAddressExA = (void *)GetProcAddress(hntdll, "RtlIpv4StringToAddressExA"); pRtlIpv6AddressToStringExA = (void *)GetProcAddress(hntdll, "RtlIpv6AddressToStringExA"); @@ -4854,6 +4858,31 @@ static void test_RtlDelete(void) ok(root == NULL, "Got unexpected root.\n"); }
+/* data is a place holder to align stored data on a 8 byte boundary */ +struct rtl_generic_table_entry +{ + RTL_SPLAY_LINKS splay_links; + LIST_ENTRY list_entry; + LONGLONG data; +}; + +static void *get_data_from_list_entry(LIST_ENTRY *list_entry) +{ + return (unsigned char *)list_entry + FIELD_OFFSET(struct rtl_generic_table_entry, data) + - FIELD_OFFSET(struct rtl_generic_table_entry, list_entry); +} + +static RTL_SPLAY_LINKS *get_splay_links_from_data(void *data) +{ + return (RTL_SPLAY_LINKS *)((unsigned char *)data - FIELD_OFFSET(struct rtl_generic_table_entry, data)); +} + +static LIST_ENTRY *get_list_entry_from_data(void *data) +{ + return (LIST_ENTRY *)((unsigned char *)data - FIELD_OFFSET(struct rtl_generic_table_entry, data) + + FIELD_OFFSET(struct rtl_generic_table_entry, list_entry)); +} + static RTL_GENERIC_COMPARE_RESULTS WINAPI generic_compare_proc(RTL_GENERIC_TABLE *table, void *p1, void *p2) { int *value1 = p1, *value2 = p2; @@ -4868,6 +4897,10 @@ static RTL_GENERIC_COMPARE_RESULTS WINAPI generic_compare_proc(RTL_GENERIC_TABLE
static void * WINAPI generic_allocate_proc(RTL_GENERIC_TABLE *table, CLONG size) { + CLONG *last_allocated = table->TableContext; + + if (last_allocated) + *last_allocated = size; return malloc(size); }
@@ -4940,6 +4973,91 @@ static void test_RtlIsGenericTableEmpty(void) ok(!empty, "Expected not empty.\n"); }
+static void test_RtlInsertElementGenericTable(void) +{ + static const int elements[] = {1, 9, 5, 4, 7, 2, 3, 8, 6}; + int i, value, *ret, *first_ret = NULL, *last_ret = NULL; + ULONG count, size, last_allocated; + BOOLEAN new_element, success; + RTL_GENERIC_TABLE table; + LIST_ENTRY *entry; + + if (!pRtlInsertElementGenericTable) + { + win_skip("RtlInsertElementGenericTable is unavailable.\n"); + return; + } + + pRtlInitializeGenericTable(&table, generic_compare_proc, generic_allocate_proc, + generic_free_proc, (void *)&last_allocated); + + for (i = 0; i < ARRAY_SIZE(elements); i++) + { + value = elements[i]; + ret = pRtlInsertElementGenericTable(&table, &value, sizeof(value), &new_element); + ok(ret && *ret == value, "Got unexpected pointer.\n"); + ok(new_element, "Expected new element.\n"); + ok(table.TableRoot == get_splay_links_from_data(ret), "Got unexpected TableRoot.\n"); + + if (i == 0) + first_ret = ret; + if (i == ARRAY_SIZE(elements) - 1) + last_ret = ret; + } + + count = pRtlNumberGenericTableElements(&table); + ok(count == ARRAY_SIZE(elements), "Got unexpected count %ld.\n", count); + + /* Test that the allocated memory includes a RTL_SPLAY_LINKS and a LIST_ENTRY header. The data + * is aligned on a 8 byte boundary */ + size = FIELD_OFFSET(struct rtl_generic_table_entry, data) + sizeof(value); + ok(last_allocated == size, "Expected %lu, got %lu.\n", size, last_allocated); + + /* Check that InsertOrderList points to a doubly linked list of elements in insertion order */ + ok(table.InsertOrderList.Flink == get_list_entry_from_data(first_ret), "Got unexpected Flink.\n"); + ok(table.InsertOrderList.Blink == get_list_entry_from_data(last_ret), "Got unexpected Blink.\n"); + for (i = 0, entry = table.InsertOrderList.Flink; entry->Flink != table.InsertOrderList.Flink; + i++, entry = entry->Flink) + { + ret = (int *)get_data_from_list_entry(entry); + ok(*ret == elements[i], "Got unexpected pointer, value %d.\n", *ret); + } + ok(i == ARRAY_SIZE(elements), "Got unexpected index %d.\n", i); + for (i = ARRAY_SIZE(elements) - 1, entry = table.InsertOrderList.Blink; + entry->Blink != table.InsertOrderList.Blink; i--, entry = entry->Blink) + { + ret = (int *)get_data_from_list_entry(entry); + ok(*ret == elements[i], "Got unexpected pointer, value %d.\n", *ret); + } + ok(i == -1, "Got unexpected index %d.\n", i); + + /* Insert the same element again */ + ret = pRtlInsertElementGenericTable(&table, &value, sizeof(value), &new_element); + ok(ret && *ret == value, "Got unexpected pointer.\n"); + ok(!new_element, "Expected old element.\n"); + + count = pRtlNumberGenericTableElements(&table); + ok(count == ARRAY_SIZE(elements), "Got unexpected count %ld.\n", count); + + /* Insert a new element with new_element pointer being NULL */ + value = 0; + ret = pRtlInsertElementGenericTable(&table, &value, sizeof(value), NULL); + ok(ret && ret != &value && *ret == 0, "Got unexpected pointer.\n"); + + count = pRtlNumberGenericTableElements(&table); + ok(count == ARRAY_SIZE(elements) + 1, "Got unexpected count %ld.\n", count); + + success = pRtlDeleteElementGenericTable(&table, &value); + ok(success, "RtlDeleteElementGenericTable failed.\n"); + + for (i = 0; i < ARRAY_SIZE(elements); i++) + { + value = elements[i]; + success = pRtlDeleteElementGenericTable(&table, &value); + ok(success, "RtlDeleteElementGenericTable failed.\n"); + } +} + START_TEST(rtl) { InitFunctionPtrs(); @@ -5002,4 +5120,5 @@ START_TEST(rtl) test_RtlInitializeGenericTable(); test_RtlNumberGenericTableElements(); test_RtlIsGenericTableEmpty(); + test_RtlInsertElementGenericTable(); }