mirror of https://git.tukaani.org/xz.git
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: 40e5733055
This commit is contained in:
parent
2a9e91d796
commit
c405264c03
|
@ -12,6 +12,7 @@
|
||||||
#include "tuklib_mbstr_nonprint.h"
|
#include "tuklib_mbstr_nonprint.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#ifdef HAVE_MBRTOWC
|
#ifdef HAVE_MBRTOWC
|
||||||
# include <wchar.h>
|
# include <wchar.h>
|
||||||
|
@ -94,13 +95,18 @@ has_nonprint(const char *str, size_t len)
|
||||||
extern bool
|
extern bool
|
||||||
tuklib_has_nonprint(const char *str)
|
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 *
|
extern const char *
|
||||||
tuklib_mask_nonprint_r(const char *str, char **mem)
|
tuklib_mask_nonprint_r(const char *str, char **mem)
|
||||||
{
|
{
|
||||||
|
const int saved_errno = errno;
|
||||||
|
|
||||||
// Free the old string, if any.
|
// Free the old string, if any.
|
||||||
free(*mem);
|
free(*mem);
|
||||||
*mem = NULL;
|
*mem = NULL;
|
||||||
|
@ -108,8 +114,10 @@ tuklib_mask_nonprint_r(const char *str, char **mem)
|
||||||
// If the whole input string contains only printable characters,
|
// If the whole input string contains only printable characters,
|
||||||
// return the input string.
|
// return the input string.
|
||||||
const size_t len = strlen(str);
|
const size_t len = strlen(str);
|
||||||
if (!has_nonprint(str, len))
|
if (!has_nonprint(str, len)) {
|
||||||
|
errno = saved_errno;
|
||||||
return str;
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
// Allocate memory for the masked string. Since we use the single-byte
|
// Allocate memory for the masked string. Since we use the single-byte
|
||||||
// character '?' to mask non-printable characters, it's possible that
|
// 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
|
// If allocation fails, return "???" because it should be safer than
|
||||||
// returning the unmasked string.
|
// returning the unmasked string.
|
||||||
*mem = malloc(len + 1);
|
*mem = malloc(len + 1);
|
||||||
if (*mem == NULL)
|
if (*mem == NULL) {
|
||||||
|
errno = saved_errno;
|
||||||
return "???";
|
return "???";
|
||||||
|
}
|
||||||
|
|
||||||
// Replace all non-printable characters with '?'.
|
// Replace all non-printable characters with '?'.
|
||||||
char *dest = *mem;
|
char *dest = *mem;
|
||||||
|
@ -139,6 +149,7 @@ tuklib_mask_nonprint_r(const char *str, char **mem)
|
||||||
|
|
||||||
*dest = '\0';
|
*dest = '\0';
|
||||||
|
|
||||||
|
errno = saved_errno;
|
||||||
return *mem;
|
return *mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,8 @@ extern bool tuklib_has_nonprint(const char *str);
|
||||||
/// \brief Check if a string contains any non-printable characters
|
/// \brief Check if a string contains any non-printable characters
|
||||||
///
|
///
|
||||||
/// \return false if str contains only valid multibyte characters and
|
/// \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
|
/// \note In case mbrtowc(3) isn't available, single-byte character set
|
||||||
/// is assumed and isprint(3) is used instead of iswprint(3).
|
/// 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
|
/// allocated memory is also stored to *mem. A modified string
|
||||||
/// has the problematic characters replaced by '?'. If memory
|
/// has the problematic characters replaced by '?'. If memory
|
||||||
/// allocation fails, "???" is returned and *mem is NULL.
|
/// allocation fails, "???" is returned and *mem is NULL.
|
||||||
|
/// The value of errno is preserved.
|
||||||
|
|
||||||
#define tuklib_mask_nonprint TUKLIB_SYMBOL(tuklib_mask_nonprint)
|
#define tuklib_mask_nonprint TUKLIB_SYMBOL(tuklib_mask_nonprint)
|
||||||
extern const char *tuklib_mask_nonprint(const char *str);
|
extern const char *tuklib_mask_nonprint(const char *str);
|
||||||
|
|
Loading…
Reference in New Issue