diff --git a/common/alloc.c b/common/alloc.c index e91959ee..d20bf370 100644 --- a/common/alloc.c +++ b/common/alloc.c @@ -1,4 +1,5 @@ // 16 may 2019 +#include #include #include #include "ui.h" diff --git a/sharedbits/strsafe_header.h b/sharedbits/strsafe_header.h index cd1ba991..e6c489df 100644 --- a/sharedbits/strsafe_header.h +++ b/sharedbits/strsafe_header.h @@ -3,5 +3,6 @@ #include "start.h" extern int sharedbitsPrefixName(Vsnprintf)(char *s, size_t n, const char *fmt, va_list ap); +extern char *sharedbitsPrefixName(Strncpy)(char *dest, const char *src, size_t n); #include "end.h" diff --git a/sharedbits/strsafe_impl.h b/sharedbits/strsafe_impl.h index 041410a1..20308632 100644 --- a/sharedbits/strsafe_impl.h +++ b/sharedbits/strsafe_impl.h @@ -3,6 +3,13 @@ #include "start.h" +#ifdef sharedbitsStatic +sharedBitsStatic +#else +extern +#endif +void sharedbitsPrefixName(InternalError)(const char *fmt, ...); + #ifdef sharedbitsStatic sharedbitsStatic #endif @@ -16,11 +23,31 @@ int sharedbitsPrefixName(Vsnprintf)(char *s, size_t n, const char *fmt, va_list // TODO figure out how to disambiguate between encoding errors (returns negative value; does not have documented errno values), other errors (returns negative value; errno == EINVAL), and truncations (returns -1; does not have documented errno values) ret = vsnprintf_s(s, n, _TRUNCATE, fmt, ap); if (ret == -1) - return n; + // TODO make this safe + return (int) n; return ret; #else return vsnprintf(s, n, fmt, ap); #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) + sharedbitsStaticName(InternalError)("error calling strncpy_s(): %s (%d)", strerror(err), err); + return dest; +#else + return strncpy(dest, src, n); +#endif +} + #include "end.h" diff --git a/test/lib/testingpriv.c b/test/lib/testingpriv.c index c478cff9..3cb591f6 100644 --- a/test/lib/testingpriv.c +++ b/test/lib/testingpriv.c @@ -56,7 +56,7 @@ char *testingprivStrdup(const char *s) n = strlen(s); t = (char *) testingprivAlloc((n + 1) * sizeof (char), "char[]"); - strncpy(t, s, n + 1); + testingprivImplStrncpy(t, s, n + 1); return t; } diff --git a/test/noinitwrongthread.c b/test/noinitwrongthread.c index 52127379..95071b22 100644 --- a/test/noinitwrongthread.c +++ b/test/noinitwrongthread.c @@ -15,7 +15,38 @@ struct errorCase { }; static struct errorCase *current = NULL; -static bool memoryExhausted = false; +static char *caseError = NULL; +static char caseErrorMemoryExhausted[] = "memory exhausted"; +static char caseErrorEncodingError[] = "encoding error while handling other case error"; + +#define sharedbitsPrefix priv +#define sharedbitsStatic static +#include "../../sharedbits/strsafe_impl.h" +#undef sharedbitsStatic +#undef sharedbitsPrefix + +static void privInternalError(const char *fmt, ...) +{ + va_list ap, ap2; + + va_start(ap, fmt); + va_copy(ap2, ap); + n = privVsnprintf(NULL, 0, fmt, ap2); + va_end(ap2); + if (n < 0) { + caseError = caseErrorEncodingError; + va_end(ap); + return; + } + caseError = (char *) malloc((n + 1) * sizeof (char)); + if (caseError == NULL) { + caseError = caseErrorMemoryExhausted; + va_end(ap); + return; + } + privVsnprintf(otherError, n + 1, fmt, ap); + va_end(ap); +} static void catalogProgrammerError(const char *prefix, const char *msg, const char *suffix, bool internal) { @@ -26,20 +57,24 @@ static void catalogProgrammerError(const char *prefix, const char *msg, const ch n = strlen(prefix); current->prefixGot = (char *) malloc((n + 1) * sizeof (char)); if (current->prefixGot == NULL) { - memoryExhausted = true; + caseError = caseErrorMemoryExhausted; return; } - strncpy(current->prefixGot, prefix, n + 1); + privStrncpy(current->prefixGot, prefix, n + 1); + if (caseError != NULL) + return; } current->internalGot = internal; if (strstr(msg, current->msgWant) == NULL) { n = strlen(msg); current->msgGot = (char *) malloc((n + 1) * sizeof (char)); if (current->msgGot == NULL) { - memoryExhausted = true; + caseError = caseErrorMemoryExhausted; return; } - strncpy(current->msgGot, msg, n + 1); + privStrncpy(current->msgGot, msg, n + 1); + if (caseError != NULL) + return; } } @@ -49,7 +84,7 @@ static struct errorCase *newCase(void) p = (struct errorCase *) malloc(sizeof (struct errorCase)); if (p == NULL) { - memoryExhausted = true; + caseError = caseErrorMemoryExhausted; return NULL; } memset(p, 0, sizeof (struct errorCase)); @@ -94,7 +129,7 @@ static void reportCases(testingT *t, struct errorCase *p) #define allcallsCase(f, ...) { \ current = newCase(); \ - if (memoryExhausted) \ + if (caseError != NULL) \ return first; \ current->name = #f "()"; \ current->msgWant = "attempt to call " #f "() " allcallsMsgSuffix; \ @@ -104,7 +139,7 @@ static void reportCases(testingT *t, struct errorCase *p) if (last != NULL) \ last->next = current; \ last = current; \ - if (memoryExhausted) \ + if (caseError != NULL) \ return first; \ } @@ -124,13 +159,17 @@ testingTestInSet(beforeTests, FunctionsFailBeforeInit) { struct errorCase *cases; - memoryExhausted = false; + caseError = NULL; uiprivTestHookReportProgrammerError(catalogProgrammerError); cases = runCasesBeforeInit(); uiprivTestHookReportProgrammerError(NULL); - if (memoryExhausted) { + if (caseError != NULL) { freeCases(cases); - testingTFatalf(t, "memory exhausted running tests"); + testingTErrorf(t, "%s running tests", caseError); + if (caseError != caseErrorMemoryExhausted && caseError != caseErrorEncodingError) + free(caseError); + caseError = NULL; + testingTFailNow(); } reportCases(t, cases); freeCases(cases); @@ -154,8 +193,8 @@ static void wrongThreadThreadProc(void *data) uiprivTestHookReportProgrammerError(catalogProgrammerError); *pCases = runCasesWrongThread(); uiprivTestHookReportProgrammerError(NULL); - // do this now in case something gets allocated before we return to the main thread - if (memoryExhausted) { + // do this now in case memory was exhausted and something gets allocated before we return to the main thread + if (caseError != NULL) { freeCases(*pCases); *pCases = NULL; } @@ -167,15 +206,21 @@ testingTest(FunctionsFailOnWrongThread) threadThread *thread; threadSysError err; - memoryExhausted = false; + caseError = NULL; err = threadNewThread(wrongThreadThreadProc, &cases, &thread); if (err != 0) testingTFatalf(t, "error creating thread: " threadSysErrorFmt, threadSysErrorFmtArg(err)); err = threadThreadWaitAndFree(thread); if (err != 0) testingTFatalf(t, "error waiting for thread to finish: " threadSysErrorFmt, threadSysErrorFmtArg(err)); - if (memoryExhausted) - testingTFatalf(t, "memory exhausted running tests"); + if (caseError != NULL) { + freeCases(cases); + testingTErrorf(t, "%s running tests", caseError); + if (caseError != caseErrorMemoryExhausted && caseError != caseErrorEncodingError) + free(caseError); + caseError = NULL; + testingTFailNow(); + } reportCases(t, cases); freeCases(cases); }