From c405264c031aceaf68dfd1546d6337afcebd48e5 Mon Sep 17 00:00:00 2001 From: Lasse Collin Date: Sun, 5 Jan 2025 20:14:49 +0200 Subject: [PATCH] tuklib_mbstr_nonprint: Preserve the value of errno A typical use case is like this: printf("%s: %s\n", tuklib_mask_nonprint(filename), strerror(errno)); tuklib_mask_nonprint() may call mbrtowc() and malloc() which may modify errno. If errno isn't preserved, the error message might be wrong if a compiler decides to call tuklib_mask_nonprint() before strerror(). Fixes: 40e573305535960574404d2eae848b248c95ea7e --- src/common/tuklib_mbstr_nonprint.c | 17 ++++++++++++++--- src/common/tuklib_mbstr_nonprint.h | 4 +++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/common/tuklib_mbstr_nonprint.c b/src/common/tuklib_mbstr_nonprint.c index cac10bfe..dc778757 100644 --- a/src/common/tuklib_mbstr_nonprint.c +++ b/src/common/tuklib_mbstr_nonprint.c @@ -12,6 +12,7 @@ #include "tuklib_mbstr_nonprint.h" #include #include +#include #ifdef HAVE_MBRTOWC # include @@ -94,13 +95,18 @@ has_nonprint(const char *str, size_t len) extern bool tuklib_has_nonprint(const char *str) { - return has_nonprint(str, strlen(str)); + const int saved_errno = errno; + const bool ret = has_nonprint(str, strlen(str)); + errno = saved_errno; + return ret; } extern const char * tuklib_mask_nonprint_r(const char *str, char **mem) { + const int saved_errno = errno; + // Free the old string, if any. free(*mem); *mem = NULL; @@ -108,8 +114,10 @@ tuklib_mask_nonprint_r(const char *str, char **mem) // If the whole input string contains only printable characters, // return the input string. const size_t len = strlen(str); - if (!has_nonprint(str, len)) + if (!has_nonprint(str, len)) { + errno = saved_errno; return str; + } // Allocate memory for the masked string. Since we use the single-byte // character '?' to mask non-printable characters, it's possible that @@ -119,8 +127,10 @@ tuklib_mask_nonprint_r(const char *str, char **mem) // If allocation fails, return "???" because it should be safer than // returning the unmasked string. *mem = malloc(len + 1); - if (*mem == NULL) + if (*mem == NULL) { + errno = saved_errno; return "???"; + } // Replace all non-printable characters with '?'. char *dest = *mem; @@ -139,6 +149,7 @@ tuklib_mask_nonprint_r(const char *str, char **mem) *dest = '\0'; + errno = saved_errno; return *mem; } diff --git a/src/common/tuklib_mbstr_nonprint.h b/src/common/tuklib_mbstr_nonprint.h index 7c2bef15..6fc96910 100644 --- a/src/common/tuklib_mbstr_nonprint.h +++ b/src/common/tuklib_mbstr_nonprint.h @@ -25,7 +25,8 @@ extern bool tuklib_has_nonprint(const char *str); /// \brief Check if a string contains any non-printable characters /// /// \return false if str contains only valid multibyte characters and -/// iswprint(3) returns non-zero for all of them; true otherwise +/// iswprint(3) returns non-zero for all of them; true otherwise. +/// The value of errno is preserved. /// /// \note In case mbrtowc(3) isn't available, single-byte character set /// is assumed and isprint(3) is used instead of iswprint(3). @@ -49,6 +50,7 @@ extern const char *tuklib_mask_nonprint_r(const char *str, char **mem); /// allocated memory is also stored to *mem. A modified string /// has the problematic characters replaced by '?'. If memory /// allocation fails, "???" is returned and *mem is NULL. +/// The value of errno is preserved. #define tuklib_mask_nonprint TUKLIB_SYMBOL(tuklib_mask_nonprint) extern const char *tuklib_mask_nonprint(const char *str);