diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2017-06-10 03:02:39 -0400 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2017-06-10 03:02:39 -0400 |
commit | a3faa73f03a4d539de4c808d1a4f3b8ebc5ce537 (patch) | |
tree | f64b21a1459e4b9774cd27a888dd66a1ec0cdce6 | |
parent | a6c25c7c74f762cb40639da0b9b98bfcf3f4c590 (diff) | |
download | bfs-a3faa73f03a4d539de4c808d1a4f3b8ebc5ce537.tar.xz |
printf: Fix embedded nul bytes
Fixes #26.
-rw-r--r-- | dstring.c | 4 | ||||
-rw-r--r-- | dstring.h | 11 | ||||
-rw-r--r-- | printf.c | 27 | ||||
-rwxr-xr-x | tests.sh | 6 | ||||
-rw-r--r-- | tests/test_printf_nul.out | bin | 0 -> 198 bytes |
5 files changed, 37 insertions, 11 deletions
@@ -95,6 +95,10 @@ int dstrncat(char **dest, const char *src, size_t n) { return dstrcat_impl(dest, src, strnlen(src, n)); } +int dstrapp(char **str, char c) { + return dstrcat_impl(str, &c, 1); +} + void dstrfree(char *dstr) { if (dstr) { free(dstrheader(dstr)); @@ -78,6 +78,17 @@ int dstrcat(char **dest, const char *src); int dstrncat(char **dest, const char *src, size_t n); /** + * Append a single character to a dynamic string. + * + * @param str + * The string to append to. + * @param c + * The character to append. + * @return 0 on success, -1 on failure. + */ +int dstrapp(char **str, char c); + +/** * Free a dynamic string. * * @param dstr @@ -48,7 +48,12 @@ struct bfs_printf_directive { /** Print some text as-is. */ static int bfs_printf_literal(FILE *file, const struct bfs_printf_directive *directive, const struct BFTW *ftwbuf) { - return fprintf(file, "%s", directive->str); + size_t len = dstrlen(directive->str); + if (fwrite(directive->str, 1, len, file) == len) { + return 0; + } else { + return -1; + } } /** \c: flush */ @@ -517,8 +522,8 @@ struct bfs_printf *parse_bfs_printf(const char *format, struct cmdline *cmdline) if (!directive) { goto directive_error; } - if (dstrncat(&directive->str, &c, 1) != 0) { - perror("dstralloc()"); + if (dstrapp(&directive->str, c) != 0) { + perror("dstrapp()"); goto directive_error; } @@ -540,8 +545,8 @@ struct bfs_printf *parse_bfs_printf(const char *format, struct cmdline *cmdline) cfprintf(cerr, "%{er}error: '%s': Duplicate flag '%c'.%{rs}\n", format, c); goto directive_error; } - if (dstrncat(&directive->str, &c, 1) != 0) { - perror("dstrncat()"); + if (dstrapp(&directive->str, c) != 0) { + perror("dstrapp()"); goto directive_error; } continue; @@ -552,8 +557,8 @@ struct bfs_printf *parse_bfs_printf(const char *format, struct cmdline *cmdline) // Parse the field width while (c >= '0' && c <= '9') { - if (dstrncat(&directive->str, &c, 1) != 0) { - perror("dstrncat()"); + if (dstrapp(&directive->str, c) != 0) { + perror("dstrapp()"); goto directive_error; } c = *++i; @@ -562,8 +567,8 @@ struct bfs_printf *parse_bfs_printf(const char *format, struct cmdline *cmdline) // Parse the precision if (c == '.') { do { - if (dstrncat(&directive->str, &c, 1) != 0) { - perror("dstrncat()"); + if (dstrapp(&directive->str, c) != 0) { + perror("dstrapp()"); goto directive_error; } c = *++i; @@ -774,8 +779,8 @@ struct bfs_printf *parse_bfs_printf(const char *format, struct cmdline *cmdline) } one_char: - if (dstrncat(&literal->str, &c, 1) != 0) { - perror("dstrncat()"); + if (dstrapp(&literal->str, c) != 0) { + perror("dstrapp()"); goto error; } } @@ -302,6 +302,7 @@ gnu_tests=( test_printf_escapes test_printf_times test_printf_leak + test_printf_nul test_quit_after_print test_quit_before_print test_fstype @@ -1036,6 +1037,11 @@ function test_printf_leak() { bfs_diff basic -maxdepth 0 -printf '%p' } +function test_printf_nul() { + # NUL byte regression test + bfs_diff basic -printf '%h\0%f\n' +} + function test_fstype() { fstype="$($BFS -printf '%F\n' | head -n1)" bfs_diff basic -fstype "$fstype" diff --git a/tests/test_printf_nul.out b/tests/test_printf_nul.out Binary files differnew file mode 100644 index 0000000..3e30a4f --- /dev/null +++ b/tests/test_printf_nul.out |