all: merge branch 'th/ascii-control-chars'

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/932
This commit is contained in:
Thomas Haller 2021-07-19 09:06:21 +02:00
commit 299117f619
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
8 changed files with 153 additions and 53 deletions

View file

@ -172,7 +172,7 @@ _escape_ansic(const char *source)
n_alloc += 2;
break;
default:
if ((*p < ' ') || (*p >= 0177))
if (!nm_ascii_is_regular(*p))
n_alloc += 4;
else
n_alloc += 1;
@ -221,7 +221,7 @@ _escape_ansic(const char *source)
*q++ = *p;
break;
default:
if ((*p < ' ') || (*p >= 0177)) {
if (!nm_ascii_is_regular(*p)) {
*q++ = '\\';
*q++ = '0' + (((*p) >> 6) & 07);
*q++ = '0' + (((*p) >> 3) & 07);
@ -262,13 +262,14 @@ svEscape(const char *s, char **to_free)
mangle++;
else if (_char_req_quotes(s[slen]))
requires_quotes = TRUE;
else if (((guchar) s[slen]) < ' ') {
/* if the string contains newline we can only express it using ANSI C quotation
* (as we don't support line continuation).
* Additionally, ANSI control characters look odd with regular quotation, so handle
* them too. */
return (*to_free = _escape_ansic(s));
} else if (((guchar) s[slen]) >= 0177) {
else if (!nm_ascii_is_regular(s[slen])) {
if (nm_ascii_is_ctrl_or_del(s[slen])) {
/* if the string contains newline we can only express it using ANSI C quotation
* (as we don't support line continuation).
* Additionally, ANSI control characters look odd with regular quotation, so handle
* them too. */
return (*to_free = _escape_ansic(s));
}
all_ascii = FALSE;
requires_quotes = TRUE;
}

View file

@ -160,14 +160,17 @@ _fixup_string(const char * desc,
p = q + 1;
}
/* replace '_', ',', ASCII control characters and parentheses, with space. */
/* replace '_', ',', ASCII control characters and everything inside parentheses, with space. */
for (p = desc_full; p[0]; p++) {
if (*p == '(')
in_paren = TRUE;
if (NM_IN_SET(*p, '_', ',') || *p < ' ' || in_paren)
*p = ' ';
if (*p == ')')
else if (*p == ')')
in_paren = FALSE;
else if (NM_IN_SET(*p, '_', ',') || nm_ascii_is_ctrl_or_del(*p) || in_paren) {
/* pass */
} else
continue;
*p = ' ';
}
/* Attempt to shorten ID by ignoring certain phrases */

View file

@ -219,7 +219,7 @@ test_fixup_vendor_string(void)
T_DATA("Memorex", "Memorex"),
T_DATA("Micrel-Kendin", "Micrel-Kendin"),
T_DATA("Microchip Technology, Inc.", "Microchip"),
T_DATA("Microcomputer Systems (M) Son", "Microcomputer"),
T_DATA("Microcomputer Systems (M) Son", "Microcomputer Son"),
T_DATA("Microsoft Corp.", "Microsoft"),
T_DATA("Microsoft Corporation", "Microsoft"),
T_DATA("Micro-Star International Co., Ltd. [MSI]", "MSI"),
@ -594,11 +594,11 @@ test_fixup_product_string(void)
T_DATA("82599 Ethernet Controller Virtual Function", "82599 Virtual Function"),
T_DATA("82599 Virtual Function", "82599 Virtual Function"),
T_DATA("82801BA/BAM/CA/CAM Ethernet Controller", "82801BA/BAM/CA/CAM"),
T_DATA("82801CAM (ICH3) PRO/100 VE Ethernet Controller", "82801CAM"),
T_DATA("82801CAM (ICH3) PRO/100 VE (LOM) Ethernet Controller", "82801CAM"),
T_DATA("82801CAM (ICH3) PRO/100 VM Ethernet Controller", "82801CAM"),
T_DATA("82801CAM (ICH3) PRO/100 VM (KM) Ethernet Controller", "82801CAM"),
T_DATA("82801CAM (ICH3) PRO/100 VM (LOM) Ethernet Controller", "82801CAM"),
T_DATA("82801CAM (ICH3) PRO/100 VE Ethernet Controller", "82801CAM PRO/100 VE"),
T_DATA("82801CAM (ICH3) PRO/100 VE (LOM) Ethernet Controller", "82801CAM PRO/100 VE"),
T_DATA("82801CAM (ICH3) PRO/100 VM Ethernet Controller", "82801CAM PRO/100 VM"),
T_DATA("82801CAM (ICH3) PRO/100 VM (KM) Ethernet Controller", "82801CAM PRO/100 VM"),
T_DATA("82801CAM (ICH3) PRO/100 VM (LOM) Ethernet Controller", "82801CAM PRO/100 VM"),
T_DATA("82801DB PRO/100 VE (CNR) Ethernet Controller", "82801DB PRO/100 VE"),
T_DATA("82801DB PRO/100 VE (LOM) Ethernet Controller", "82801DB PRO/100 VE"),
T_DATA("82801DB PRO/100 VE (MOB) Ethernet Controller", "82801DB PRO/100 VE"),
@ -1009,25 +1009,25 @@ test_fixup_product_string(void)
T_DATA("Ethernet Adapter", NULL),
T_DATA("Ethernet adapter [U2L 100P-Y1]", "U2L 100P-Y1"),
T_DATA("Ethernet Adaptive Virtual Function", "Adaptive Virtual Function"),
T_DATA("Ethernet Connection (2) I218-LM", NULL),
T_DATA("Ethernet Connection (2) I218-V", NULL),
T_DATA("Ethernet Connection (2) I219-LM", NULL),
T_DATA("Ethernet Connection (2) I219-V", NULL),
T_DATA("Ethernet Connection (3) I218-LM", NULL),
T_DATA("Ethernet Connection (3) I218-V", NULL),
T_DATA("Ethernet Connection (3) I219-LM", NULL),
T_DATA("Ethernet Connection (4) I219-LM", NULL),
T_DATA("Ethernet Connection (4) I219-V", NULL),
T_DATA("Ethernet Connection (5) I219-LM", NULL),
T_DATA("Ethernet Connection (5) I219-V", NULL),
T_DATA("Ethernet Connection (6) I219-LM", NULL),
T_DATA("Ethernet Connection (6) I219-V", NULL),
T_DATA("Ethernet Connection (7) I219-LM", NULL),
T_DATA("Ethernet Connection (7) I219-V", NULL),
T_DATA("Ethernet Connection (8) I219-LM", NULL),
T_DATA("Ethernet Connection (8) I219-V", NULL),
T_DATA("Ethernet Connection (9) I219-LM", NULL),
T_DATA("Ethernet Connection (9) I219-V", NULL),
T_DATA("Ethernet Connection (2) I218-LM", "I218-LM"),
T_DATA("Ethernet Connection (2 I218-V", NULL),
T_DATA("Ethernet Connection (2 I219-LM", NULL),
T_DATA("Ethernet Connection (2 I219-V", NULL),
T_DATA("Ethernet Connection (3) I218-LM", "I218-LM"),
T_DATA("Ethernet Connection (3) I218-V", "I218-V"),
T_DATA("Ethernet Connection (3 I219-LM", NULL),
T_DATA("Ethernet Connection (4 I219-LM", NULL),
T_DATA("Ethernet Connection (4 I219-V", NULL),
T_DATA("Ethernet Connection (5 I219-LM", NULL),
T_DATA("Ethernet Connection (5 I219-V", NULL),
T_DATA("Ethernet Connection (6 I219-LM", NULL),
T_DATA("Ethernet Connection (6 I219-V", NULL),
T_DATA("Ethernet Connection (7 I219-LM", NULL),
T_DATA("Ethernet Connection (7 I219-V", NULL),
T_DATA("Ethernet Connection (8 I219-LM", NULL),
T_DATA("Ethernet Connection (8 I219-V", NULL),
T_DATA("Ethernet Connection (9 I219-LM", NULL),
T_DATA("Ethernet Connection (9 I219-V", NULL),
T_DATA("Ethernet Connection I217-LM", "I217-LM"),
T_DATA("Ethernet Connection I217-V", "I217-V"),
T_DATA("Ethernet Connection I218-LM", "I218-LM"),
@ -2160,12 +2160,12 @@ test_fixup_product_string(void)
"WLM-20U2/GN-1080"),
T_DATA("WLP-UC-AG300 Wireless LAN Adapter", "WLP-UC-AG300"),
T_DATA("WM168g 802.11bg Wireless Adapter [Intersil ISL3886]", "WM168g"),
T_DATA("WN111(v2) RangeMax Next Wireless [Atheros AR9170+AR9101]", "WN111"),
T_DATA("WN111(v2) RangeMax Next Wireless [Atheros AR9170+AR9101]", "WN111 RangeMax Next"),
T_DATA("WNA1000M 802.11bgn [Realtek RTL8188CUS]", "WNA1000M"),
T_DATA("WNA1000Mv2 802.11bgn [Realtek RTL8188CUS?]", "WNA1000Mv2"),
T_DATA("WNA1000 Wireless-N 150 [Atheros AR9170+AR9101]", "WNA1000 150"),
T_DATA("WNA1100 Wireless-N 150 [Atheros AR9271]", "WNA1100 150"),
T_DATA("WNA3100M(v1) Wireless-N 300 [Realtek RTL8192CU]", "WNA3100M"),
T_DATA("WNA3100M(v1) Wireless-N 300 [Realtek RTL8192CU]", "WNA3100M 300"),
T_DATA("WNDA3100v1 802.11abgn [Atheros AR9170+AR9104]", "WNDA3100v1"),
T_DATA("WNDA3200 802.11abgn Wireless Adapter [Atheros AR7010+AR9280]", "WNDA3200"),
T_DATA("WNDA4100 802.11abgn 3x3:3 [Ralink RT3573]", "WNDA4100"),

View file

@ -531,7 +531,7 @@ _keyfile_key_encode(const char *name, char **out_to_free)
if (ch == '\0')
return name;
if (ch < 0x20 || ch >= 127 || NM_IN_SET(ch, '=', '[', ']')
if (!nm_ascii_is_regular(ch) || NM_IN_SET(ch, '=', '[', ']')
|| (ch == '\\' && g_ascii_isxdigit(name[i + 1]) && g_ascii_isxdigit(name[i + 2]))
|| (ch == ' ' && name[i + 1] == '\0'))
break;
@ -557,7 +557,7 @@ _keyfile_key_encode(const char *name, char **out_to_free)
if (ch == '\0')
break;
if (ch < 0x20 || ch >= 127 || NM_IN_SET(ch, '=', '[', ']')
if (!nm_ascii_is_regular(ch) || NM_IN_SET(ch, '=', '[', ']')
|| (ch == '\\' && g_ascii_isxdigit(name[i + 1]) && g_ascii_isxdigit(name[i + 2]))
|| (ch == ' ' && name[i + 1] == '\0')) {
nm_str_buf_append_c(&str, '\\');

View file

@ -9228,6 +9228,12 @@ _do_test_utils_str_utf8safe(const char * str,
((nmtst_get_rand_bool()) ? NM_UTILS_STR_UTF8_SAFE_FLAG_NONE \
: NM_UTILS_STR_UTF8_SAFE_FLAG_SECRET)
if (expected && strlen(expected) == str_len && memcmp(str, expected, str_len) == 0) {
g_error("Test error: pass expected as NULL (instead of \"%s\", if the escaping will "
"produce no difference.",
expected);
}
buf_safe = nm_utils_buf_utf8safe_escape(str, str_len, flags | RND_FLAG, &str_free_1);
str_safe = nm_utils_str_utf8safe_escape(str, flags | RND_FLAG, &str_free_2);
@ -9364,6 +9370,13 @@ test_utils_str_utf8safe(void)
do_test_utils_str_utf8safe_unescape("\n\\012", "\n\012");
do_test_utils_str_utf8safe_unescape("\n\\.", "\n.");
do_test_utils_str_utf8safe_unescape("\\n\\.3\\r", "\n.3\r");
do_test_utils_str_utf8safe("ab∞c", NULL, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL);
do_test_utils_str_utf8safe("ab\ab∞c", "ab\\007b∞c", NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL);
do_test_utils_str_utf8safe("ab\ab∞c",
"ab\\007b\\342\\210\\236c",
NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL
| NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII);
}
/*****************************************************************************/

View file

@ -2991,13 +2991,13 @@ nm_utils_buf_utf8safe_escape(gconstpointer buf,
if (g_utf8_validate(str, buflen, &p) && nul_terminated) {
/* note that g_utf8_validate() does not allow NUL character inside @str. Good.
* We can treat @str like a NUL terminated string. */
if (!NM_STRCHAR_ANY(
str,
ch,
(ch == '\\'
|| (NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL) && ch < ' ')
|| (NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII)
&& ((guchar) ch) >= 127))))
if (!NM_STRCHAR_ANY(str,
ch,
(ch == '\\'
|| (NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL)
&& nm_ascii_is_ctrl_or_del(ch))
|| (NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII)
&& nm_ascii_is_non_ascii(ch)))))
return str;
}
@ -3014,9 +3014,10 @@ nm_utils_buf_utf8safe_escape(gconstpointer buf,
nm_assert(ch);
if (ch == '\\')
nm_str_buf_append_c(&strbuf, '\\', '\\');
else if ((NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL) && ch < ' ')
else if ((NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL)
&& nm_ascii_is_ctrl_or_del(ch))
|| (NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII)
&& ((guchar) ch) >= 127))
&& nm_ascii_is_non_ascii(ch)))
_str_buf_append_c_escape_octal(&strbuf, ch);
else
nm_str_buf_append_c(&strbuf, ch);

View file

@ -1462,10 +1462,14 @@ GType nm_g_type_find_implementing_class_for_property(GType gtype, const char *pn
typedef enum {
NM_UTILS_STR_UTF8_SAFE_FLAG_NONE = 0,
/* This flag only has an effect during escaping. */
/* This flag only has an effect during escaping.
*
* It will backslash escape ascii characters according to nm_ascii_is_ctrl_or_del(). */
NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL = 0x0001,
/* This flag only has an effect during escaping. */
/* This flag only has an effect during escaping.
*
* It will backslash escape ascii characters according to nm_ascii_is_non_ascii(). */
NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII = 0x0002,
/* This flag only has an effect during escaping to ensure we
@ -2481,6 +2485,40 @@ nm_hexchar(int x, gboolean upper_case)
return upper_case ? _nm_hexchar_table_upper[x & 15] : _nm_hexchar_table_lower[x & 15];
}
static inline gboolean
nm_ascii_is_ctrl(char ch)
{
/* 0 to ' '-1 is the C0 range.
*
* Other ranges may also be considered control characters, but NOT
* CONSIDERED by this function. For example:
* - DEL (127) is also a control character.
* - SP (' ', 0x20) is also considered a control character.
* - DEL+1 (0x80) to 0x9F is C1 range.
* - NBSP (0xA0) and SHY (0xAD) are ISO 8859 special characters
*/
return ((guchar) ch) < ' ';
}
static inline gboolean
nm_ascii_is_ctrl_or_del(char ch)
{
return ((guchar) ch) < ' ' || ch == 127;
}
static inline gboolean
nm_ascii_is_non_ascii(char ch)
{
return ((guchar) ch) > 127;
}
static inline gboolean
nm_ascii_is_regular(char ch)
{
/* same as(!nm_ascii_is_ctrl_or_del(ch) && !nm_ascii_is_non_ascii(ch)) */
return ch >= ' ' && ch < 127;
}
char *nm_utils_bin2hexstr_full(gconstpointer addr,
gsize length,
char delimiter,

View file

@ -1370,6 +1370,49 @@ test_nm_g_source_sentinel(void)
/*****************************************************************************/
static void
test_nm_ascii(void)
{
int i;
for (i = 0; i < 256; i++) {
const char ch = i;
gboolean is_space;
if (ch == 127) {
g_assert(nm_ascii_is_ctrl_or_del(ch));
g_assert(!nm_ascii_is_ctrl(ch));
} else
g_assert(nm_ascii_is_ctrl_or_del(ch) == nm_ascii_is_ctrl(ch));
g_assert(nm_ascii_is_ctrl_or_del(ch) == g_ascii_iscntrl(ch));
g_assert(nm_ascii_is_non_ascii(ch) == (i >= 128));
g_assert(!nm_ascii_is_ctrl_or_del(ch) || !nm_ascii_is_non_ascii(ch));
g_assert((nm_ascii_is_ctrl_or_del(ch) || nm_ascii_is_regular(ch))
!= nm_ascii_is_non_ascii(ch));
g_assert(nm_ascii_is_regular(ch)
== (!nm_ascii_is_ctrl_or_del(ch) && !nm_ascii_is_non_ascii(ch)));
is_space = g_ascii_isspace(ch);
if (NM_IN_SET(ch, '\t', '\n', '\f', '\r')) {
/* hack is-space, so that the check below works to check for regular ASCII characters. */
g_assert(!nm_ascii_is_regular(ch));
g_assert(is_space);
is_space = FALSE;
}
g_assert(nm_ascii_is_regular(ch)
== (g_ascii_isalnum(ch) || g_ascii_isalpha(ch) || g_ascii_isdigit(ch)
|| g_ascii_isgraph(ch) || g_ascii_islower(ch) || g_ascii_isprint(ch)
|| g_ascii_ispunct(ch) || is_space || g_ascii_isupper(ch)
|| g_ascii_isxdigit(ch)));
}
}
/*****************************************************************************/
NMTST_DEFINE();
int
@ -1402,6 +1445,7 @@ main(int argc, char **argv)
g_test_add_func("/general/test_strv_dup_packed", test_strv_dup_packed);
g_test_add_func("/general/test_utils_hashtable_cmp", test_utils_hashtable_cmp);
g_test_add_func("/general/test_nm_g_source_sentinel", test_nm_g_source_sentinel);
g_test_add_func("/general/test_nm_ascii", test_nm_ascii);
return g_test_run();
}