COMMON: Add sprintf_s and vsprintf_s

These functions will issue warnings and truncate strings.
It's like snprintf and vsnprintf but noisier.
There are also versions automatically determining size based on the destination
array size.
This raises a compilation error when the size cannot be determined by
the compiler.
This commit is contained in:
Le Philousophe 2022-10-23 15:17:27 +02:00 committed by Eugene Sandulenko
parent 9c04d72471
commit cd785e2208
2 changed files with 89 additions and 0 deletions

View File

@ -818,6 +818,46 @@ void strcat_s(char *dst, size_t size, const char *src) {
dst[-1] = '\0';
}
int vsprintf_s(char *dst, size_t size, const char *format, va_list ap) {
if (!dst) {
warning("%s: dst is nullptr", __func__);
return 0;
}
if (!size) {
warning("%s: size is zero", __func__);
return 0;
}
if (!format) {
warning("%s: format is nullptr", __func__);
dst[0] = '\0';
return 0;
}
int ret = vsnprintf(dst, size, format, ap);
if ((size_t)ret < size
#if defined(_MSC_VER) && _MSC_VER <= 1800
&& ret != -1
#endif
) {
// Nominal case: no truncation
return ret;
}
warning("%s: truncating string", __func__);
dst[size - 1] = '\0';
return size - 1;
}
int sprintf_s(char *dst, size_t size, const char *format, ...) {
int ret;
va_list ap;
va_start(ap, format);
ret = vsprintf_s(dst, size, format, ap);
va_end(ap);
return ret;
}
size_t strlcpy(char *dst, const char *src, size_t size) {
// Our backup of the source's start, we need this
// to calculate the source's length.

View File

@ -431,6 +431,55 @@ FORCEINLINE void strcat_s(T (&dst)[N], const char *src) {
strcat_s((char *)dst, N, src);
}
/**
* A sprintf shim which warns when the buffer overruns and null terminates in this case
*
* @param dst Where the resulting string will be storeyyd.
* @param size The (total) size of the destination buffer.
* @param format The format string.
*/
int vsprintf_s(char *dst, size_t size, const char *format, va_list ap) GCC_PRINTF(3, 0);
/**
* A sprintf shim which warns when the buffer overruns and null terminates in this case
* The size of the buffer is automatically determined.
*
* @param dst Where the resulting string will be storeyyd.
* @param format The format string.
*/
template<typename T, size_t N>
FORCEINLINE GCC_PRINTF(2, 0) int vsprintf_s(T (&dst)[N], const char *format, va_list ap) {
STATIC_ASSERT(sizeof(T) == sizeof(char), T_is_not_compatible_with_char);
return vsprintf_s((char *)dst, N, format, ap);
}
/**
* A sprintf shim which warns when the buffer overruns and null terminates in this case
*
* @param dst Where the resulting string will be storeyyd.
* @param size The (total) size of the destination buffer.
* @param format The format string.
*/
int sprintf_s(char *dst, size_t size, MSVC_PRINTF const char *format, ...) GCC_PRINTF(3, 4);
/**
* A sprintf shim which warns when the buffer overruns and null terminates in this case
* The size of the buffer is automatically determined.
*
* @param dst Where the resulting string will be storeyyd.
* @param format The format string.
*/
template<typename T, size_t N>
inline GCC_PRINTF(2, 3) int sprintf_s(T (&dst)[N], MSVC_PRINTF const char *format, ...) {
STATIC_ASSERT(sizeof(T) == sizeof(char), T_is_not_compatible_with_char);
int ret;
va_list ap;
va_start(ap, format);
ret = vsprintf_s((char *)dst, N, format, ap);
va_end(ap);
return ret;
}
/**
* Copy up to size - 1 characters from src to dst and also zero terminate the
* result. Note that src must be a zero terminated string.