1 /*
2  * PROJECT:         ReactOS api tests
3  * LICENSE:         GPLv2+ - See COPYING in the top level directory
4  * PURPOSE:         Test for sprintf
5  * PROGRAMMER:      Thomas Faber <thomas.faber@reactos.org>
6  */
7 
8 #include <apitest.h>
9 
10 #define WIN32_NO_STATUS
11 #include <stdio.h>
12 #include <tchar.h>
13 #include <pseh/pseh2.h>
14 #include <ndk/mmfuncs.h>
15 #include <ndk/rtlfuncs.h>
16 
17 #ifdef _MSC_VER
18 #pragma warning(disable:4778) // unterminated format string '%'
19 #else
20 #pragma GCC diagnostic ignored "-Wformat"
21 #pragma GCC diagnostic ignored "-Wformat-zero-length"
22 #pragma GCC diagnostic ignored "-Wnonnull"
23 #endif
24 
25 static
26 PVOID
27 AllocateGuarded(
28     SIZE_T SizeRequested)
29 {
30     NTSTATUS Status;
31     SIZE_T Size = PAGE_ROUND_UP(SizeRequested + PAGE_SIZE);
32     PVOID VirtualMemory = NULL;
33     PCHAR StartOfBuffer;
34 
35     Status = NtAllocateVirtualMemory(NtCurrentProcess(), &VirtualMemory, 0, &Size, MEM_RESERVE, PAGE_NOACCESS);
36 
37     if (!NT_SUCCESS(Status))
38         return NULL;
39 
40     Size -= PAGE_SIZE;
41     if (Size)
42     {
43         Status = NtAllocateVirtualMemory(NtCurrentProcess(), &VirtualMemory, 0, &Size, MEM_COMMIT, PAGE_READWRITE);
44         if (!NT_SUCCESS(Status))
45         {
46             Size = 0;
47             Status = NtFreeVirtualMemory(NtCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE);
48             ok(Status == STATUS_SUCCESS, "Status = %lx\n", Status);
49             return NULL;
50         }
51     }
52 
53     StartOfBuffer = VirtualMemory;
54     StartOfBuffer += Size - SizeRequested;
55 
56     return StartOfBuffer;
57 }
58 
59 static
60 VOID
61 FreeGuarded(
62     PVOID Pointer)
63 {
64     NTSTATUS Status;
65     PVOID VirtualMemory = (PVOID)PAGE_ROUND_DOWN((SIZE_T)Pointer);
66     SIZE_T Size = 0;
67 
68     Status = NtFreeVirtualMemory(NtCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE);
69     ok(Status == STATUS_SUCCESS, "Status = %lx\n", Status);
70 }
71 
72 /* NOTE: This test is not only used for all the CRT apitests, but also for
73  *       user32's wsprintf. Make sure to test them all */
74 START_TEST(sprintf)
75 {
76     int Length;
77     CHAR Buffer[128];
78     PCHAR String;
79 
80     /* basic parameter tests */
81     StartSeh()
82         Length = sprintf(NULL, NULL);
83     EndSeh(STATUS_ACCESS_VIOLATION);
84 
85     StartSeh()
86         Length = sprintf(NULL, "");
87         ok_int(Length, 0);
88     EndSeh(STATUS_ACCESS_VIOLATION);
89 
90     StartSeh()
91         Length = sprintf(NULL, "Hello");
92         ok_int(Length, 5);
93     EndSeh(STATUS_ACCESS_VIOLATION);
94 
95     /* some basic formats */
96     Length = sprintf(Buffer, "abcde");
97     ok_str(Buffer, "abcde");
98     ok_int(Length, 5);
99 
100     Length = sprintf(Buffer, "%%");
101     ok_str(Buffer, "%");
102     ok_int(Length, 1);
103 
104     Length = sprintf(Buffer, "%");
105     ok_str(Buffer, "");
106     ok_int(Length, 0);
107 
108     Length = sprintf(Buffer, "%%%");
109     ok_str(Buffer, "%");
110     ok_int(Length, 1);
111 
112     Length = sprintf(Buffer, "%d", 8);
113     ok_str(Buffer, "8");
114     ok_int(Length, 1);
115 
116     Length = sprintf(Buffer, "%s", "hello");
117     ok_str(Buffer, "hello");
118     ok_int(Length, 5);
119 
120     /* field width for %s */
121     Length = sprintf(Buffer, "%8s", "hello");
122     ok_str(Buffer, "   hello");
123     ok_int(Length, 8);
124 
125     Length = sprintf(Buffer, "%4s", "hello");
126     ok_str(Buffer, "hello");
127     ok_int(Length, 5);
128 
129     Length = sprintf(Buffer, "%-8s", "hello");
130     ok_str(Buffer, "hello   ");
131     ok_int(Length, 8);
132 
133     Length = sprintf(Buffer, "%-5s", "hello");
134     ok_str(Buffer, "hello");
135     ok_int(Length, 5);
136 
137     Length = sprintf(Buffer, "%0s", "hello");
138     ok_str(Buffer, "hello");
139     ok_int(Length, 5);
140 
141     Length = sprintf(Buffer, "%-0s", "hello");
142     ok_str(Buffer, "hello");
143     ok_int(Length, 5);
144 
145     Length = sprintf(Buffer, "%*s", -8, "hello");
146 #ifdef TEST_USER32
147     ok_str(Buffer, "*s");
148     ok_int(Length, 2);
149 #else
150     ok_str(Buffer, "hello   ");
151     ok_int(Length, 8);
152 #endif
153 
154     /* precision for %s */
155     Length = sprintf(Buffer, "%.s", "hello");
156     ok_str(Buffer, "");
157     ok_int(Length, 0);
158 
159     Length = sprintf(Buffer, "%.0s", "hello");
160     ok_str(Buffer, "");
161     ok_int(Length, 0);
162 
163     Length = sprintf(Buffer, "%.10s", "hello");
164     ok_str(Buffer, "hello");
165     ok_int(Length, 5);
166 
167     Length = sprintf(Buffer, "%.5s", "hello");
168     ok_str(Buffer, "hello");
169     ok_int(Length, 5);
170 
171     Length = sprintf(Buffer, "%.4s", "hello");
172     ok_str(Buffer, "hell");
173     ok_int(Length, 4);
174 
175     StartSeh()
176         Length = sprintf(Buffer, "%.*s", -1, "hello");
177 #ifdef TEST_USER32
178         ok_str(Buffer, "*s");
179         ok_int(Length, 2);
180 #else
181         ok_str(Buffer, "hello");
182         ok_int(Length, 5);
183 #endif
184     EndSeh(STATUS_SUCCESS);
185 
186     String = AllocateGuarded(6);
187     if (!String)
188     {
189         skip("Guarded allocation failure\n");
190         return;
191     }
192 
193     strcpy(String, "hello");
194     StartSeh()
195         Length = sprintf(Buffer, "%.8s", String);
196         ok_str(Buffer, "hello");
197         ok_int(Length, 5);
198     EndSeh(STATUS_SUCCESS);
199 
200     StartSeh()
201         Length = sprintf(Buffer, "%.6s", String);
202         ok_str(Buffer, "hello");
203         ok_int(Length, 5);
204     EndSeh(STATUS_SUCCESS);
205 
206     StartSeh()
207         Length = sprintf(Buffer, "%.5s", String);
208         ok_str(Buffer, "hello");
209         ok_int(Length, 5);
210     EndSeh(STATUS_SUCCESS);
211 
212     StartSeh()
213         Length = sprintf(Buffer, "%.4s", String);
214         ok_str(Buffer, "hell");
215         ok_int(Length, 4);
216     EndSeh(STATUS_SUCCESS);
217 
218     String[5] = '!';
219     StartSeh()
220         Length = sprintf(Buffer, "%.5s", String);
221         ok_str(Buffer, "hello");
222         ok_int(Length, 5);
223 #ifdef TEST_USER32
224     EndSeh(STATUS_ACCESS_VIOLATION);
225 #else
226     EndSeh(STATUS_SUCCESS);
227 #endif
228 
229     StartSeh()
230         Length = sprintf(Buffer, "%.6s", String);
231         ok_str(Buffer, "hello!");
232         ok_int(Length, 6);
233 #ifdef TEST_USER32
234     EndSeh(STATUS_ACCESS_VIOLATION);
235 #else
236     EndSeh(STATUS_SUCCESS);
237 #endif
238 
239     StartSeh()
240         Length = sprintf(Buffer, "%.*s", 5, String);
241 #ifdef TEST_USER32
242         ok_str(Buffer, "*s");
243         ok_int(Length, 2);
244 #else
245         ok_str(Buffer, "hello");
246         ok_int(Length, 5);
247 #endif
248     EndSeh(STATUS_SUCCESS);
249 
250     StartSeh()
251         Length = sprintf(Buffer, "%.*s", 6, String);
252 #ifdef TEST_USER32
253         ok_str(Buffer, "*s");
254         ok_int(Length, 2);
255 #else
256         ok_str(Buffer, "hello!");
257         ok_int(Length, 6);
258 #endif
259     EndSeh(STATUS_SUCCESS);
260 
261     /* both field width and precision */
262     StartSeh()
263         Length = sprintf(Buffer, "%8.5s", String);
264         ok_str(Buffer, "   hello");
265         ok_int(Length, 8);
266 #ifdef TEST_USER32
267     EndSeh(STATUS_ACCESS_VIOLATION);
268 #else
269     EndSeh(STATUS_SUCCESS);
270 #endif
271 
272     StartSeh()
273         Length = sprintf(Buffer, "%-*.6s", -8, String);
274 #ifdef TEST_USER32
275         ok_str(Buffer, "*.6s");
276         ok_int(Length, 4);
277 #else
278         ok_str(Buffer, "hello!  ");
279         ok_int(Length, 8);
280 #endif
281     EndSeh(STATUS_SUCCESS);
282 
283     StartSeh()
284         Length = sprintf(Buffer, "%*.*s", -8, 6, String);
285 #ifdef TEST_USER32
286         ok_str(Buffer, "*.*s");
287         ok_int(Length, 4);
288 #else
289         ok_str(Buffer, "hello!  ");
290         ok_int(Length, 8);
291 #endif
292     EndSeh(STATUS_SUCCESS);
293 
294     FreeGuarded(String);
295 }
296