vsprintf.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. //
  2. // Copyright (c) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE file in the project root for full license information.
  4. //
  5. /***
  6. *vsprintf.c - print formatted data into a string from var arg list
  7. *
  8. *
  9. *Purpose:
  10. * defines vsprintf(), _vsnprintf() and _vsnprintf_s() - print formatted output to
  11. * a string, get the data from an argument ptr instead of explicit
  12. * arguments.
  13. *
  14. *******************************************************************************/
  15. #include <string.h>
  16. #include <errno.h>
  17. #include <limits.h>
  18. #include "internal_securecrt.h"
  19. #include "mbusafecrt_internal.h"
  20. typedef int (*OUTPUTFN)(miniFILE *, const char *, va_list);
  21. static int _vsnprintf_helper( OUTPUTFN outfn, char *string, size_t count, const char *format, va_list ap );
  22. /***
  23. *ifndef _COUNT_
  24. *int vsprintf(string, format, ap) - print formatted data to string from arg ptr
  25. *else
  26. *int _vsnprintf(string, cnt, format, ap) - print formatted data to string from arg ptr
  27. *endif
  28. *
  29. *Purpose:
  30. * Prints formatted data, but to a string and gets data from an argument
  31. * pointer.
  32. * Sets up a FILE so file i/o operations can be used, make string look
  33. * like a huge buffer to it, but _flsbuf will refuse to flush it if it
  34. * fills up. Appends '\0' to make it a true string.
  35. *
  36. * Allocate the 'fake' _iob[] entryit statically instead of on
  37. * the stack so that other routines can assume that _iob[] entries are in
  38. * are in DGROUP and, thus, are near.
  39. *
  40. *ifdef _COUNT_
  41. * The _vsnprintf() flavor takes a count argument that is
  42. * the max number of bytes that should be written to the
  43. * user's buffer.
  44. *endif
  45. *
  46. * Multi-thread: (1) Since there is no stream, this routine must never try
  47. * to get the stream lock (i.e., there is no stream lock either). (2)
  48. * Also, since there is only one staticly allocated 'fake' iob, we must
  49. * lock/unlock to prevent collisions.
  50. *
  51. *Entry:
  52. * char *string - place to put destination string
  53. *ifdef _COUNT_
  54. * size_t count - max number of bytes to put in buffer
  55. *endif
  56. * char *format - format string, describes format of data
  57. * va_list ap - varargs argument pointer
  58. *
  59. *Exit:
  60. * returns number of characters in string
  61. * returns -2 if the string has been truncated (only in _vsnprintf_helper)
  62. * returns -1 in other error cases
  63. *
  64. *Exceptions:
  65. *
  66. *******************************************************************************/
  67. int __cdecl _vsnprintf_helper (
  68. OUTPUTFN outfn,
  69. char *string,
  70. size_t count,
  71. const char *format,
  72. va_list ap
  73. )
  74. {
  75. miniFILE str;
  76. miniFILE *outfile = &str;
  77. int retval;
  78. _VALIDATE_RETURN( (format != NULL), EINVAL, -1);
  79. _VALIDATE_RETURN( (count == 0) || (string != NULL), EINVAL, -1 );
  80. if(count>INT_MAX)
  81. {
  82. /* old-style functions allow any large value to mean unbounded */
  83. outfile->_cnt = INT_MAX;
  84. }
  85. else
  86. {
  87. outfile->_cnt = (int)count;
  88. }
  89. outfile->_flag = _IOWRT|_IOSTRG;
  90. outfile->_ptr = outfile->_base = string;
  91. retval = outfn(outfile, format, ap );
  92. if ( string==NULL)
  93. return(retval);
  94. if((retval >= 0) && (_putc_nolock('\0',outfile) != EOF))
  95. return(retval);
  96. string[count - 1] = 0;
  97. if (outfile->_cnt < 0)
  98. {
  99. /* the buffer was too small; we return -2 to indicate truncation */
  100. return -2;
  101. }
  102. return -1;
  103. }
  104. int __cdecl _vsprintf_s (
  105. char *string,
  106. size_t sizeInBytes,
  107. const char *format,
  108. va_list ap
  109. )
  110. {
  111. int retvalue = -1;
  112. /* validation section */
  113. _VALIDATE_RETURN(format != NULL, EINVAL, -1);
  114. _VALIDATE_RETURN(string != NULL && sizeInBytes > 0, EINVAL, -1);
  115. retvalue = _vsnprintf_helper(_output_s, string, sizeInBytes, format, ap);
  116. if (retvalue < 0)
  117. {
  118. string[0] = 0;
  119. _SECURECRT__FILL_STRING(string, sizeInBytes, 1);
  120. }
  121. if (retvalue == -2)
  122. {
  123. _VALIDATE_RETURN(("Buffer too small" && 0), ERANGE, -1);
  124. }
  125. if (retvalue >= 0)
  126. {
  127. _SECURECRT__FILL_STRING(string, sizeInBytes, retvalue + 1);
  128. }
  129. return retvalue;
  130. }
  131. int __cdecl vsprintf_s(char *_Dst, size_t _SizeInBytes, const char *_Format, va_list _ArgList)
  132. {
  133. return _vsprintf_s(_Dst, _SizeInBytes, _Format, _ArgList);
  134. }
  135. int __cdecl _vsnprintf_s (
  136. char *string,
  137. size_t sizeInBytes,
  138. size_t count,
  139. const char *format,
  140. va_list ap
  141. )
  142. {
  143. int retvalue = -1;
  144. errno_t save_errno = 0;
  145. /* validation section */
  146. _VALIDATE_RETURN(format != NULL, EINVAL, -1);
  147. if (count == 0 && string == NULL && sizeInBytes == 0)
  148. {
  149. /* this case is allowed; nothing to do */
  150. return 0;
  151. }
  152. _VALIDATE_RETURN(string != NULL && sizeInBytes > 0, EINVAL, -1);
  153. if (sizeInBytes > count)
  154. {
  155. save_errno = errno;
  156. retvalue = _vsnprintf_helper(_output_s, string, count + 1, format, ap);
  157. if (retvalue == -2)
  158. {
  159. /* the string has been truncated, return -1 */
  160. _SECURECRT__FILL_STRING(string, sizeInBytes, count + 1);
  161. if (errno == ERANGE)
  162. {
  163. errno = save_errno;
  164. }
  165. return -1;
  166. }
  167. }
  168. else /* sizeInBytes <= count */
  169. {
  170. save_errno = errno;
  171. retvalue = _vsnprintf_helper(_output_s, string, sizeInBytes, format, ap);
  172. string[sizeInBytes - 1] = 0;
  173. /* we allow truncation if count == _TRUNCATE */
  174. if (retvalue == -2 && count == _TRUNCATE)
  175. {
  176. if (errno == ERANGE)
  177. {
  178. errno = save_errno;
  179. }
  180. return -1;
  181. }
  182. }
  183. if (retvalue < 0)
  184. {
  185. string[0] = 0;
  186. _SECURECRT__FILL_STRING(string, sizeInBytes, 1);
  187. if (retvalue == -2)
  188. {
  189. _VALIDATE_RETURN(("Buffer too small" && 0), ERANGE, -1);
  190. }
  191. return -1;
  192. }
  193. _SECURECRT__FILL_STRING(string, sizeInBytes, retvalue + 1);
  194. return (retvalue < 0 ? -1 : retvalue);
  195. }