mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-11 05:17:44 +03:00
Merge pull request #23453 from keszybz/strv-parsing
Add strv methods with externally-supplied size argument and speed up parsing of /etc/hosts
This commit is contained in:
commit
6910d43af5
@ -403,27 +403,33 @@ char* strv_join_full(char * const *l, const char *separator, const char *prefix,
|
||||
return r;
|
||||
}
|
||||
|
||||
int strv_push(char ***l, char *value) {
|
||||
char **c;
|
||||
size_t n;
|
||||
int strv_push_with_size(char ***l, size_t *n, char *value) {
|
||||
/* n is a pointer to a variable to store the size of l.
|
||||
* If not given (i.e. n is NULL or *n is SIZE_MAX), size will be calculated using strv_length().
|
||||
* If n is not NULL, the size after the push will be returned.
|
||||
* If value is empty, no action is taken and *n is not set. */
|
||||
|
||||
if (!value)
|
||||
return 0;
|
||||
|
||||
n = strv_length(*l);
|
||||
size_t size = n ? *n : SIZE_MAX;
|
||||
if (size == SIZE_MAX)
|
||||
size = strv_length(*l);
|
||||
|
||||
/* Check for overflow */
|
||||
if (n > SIZE_MAX-2)
|
||||
if (size > SIZE_MAX-2)
|
||||
return -ENOMEM;
|
||||
|
||||
c = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(n + 2), sizeof(char*));
|
||||
char **c = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(size + 2), sizeof(char*));
|
||||
if (!c)
|
||||
return -ENOMEM;
|
||||
|
||||
c[n] = value;
|
||||
c[n+1] = NULL;
|
||||
c[size] = value;
|
||||
c[size+1] = NULL;
|
||||
|
||||
*l = c;
|
||||
if (n)
|
||||
*n = size + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -484,10 +490,10 @@ int strv_insert(char ***l, size_t position, char *value) {
|
||||
return free_and_replace(*l, c);
|
||||
}
|
||||
|
||||
int strv_consume(char ***l, char *value) {
|
||||
int strv_consume_with_size(char ***l, size_t *n, char *value) {
|
||||
int r;
|
||||
|
||||
r = strv_push(l, value);
|
||||
r = strv_push_with_size(l, n, value);
|
||||
if (r < 0)
|
||||
free(value);
|
||||
|
||||
@ -529,7 +535,7 @@ int strv_prepend(char ***l, const char *value) {
|
||||
return strv_consume_prepend(l, v);
|
||||
}
|
||||
|
||||
int strv_extend(char ***l, const char *value) {
|
||||
int strv_extend_with_size(char ***l, size_t *n, const char *value) {
|
||||
char *v;
|
||||
|
||||
if (!value)
|
||||
@ -539,7 +545,7 @@ int strv_extend(char ***l, const char *value) {
|
||||
if (!v)
|
||||
return -ENOMEM;
|
||||
|
||||
return strv_consume(l, v);
|
||||
return strv_consume_with_size(l, n, v);
|
||||
}
|
||||
|
||||
int strv_extend_front(char ***l, const char *value) {
|
||||
|
@ -35,18 +35,36 @@ size_t strv_length(char * const *l) _pure_;
|
||||
int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates);
|
||||
int strv_extend_strv_concat(char ***a, char * const *b, const char *suffix);
|
||||
int strv_prepend(char ***l, const char *value);
|
||||
int strv_extend(char ***l, const char *value);
|
||||
|
||||
/* _with_size() are lower-level functions where the size can be provided externally,
|
||||
* which allows us to skip iterating over the strv to find the end, which saves
|
||||
* a bit of time and reduces the complexity of appending from O(n²) to O(n). */
|
||||
|
||||
int strv_extend_with_size(char ***l, size_t *n, const char *value);
|
||||
static inline int strv_extend(char ***l, const char *value) {
|
||||
return strv_extend_with_size(l, NULL, value);
|
||||
}
|
||||
|
||||
int strv_extendf(char ***l, const char *format, ...) _printf_(2,0);
|
||||
int strv_extend_front(char ***l, const char *value);
|
||||
int strv_push(char ***l, char *value);
|
||||
|
||||
int strv_push_with_size(char ***l, size_t *n, char *value);
|
||||
static inline int strv_push(char ***l, char *value) {
|
||||
return strv_push_with_size(l, NULL, value);
|
||||
}
|
||||
int strv_push_pair(char ***l, char *a, char *b);
|
||||
|
||||
int strv_insert(char ***l, size_t position, char *value);
|
||||
|
||||
static inline int strv_push_prepend(char ***l, char *value) {
|
||||
return strv_insert(l, 0, value);
|
||||
}
|
||||
|
||||
int strv_consume(char ***l, char *value);
|
||||
int strv_consume_with_size(char ***l, size_t *n, char *value);
|
||||
static inline int strv_consume(char ***l, char *value) {
|
||||
return strv_consume_with_size(l, NULL, value);
|
||||
}
|
||||
|
||||
int strv_consume_pair(char ***l, char *a, char *b);
|
||||
int strv_consume_prepend(char ***l, char *value);
|
||||
|
||||
|
@ -127,7 +127,7 @@ static int parse_line(EtcHosts *hosts, unsigned nr, const char *line) {
|
||||
continue;
|
||||
}
|
||||
|
||||
r = strv_extend(&item->names, name);
|
||||
r = strv_extend_with_size(&item->names, &item->n_names, name);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
@ -391,7 +391,7 @@ int manager_etc_hosts_lookup(Manager *m, DnsQuestion* q, DnsAnswer **answer) {
|
||||
}
|
||||
|
||||
if (found_ptr) {
|
||||
r = dns_answer_reserve(answer, strv_length(item->names));
|
||||
r = dns_answer_reserve(answer, item->n_names);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -9,6 +9,7 @@ typedef struct EtcHostsItem {
|
||||
struct in_addr_data address;
|
||||
|
||||
char **names;
|
||||
size_t n_names;
|
||||
} EtcHostsItem;
|
||||
|
||||
typedef struct EtcHostsItemByName {
|
||||
|
@ -601,6 +601,25 @@ TEST(strv_extend_strv) {
|
||||
assert_se(strv_length(n) == 4);
|
||||
}
|
||||
|
||||
TEST(strv_extend_with_size) {
|
||||
_cleanup_strv_free_ char **a = NULL;
|
||||
size_t n = SIZE_MAX;
|
||||
|
||||
a = strv_new("test", "test1");
|
||||
assert_se(a);
|
||||
|
||||
assert_se(strv_extend_with_size(&a, &n, "test2") >= 0);
|
||||
assert_se(n == 3);
|
||||
assert_se(strv_extend_with_size(&a, &n, "test3") >= 0);
|
||||
assert_se(n == 4);
|
||||
|
||||
assert_se(streq(a[0], "test"));
|
||||
assert_se(streq(a[1], "test1"));
|
||||
assert_se(streq(a[2], "test2"));
|
||||
assert_se(streq(a[3], "test3"));
|
||||
assert_se(a[4] == NULL);
|
||||
}
|
||||
|
||||
TEST(strv_extend) {
|
||||
_cleanup_strv_free_ char **a = NULL, **b = NULL;
|
||||
|
||||
@ -746,6 +765,30 @@ TEST(strv_push_prepend) {
|
||||
assert_se(!a[5]);
|
||||
}
|
||||
|
||||
TEST(strv_push_with_size) {
|
||||
_cleanup_strv_free_ char **a = NULL;
|
||||
size_t n = 0;
|
||||
char *i, *j;
|
||||
|
||||
assert_se(i = strdup("foo"));
|
||||
assert_se(strv_push_with_size(&a, &n, i) >= 0);
|
||||
assert_se(n == 1);
|
||||
|
||||
assert_se(i = strdup("a"));
|
||||
assert_se(j = strdup("b"));
|
||||
assert_se(strv_push_with_size(&a, &n, i) >= 0);
|
||||
assert_se(n == 2);
|
||||
assert_se(strv_push_with_size(&a, &n, j) >= 0);
|
||||
assert_se(n == 3);
|
||||
|
||||
assert_se(streq_ptr(a[0], "foo"));
|
||||
assert_se(streq_ptr(a[1], "a"));
|
||||
assert_se(streq_ptr(a[2], "b"));
|
||||
assert_se(streq_ptr(a[3], NULL));
|
||||
|
||||
assert_se(n = strv_length(a));
|
||||
}
|
||||
|
||||
TEST(strv_push) {
|
||||
_cleanup_strv_free_ char **a = NULL;
|
||||
char *i, *j;
|
||||
|
1000
test/fuzz/fuzz-etc-hosts/timeout-strv
Normal file
1000
test/fuzz/fuzz-etc-hosts/timeout-strv
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user