janitorial: Remove remaining NULL checks before free() (found by Smatch).
[wine] / dlls / ntdll / tests / reg.c
1 /* Unit test suite for Rtl* Registry API functions
2  *
3  * Copyright 2003 Thomas Mertes
4  * Copyright 2005 Brad DeMorrow
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * NOTE: I don't test every RelativeTo value because it would be redundant, all calls go through
21  * helper function RTL_GetKeyHandle().--Brad DeMorrow
22  *
23  */
24
25 #include "ntdll_test.h"
26 #include "winternl.h"
27 #include "stdio.h"
28 #include "winnt.h"
29 #include "winnls.h"
30 #include "stdlib.h"
31
32 #ifndef __WINE_WINTERNL_H
33
34 /* RtlQueryRegistryValues structs and defines */
35 #define RTL_REGISTRY_ABSOLUTE             0
36 #define RTL_REGISTRY_SERVICES             1
37 #define RTL_REGISTRY_CONTROL              2
38 #define RTL_REGISTRY_WINDOWS_NT           3
39 #define RTL_REGISTRY_DEVICEMAP            4
40 #define RTL_REGISTRY_USER                 5
41
42 #define RTL_REGISTRY_HANDLE       0x40000000
43 #define RTL_REGISTRY_OPTIONAL     0x80000000
44
45 #define RTL_QUERY_REGISTRY_SUBKEY         0x00000001
46 #define RTL_QUERY_REGISTRY_TOPKEY         0x00000002
47 #define RTL_QUERY_REGISTRY_REQUIRED       0x00000004
48 #define RTL_QUERY_REGISTRY_NOVALUE        0x00000008
49 #define RTL_QUERY_REGISTRY_NOEXPAND       0x00000010
50 #define RTL_QUERY_REGISTRY_DIRECT         0x00000020
51 #define RTL_QUERY_REGISTRY_DELETE         0x00000040
52
53 typedef NTSTATUS (WINAPI *PRTL_QUERY_REGISTRY_ROUTINE)( PCWSTR  ValueName,
54                                                         ULONG  ValueType,
55                                                         PVOID  ValueData,
56                                                         ULONG  ValueLength,
57                                                         PVOID  Context,
58                                                         PVOID  EntryContext);
59
60 typedef struct _RTL_QUERY_REGISTRY_TABLE {
61   PRTL_QUERY_REGISTRY_ROUTINE  QueryRoutine;
62   ULONG  Flags;
63   PWSTR  Name;
64   PVOID  EntryContext;
65   ULONG  DefaultType;
66   PVOID  DefaultData;
67   ULONG  DefaultLength;
68 } RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE;
69
70 #define InitializeObjectAttributes(p,n,a,r,s) \
71     do { \
72         (p)->Length = sizeof(OBJECT_ATTRIBUTES); \
73         (p)->RootDirectory = r; \
74         (p)->Attributes = a; \
75         (p)->ObjectName = n; \
76         (p)->SecurityDescriptor = s; \
77         (p)->SecurityQualityOfService = NULL; \
78     } while (0)
79
80 #endif
81
82 static NTSTATUS (WINAPI * pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING, LPCSTR);
83 static NTSTATUS (WINAPI * pRtlFreeUnicodeString)(PUNICODE_STRING);
84 static NTSTATUS (WINAPI * pNtDeleteValueKey)(IN HANDLE, IN PUNICODE_STRING);
85 static NTSTATUS (WINAPI * pRtlQueryRegistryValues)(IN ULONG, IN PCWSTR,IN PRTL_QUERY_REGISTRY_TABLE, IN PVOID,IN PVOID);
86 static NTSTATUS (WINAPI * pRtlCheckRegistryKey)(IN ULONG,IN PWSTR);
87 static NTSTATUS (WINAPI * pRtlOpenCurrentUser)(IN ACCESS_MASK, OUT PHKEY);
88 static NTSTATUS (WINAPI * pNtOpenKey)(PHANDLE, IN ACCESS_MASK, IN POBJECT_ATTRIBUTES);
89 static NTSTATUS (WINAPI * pNtClose)(IN HANDLE);
90 static NTSTATUS (WINAPI * pNtDeleteValueKey)(IN HANDLE, IN PUNICODE_STRING);
91 static NTSTATUS (WINAPI * pNtFlushKey)(HKEY);
92 static NTSTATUS (WINAPI * pNtDeleteKey)(HKEY);
93 static NTSTATUS (WINAPI * pNtCreateKey)( PHKEY retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
94                              ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
95                              PULONG dispos );
96 static NTSTATUS (WINAPI * pNtSetValueKey)( PHKEY, const PUNICODE_STRING, ULONG,
97                                ULONG, const PVOID, ULONG  );
98 static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(PUNICODE_STRING);
99 static NTSTATUS (WINAPI * pRtlCreateUnicodeString)( PUNICODE_STRING, LPCWSTR);
100 static NTSTATUS (WINAPI * pRtlReAllocateHeap)(IN PVOID, IN ULONG, IN PVOID, IN ULONG);
101 static NTSTATUS (WINAPI * pRtlAppendUnicodeToString)(PUNICODE_STRING, PCWSTR);
102 static NTSTATUS (WINAPI * pRtlUnicodeStringToAnsiString)(PSTRING, PUNICODE_STRING, BOOL);
103 static NTSTATUS (WINAPI * pRtlFreeHeap)(PVOID, ULONG, PVOID);
104 static NTSTATUS (WINAPI * pRtlAllocateHeap)(PVOID,ULONG,ULONG);
105 static NTSTATUS (WINAPI * pRtlZeroMemory)(PVOID, ULONG);
106 static NTSTATUS (WINAPI * pRtlpNtQueryValueKey)(HANDLE,ULONG*,PBYTE,DWORD*);
107
108 static HMODULE hntdll = 0;
109 static int CurrentTest = 0;
110 static UNICODE_STRING winetestpath;
111
112 #define NTDLL_GET_PROC(func) \
113     p ## func = (void*)GetProcAddress(hntdll, #func); \
114     if(!p ## func) { \
115         trace("GetProcAddress(%s) failed\n", #func); \
116         FreeLibrary(hntdll); \
117         return FALSE; \
118     }
119
120 static BOOL InitFunctionPtrs(void)
121 {
122     hntdll = LoadLibraryA("ntdll.dll");
123     if(!hntdll) {
124         trace("Could not load ntdll.dll\n");
125         return FALSE;
126     }
127     if (hntdll)
128     {
129         NTDLL_GET_PROC(RtlCreateUnicodeStringFromAsciiz)
130         NTDLL_GET_PROC(RtlCreateUnicodeString)
131         NTDLL_GET_PROC(RtlFreeUnicodeString)
132         NTDLL_GET_PROC(NtDeleteValueKey)
133         NTDLL_GET_PROC(RtlQueryRegistryValues)
134         NTDLL_GET_PROC(RtlCheckRegistryKey)
135         NTDLL_GET_PROC(RtlOpenCurrentUser)
136         NTDLL_GET_PROC(NtClose)
137         NTDLL_GET_PROC(NtDeleteValueKey)
138         NTDLL_GET_PROC(NtCreateKey)
139         NTDLL_GET_PROC(NtFlushKey)
140         NTDLL_GET_PROC(NtDeleteKey)
141         NTDLL_GET_PROC(NtSetValueKey)
142         NTDLL_GET_PROC(NtOpenKey)
143         NTDLL_GET_PROC(RtlFormatCurrentUserKeyPath)
144         NTDLL_GET_PROC(RtlReAllocateHeap)
145         NTDLL_GET_PROC(RtlAppendUnicodeToString)
146         NTDLL_GET_PROC(RtlUnicodeStringToAnsiString)
147         NTDLL_GET_PROC(RtlFreeHeap)
148         NTDLL_GET_PROC(RtlAllocateHeap)
149         NTDLL_GET_PROC(RtlZeroMemory)
150         NTDLL_GET_PROC(RtlpNtQueryValueKey)
151     }
152     return TRUE;
153 }
154 #undef NTDLL_GET_PROC
155
156 static NTSTATUS WINAPI QueryRoutine (IN PCWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData,
157                               IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
158 {
159     NTSTATUS ret = STATUS_SUCCESS;
160     int ValueNameLength = 0;
161     LPSTR ValName = 0;
162     trace("**Test %d**\n", CurrentTest);
163
164     if(ValueName)
165     {
166         ValueNameLength = lstrlenW(ValueName);
167
168         ValName = (LPSTR)pRtlAllocateHeap(GetProcessHeap(), 0, ValueNameLength);
169
170         WideCharToMultiByte(0, 0, ValueName, ValueNameLength+1,ValName, ValueNameLength, 0, 0);
171
172         trace("ValueName: %s\n", ValName);
173     }
174     else
175         trace("ValueName: (null)\n");
176
177     switch(ValueType)
178     {
179             case REG_NONE:
180                 trace("ValueType: REG_NONE\n");
181                 trace("ValueData: %d\n", (int)ValueData);
182                 break;
183
184             case REG_BINARY:
185                 trace("ValueType: REG_BINARY\n");
186                 trace("ValueData: %d\n", (int)ValueData);
187                 break;
188
189             case REG_SZ:
190                 trace("ValueType: REG_SZ\n");
191                 trace("ValueData: %s\n", (char*)ValueData);
192                 break;
193
194             case REG_MULTI_SZ:
195                 trace("ValueType: REG_MULTI_SZ\n");
196                 trace("ValueData: %s\n", (char*)ValueData);
197                 break;
198
199             case REG_EXPAND_SZ:
200                 trace("ValueType: REG_EXPAND_SZ\n");
201                 trace("ValueData: %s\n", (char*)ValueData);
202                 break;
203
204             case REG_DWORD:
205                 trace("ValueType: REG_DWORD\n");
206                 trace("ValueData: %d\n", (int)ValueData);
207                 break;
208     };
209     trace("ValueLength: %d\n", (int)ValueLength);
210
211     if(CurrentTest == 0)
212         ok(1, "\n"); /*checks that QueryRoutine is called*/
213     if(CurrentTest > 7)
214         ok(!1, "Invalid Test Specified!\n");
215
216     CurrentTest++;
217
218     if(ValName)
219         pRtlFreeHeap(GetProcessHeap(), 0, ValName);
220
221     return ret;
222 }
223
224 static void test_RtlQueryRegistryValues(void)
225 {
226
227     /*
228     ******************************
229     *       QueryTable Flags     *
230     ******************************
231     *RTL_QUERY_REGISTRY_SUBKEY   * Name is the name of a subkey relative to Path
232     *RTL_QUERY_REGISTRY_TOPKEY   * Resets location to original RelativeTo and Path
233     *RTL_QUERY_REGISTRY_REQUIRED * Key required. returns STATUS_OBJECT_NAME_NOT_FOUND if not present
234     *RTL_QUERY_REGISTRY_NOVALUE  * We just want a call-back
235     *RTL_QUERY_REGISTRY_NOEXPAND * Don't expand the variables!
236     *RTL_QUERY_REGISTRY_DIRECT   * Results of query will be stored in EntryContext(QueryRoutine ignored)
237     *RTL_QUERY_REGISTRY_DELETE   * Delete value key after query
238     ******************************
239
240
241     **Test layout(numbered according to CurrentTest value)**
242     0)NOVALUE           Just make sure call-back works
243     1)Null Name         See if QueryRoutine is called for every value in current key
244     2)SUBKEY            See if we can use SUBKEY to change the current path on the fly
245     3)REQUIRED          Test for value that's not there
246     4)NOEXPAND          See if it will return multiple strings(no expand should split strings up)
247     5)DIRECT            Make it store data directly in EntryContext and not call QueryRoutine
248     6)DefaultType       Test return values when key isn't present
249     7)DefaultValue      Test Default Value returned with key isn't present(and no REQUIRED flag set)
250     8)DefaultLength     Test Default Length with DefaultType = REG_SZ
251    9)DefaultLength      Test Default Length with DefaultType = REG_MULTI_SZ
252    10)DefaultLength     Test Default Length with DefaultType = REG_EXPAND_SZ
253    11)DefaultData       Test whether DefaultData is used while DefaltType = REG_NONE(shouldn't be)
254    12)Delete            Try to delete value key
255
256     */
257     NTSTATUS status;
258     ULONG RelativeTo;
259
260     PRTL_QUERY_REGISTRY_TABLE QueryTable = NULL;
261     RelativeTo = RTL_REGISTRY_ABSOLUTE;/*Only using absolute - no need to test all relativeto variables*/
262
263     QueryTable = (PRTL_QUERY_REGISTRY_TABLE)pRtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_QUERY_REGISTRY_TABLE)*26);
264
265     pRtlZeroMemory( QueryTable, sizeof(RTL_QUERY_REGISTRY_TABLE) * 26);
266
267     QueryTable[0].QueryRoutine = QueryRoutine;
268     QueryTable[0].Flags = RTL_QUERY_REGISTRY_NOVALUE;
269     QueryTable[0].Name = NULL;
270     QueryTable[0].EntryContext = NULL;
271     QueryTable[0].DefaultType = REG_BINARY;
272     QueryTable[0].DefaultData = NULL;
273     QueryTable[0].DefaultLength = 100;
274
275     QueryTable[1].QueryRoutine = QueryRoutine;
276     QueryTable[1].Flags = 0;
277     QueryTable[1].Name = NULL;
278     QueryTable[1].EntryContext = 0;
279     QueryTable[1].DefaultType = REG_NONE;
280     QueryTable[1].DefaultData = NULL;
281     QueryTable[1].DefaultLength = 0;
282
283     QueryTable[2].QueryRoutine = NULL;
284     QueryTable[2].Flags = 0;
285     QueryTable[2].Name = NULL;
286     QueryTable[2].EntryContext = 0;
287     QueryTable[2].DefaultType = REG_NONE;
288     QueryTable[2].DefaultData = NULL;
289     QueryTable[2].DefaultLength = 0;
290
291     status = pRtlQueryRegistryValues(RelativeTo, winetestpath.Buffer, QueryTable, 0, 0);
292     ok(status == STATUS_SUCCESS, "RtlQueryRegistryValues return: 0x%08lx\n", status);
293
294     pRtlFreeHeap(GetProcessHeap(), 0, QueryTable);
295 }
296
297 static void test_NtOpenKey(void)
298 {
299     HANDLE key;
300     NTSTATUS status;
301     OBJECT_ATTRIBUTES attr;
302     ACCESS_MASK am = KEY_READ;
303
304 #if 0 /* Crashes Wine */
305     /* All NULL */
306     status = pNtOpenKey(NULL, 0, NULL);
307     ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08lx\n", status);
308
309     /* NULL attributes */
310     status = pNtOpenKey(&key, 0, NULL);
311     ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
312         "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08lx\n", status);
313 #endif 
314
315     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
316
317     /* NULL key */
318     status = pNtOpenKey(NULL, 0, &attr);
319     todo_wine
320         ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08lx\n", status);
321
322     /* Length > sizeof(OBJECT_ATTRIBUTES) */
323     attr.Length *= 2;
324     status = pNtOpenKey(&key, am, &attr);
325     todo_wine
326         ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08lx\n", status);
327 }
328
329 static void test_NtCreateKey(void)
330 {
331     /*Create WineTest*/
332     OBJECT_ATTRIBUTES attr;
333     HKEY key;
334     ACCESS_MASK am = GENERIC_ALL;
335     NTSTATUS status;
336
337     /* All NULL */
338     status = pNtCreateKey(NULL, 0, NULL, 0, 0, 0, 0);
339     ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08lx\n", status);
340
341     /* Only the key */
342     status = pNtCreateKey(&key, 0, NULL, 0, 0, 0, 0);
343     ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
344         "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08lx\n", status);
345
346     /* Only accessmask */
347     status = pNtCreateKey(NULL, am, NULL, 0, 0, 0, 0);
348     ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08lx\n", status);
349
350     /* Key and accessmask */
351     status = pNtCreateKey(&key, am, NULL, 0, 0, 0, 0);
352     ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
353         "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08lx\n", status);
354
355     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
356
357     /* Only attributes */
358     status = pNtCreateKey(NULL, 0, &attr, 0, 0, 0, 0);
359     ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08lx\n", status);
360
361     status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
362     ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08lx\n", status);
363
364     /* Length > sizeof(OBJECT_ATTRIBUTES) */
365     attr.Length *= 2;
366     status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
367     ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08lx\n", status);
368
369     pNtClose(&key);
370 }
371
372 static void test_NtSetValueKey(void)
373 {
374     HANDLE key;
375     NTSTATUS status;
376     OBJECT_ATTRIBUTES attr;
377     ACCESS_MASK am = KEY_WRITE;
378     UNICODE_STRING ValName;
379     DWORD data = 711;
380
381     pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
382
383     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
384     status = pNtOpenKey(&key, am, &attr);
385     ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08lx\n", status);
386
387     status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &data, sizeof(data));
388     ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08lx\n", status);
389
390     pRtlFreeUnicodeString(&ValName);
391     pNtClose(&key);
392 }
393
394 static void test_RtlOpenCurrentUser(void)
395 {
396     NTSTATUS status;
397     HKEY handle;
398     status=pRtlOpenCurrentUser(KEY_READ, &handle);
399     ok(status == STATUS_SUCCESS, "RtlOpenCurrentUser Failed: 0x%08lx\n", status);
400     pNtClose(&handle);
401 }
402
403 static void test_RtlCheckRegistryKey(void)
404 {
405     NTSTATUS status;
406
407     status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer);
408     ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE: 0x%08lx\n", status);
409
410     status = pRtlCheckRegistryKey((RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL), winetestpath.Buffer);
411     ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and RTL_REGISTRY_OPTIONAL: 0x%08lx\n", status);
412 }
413
414 static void test_NtFlushKey(void)
415 {
416     NTSTATUS status;
417     HANDLE hkey;
418     OBJECT_ATTRIBUTES attr;
419     ACCESS_MASK am = KEY_ALL_ACCESS;
420
421     status = pNtFlushKey(NULL);
422     ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08lx\n", status);
423
424     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
425     pNtOpenKey(&hkey, am, &attr);
426
427     status = pNtFlushKey(hkey);
428     ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08lx\n", status);
429
430     pNtClose(hkey);
431 }
432
433 static void test_NtDeleteKey(void)
434 {
435     NTSTATUS status;
436     HANDLE hkey;
437     OBJECT_ATTRIBUTES attr;
438     ACCESS_MASK am = KEY_ALL_ACCESS;
439
440     status = pNtDeleteKey(NULL);
441     ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08lx\n", status);
442
443     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
444     status = pNtOpenKey(&hkey, am, &attr);
445
446     status = pNtDeleteKey(hkey);
447     ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08lx\n", status);
448 }
449
450 static void test_RtlpNtQueryValueKey(void)
451 {
452     NTSTATUS status;
453
454     status = pRtlpNtQueryValueKey(NULL, NULL, NULL, NULL);
455     ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08lx\n", status);
456 }
457
458 START_TEST(reg)
459 {
460     static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t','\\',0};
461     if(!InitFunctionPtrs())
462         return;
463     pRtlFormatCurrentUserKeyPath(&winetestpath);
464     winetestpath.Buffer = (PWSTR)pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, winetestpath.Buffer,
465                            winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR));
466     winetestpath.MaximumLength = winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR);
467
468     pRtlAppendUnicodeToString(&winetestpath, winetest);
469
470     test_NtOpenKey();
471     test_NtCreateKey();
472     test_NtSetValueKey();
473     test_RtlCheckRegistryKey();
474     test_RtlOpenCurrentUser();
475     test_RtlQueryRegistryValues();
476     test_RtlpNtQueryValueKey();
477     test_NtFlushKey();
478     test_NtDeleteKey();
479
480     pRtlFreeUnicodeString(&winetestpath);
481
482     FreeLibrary(hntdll);
483 }