Skip to content

Commit

Permalink
tuklib_mbstr_nonprint: Preserve the value of errno
Browse files Browse the repository at this point in the history
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: 40e5733
  • Loading branch information
Larhzu committed Jan 5, 2025
1 parent 2a9e91d commit c405264
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 4 deletions.
17 changes: 14 additions & 3 deletions src/common/tuklib_mbstr_nonprint.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "tuklib_mbstr_nonprint.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#ifdef HAVE_MBRTOWC
# include <wchar.h>
Expand Down Expand Up @@ -94,22 +95,29 @@ 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;

// 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
Expand All @@ -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;
Expand All @@ -139,6 +149,7 @@ tuklib_mask_nonprint_r(const char *str, char **mem)

*dest = '\0';

errno = saved_errno;
return *mem;
}

Expand Down
4 changes: 3 additions & 1 deletion src/common/tuklib_mbstr_nonprint.h
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand All @@ -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);
Expand Down

0 comments on commit c405264

Please sign in to comment.