Split the strsafe strncpy() into its own header file and simplified its usage a bit.

This commit is contained in:
Pietro Gagliardi 2019-05-31 22:34:34 -04:00
parent 7d0f8403ab
commit a93f5c8f53
3 changed files with 52 additions and 49 deletions

View File

@ -3,19 +3,6 @@
#include "start.h"
#ifdef sharedbitsInternalError
#define sharedbitsprivInternalError sharedbitsInternalError
#else
#define sharedbitsprivInternalError sharedbitsPrefixName(InternalError)
#ifdef sharedbitsStatic
sharedbitsStatic
#else
extern
#endif
void sharedbitsprivInternalError(const char *fmt, ...);
#endif
#ifndef sharedbitsNoVsnprintf
#ifdef sharedbitsStatic
sharedbitsStatic
#endif
@ -36,33 +23,7 @@ int sharedbitsPrefixName(Vsnprintf)(char *s, size_t n, const char *fmt, va_list
return vsnprintf(s, n, fmt, ap);
#endif
}
#endif
#ifdef sharedbitsStatic
sharedbitsStatic
#endif
char *sharedbitsPrefixName(Strncpy)(char *dest, const char *src, size_t n)
{
#ifdef _WIN32
errno_t err;
// because strncpy_s() doesn't do this
memset(dest, '\0', n * sizeof (char));
err = strncpy_s(dest, n, src, _TRUNCATE);
if (err != 0 && err != STRUNCATE)
// Yes folks, apparently strerror() is unsafe (it's not reentrant, but that's not the point of the MSVC security functions; that's about buffer overflows, and as you'll soon see there really is no need for what the "safe' version is given reentrancy concerns), and not only that, but the replacement, strerror_s(), requires copying and allocation! it's almost like they were TRYING to shove as many error conditions as possible in!
// Oh, and you can't just use _sys_errlist[] to bypass this, because even that has a deprecation warning, telling you to use strerror() instead, which in turn sends you back to strerror_s()!
// Of course, the fact _sys_errlist[] is a thing and that it's deprecated out of security and not reentrancy shows that the error strings returned by strerror()/strerror_s() are static and unchanging throughout the lifetime of the program, so a truly reentrant strerror_s() would just return the raw const string array directly, or a placeholder like "unknown error" otherwise, but that would be too easy!
// And even better, there's no way to get the length of the error message, so you can't even dynamically allocate a large enough buffer if you wanted to!
// (Furthermore, cppreference.com says there's strerrorlen_s(), but a) fuck C11, and b) MSDN does not concur.)
// So, alas, you'll have to live with just having the error code; sorry.
sharedbitsprivInternalError("error calling strncpy_s(): %d", err);
return dest;
#else
return strncpy(dest, src, n);
#endif
}
#undef sharedbitsprivInternalError
#include "end.h"
#include "strsafe_strncpy_impl.h"

View File

@ -0,0 +1,47 @@
// 31 may 2019
// only requires strsafe_header.h if you don't define sharedbitsStatic as static
#include "start.h"
#ifdef _WIN32
#ifdef sharedbitsInternalError
#define sharedbitsprivInternalError sharedbitsInternalError
#else
#define sharedbitsprivInternalError sharedbitsPrefixName(InternalError)
#ifdef sharedbitsStatic
sharedbitsStatic
#else
extern
#endif
void sharedbitsprivInternalError(const char *fmt, ...);
#endif
#endif
#ifdef sharedbitsStatic
sharedbitsStatic
#endif
char *sharedbitsPrefixName(Strncpy)(char *dest, const char *src, size_t n)
{
#ifdef _WIN32
errno_t err;
// because strncpy_s() doesn't do this
memset(dest, '\0', n * sizeof (char));
err = strncpy_s(dest, n, src, _TRUNCATE);
if (err != 0 && err != STRUNCATE)
// Yes folks, apparently strerror() is unsafe (it's not reentrant, but that's not the point of the MSVC security functions; that's about buffer overflows, and as you'll soon see there really is no need for what the "safe' version is given reentrancy concerns), and not only that, but the replacement, strerror_s(), requires copying and allocation! it's almost like they were TRYING to shove as many error conditions as possible in!
// Oh, and you can't just use _sys_errlist[] to bypass this, because even that has a deprecation warning, telling you to use strerror() instead, which in turn sends you back to strerror_s()!
// Of course, the fact _sys_errlist[] is a thing and that it's deprecated out of security and not reentrancy shows that the error strings returned by strerror()/strerror_s() are static and unchanging throughout the lifetime of the program, so a truly reentrant strerror_s() would just return the raw const string array directly, or a placeholder like "unknown error" otherwise, but that would be too easy!
// And even better, there's no way to get the length of the error message, so you can't even dynamically allocate a large enough buffer if you wanted to!
// (Furthermore, cppreference.com says there's strerrorlen_s(), but a) fuck C11, and b) MSDN does not concur.)
// So, alas, you'll have to live with just having the error code; sorry.
sharedbitsprivInternalError("error calling strncpy_s(): %d", err);
return dest;
#else
return strncpy(dest, src, n);
#endif
}
#undef sharedbitsprivInternalError
#include "end.h"

View File

@ -23,8 +23,9 @@ static char caseErrorEncodingError[] = "encoding error while handling other case
#define sharedbitsPrefix priv
#define sharedbitsStatic static
// do this conditionally to avoid warnings on non-Windows
#ifdef _WIN32
// While we do only need strncpy(), our privInternalError() calls vsnprintf(), so include that too.
#include "../../sharedbits/strsafe_impl.h"
static void privInternalError(const char *fmt, ...)
{
va_list ap, ap2;
@ -49,13 +50,7 @@ static void privInternalError(const char *fmt, ...)
va_end(ap);
}
#else
#define sharedbitsInternalError
#define sharedbitsNoVsnprintf
#endif
#include "../../sharedbits/strsafe_impl.h"
#ifndef _WIN32
#undef sharedbitsNoVsnprintf
#undef sharedbitsInternalError
#include "../../sharedbits/strsafe_strncpy_impl.h"
#endif
#undef sharedbitsStatic
#undef sharedbitsPrefix