1 /*
2  * PROJECT:         ReactOS kernel-mode tests
3  * LICENSE:         GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:         Test for ntstrsafe.h functions
5  * COPYRIGHT:       Copyright 2018 Hern�n Di Pietro <hernan.di.pietro@gmail.com>
6  *                  Copyright 2019 Colin Finck <colin@reactos.org>
7  */
8 
9 #define KMT_EMULATE_KERNEL
10 #include <kmt_test.h>
11 #include <ntstrsafe.h>
12 #include <ntdef.h>
13 #include <ndk/rtlfuncs.h>
14 
15 #define TESTAPI static void
16 
17 static const WCHAR FormatStringInts[] = L"%d %d %d";
18 static const WCHAR FormatStringIntsResult[] = L"1 2 3";
19 static const WCHAR FormatStringStrs[] = L"%s %s %s";
20 
21 
22 TESTAPI
23 Test_RtlUnicodeStringPrintf()
24 {
25     NTSTATUS Status;
26     PWSTR pBuffer = NULL;
27     USHORT BufferSize;
28     size_t EqualBytes;
29     UNICODE_STRING UsString;
30 
31     KmtStartSeh();
32 
33     /* STATUS_SUCCESS test */
34     BufferSize = 6 * sizeof(WCHAR);
35     pBuffer = KmtAllocateGuarded(BufferSize);
36     if (!pBuffer)
37         goto Cleanup;
38 
39     RtlFillMemory(pBuffer, BufferSize, 0xAA);
40     RtlInitEmptyUnicodeString(&UsString, pBuffer, BufferSize);
41 
42     Status = RtlUnicodeStringPrintf(&UsString, FormatStringInts, 1, 2, 3);
43     EqualBytes = RtlCompareMemory(UsString.Buffer, FormatStringIntsResult, sizeof(FormatStringIntsResult));
44     ok_eq_hex(Status, STATUS_SUCCESS);
45     ok_eq_size(EqualBytes, sizeof(FormatStringIntsResult));
46     ok_eq_uint(UsString.Length, sizeof(FormatStringIntsResult) - sizeof(WCHAR));
47     ok_eq_uint(UsString.MaximumLength, BufferSize);
48 
49     KmtFreeGuarded(pBuffer);
50     pBuffer = NULL;
51 
52     /* STATUS_BUFFER_OVERFLOW tests */
53     BufferSize = 2 * sizeof(WCHAR);
54     pBuffer = KmtAllocateGuarded(BufferSize);
55     if (!pBuffer)
56         goto Cleanup;
57 
58     RtlInitEmptyUnicodeString(&UsString, pBuffer, BufferSize);
59 
60     Status = RtlUnicodeStringPrintf(&UsString, FormatStringStrs, L"AAA", L"BBB", L"CCC");
61     EqualBytes = RtlCompareMemory(UsString.Buffer, L"AA", BufferSize);
62     ok_eq_hex(Status, STATUS_BUFFER_OVERFLOW);
63     ok_eq_size(EqualBytes, BufferSize);
64     ok_eq_uint(UsString.Length, UsString.MaximumLength);
65 
66     KmtFreeGuarded(pBuffer);
67     pBuffer = NULL;
68 
69 
70     BufferSize = 7 * sizeof(WCHAR);
71     pBuffer = KmtAllocateGuarded(BufferSize);
72     if (!pBuffer)
73         goto Cleanup;
74 
75     RtlInitEmptyUnicodeString(&UsString, pBuffer, BufferSize);
76 
77     Status = RtlUnicodeStringPrintf(&UsString, FormatStringStrs, L"0123", L"4567", L"89AB");
78     EqualBytes = RtlCompareMemory(UsString.Buffer, L"0123 45", BufferSize);
79     ok_eq_hex(Status, STATUS_BUFFER_OVERFLOW);
80     ok_eq_size(EqualBytes, BufferSize);
81     ok_eq_uint(UsString.Length, UsString.MaximumLength);
82 
83     KmtFreeGuarded(pBuffer);
84     pBuffer = NULL;
85 
86     // Note: RtlUnicodeStringPrintf returns STATUS_BUFFER_OVERFLOW here while RtlUnicodeStringPrintfEx returns STATUS_INVALID_PARAMETER!
87     // Documented on MSDN and verified with the Win10 version of ntstrsafe.h
88     RtlInitEmptyUnicodeString(&UsString, NULL, 0);
89     Status = RtlUnicodeStringPrintf(&UsString, FormatStringStrs, L"AAA", L"BBB", L"CCC");
90     ok_eq_hex(Status, STATUS_BUFFER_OVERFLOW);
91 
92 
93 Cleanup:
94     if (pBuffer)
95         KmtFreeGuarded(pBuffer);
96 
97     // None of these functions should have crashed.
98     KmtEndSeh(STATUS_SUCCESS);
99 }
100 
101 TESTAPI
102 Test_RtlUnicodeStringPrintfEx()
103 {
104     NTSTATUS Status;
105     PWSTR pBuffer = NULL;
106     USHORT BufferSize;
107     size_t EqualBytes;
108     UNICODE_STRING RemString;
109     UNICODE_STRING UsString;
110     WCHAR FillResult[10];
111 
112     RtlFillMemory(FillResult, sizeof(FillResult), 0xAA);
113 
114     KmtStartSeh();
115 
116     /* STATUS_SUCCESS test, fill behind flag: low-byte as fill character */
117     BufferSize = sizeof(FormatStringIntsResult) - sizeof(UNICODE_NULL) + sizeof(FillResult);
118     pBuffer = KmtAllocateGuarded(BufferSize);
119     if (!pBuffer)
120         goto Cleanup;
121 
122     RtlInitEmptyUnicodeString(&UsString, pBuffer, BufferSize);
123     RtlInitEmptyUnicodeString(&RemString, NULL, 0);
124 
125     Status = RtlUnicodeStringPrintfEx(&UsString, &RemString, STRSAFE_FILL_BEHIND | 0xAA, FormatStringInts, 1, 2, 3);
126     EqualBytes = RtlCompareMemory(UsString.Buffer, FormatStringIntsResult, sizeof(FormatStringIntsResult) - sizeof(WCHAR));
127     ok_eq_hex(Status, STATUS_SUCCESS);
128     ok_eq_size(EqualBytes, sizeof(FormatStringIntsResult) - sizeof(WCHAR));
129     ok_eq_uint(UsString.Length, sizeof(FormatStringIntsResult) - sizeof(WCHAR));
130     ok_eq_uint(UsString.MaximumLength, BufferSize);
131 
132     ok_eq_pointer(RemString.Buffer, &UsString.Buffer[UsString.Length / sizeof(WCHAR)]);
133     ok_eq_uint(RemString.Length, 0);
134     ok_eq_uint(RemString.MaximumLength, UsString.MaximumLength - UsString.Length);
135 
136     EqualBytes = RtlCompareMemory(RemString.Buffer, FillResult, RemString.MaximumLength);
137     ok_eq_size(EqualBytes, sizeof(FillResult));
138 
139     KmtFreeGuarded(pBuffer);
140     pBuffer = NULL;
141 
142 
143     /* STATUS_BUFFER_OVERFLOW test  */
144     BufferSize = 8 * sizeof(WCHAR);
145     pBuffer = KmtAllocateGuarded(BufferSize);
146     if (!pBuffer)
147         goto Cleanup;
148 
149     RtlInitEmptyUnicodeString(&UsString, pBuffer, BufferSize);
150     RtlInitEmptyUnicodeString(&RemString, NULL, 0);
151 
152     Status = RtlUnicodeStringPrintfEx(&UsString, &RemString, 0, FormatStringStrs, L"AAA", L"BBB", L"CCC");
153     EqualBytes = RtlCompareMemory(UsString.Buffer, L"AAA BBB ", UsString.Length);
154     ok_eq_hex(Status, STATUS_BUFFER_OVERFLOW);
155     ok_eq_size(EqualBytes, UsString.Length);
156     ok_eq_uint(UsString.Length, UsString.MaximumLength);
157 
158     ok_eq_pointer(RemString.Buffer, &UsString.Buffer[UsString.Length / sizeof(WCHAR)]);
159     ok_eq_uint(RemString.Length, 0);
160     ok_eq_uint(RemString.MaximumLength, 0);
161 
162     KmtFreeGuarded(pBuffer);
163     pBuffer = NULL;
164 
165 
166     // Note: RtlUnicodeStringPrintf returns STATUS_BUFFER_OVERFLOW here while RtlUnicodeStringPrintfEx returns STATUS_INVALID_PARAMETER!
167     // Documented on MSDN and verified with the Win10 version of ntstrsafe.h
168     RtlInitEmptyUnicodeString(&UsString, NULL, 0);
169     Status = RtlUnicodeStringPrintfEx(&UsString, NULL, 0, FormatStringStrs, L"AAA", L"BBB", L"CCC");
170     ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
171 
172 
173 Cleanup:
174     if (pBuffer)
175         KmtFreeGuarded(pBuffer);
176 
177     // None of these functions should have crashed.
178     KmtEndSeh(STATUS_SUCCESS);
179 }
180 
181 START_TEST(RtlStrSafe)
182 {
183     Test_RtlUnicodeStringPrintf();
184     Test_RtlUnicodeStringPrintfEx();
185 }
186