glib-aux: merge branch 'th/str-buf-stack-allocated'

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1203
This commit is contained in:
Thomas Haller 2022-05-09 19:18:48 +02:00
commit c6e41b2df3
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
13 changed files with 143 additions and 60 deletions

View file

@ -1553,7 +1553,7 @@ _external_ids_to_string(const GArray *arr)
if (!arr) if (!arr)
return g_strdup("empty"); return g_strdup("empty");
nm_str_buf_init(&strbuf, NM_UTILS_GET_NEXT_REALLOC_SIZE_104, FALSE); strbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_104, FALSE);
nm_str_buf_append(&strbuf, "["); nm_str_buf_append(&strbuf, "[");
for (i = 0; i < arr->len; i++) { for (i = 0; i < arr->len; i++) {
const NMUtilsNamedValue *n = &g_array_index(arr, NMUtilsNamedValue, i); const NMUtilsNamedValue *n = &g_array_index(arr, NMUtilsNamedValue, i);

View file

@ -5113,7 +5113,7 @@ nm_utils_spawn_helper(const char *const *args,
fcntl(info->child_stdout, F_SETFL, fd_flags | O_NONBLOCK); fcntl(info->child_stdout, F_SETFL, fd_flags | O_NONBLOCK);
/* Watch process stdin */ /* Watch process stdin */
nm_str_buf_init(&info->out_buffer, 32, TRUE); info->out_buffer = NM_STR_BUF_INIT(32, TRUE);
for (arg = args; *arg; arg++) { for (arg = args; *arg; arg++) {
nm_str_buf_append(&info->out_buffer, *arg); nm_str_buf_append(&info->out_buffer, *arg);
nm_str_buf_append_c(&info->out_buffer, '\0'); nm_str_buf_append_c(&info->out_buffer, '\0');
@ -5127,7 +5127,7 @@ nm_utils_spawn_helper(const char *const *args,
g_source_attach(info->output_source, g_main_context_get_thread_default()); g_source_attach(info->output_source, g_main_context_get_thread_default());
/* Watch process stdout */ /* Watch process stdout */
nm_str_buf_init(&info->in_buffer, NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE); info->in_buffer = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE);
info->input_source = nm_g_unix_fd_source_new(info->child_stdout, info->input_source = nm_g_unix_fd_source_new(info->child_stdout,
G_IO_IN | G_IO_ERR | G_IO_HUP, G_IO_IN | G_IO_ERR | G_IO_HUP,
G_PRIORITY_DEFAULT, G_PRIORITY_DEFAULT,

View file

@ -210,7 +210,7 @@ nm_keyfile_plugin_kf_set_integer_list_uint(GKeyFile *kf,
g_return_if_fail(group && group[0]); g_return_if_fail(group && group[0]);
g_return_if_fail(key && key[0]); g_return_if_fail(key && key[0]);
nm_str_buf_init(&strbuf, length * 4u + 2u, FALSE); strbuf = NM_STR_BUF_INIT(length * 4u + 2u, FALSE);
for (i = 0; i < length; i++) for (i = 0; i < length; i++)
nm_str_buf_append_printf(&strbuf, "%u;", data[i]); nm_str_buf_append_printf(&strbuf, "%u;", data[i]);
nm_keyfile_plugin_kf_set_value(kf, group, key, nm_str_buf_get_str(&strbuf)); nm_keyfile_plugin_kf_set_value(kf, group, key, nm_str_buf_get_str(&strbuf));
@ -231,7 +231,7 @@ nm_keyfile_plugin_kf_set_integer_list_uint8(GKeyFile *kf,
g_return_if_fail(group && group[0]); g_return_if_fail(group && group[0]);
g_return_if_fail(key && key[0]); g_return_if_fail(key && key[0]);
nm_str_buf_init(&strbuf, length * 4u + 2u, FALSE); strbuf = NM_STR_BUF_INIT(length * 4u + 2u, FALSE);
for (i = 0; i < length; i++) for (i = 0; i < length; i++)
nm_str_buf_append_printf(&strbuf, "%u;", (guint) data[i]); nm_str_buf_append_printf(&strbuf, "%u;", (guint) data[i]);
nm_keyfile_plugin_kf_set_value(kf, group, key, nm_str_buf_get_str(&strbuf)); nm_keyfile_plugin_kf_set_value(kf, group, key, nm_str_buf_get_str(&strbuf));
@ -542,7 +542,7 @@ _keyfile_key_encode(const char *name, char **out_to_free)
len = i + strlen(&name[i]); len = i + strlen(&name[i]);
nm_assert(len == strlen(name)); nm_assert(len == strlen(name));
nm_str_buf_init(&str, len + 15u, FALSE); str = NM_STR_BUF_INIT(len + 15u, FALSE);
if (name[0] == ' ') { if (name[0] == ' ') {
nm_assert(i == 0); nm_assert(i == 0);

View file

@ -4374,7 +4374,7 @@ nm_keyfile_utils_create_filename(const char *name, gboolean with_extension)
g_return_val_if_fail(name && name[0], NULL); g_return_val_if_fail(name && name[0], NULL);
nm_str_buf_init(&str, 0, FALSE); str = NM_STR_BUF_INIT(0, FALSE);
len = strlen(name); len = strlen(name);

View file

@ -435,7 +435,7 @@ nm_bridge_vlan_to_str(const NMBridgeVlan *vlan, GError **error)
* future if more parameters are added to the object that could * future if more parameters are added to the object that could
* make it invalid. */ * make it invalid. */
nm_str_buf_init(&string, NM_UTILS_GET_NEXT_REALLOC_SIZE_32, FALSE); string = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_32, FALSE);
if (vlan->vid_start == vlan->vid_end) if (vlan->vid_start == vlan->vid_end)
nm_str_buf_append_printf(&string, "%u", vlan->vid_start); nm_str_buf_append_printf(&string, "%u", vlan->vid_start);

View file

@ -3814,7 +3814,7 @@ nm_ip_routing_rule_to_string(const NMIPRoutingRule *self,
} }
} }
nm_str_buf_init(&str, NM_UTILS_GET_NEXT_REALLOC_SIZE_32, FALSE); str = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_32, FALSE);
if (self->priority_has) { if (self->priority_has) {
nm_str_buf_append_printf(nm_str_buf_append_required_delimiter(&str, ' '), nm_str_buf_append_printf(nm_str_buf_append_required_delimiter(&str, ' '),

View file

@ -142,7 +142,7 @@ _nm_utils_enum_to_str_full(GType type,
flags_separator = flags_separator ?: " "; flags_separator = flags_separator ?: " ";
nm_str_buf_init(&strbuf, 16, FALSE); strbuf = NM_STR_BUF_INIT(16, FALSE);
for (; value_infos && value_infos->nick; value_infos++) { for (; value_infos && value_infos->nick; value_infos++) {
nm_assert(_enum_is_valid_flags_nick(value_infos->nick)); nm_assert(_enum_is_valid_flags_nick(value_infos->nick));

View file

@ -2998,7 +2998,7 @@ nm_utils_buf_utf8safe_unescape(const char *str,
return str; return str;
} }
nm_str_buf_init(&strbuf, len + 1u, FALSE); strbuf = NM_STR_BUF_INIT(len + 1u, FALSE);
nm_str_buf_append_len(&strbuf, str, s - str); nm_str_buf_append_len(&strbuf, str, s - str);
str = s; str = s;
@ -3165,7 +3165,7 @@ nm_utils_buf_utf8safe_escape(gconstpointer buf,
return str; return str;
} }
nm_str_buf_init(&strbuf, buflen + 5, NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_SECRET)); strbuf = NM_STR_BUF_INIT(buflen + 5, NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_SECRET));
s = str; s = str;
do { do {
@ -5841,10 +5841,22 @@ _nm_str_buf_ensure_size(NMStrBuf *strbuf, gsize new_size, gboolean reserve_exact
new_size = nm_utils_get_next_realloc_size(!strbuf->_priv_do_bzero_mem, new_size); new_size = nm_utils_get_next_realloc_size(!strbuf->_priv_do_bzero_mem, new_size);
} }
strbuf->_priv_str = nm_secret_mem_realloc(strbuf->_priv_str, if (strbuf->_priv_malloced) {
strbuf->_priv_do_bzero_mem, strbuf->_priv_str = nm_secret_mem_realloc(strbuf->_priv_str,
strbuf->_priv_allocated, strbuf->_priv_do_bzero_mem,
new_size); strbuf->_priv_allocated,
new_size);
} else {
char *old = strbuf->_priv_str;
strbuf->_priv_str = g_malloc(new_size);
if (strbuf->_priv_len > 0) {
memcpy(strbuf->_priv_str, old, strbuf->_priv_len);
if (strbuf->_priv_do_bzero_mem)
nm_explicit_bzero(old, strbuf->_priv_len);
}
strbuf->_priv_malloced = TRUE;
}
strbuf->_priv_allocated = new_size; strbuf->_priv_allocated = new_size;
} }

View file

@ -26,6 +26,7 @@ typedef struct _NMStrBuf {
}; };
bool _priv_do_bzero_mem; bool _priv_do_bzero_mem;
bool _priv_malloced;
} NMStrBuf; } NMStrBuf;
/*****************************************************************************/ /*****************************************************************************/
@ -36,28 +37,55 @@ _nm_str_buf_assert(const NMStrBuf *strbuf)
nm_assert(strbuf); nm_assert(strbuf);
nm_assert((!!strbuf->_priv_str) == (strbuf->_priv_allocated > 0)); nm_assert((!!strbuf->_priv_str) == (strbuf->_priv_allocated > 0));
nm_assert(strbuf->_priv_len <= strbuf->_priv_allocated); nm_assert(strbuf->_priv_len <= strbuf->_priv_allocated);
nm_assert(!strbuf->_priv_malloced || strbuf->_priv_str);
}
static inline NMStrBuf
NM_STR_BUF_INIT_FULL(char *str,
gsize len,
gsize allocated,
gboolean malloced,
gboolean do_bzero_mem)
{
NMStrBuf strbuf = {
._priv_str = allocated > 0 ? str : NULL,
._priv_allocated = allocated,
._priv_len = len,
._priv_do_bzero_mem = do_bzero_mem,
._priv_malloced = allocated > 0 && malloced,
};
_nm_str_buf_assert(&strbuf);
return strbuf;
} }
static inline NMStrBuf static inline NMStrBuf
NM_STR_BUF_INIT(gsize allocated, gboolean do_bzero_mem) NM_STR_BUF_INIT(gsize allocated, gboolean do_bzero_mem)
{ {
NMStrBuf strbuf = { return NM_STR_BUF_INIT_FULL(allocated > 0 ? g_malloc(allocated) : NULL,
._priv_str = allocated ? g_malloc(allocated) : NULL, 0,
._priv_allocated = allocated, allocated,
._priv_len = 0, allocated > 0,
._priv_do_bzero_mem = do_bzero_mem, do_bzero_mem);
};
return strbuf;
} }
static inline void #define NM_STR_BUF_INIT_A(size, do_bzero_mem) \
nm_str_buf_init(NMStrBuf *strbuf, gsize len, bool do_bzero_mem) NM_STR_BUF_INIT_FULL( \
{ g_alloca(size), \
nm_assert(strbuf); 0, \
*strbuf = NM_STR_BUF_INIT(len, do_bzero_mem); NM_STATIC_ASSERT_EXPR_1((size) > 0 && (size) <= NM_UTILS_GET_NEXT_REALLOC_SIZE_488) \
_nm_str_buf_assert(strbuf); ? (size) \
} : 0, \
FALSE, \
(do_bzero_mem));
#define NM_STR_BUF_INIT_ARR(arr, do_bzero_mem) \
NM_STR_BUF_INIT_FULL((arr), \
0, \
NM_STATIC_ASSERT_EXPR_1(sizeof(arr) > sizeof(char *)) ? sizeof(arr) : 0, \
FALSE, \
(do_bzero_mem));
void _nm_str_buf_ensure_size(NMStrBuf *strbuf, gsize new_size, gboolean reserve_exact); void _nm_str_buf_ensure_size(NMStrBuf *strbuf, gsize new_size, gboolean reserve_exact);
@ -359,10 +387,10 @@ static inline gboolean
nm_str_buf_is_initalized(NMStrBuf *strbuf) nm_str_buf_is_initalized(NMStrBuf *strbuf)
{ {
nm_assert(strbuf); nm_assert(strbuf);
#if NM_MORE_ASSERTS if (NM_MORE_ASSERTS > 0) {
if (strbuf->_priv_str) if (strbuf->_priv_str)
_nm_str_buf_assert(strbuf); _nm_str_buf_assert(strbuf);
#endif }
return !!strbuf->_priv_str; return !!strbuf->_priv_str;
} }
@ -463,9 +491,11 @@ nm_str_buf_get_char(const NMStrBuf *strbuf, gsize index)
* Returns: (transfer full): the string of the buffer * Returns: (transfer full): the string of the buffer
* which must be freed by the caller. The @strbuf * which must be freed by the caller. The @strbuf
* is afterwards in undefined state, though it can be * is afterwards in undefined state, though it can be
* reused after nm_str_buf_init(). * reused after resetting with NM_STR_BUF_INIT().
* Note that if no string is allocated yet (after nm_str_buf_init() with * Note that if no string is allocated yet (after NM_STR_BUF_INIT() with
* length zero), this will return %NULL. */ * length zero), this will return %NULL.
*
* If the buffer was not malloced before, it will be malloced now. */
static inline char * static inline char *
nm_str_buf_finalize(NMStrBuf *strbuf, gsize *out_len) nm_str_buf_finalize(NMStrBuf *strbuf, gsize *out_len)
{ {
@ -476,6 +506,16 @@ nm_str_buf_finalize(NMStrBuf *strbuf, gsize *out_len)
if (!strbuf->_priv_str) if (!strbuf->_priv_str)
return NULL; return NULL;
if (!strbuf->_priv_malloced) {
char *str = g_steal_pointer(&strbuf->_priv_str);
char *result;
result = g_strndup(str, strbuf->_priv_len);
if (strbuf->_priv_do_bzero_mem)
nm_explicit_bzero(str, strbuf->_priv_len);
return result;
}
nm_str_buf_maybe_expand(strbuf, 1, TRUE); nm_str_buf_maybe_expand(strbuf, 1, TRUE);
strbuf->_priv_str[strbuf->_priv_len] = '\0'; strbuf->_priv_str[strbuf->_priv_len] = '\0';
@ -507,7 +547,7 @@ nm_str_buf_finalize_to_gbytes(NMStrBuf *strbuf)
* *
* Frees the associated memory of @strbuf. The buffer * Frees the associated memory of @strbuf. The buffer
* afterwards is in undefined state, but can be re-initialized * afterwards is in undefined state, but can be re-initialized
* with nm_str_buf_init(). * with NM_STR_BUF_INIT().
*/ */
static inline void static inline void
nm_str_buf_destroy(NMStrBuf *strbuf) nm_str_buf_destroy(NMStrBuf *strbuf)
@ -517,7 +557,8 @@ nm_str_buf_destroy(NMStrBuf *strbuf)
_nm_str_buf_assert(strbuf); _nm_str_buf_assert(strbuf);
if (strbuf->_priv_do_bzero_mem) if (strbuf->_priv_do_bzero_mem)
nm_explicit_bzero(strbuf->_priv_str, strbuf->_priv_len); nm_explicit_bzero(strbuf->_priv_str, strbuf->_priv_len);
g_free(strbuf->_priv_str); if (strbuf->_priv_malloced)
g_free(strbuf->_priv_str);
/* the buffer is in invalid state afterwards, however, we clear it /* the buffer is in invalid state afterwards, however, we clear it
* so far, that nm_auto_str_buf is happy when calling * so far, that nm_auto_str_buf is happy when calling

View file

@ -917,27 +917,58 @@ test_nm_str_buf(void)
{ {
guint i_run; guint i_run;
for (i_run = 0; TRUE; i_run++) { for (i_run = 0; i_run < 1000; i_run++) {
nm_auto_str_buf NMStrBuf strbuf = {}; char stack_buf[1024];
nm_auto_free_gstring GString *gstr = NULL; nm_auto_str_buf NMStrBuf strbuf;
nm_auto_free_gstring GString *gstr = NULL;
int i, j, k; int i, j, k;
int c; int c;
nm_str_buf_init(&strbuf, nmtst_get_rand_uint32() % 200u + 1u, nmtst_get_rand_bool()); switch (nmtst_get_rand_uint32() % 10) {
case 0:
memset(&strbuf, 0, sizeof(strbuf));
break;
case 1 ... 4:
strbuf = NM_STR_BUF_INIT_FULL(stack_buf,
0,
nmtst_get_rand_uint32() % sizeof(stack_buf),
FALSE,
nmtst_get_rand_bool());
break;
default:
strbuf = NM_STR_BUF_INIT(nmtst_get_rand_uint32() % 200u + 1u, nmtst_get_rand_bool());
break;
}
if (i_run < 1000) { c = nmtst_get_rand_word_length(NULL);
c = nmtst_get_rand_word_length(NULL); for (i = 0; i < c; i++)
for (i = 0; i < c; i++) nm_str_buf_append_c(&strbuf, '0' + (i % 10));
nm_str_buf_append_c(&strbuf, '0' + (i % 10)); gstr = g_string_new(nm_str_buf_get_str(&strbuf));
gstr = g_string_new(nm_str_buf_get_str(&strbuf)); j = nmtst_get_rand_uint32() % (strbuf.len + 1);
j = nmtst_get_rand_uint32() % (strbuf.len + 1); k = nmtst_get_rand_uint32() % (strbuf.len - j + 2) - 1;
k = nmtst_get_rand_uint32() % (strbuf.len - j + 2) - 1;
nm_str_buf_erase(&strbuf, j, k, nmtst_get_rand_bool()); nm_str_buf_erase(&strbuf, j, k, nmtst_get_rand_bool());
g_string_erase(gstr, j, k); g_string_erase(gstr, j, k);
if (gstr->str[0])
g_assert_cmpstr(gstr->str, ==, nm_str_buf_get_str(&strbuf)); g_assert_cmpstr(gstr->str, ==, nm_str_buf_get_str(&strbuf));
else
g_assert(NM_IN_STRSET(nm_str_buf_get_str(&strbuf), NULL, ""));
}
for (i_run = 0; i_run < 50; i_run++) {
char stack_buf[20];
nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT_ARR(stack_buf, nmtst_get_rand_bool());
nm_str_buf_append_c_len(&strbuf, 'a', nmtst_get_rand_uint32() % (sizeof(stack_buf) * 2));
if (strbuf.len <= sizeof(stack_buf)) {
g_assert(stack_buf == nm_str_buf_get_str_unsafe(&strbuf));
} else } else
return; g_assert(stack_buf != nm_str_buf_get_str_unsafe(&strbuf));
if (strbuf.len < sizeof(stack_buf)) {
g_assert(stack_buf == nm_str_buf_get_str(&strbuf));
} else
g_assert(stack_buf != nm_str_buf_get_str(&strbuf));
} }
} }

View file

@ -468,7 +468,7 @@ _domains_to_string(gboolean include_level_override,
* nm_logging_setup(), because we want to expand "DEFAULT" and "ALL". * nm_logging_setup(), because we want to expand "DEFAULT" and "ALL".
*/ */
nm_str_buf_init(&sbuf, NM_UTILS_GET_NEXT_REALLOC_SIZE_40, FALSE); sbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_40, FALSE);
for (diter = &domain_desc[0]; diter->name; diter++) { for (diter = &domain_desc[0]; diter->name; diter++) {
/* If it's set for any lower level, it will also be set for LOGL_ERR */ /* If it's set for any lower level, it will also be set for LOGL_ERR */

View file

@ -14,12 +14,12 @@
* certain buffer sizes. * certain buffer sizes.
* *
* The use of these defines is to get favorable allocation sequences. * The use of these defines is to get favorable allocation sequences.
* For example, nm_str_buf_init() asks for an initial allocation size. Note that * For example, NM_STR_BUF_INIT() asks for an initial allocation size. Note that
* it reserves the exactly requested amount, under the assumption that the * it reserves the exactly requested amount, under the assumption that the
* user may know how many bytes will be required. However, often the caller * user may know how many bytes will be required. However, often the caller
* doesn't know in advance, and NMStrBuf grows exponentially by calling * doesn't know in advance, and NMStrBuf grows exponentially by calling
* nm_utils_get_next_realloc_size(). * nm_utils_get_next_realloc_size().
* Imagine you call nm_str_buf_init() with an initial buffer size 100, and you * Imagine you call NM_STR_BUF_INIT() with an initial buffer size 100, and you
* add one character at a time. Then the first reallocation will increase the * add one character at a time. Then the first reallocation will increase the
* buffer size only from 100 to 104. * buffer size only from 100 to 104.
* If you however start with an initial buffer size of 104, then the next reallocation * If you however start with an initial buffer size of 104, then the next reallocation

View file

@ -393,7 +393,7 @@ queue_string_to_helper(AuthRequest *request, const char *response)
g_return_if_fail(response); g_return_if_fail(response);
if (!nm_str_buf_is_initalized(&request->out_buffer)) if (!nm_str_buf_is_initalized(&request->out_buffer))
nm_str_buf_init(&request->out_buffer, strlen(response) + 2u, TRUE); request->out_buffer = NM_STR_BUF_INIT(strlen(response) + 2u, TRUE);
nm_str_buf_append(&request->out_buffer, response); nm_str_buf_append(&request->out_buffer, response);
nm_str_buf_ensure_trailing_c(&request->out_buffer, '\n'); nm_str_buf_ensure_trailing_c(&request->out_buffer, '\n');
@ -587,10 +587,9 @@ create_request(NMPolkitListener *listener,
.cookie = g_strdup(cookie), .cookie = g_strdup(cookie),
.request_any_response = FALSE, .request_any_response = FALSE,
.request_is_completed = FALSE, .request_is_completed = FALSE,
.in_buffer = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE),
}; };
nm_str_buf_init(&request->in_buffer, NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE);
c_list_link_tail(&listener->request_lst_head, &request->request_lst); c_list_link_tail(&listener->request_lst_head, &request->request_lst);
return request; return request;
} }