summaryrefslogtreecommitdiffstats
path: root/src/lib/test-printf-format-fix.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 17:36:47 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 17:36:47 +0000
commit0441d265f2bb9da249c7abf333f0f771fadb4ab5 (patch)
tree3f3789daa2f6db22da6e55e92bee0062a7d613fe /src/lib/test-printf-format-fix.c
parentInitial commit. (diff)
downloaddovecot-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.c142
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;
+}