all: merge branch 'th/strstrip'

https://github.com/NetworkManager/NetworkManager/pull/329
This commit is contained in:
Thomas Haller
2019-04-04 21:04:26 +02:00
5 changed files with 219 additions and 143 deletions

View File

@@ -305,7 +305,7 @@ _parse_ip_route (int family,
nm_assert (str);
nm_assert (!error || !*error);
str_clean = nm_strstrip_avoid_copy (str, &str_clean_free);
str_clean = nm_strstrip_avoid_copy_a (300, str, &str_clean_free);
routev = nm_utils_strsplit_set (str_clean, " \t", FALSE);
if (!routev) {
g_set_error (error, 1, 0,
@@ -479,7 +479,7 @@ _parse_team_link_watcher (const char *str,
nm_assert (str);
nm_assert (!error || !*error);
str_clean = nm_strstrip_avoid_copy (str, &str_clean_free);
str_clean = nm_strstrip_avoid_copy_a (300, str, &str_clean_free);
watcherv = nm_utils_strsplit_set (str_clean, " \t", FALSE);
if (!watcherv) {
g_set_error (error, 1, 0, "'%s' is not valid", str);
@@ -1275,7 +1275,7 @@ _set_fcn_gobject_int (ARGS_SET_FCN)
gs_free char *vv_free = NULL;
const char *vv;
vv = nm_strstrip_avoid_copy (value, &vv_free);
vv = nm_strstrip_avoid_copy_a (300, value, &vv_free);
for (; value_infos->nick; value_infos++) {
if (nm_streq (value_infos->nick, vv)) {
v = value_infos->value;
@@ -2169,7 +2169,7 @@ _set_fcn_gobject_bytes (ARGS_SET_FCN)
if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value))
return _gobject_property_reset_default (setting, property_info->property_name);
val_strip = nm_strstrip_avoid_copy (value, &val_strip_free);
val_strip = nm_strstrip_avoid_copy_a (300, value, &val_strip_free);
/* First try hex string in the format of AAbbCCDd */
bytes = nm_utils_hexstr2bin (val_strip);
@@ -2253,7 +2253,7 @@ _set_fcn_cert_8021x (ARGS_SET_FCN)
if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value))
return _gobject_property_reset_default (setting, property_info->property_name);
value = nm_strstrip_avoid_copy (value, &value_to_free);
value = nm_strstrip_avoid_copy_a (300, value, &value_to_free);
if (strncmp (value, NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PKCS11, NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PKCS11)) == 0)
scheme = NM_SETTING_802_1X_CK_SCHEME_PKCS11;
@@ -3330,7 +3330,7 @@ _set_fcn_ip_config_gateway (ARGS_SET_FCN)
if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value))
return _gobject_property_reset_default (setting, property_info->property_name);
value = nm_strstrip_avoid_copy (value, &value_to_free);
value = nm_strstrip_avoid_copy_a (300, value, &value_to_free);
if (!nm_utils_ipaddr_valid (addr_family, value)) {
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
@@ -4209,7 +4209,7 @@ _set_fcn_ethtool (ARGS_SET_FCN)
goto set;
}
value = nm_strstrip_avoid_copy (value, &value_to_free);
value = nm_strstrip_avoid_copy_a (300, value, &value_to_free);
if (NM_IN_STRSET (value, "1", "yes", "true", "on"))
val = NM_TERNARY_TRUE;

View File

@@ -1342,14 +1342,14 @@ _NM_BACKPORT_SYMBOL_IMPL(version, return_type, func, _##func##_##version, args_t
#define nm_str_skip_leading_spaces(str) \
({ \
typeof (*(str)) *_str = (str); \
_nm_unused const char *_str_type_check = _str; \
typeof (*(str)) *_str_sls = (str); \
_nm_unused const char *const _str_type_check = _str_sls; \
\
if (_str) { \
while (g_ascii_isspace (_str[0])) \
_str++; \
if (_str_sls) { \
while (g_ascii_isspace (_str_sls[0])) \
_str_sls++; \
} \
_str; \
_str_sls; \
})
static inline char *
@@ -1386,6 +1386,34 @@ nm_strstrip_avoid_copy (const char *str, char **str_free)
return s;
}
#define nm_strstrip_avoid_copy_a(alloca_maxlen, str, out_str_free) \
({ \
const char *_str_ssac = (str); \
char **_out_str_free_ssac = (out_str_free); \
\
G_STATIC_ASSERT_EXPR ((alloca_maxlen) > 0); \
\
nm_assert ( _out_str_free_ssac || ((alloca_maxlen) > (str ? strlen (str) : 0u))); \
nm_assert (!_out_str_free_ssac || !*_out_str_free_ssac); \
\
if (_str_ssac) { \
_str_ssac = nm_str_skip_leading_spaces (_str_ssac); \
if (_str_ssac[0] != '\0') { \
gsize _l = strlen (_str_ssac); \
\
if (g_ascii_isspace (_str_ssac[--_l])) { \
while ( _l > 0 \
&& g_ascii_isspace (_str_ssac[_l - 1])) { \
_l--; \
} \
_str_ssac = nm_strndup_a ((alloca_maxlen), _str_ssac, _l, _out_str_free_ssac); \
} \
} \
} \
\
_str_ssac; \
})
/* g_ptr_array_sort()'s compare function takes pointers to the
* value. Thus, you cannot use strcmp directly. You can use
* nm_strcmp_p().
@@ -1464,6 +1492,118 @@ nm_strcmp_p (gconstpointer a, gconstpointer b)
/*****************************************************************************/
/* like g_memdup(). The difference is that the @size argument is of type
* gsize, while g_memdup() has type guint. Since, the size of container types
* like GArray is guint as well, this means trying to g_memdup() an
* array,
* g_memdup (array->data, array->len * sizeof (ElementType))
* will lead to integer overflow, if there are more than G_MAXUINT/sizeof(ElementType)
* bytes. That seems unnecessarily dangerous to me.
* nm_memdup() avoids that, because its size argument is always large enough
* to contain all data that a GArray can hold.
*
* Another minor difference to g_memdup() is that the glib version also
* returns %NULL if @data is %NULL. E.g. g_memdup(NULL, 1)
* gives %NULL, but nm_memdup(NULL, 1) crashes. I think that
* is desirable, because @size MUST be correct at all times. @size
* may be zero, but one must not claim to have non-zero bytes when
* passing a %NULL @data pointer.
*/
static inline gpointer
nm_memdup (gconstpointer data, gsize size)
{
gpointer p;
if (size == 0)
return NULL;
p = g_malloc (size);
memcpy (p, data, size);
return p;
}
static inline char *
_nm_strndup_a_step (char *s, const char *str, gsize len)
{
NM_PRAGMA_WARNING_DISABLE ("-Wstringop-truncation");
if (len > 0)
strncpy (s, str, len);
s[len] = '\0';
return s;
NM_PRAGMA_WARNING_REENABLE;
}
/* Similar to g_strndup(), however, if the string (including the terminating
* NUL char) fits into alloca_maxlen, this will alloca() the memory.
*
* It's a mix of strndup() and strndupa(), but deciding based on @alloca_maxlen
* which one to use.
*
* In case malloc() is necessary, @out_str_free will be set (this string
* must be freed afterwards). It is permissible to pass %NULL as @out_str_free,
* if you ensure that len < alloca_maxlen.
*
* Note that just like g_strndup(), this always returns a buffer with @len + 1
* bytes, even if strlen(@str) is shorter than that (NUL terminated early). We fill
* the buffer with strncpy(), which means, that @str is copied up to the first
* NUL character and then filled with NUL characters. */
#define nm_strndup_a(alloca_maxlen, str, len, out_str_free) \
({ \
const gsize _alloca_maxlen_snd = (alloca_maxlen); \
const char *const _str_snd = (str); \
const gsize _len_snd = (len); \
char **const _out_str_free_snd = (out_str_free); \
char *_s_snd; \
\
G_STATIC_ASSERT_EXPR ((alloca_maxlen) <= 300); \
\
if ( _out_str_free_snd \
&& _len_snd >= _alloca_maxlen_snd) { \
_s_snd = g_malloc (_len_snd + 1); \
*_out_str_free_snd = _s_snd; \
} else { \
g_assert (_len_snd < _alloca_maxlen_snd); \
_s_snd = g_alloca (_len_snd + 1); \
} \
_nm_strndup_a_step (_s_snd, _str_snd, _len_snd); \
})
/*****************************************************************************/
/* generic macro to convert an int to a (heap allocated) string.
*
* Usually, an inline function nm_strdup_int64() would be enough. However,
* that cannot be used for guint64. So, we would also need nm_strdup_uint64().
* This causes subtle error potential, because the caller needs to ensure to
* use the right one (and compiler isn't going to help as it silently casts).
*
* Instead, this generic macro is supposed to handle all integers correctly. */
#if _NM_CC_SUPPORT_GENERIC
#define nm_strdup_int(val) \
_Generic ((val), \
char: g_strdup_printf ("%d", (int) (val)), \
\
signed char: g_strdup_printf ("%d", (signed) (val)), \
signed short: g_strdup_printf ("%d", (signed) (val)), \
signed: g_strdup_printf ("%d", (signed) (val)), \
signed long: g_strdup_printf ("%ld", (signed long) (val)), \
signed long long: g_strdup_printf ("%lld", (signed long long) (val)), \
\
unsigned char: g_strdup_printf ("%u", (unsigned) (val)), \
unsigned short: g_strdup_printf ("%u", (unsigned) (val)), \
unsigned: g_strdup_printf ("%u", (unsigned) (val)), \
unsigned long: g_strdup_printf ("%lu", (unsigned long) (val)), \
unsigned long long: g_strdup_printf ("%llu", (unsigned long long) (val)) \
)
#else
#define nm_strdup_int(val) \
( ( sizeof (val) == sizeof (guint64) \
&& ((typeof (val)) -1) > 0) \
? g_strdup_printf ("%"G_GUINT64_FORMAT, (guint64) (val)) \
: g_strdup_printf ("%"G_GINT64_FORMAT, (gint64) (val)))
#endif
/*****************************************************************************/
static inline guint
nm_encode_version (guint major, guint minor, guint micro)
{

View File

@@ -1181,31 +1181,27 @@ int
_nm_utils_ascii_str_to_bool (const char *str,
int default_value)
{
gsize len;
char *s = NULL;
gs_free char *str_free = NULL;
if (!str)
return default_value;
while (str[0] && g_ascii_isspace (str[0]))
str++;
if (!str[0])
str = nm_strstrip_avoid_copy_a (300, str, &str_free);
if (str[0] == '\0')
return default_value;
len = strlen (str);
if (g_ascii_isspace (str[len - 1])) {
s = g_strdup (str);
g_strchomp (s);
str = s;
}
if ( !g_ascii_strcasecmp (str, "true")
|| !g_ascii_strcasecmp (str, "yes")
|| !g_ascii_strcasecmp (str, "on")
|| !g_ascii_strcasecmp (str, "1"))
return TRUE;
if ( !g_ascii_strcasecmp (str, "false")
|| !g_ascii_strcasecmp (str, "no")
|| !g_ascii_strcasecmp (str, "off")
|| !g_ascii_strcasecmp (str, "0"))
return FALSE;
if (!g_ascii_strcasecmp (str, "true") || !g_ascii_strcasecmp (str, "yes") || !g_ascii_strcasecmp (str, "on") || !g_ascii_strcasecmp (str, "1"))
default_value = TRUE;
else if (!g_ascii_strcasecmp (str, "false") || !g_ascii_strcasecmp (str, "no") || !g_ascii_strcasecmp (str, "off") || !g_ascii_strcasecmp (str, "0"))
default_value = FALSE;
if (s)
g_free (s);
return default_value;
}

View File

@@ -258,118 +258,6 @@ gboolean nm_utils_memeqzero (gconstpointer data, gsize length);
/*****************************************************************************/
/* like g_memdup(). The difference is that the @size argument is of type
* gsize, while g_memdup() has type guint. Since, the size of container types
* like GArray is guint as well, this means trying to g_memdup() an
* array,
* g_memdup (array->data, array->len * sizeof (ElementType))
* will lead to integer overflow, if there are more than G_MAXUINT/sizeof(ElementType)
* bytes. That seems unnecessarily dangerous to me.
* nm_memdup() avoids that, because its size argument is always large enough
* to contain all data that a GArray can hold.
*
* Another minor difference to g_memdup() is that the glib version also
* returns %NULL if @data is %NULL. E.g. g_memdup(NULL, 1)
* gives %NULL, but nm_memdup(NULL, 1) crashes. I think that
* is desirable, because @size MUST be correct at all times. @size
* may be zero, but one must not claim to have non-zero bytes when
* passing a %NULL @data pointer.
*/
static inline gpointer
nm_memdup (gconstpointer data, gsize size)
{
gpointer p;
if (size == 0)
return NULL;
p = g_malloc (size);
memcpy (p, data, size);
return p;
}
static inline char *
_nm_strndup_a_step (char *s, const char *str, gsize len)
{
NM_PRAGMA_WARNING_DISABLE ("-Wstringop-truncation");
if (len > 0)
strncpy (s, str, len);
s[len] = '\0';
return s;
NM_PRAGMA_WARNING_REENABLE;
}
/* Similar to g_strndup(), however, if the string (including the terminating
* NUL char) fits into alloca_maxlen, this will alloca() the memory.
*
* It's a mix of strndup() and strndupa(), but deciding based on @alloca_maxlen
* which one to use.
*
* In case malloc() is necessary, @out_str_free will be set (this string
* must be freed afterwards). It is permissible to pass %NULL as @out_str_free,
* if you ensure that len < alloca_maxlen.
*
* Note that just like g_strndup(), this always returns a buffer with @len + 1
* bytes, even if strlen(@str) is shorter than that (NUL terminated early). We fill
* the buffer with strncpy(), which means, that @str is copied up to the first
* NUL character and then filled with NUL characters. */
#define nm_strndup_a(alloca_maxlen, str, len, out_str_free) \
({ \
const gsize _alloca_maxlen = (alloca_maxlen); \
const char *const _str = (str); \
const gsize _len = (len); \
char **const _out_str_free = (out_str_free); \
char *_s; \
\
G_STATIC_ASSERT_EXPR ((alloca_maxlen) <= 300); \
\
if ( _out_str_free \
&& _len >= _alloca_maxlen) { \
_s = g_malloc (_len + 1); \
*_out_str_free = _s; \
} else { \
g_assert (_len < _alloca_maxlen); \
_s = g_alloca (_len + 1); \
} \
_nm_strndup_a_step (_s, _str, _len); \
})
/*****************************************************************************/
/* generic macro to convert an int to a (heap allocated) string.
*
* Usually, an inline function nm_strdup_int64() would be enough. However,
* that cannot be used for guint64. So, we would also need nm_strdup_uint64().
* This causes subtle error potential, because the caller needs to ensure to
* use the right one (and compiler isn't going to help as it silently casts).
*
* Instead, this generic macro is supposed to handle all integers correctly. */
#if _NM_CC_SUPPORT_GENERIC
#define nm_strdup_int(val) \
_Generic ((val), \
char: g_strdup_printf ("%d", (int) (val)), \
\
signed char: g_strdup_printf ("%d", (signed) (val)), \
signed short: g_strdup_printf ("%d", (signed) (val)), \
signed: g_strdup_printf ("%d", (signed) (val)), \
signed long: g_strdup_printf ("%ld", (signed long) (val)), \
signed long long: g_strdup_printf ("%lld", (signed long long) (val)), \
\
unsigned char: g_strdup_printf ("%u", (unsigned) (val)), \
unsigned short: g_strdup_printf ("%u", (unsigned) (val)), \
unsigned: g_strdup_printf ("%u", (unsigned) (val)), \
unsigned long: g_strdup_printf ("%lu", (unsigned long) (val)), \
unsigned long long: g_strdup_printf ("%llu", (unsigned long long) (val)) \
)
#else
#define nm_strdup_int(val) \
( ( sizeof (val) == sizeof (guint64) \
&& ((typeof (val)) -1) > 0) \
? g_strdup_printf ("%"G_GUINT64_FORMAT, (guint64) (val)) \
: g_strdup_printf ("%"G_GINT64_FORMAT, (gint64) (val)))
#endif
/*****************************************************************************/
extern const void *const _NM_PTRARRAY_EMPTY[1];
#define NM_PTRARRAY_EMPTY(type) ((type const*) _NM_PTRARRAY_EMPTY)

View File

@@ -392,6 +392,57 @@ test_strv_cmp (void)
/*****************************************************************************/
static void
_do_strstrip_avoid_copy (const char *str)
{
gs_free char *str1 = g_strdup (str);
gs_free char *str2 = g_strdup (str);
gs_free char *str3 = NULL;
gs_free char *str4 = NULL;
const char *s3;
const char *s4;
if (str1)
g_strstrip (str1);
nm_strstrip (str2);
g_assert_cmpstr (str1, ==, str2);
s3 = nm_strstrip_avoid_copy (str, &str3);
g_assert_cmpstr (str1, ==, s3);
s4 = nm_strstrip_avoid_copy_a (10, str, &str4);
g_assert_cmpstr (str1, ==, s4);
g_assert (!str == !s4);
g_assert (!s4 || strlen (s4) <= strlen (str));
if (s4 && s4 == &str[strlen (str) - strlen (s4)]) {
g_assert (!str4);
g_assert (s3 == s4);
} else if (s4 && strlen (s4) >= 10) {
g_assert (str4);
g_assert (s4 == str4);
} else
g_assert (!str4);
if (!nm_streq0 (str1, str))
_do_strstrip_avoid_copy (str1);
}
static void
test_strstrip_avoid_copy (void)
{
_do_strstrip_avoid_copy (NULL);
_do_strstrip_avoid_copy ("");
_do_strstrip_avoid_copy (" ");
_do_strstrip_avoid_copy (" a ");
_do_strstrip_avoid_copy (" 012345678 ");
_do_strstrip_avoid_copy (" 0123456789 ");
_do_strstrip_avoid_copy (" 01234567890 ");
_do_strstrip_avoid_copy (" 012345678901 ");
}
/*****************************************************************************/
NMTST_DEFINE ();
int main (int argc, char **argv)
@@ -406,6 +457,7 @@ int main (int argc, char **argv)
g_test_add_func ("/general/test_nm_ip4_addr_is_localhost", test_nm_ip4_addr_is_localhost);
g_test_add_func ("/general/test_unaligned", test_unaligned);
g_test_add_func ("/general/test_strv_cmp", test_strv_cmp);
g_test_add_func ("/general/test_strstrip_avoid_copy", test_strstrip_avoid_copy);
return g_test_run ();
}