diff options
-rw-r--r-- | TODO | 3 | ||||
-rw-r--r-- | src/shared/fileio.c | 11 | ||||
-rw-r--r-- | src/shared/utf8.c | 26 | ||||
-rw-r--r-- | src/shared/utf8.h | 3 | ||||
-rw-r--r-- | src/test/test-utf8.c | 17 |
5 files changed, 53 insertions, 7 deletions
@@ -16,9 +16,6 @@ Bugfixes: * properly handle .mount unit state tracking when two mount points are stacked one on top of another on the exact same mount point. -* When we detect invalid UTF-8, we cannot use it in an error message: - log...("Path is not UTF-8 clean, ignoring assignment: %s", rvalue); - * shorten the message to sane length: Cannot add dependency job for unit display-manager.service, ignoring: Unit display-manager.service failed to load: No such file or directory. See system logs and 'systemctl status display-manager.service' for details. diff --git a/src/shared/fileio.c b/src/shared/fileio.c index 838d128433..b81eeb272a 100644 --- a/src/shared/fileio.c +++ b/src/shared/fileio.c @@ -539,15 +539,18 @@ static int parse_env_file_push(const char *filename, unsigned line, va_list aq, *ap = userdata; if (!utf8_is_valid(key)) { - log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", - filename, line, key); + _cleanup_free_ char *p = utf8_escape_invalid(key); + + log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", + filename, line, p); return -EINVAL; } if (value && !utf8_is_valid(value)) { - /* FIXME: filter UTF-8 */ + _cleanup_free_ char *p = utf8_escape_invalid(value); + log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", - filename, line, key, value); + filename, line, key, p); return -EINVAL; } diff --git a/src/shared/utf8.c b/src/shared/utf8.c index 6e5ba9abf4..0b524d8a90 100644 --- a/src/shared/utf8.c +++ b/src/shared/utf8.c @@ -174,6 +174,32 @@ const char *utf8_is_valid(const char *str) { return str; } +char *utf8_escape_invalid(const char *str) { + char *p, *s; + + assert(str); + + p = s = malloc(strlen(str) * 4 + 1); + if (!p) + return NULL; + + while (*str) { + int len; + + len = utf8_encoded_valid_unichar(str); + if (len > 0) { + s = mempcpy(s, str, len); + str += len; + } else { + s = mempcpy(s, UTF8_REPLACEMENT_CHARACTER, strlen(UTF8_REPLACEMENT_CHARACTER)); + str += 1; + } + } + *s = '\0'; + + return p; +} + char *ascii_is_valid(const char *str) { const char *p; diff --git a/src/shared/utf8.h b/src/shared/utf8.h index f56077438a..c0eb73a21d 100644 --- a/src/shared/utf8.h +++ b/src/shared/utf8.h @@ -25,8 +25,11 @@ #include "macro.h" +#define UTF8_REPLACEMENT_CHARACTER "\xef\xbf\xbd" + const char *utf8_is_valid(const char *s) _pure_; char *ascii_is_valid(const char *s) _pure_; +char *utf8_escape_invalid(const char *s); bool utf8_is_printable(const char* str, size_t length) _pure_; diff --git a/src/test/test-utf8.c b/src/test/test-utf8.c index d2198fdc74..b7d988f22d 100644 --- a/src/test/test-utf8.c +++ b/src/test/test-utf8.c @@ -50,11 +50,28 @@ static void test_utf8_encoded_valid_unichar(void) { } +static void test_utf8_escaping(void) { + _cleanup_free_ char *p1, *p2, *p3; + + p1 = utf8_escape_invalid("goo goo goo"); + puts(p1); + assert_se(utf8_is_valid(p1)); + + p2 = utf8_escape_invalid("\341\204\341\204"); + puts(p2); + assert_se(utf8_is_valid(p2)); + + p3 = utf8_escape_invalid("\341\204"); + puts(p3); + assert_se(utf8_is_valid(p3)); +} + int main(int argc, char *argv[]) { test_utf8_is_valid(); test_utf8_is_printable(); test_ascii_is_valid(); test_utf8_encoded_valid_unichar(); + test_utf8_escaping(); return 0; } |