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> 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 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 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 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 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 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 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) 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 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 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) 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 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 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) 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 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 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 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 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