/* BEGIN_HEADER */ /* The printf test functions take a format argument from the test data * for several reasons: * - For some tests, it makes sense to vary the format. * - For all tests, it means we're testing the actual printf function * that parses the format at runtime, and not a compiler optimization. * (It may be useful to add tests that allow compiler optimizations. * There aren't any yet at the time of writing.) */ #include "mbedtls/platform.h" #include #include #include #if SIZE_MAX >= 0xffffffffffffffff #define SIZE_T_AT_LEAST_64_BIT #endif /* Older Windows runtimes have a non-compliant printf family, e.g. * it doesn't understand `%zu` to print a `size_t`. MSVC provides a * C99-compliant printf family (at least enough for our purposes), * since Visual Studio 2015. With MinGW, you get the non-compliant legacy * printf by default, but can select the standard-compliant version * at compile time. In the Mbed TLS 3.6 LTS, we use the default, so * we can't rely on %z being understood. The debug module defines * `MBEDTLS_PRINTF_SIZET` for that, and this is tested in test_suite_debug. * Here we just skip the test cases that break the legacy Windows printf. */ #if !(defined(__MINGW32__)) #define HAVE_C99_PRINTF #endif typedef enum { PRINTF_CAST_INT, PRINTF_CAST_UNSIGNED, PRINTF_CAST_SIZE_T, PRINTF_CAST_LONG, PRINTF_CAST_UNSIGNED_LONG, PRINTF_CAST_LONG_LONG, PRINTF_CAST_UNSIGNED_LONG_LONG, } printf_cast_type_t; #define NEWLINE_CHAR '\n' #define SPACE_CHAR ' ' #define DOUBLE_QUOTE_CHAR '"' #define COLON_CHAR ':' #define QUESTION_CHAR '?' #define BACKSLASH_CHAR '\\' #define LOWERCASE_N_CHAR 'n' /* END_HEADER */ /* BEGIN_CASE */ void printf_integer(char *format, /* format expecting one foo_t argument */ int type, /* enum value from printf_cast_type_t */ intmax_t value, char *result) { char *output = NULL; const size_t n = strlen(result); int ret = 0; /* Nominal case: buffer just large enough */ TEST_CALLOC(output, n + 1); switch (type) { case PRINTF_CAST_INT: ret = mbedtls_snprintf(output, n + 1, format, (int) value); break; case PRINTF_CAST_UNSIGNED: ret = mbedtls_snprintf(output, n + 1, format, (unsigned) value); break; case PRINTF_CAST_SIZE_T: ret = mbedtls_snprintf(output, n + 1, format, (size_t) value); break; case PRINTF_CAST_LONG_LONG: ret = mbedtls_snprintf(output, n + 1, format, (long long) value); break; case PRINTF_CAST_UNSIGNED_LONG_LONG: ret = mbedtls_snprintf(output, n + 1, format, (unsigned long long) value); break; default: TEST_FAIL("Unsupported type"); } TEST_EQUAL(n, ret); TEST_MEMORY_COMPARE(result, n + 1, output, n + 1); mbedtls_free(output); output = NULL; exit: mbedtls_free(output); } /* END_CASE */ /* BEGIN_CASE */ void printf_long_max(const char *format, /* "%lx" or longer type */ long value) { char *expected = NULL; char *output = NULL; /* 2 hex digits per byte */ const size_t n = sizeof(value) * 2; /* We assume that long has no padding bits! */ TEST_CALLOC(expected, n + 1); expected[0] = '7'; memset(expected + 1, 'f', sizeof(value) * 2 - 1); TEST_CALLOC(output, n + 1); TEST_EQUAL(n, mbedtls_snprintf(output, n + 1, format, value)); TEST_MEMORY_COMPARE(expected, n + 1, output, n + 1); mbedtls_free(output); output = NULL; exit: mbedtls_free(output); mbedtls_free(expected); } /* END_CASE */ /* BEGIN_CASE */ void printf_char2(char *format, /* "%c%c" */ int arg1, int arg2, char *result) { char *output = NULL; const size_t n = strlen(result); /* Nominal case: buffer just large enough */ TEST_CALLOC(output, n + 1); TEST_EQUAL(n, mbedtls_snprintf(output, n + 1, format, arg1, arg2)); TEST_MEMORY_COMPARE(result, n + 1, output, n + 1); mbedtls_free(output); output = NULL; exit: mbedtls_free(output); } /* END_CASE */