diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 17:36:47 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 17:36:47 +0000 |
commit | 0441d265f2bb9da249c7abf333f0f771fadb4ab5 (patch) | |
tree | 3f3789daa2f6db22da6e55e92bee0062a7d613fe /src/lib/test-printf-format-fix.c | |
parent | Initial commit. (diff) | |
download | dovecot-0441d265f2bb9da249c7abf333f0f771fadb4ab5.tar.xz dovecot-0441d265f2bb9da249c7abf333f0f771fadb4ab5.zip |
Adding upstream version 1:2.3.21+dfsg1.upstream/1%2.3.21+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/lib/test-printf-format-fix.c')
-rw-r--r-- | src/lib/test-printf-format-fix.c | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/src/lib/test-printf-format-fix.c b/src/lib/test-printf-format-fix.c new file mode 100644 index 0000000..c9d6203 --- /dev/null +++ b/src/lib/test-printf-format-fix.c @@ -0,0 +1,142 @@ +/* Copyright (c) 2001-2018 Dovecot authors, see the included COPYING file */ + +/* Unit tests for printf-format-fix helper */ + +#include "test-lib.h" +#include "printf-format-fix.h" + +#include <string.h> + +struct format_fix_rewrites { + const char *input; + const char *output; + size_t length; +}; + +static void test_unchanged() +{ + static const char *tests[] = { + "Hello world", + "Embedded %%, %u, %f, %s, etc. are OK", + "Allow %#0- +s flags", + "duplicate flags in different args %0-123s %0-123s", + "Minimum length %9999s", + "Minimum length parameter %*s", + "Precision %.9999s", + "Precision %1.9999s", + "Precision parameter %1.*s %.*s", + "Floating precisions such as %.0f %0.4f %-4.0f", + "Length modifiers %hd %hhd %ld %lld %Lg %jd %zd %td", + "Specifiers %s %u %d %c %i %x %X %p %o %e %E %f %F %g %G %a %A", + "%%doesn't cause confusion in %%m and %%n", + }; + unsigned int i; + + test_begin("printf_format_fix(safe)"); + for (i = 0; i < N_ELEMENTS(tests); ++i) { + size_t len; + T_BEGIN { + test_assert_idx(printf_format_fix(tests[i]) + == tests[i], i); + test_assert_idx(printf_format_fix_get_len(tests[i], &len) + == tests[i], i); + test_assert_idx(len == strlen(tests[i]), i); + } T_END; + } + test_end(); +} + +static void test_ok_changes() +{ + static const char *tests[] = { + "OK to have a trailing %m", + "%m can appear at the start too", + "Even %m in the middle with a confusing %%m elsewhere is OK", + }; + unsigned int i; + const char *needle; + unsigned int needlen; + int old_errno = errno; + + test_begin("printf_format_fix(rewrites)"); + + errno = EINVAL; + needle = strerror(errno); + i_assert(needle != NULL); + needlen = strlen(needle); + + for (i = 0; i < N_ELEMENTS(tests); ++i) { + size_t len; + char const *chgd; + char const *insert; + unsigned int offs; + + T_BEGIN { + chgd = printf_format_fix(tests[i]); + test_assert_idx(chgd != tests[i], i); + insert = strstr(chgd, needle); + test_assert_idx(insert != NULL, i); + offs = insert - chgd; + test_assert_idx(memcmp(chgd, tests[i], offs) == 0, i); + test_assert_idx(memcmp(chgd+offs, needle, needlen) == 0, i); + test_assert_idx(strcmp(chgd+offs+needlen, tests[i]+offs+2) == 0, i); + + chgd = printf_format_fix_get_len(tests[i], &len); + test_assert_idx(chgd != tests[i], i); + test_assert_idx(len == strlen(chgd), i); + insert = strstr(chgd, needle); + test_assert_idx(insert != NULL, i); + offs = insert - chgd; + test_assert_idx(memcmp(chgd, tests[i], offs) == 0, i); + test_assert_idx(memcmp(chgd+offs, needle, needlen) == 0, i); + test_assert_idx(memcmp(chgd+offs+needlen, tests[i]+offs+2, len-needlen-offs) == 0, i); + } T_END; + } + + errno = old_errno; + + test_end(); +} + +void test_printf_format_fix() +{ + test_unchanged(); + test_ok_changes(); +} + +/* Want to test the panics too? go for it! */ +enum fatal_test_state fatal_printf_format_fix(unsigned int stage) +{ + static const struct { + const char *format; + const char *expected_fatal; + } fatals[] = { + { "no no no %n's", "%n modifier used" }, + { "no no no %-1234567890123n's with extra stuff", "Too large minimum field width" }, + { "%m allowed once, but not twice: %m", "%m used twice" }, + { "%m must not obscure a later %n", "%n modifier used" }, + { "definitely can't have a tailing %", "Missing % specifier" }, + { "Evil %**%n", "Unsupported 0x2a specifier" }, + { "Evil %*#%99999$s", "Unsupported 0x23 specifier" }, + { "No weird %% with %0%", "Unsupported 0x25 specifier" }, + { "No duplicate modifiers %00s", "Duplicate % flag '0'" }, + { "Minimum length can't be too long %10000s", "Too large minimum field width" }, + { "Minimum length doesn't support %*1$s", "Unsupported 0x31 specifier" }, + { "Precision can't be too long %.10000s", "Too large precision" }, + { "Precision can't be too long %1.10000s", "Too large precision" }, + { "Precision doesn't support %1.-1s", "Unsupported 0x2d specifier" }, + }; + + if(stage >= N_ELEMENTS(fatals)) { + test_end(); + return FATAL_TEST_FINISHED; + } + + if(stage == 0) + test_begin("fatal_printf_format_fix"); + + /* let's crash! */ + test_expect_fatal_string(fatals[stage].expected_fatal); + (void)printf_format_fix(fatals[stage].format); + return FATAL_TEST_FAILURE; +} |