1 //
2 // output.cpp
3 //
4 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //
6 // The standard _output functions, which perform formatted output to a stream.
7 //
8 #include <corecrt_internal_stdio_output.h>
9
10
11
12 using namespace __crt_stdio_output;
13
14
15 // Enclaves do not have a file system, but they do allow in-memory operations
16 // from stdio.
17 #ifndef _UCRT_ENCLAVE_BUILD
18
19 template <template <typename, typename> class Base, typename Character>
common_vfprintf(unsigned __int64 const options,FILE * const stream,Character const * const format,__crt_cached_ptd_host & ptd,va_list const arglist)20 static int __cdecl common_vfprintf(
21 unsigned __int64 const options,
22 FILE* const stream,
23 Character const* const format,
24 __crt_cached_ptd_host& ptd,
25 va_list const arglist
26 ) throw()
27 {
28 typedef output_processor<
29 Character,
30 stream_output_adapter<Character>,
31 Base<Character, stream_output_adapter<Character>>
32 > processor_type;
33
34 _UCRT_VALIDATE_RETURN(ptd, stream != nullptr, EINVAL, -1);
35 _UCRT_VALIDATE_RETURN(ptd, format != nullptr, EINVAL, -1);
36
37 return __acrt_lock_stream_and_call(stream, [&]() -> int
38 {
39 __acrt_stdio_temporary_buffering_guard const buffering(stream, ptd);
40
41 processor_type processor(
42 stream_output_adapter<Character>(stream),
43 options,
44 format,
45 ptd,
46 arglist);
47
48 return processor.process();
49 });
50 }
51
__stdio_common_vfprintf(unsigned __int64 const options,FILE * const stream,char const * const format,_locale_t const locale,va_list const arglist)52 extern "C" int __cdecl __stdio_common_vfprintf(
53 unsigned __int64 const options,
54 FILE* const stream,
55 char const* const format,
56 _locale_t const locale,
57 va_list const arglist
58 )
59 {
60 __crt_cached_ptd_host ptd(locale);
61 return common_vfprintf<standard_base>(options, stream, format, ptd, arglist);
62 }
63
__stdio_common_vfwprintf(unsigned __int64 const options,FILE * const stream,wchar_t const * const format,_locale_t const locale,va_list const arglist)64 extern "C" int __cdecl __stdio_common_vfwprintf(
65 unsigned __int64 const options,
66 FILE* const stream,
67 wchar_t const* const format,
68 _locale_t const locale,
69 va_list const arglist
70 )
71 {
72 __crt_cached_ptd_host ptd(locale);
73 return common_vfprintf<standard_base>(options, stream, format, ptd, arglist);
74 }
75
__stdio_common_vfprintf_s(unsigned __int64 const options,FILE * const stream,char const * const format,_locale_t const locale,va_list const arglist)76 extern "C" int __cdecl __stdio_common_vfprintf_s(
77 unsigned __int64 const options,
78 FILE* const stream,
79 char const* const format,
80 _locale_t const locale,
81 va_list const arglist
82 )
83 {
84 __crt_cached_ptd_host ptd(locale);
85 return common_vfprintf<format_validation_base>(options, stream, format, ptd, arglist);
86 }
87
__stdio_common_vfwprintf_s(unsigned __int64 const options,FILE * const stream,wchar_t const * const format,_locale_t const locale,va_list const arglist)88 extern "C" int __cdecl __stdio_common_vfwprintf_s(
89 unsigned __int64 const options,
90 FILE* const stream,
91 wchar_t const* const format,
92 _locale_t const locale,
93 va_list const arglist
94 )
95 {
96 __crt_cached_ptd_host ptd(locale);
97 return common_vfprintf<format_validation_base>(options, stream, format, ptd, arglist);
98 }
99
__stdio_common_vfprintf_p(unsigned __int64 const options,FILE * const stream,char const * const format,_locale_t const locale,va_list const arglist)100 extern "C" int __cdecl __stdio_common_vfprintf_p(
101 unsigned __int64 const options,
102 FILE* const stream,
103 char const* const format,
104 _locale_t const locale,
105 va_list const arglist
106 )
107 {
108 __crt_cached_ptd_host ptd(locale);
109 return common_vfprintf<positional_parameter_base>(options, stream, format, ptd, arglist);
110 }
111
__stdio_common_vfwprintf_p(unsigned __int64 const options,FILE * const stream,wchar_t const * const format,_locale_t const locale,va_list const arglist)112 extern "C" int __cdecl __stdio_common_vfwprintf_p(
113 unsigned __int64 const options,
114 FILE* const stream,
115 wchar_t const* const format,
116 _locale_t const locale,
117 va_list const arglist
118 )
119 {
120 __crt_cached_ptd_host ptd(locale);
121 return common_vfprintf<positional_parameter_base>(options, stream, format, ptd, arglist);
122 }
123
124 #endif /* _UCRT_ENCLAVE_BUILD */
125
126
127 template <template <typename, typename> class Base, typename Character>
128 _Success_(return >= 0)
common_vsprintf(unsigned __int64 const options,_Out_writes_z_ (buffer_count)Character * const buffer,size_t const buffer_count,Character const * const format,__crt_cached_ptd_host & ptd,va_list const arglist)129 static int __cdecl common_vsprintf(
130 unsigned __int64 const options,
131 _Out_writes_z_(buffer_count) Character* const buffer,
132 size_t const buffer_count,
133 Character const* const format,
134 __crt_cached_ptd_host& ptd,
135 va_list const arglist
136 ) throw()
137 {
138 typedef __acrt_stdio_char_traits<Character> char_traits;
139
140 typedef output_processor<
141 Character,
142 string_output_adapter<Character>,
143 Base<Character, string_output_adapter<Character>>
144 > processor_type;
145
146 _UCRT_VALIDATE_RETURN(ptd, format != nullptr, EINVAL, -1);
147 _UCRT_VALIDATE_RETURN(ptd, buffer_count == 0 || buffer != nullptr, EINVAL, -1);
148
149 string_output_adapter_context<Character> context{};
150 context._buffer = buffer;
151 context._buffer_count = buffer_count;
152 context._buffer_used = 0;
153
154 // For the C Standard snprintf functions, we continue formatting even after
155 // the buffer is full so that we can return the number of characters that
156 // are required to complete the format operation. For all other sprintf
157 // functions that have a buffer count, if no buffer was provided then we
158 // do the same.
159 context._continue_count =
160 (options & _CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR) != 0 ||
161 buffer == nullptr;
162
163 processor_type processor(
164 string_output_adapter<Character>(&context),
165 options,
166 format,
167 ptd,
168 arglist);
169
170 int const result = processor.process();
171
172 if (buffer == nullptr)
173 {
174 return result;
175 }
176
177 // Otherwise, we formatted data into the buffer and need to terminate it:
178 if (options & _CRT_INTERNAL_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION)
179 {
180 if (buffer_count == 0 && result != 0)
181 {
182 return -1;
183 }
184 else if (context._buffer_used != buffer_count)
185 {
186 buffer[context._buffer_used] = '\0';
187 }
188 else if (result >= 0 && static_cast<size_t>(result) > buffer_count)
189 {
190 return -1;
191 }
192 }
193 else if (options & _CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR)
194 {
195 if (buffer_count == 0)
196 {
197 // No-op
198 }
199 else if (result < 0)
200 {
201 buffer[0] = '\0';
202 }
203 else if (context._buffer_used == buffer_count)
204 {
205 buffer[buffer_count - 1] = '\0';
206 }
207 else
208 {
209 buffer[context._buffer_used] = '\0';
210 }
211 }
212 else
213 {
214 if (buffer_count == 0)
215 {
216 return -1;
217 }
218 else if (context._buffer_used == buffer_count)
219 {
220 buffer[buffer_count - 1] = '\0';
221 return -2;
222 }
223 else
224 {
225 buffer[context._buffer_used] = '\0';
226 }
227 }
228
229 #pragma warning(suppress:__WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION) // 26036 needs work
230 return result;
231 }
232
__stdio_common_vsprintf(unsigned __int64 const options,char * const buffer,size_t const buffer_count,char const * const format,_locale_t const locale,va_list const arglist)233 extern "C" int __cdecl __stdio_common_vsprintf(
234 unsigned __int64 const options,
235 char* const buffer,
236 size_t const buffer_count,
237 char const* const format,
238 _locale_t const locale,
239 va_list const arglist
240 )
241 {
242 __crt_cached_ptd_host ptd(locale);
243 return common_vsprintf<standard_base>(options, buffer, buffer_count, format, ptd, arglist);
244 }
245
__stdio_common_vswprintf(unsigned __int64 const options,wchar_t * const buffer,size_t const buffer_count,wchar_t const * const format,_locale_t const locale,va_list const arglist)246 extern "C" int __cdecl __stdio_common_vswprintf(
247 unsigned __int64 const options,
248 wchar_t* const buffer,
249 size_t const buffer_count,
250 wchar_t const* const format,
251 _locale_t const locale,
252 va_list const arglist
253 )
254 {
255 __crt_cached_ptd_host ptd(locale);
256 return common_vsprintf<standard_base>(options, buffer, buffer_count, format, ptd, arglist);
257 }
258
259 template <typename Character>
260 _Success_(return >= 0)
common_vsprintf_s(unsigned __int64 const options,_Out_writes_z_ (buffer_count)Character * const buffer,size_t const buffer_count,Character const * const format,__crt_cached_ptd_host & ptd,va_list const arglist)261 static int __cdecl common_vsprintf_s(
262 unsigned __int64 const options,
263 _Out_writes_z_(buffer_count) Character* const buffer,
264 size_t const buffer_count,
265 Character const* const format,
266 __crt_cached_ptd_host& ptd,
267 va_list const arglist
268 ) throw()
269 {
270 _UCRT_VALIDATE_RETURN(ptd, format != nullptr, EINVAL, -1);
271 _UCRT_VALIDATE_RETURN(ptd, buffer != nullptr && buffer_count > 0, EINVAL, -1);
272
273 int const result = common_vsprintf<format_validation_base>(options, buffer, buffer_count, format, ptd, arglist);
274 if (result < 0)
275 {
276 buffer[0] = 0;
277 _SECURECRT__FILL_STRING(buffer, buffer_count, 1);
278 }
279
280 if (result == -2)
281 {
282 _UCRT_VALIDATE_RETURN(ptd, ("Buffer too small", 0), ERANGE, -1);
283 }
284 else if (result >= 0)
285 {
286 _SECURECRT__FILL_STRING(buffer, buffer_count, result + 1);
287 }
288
289 return result;
290 }
291
__stdio_common_vsprintf_s(unsigned __int64 const options,char * const buffer,size_t const buffer_count,char const * const format,_locale_t const locale,va_list const arglist)292 extern "C" int __cdecl __stdio_common_vsprintf_s(
293 unsigned __int64 const options,
294 char* const buffer,
295 size_t const buffer_count,
296 char const* const format,
297 _locale_t const locale,
298 va_list const arglist
299 )
300 {
301 __crt_cached_ptd_host ptd(locale);
302 return common_vsprintf_s(options, buffer, buffer_count, format, ptd, arglist);
303 }
304
__stdio_common_vswprintf_s(unsigned __int64 const options,wchar_t * const buffer,size_t const buffer_count,wchar_t const * const format,_locale_t const locale,va_list const arglist)305 extern "C" int __cdecl __stdio_common_vswprintf_s(
306 unsigned __int64 const options,
307 wchar_t* const buffer,
308 size_t const buffer_count,
309 wchar_t const* const format,
310 _locale_t const locale,
311 va_list const arglist
312 )
313 {
314 __crt_cached_ptd_host ptd(locale);
315 return common_vsprintf_s(options, buffer, buffer_count, format, ptd, arglist);
316 }
317
318 template <typename Character>
319 _Success_(return >= 0)
common_vsnprintf_s(unsigned __int64 const options,_Out_writes_z_ (buffer_count)Character * const buffer,size_t const buffer_count,size_t const max_count,Character const * const format,__crt_cached_ptd_host & ptd,va_list const arglist)320 static int __cdecl common_vsnprintf_s(
321 unsigned __int64 const options,
322 _Out_writes_z_(buffer_count) Character* const buffer,
323 size_t const buffer_count,
324 size_t const max_count,
325 Character const* const format,
326 __crt_cached_ptd_host& ptd,
327 va_list const arglist
328 ) throw()
329 {
330 _UCRT_VALIDATE_RETURN(ptd, format != nullptr, EINVAL, -1);
331
332 if (max_count == 0 && buffer == nullptr && buffer_count == 0)
333 return 0; // No work to do
334
335 _UCRT_VALIDATE_RETURN(ptd, buffer != nullptr && buffer_count > 0, EINVAL, -1);
336
337 int result = -1;
338 {
339 auto errno_restore_point = ptd.get_errno().create_guard();
340 errno_restore_point.disable();
341
342 if (buffer_count > max_count)
343 {
344 result = common_vsprintf<format_validation_base>(options, buffer, max_count + 1, format, ptd, arglist);
345
346 if (result == -2)
347 {
348 // The string has been truncated; return -1:
349 _SECURECRT__FILL_STRING(buffer, buffer_count, max_count + 1);
350 if (ptd.get_errno().check(ERANGE))
351 {
352 errno_restore_point.enable();
353 }
354
355 return -1;
356 }
357 }
358 else
359 {
360 result = common_vsprintf<format_validation_base>(options, buffer, buffer_count, format, ptd, arglist);
361 buffer[buffer_count - 1] = 0;
362
363 // We allow truncation if count == _TRUNCATE
364 if (result == -2 && max_count == _TRUNCATE)
365 {
366 if (ptd.get_errno().check(ERANGE))
367 {
368 errno_restore_point.enable();
369 }
370
371 return -1;
372 }
373 }
374 }
375
376 if (result < 0)
377 {
378 buffer[0] = 0;
379 _SECURECRT__FILL_STRING(buffer, buffer_count, 1);
380 if (result == -2)
381 {
382 _UCRT_VALIDATE_RETURN(ptd, ("Buffer too small", 0), ERANGE, -1);
383 }
384
385 return -1;
386 }
387
388 _SECURECRT__FILL_STRING(buffer, buffer_count, result + 1);
389
390 return result < 0 ? -1 : result;
391 }
392
__stdio_common_vsnprintf_s(unsigned __int64 const options,char * const buffer,size_t const buffer_count,size_t const max_count,char const * const format,_locale_t const locale,va_list const arglist)393 extern "C" int __cdecl __stdio_common_vsnprintf_s(
394 unsigned __int64 const options,
395 char* const buffer,
396 size_t const buffer_count,
397 size_t const max_count,
398 char const* const format,
399 _locale_t const locale,
400 va_list const arglist
401 )
402 {
403 __crt_cached_ptd_host ptd(locale);
404 return common_vsnprintf_s(options, buffer, buffer_count, max_count, format, ptd, arglist);
405 }
406
__stdio_common_vsnwprintf_s(unsigned __int64 const options,wchar_t * const buffer,size_t const buffer_count,size_t const max_count,wchar_t const * const format,_locale_t const locale,va_list const arglist)407 extern "C" int __cdecl __stdio_common_vsnwprintf_s(
408 unsigned __int64 const options,
409 wchar_t* const buffer,
410 size_t const buffer_count,
411 size_t const max_count,
412 wchar_t const* const format,
413 _locale_t const locale,
414 va_list const arglist
415 )
416 {
417 __crt_cached_ptd_host ptd(locale);
418 return common_vsnprintf_s(options, buffer, buffer_count, max_count, format, ptd, arglist);
419 }
420
__stdio_common_vsprintf_p(unsigned __int64 const options,char * const buffer,size_t const buffer_count,char const * const format,_locale_t const locale,va_list const arglist)421 extern "C" int __cdecl __stdio_common_vsprintf_p(
422 unsigned __int64 const options,
423 char* const buffer,
424 size_t const buffer_count,
425 char const* const format,
426 _locale_t const locale,
427 va_list const arglist
428 )
429 {
430 __crt_cached_ptd_host ptd(locale);
431 return common_vsprintf<positional_parameter_base>(options, buffer, buffer_count, format, ptd, arglist);
432 }
433
__stdio_common_vswprintf_p(unsigned __int64 const options,wchar_t * const buffer,size_t const buffer_count,wchar_t const * const format,_locale_t const locale,va_list const arglist)434 extern "C" int __cdecl __stdio_common_vswprintf_p(
435 unsigned __int64 const options,
436 wchar_t* const buffer,
437 size_t const buffer_count,
438 wchar_t const* const format,
439 _locale_t const locale,
440 va_list const arglist
441 )
442 {
443 __crt_cached_ptd_host ptd(locale);
444 return common_vsprintf<positional_parameter_base>(options, buffer, buffer_count, format, ptd, arglist);
445 }
446