From 7bf9e0d5f67f927ce3e250812e219536aff2b448 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 8 Sep 2023 04:39:15 +0900 Subject: [PATCH 1/4] hashmap: introduce HASHMAP_BASE_FOREACH() and friend --- src/basic/hashmap.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/basic/hashmap.h b/src/basic/hashmap.h index ad85093d69..233f1d7a1e 100644 --- a/src/basic/hashmap.h +++ b/src/basic/hashmap.h @@ -415,6 +415,11 @@ static inline int set_dump_sorted(Set *h, void ***ret, size_t *ret_n) { * the entries were inserted. * It is safe to remove the current entry. */ +#define _HASHMAP_BASE_FOREACH(e, h, i) \ + for (Iterator i = ITERATOR_FIRST; _hashmap_iterate((h), &i, (void**)&(e), NULL); ) +#define HASHMAP_BASE_FOREACH(e, h) \ + _HASHMAP_BASE_FOREACH(e, h, UNIQ_T(i, UNIQ)) + #define _HASHMAP_FOREACH(e, h, i) \ for (Iterator i = ITERATOR_FIRST; hashmap_iterate((h), &i, (void**)&(e), NULL); ) #define HASHMAP_FOREACH(e, h) \ @@ -425,6 +430,11 @@ static inline int set_dump_sorted(Set *h, void ***ret, size_t *ret_n) { #define ORDERED_HASHMAP_FOREACH(e, h) \ _ORDERED_HASHMAP_FOREACH(e, h, UNIQ_T(i, UNIQ)) +#define _HASHMAP_BASE_FOREACH_KEY(e, k, h, i) \ + for (Iterator i = ITERATOR_FIRST; _hashmap_iterate((h), &i, (void**)&(e), (const void**) &(k)); ) +#define HASHMAP_BASE_FOREACH_KEY(e, k, h) \ + _HASHMAP_BASE_FOREACH_KEY(e, k, h, UNIQ_T(i, UNIQ)) + #define _HASHMAP_FOREACH_KEY(e, k, h, i) \ for (Iterator i = ITERATOR_FIRST; hashmap_iterate((h), &i, (void**)&(e), (const void**) &(k)); ) #define HASHMAP_FOREACH_KEY(e, k, h) \ From 08ca764d0ae82651508e010c4f2e762e3edb92b0 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 8 Sep 2023 04:59:39 +0900 Subject: [PATCH 2/4] conf-parser: modernize config_section_new() - add assertions, - rename argument to store result. --- src/shared/conf-parser.c | 9 ++++++--- src/shared/conf-parser.h | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index 68c4b2ca1a..5476c061d7 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -748,9 +748,13 @@ static int config_section_compare_func(const ConfigSection *x, const ConfigSecti DEFINE_HASH_OPS(config_section_hash_ops, ConfigSection, config_section_hash_func, config_section_compare_func); -int config_section_new(const char *filename, unsigned line, ConfigSection **s) { +int config_section_new(const char *filename, unsigned line, ConfigSection **ret) { ConfigSection *cs; + assert(filename); + assert(line > 0); + assert(ret); + cs = malloc0(offsetof(ConfigSection, filename) + strlen(filename) + 1); if (!cs) return -ENOMEM; @@ -758,8 +762,7 @@ int config_section_new(const char *filename, unsigned line, ConfigSection **s) { strcpy(cs->filename, filename); cs->line = line; - *s = TAKE_PTR(cs); - + *ret = TAKE_PTR(cs); return 0; } diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index 902717965c..3fc434ef03 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -136,7 +136,7 @@ static inline ConfigSection* config_section_free(ConfigSection *cs) { } DEFINE_TRIVIAL_CLEANUP_FUNC(ConfigSection*, config_section_free); -int config_section_new(const char *filename, unsigned line, ConfigSection **s); +int config_section_new(const char *filename, unsigned line, ConfigSection **ret); extern const struct hash_ops config_section_hash_ops; unsigned hashmap_find_free_section_line(Hashmap *hashmap); From d9171a230deae234c5e19708c027883434a05fbc Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 8 Sep 2023 05:11:57 +0900 Subject: [PATCH 3/4] conf-parser: check overflow in hashmap_find_free_section_line() Also, this also renames the function, and makes it optionally takes a filename. --- src/network/networkd-route.c | 8 ++++++-- src/shared/conf-parser.c | 21 ++++++++++++++++----- src/shared/conf-parser.h | 5 ++++- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 587bca2b26..6cefd3a9bf 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -1945,7 +1945,9 @@ int network_add_ipv4ll_route(Network *network) { if (!network->ipv4ll_route) return 0; - section_line = hashmap_find_free_section_line(network->routes_by_section); + r = hashmap_by_section_find_unused_line(network->routes_by_section, network->filename, §ion_line); + if (r < 0) + return r; /* IPv4LLRoute= is in [Network] section. */ r = route_new_static(network, network->filename, section_line, &n); @@ -1978,7 +1980,9 @@ int network_add_default_route_on_device(Network *network) { if (!network->default_route_on_device) return 0; - section_line = hashmap_find_free_section_line(network->routes_by_section); + r = hashmap_by_section_find_unused_line(network->routes_by_section, network->filename, §ion_line); + if (r < 0) + return r; /* DefaultRouteOnDevice= is in [Network] section. */ r = route_new_static(network, network->filename, section_line, &n); diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index 5476c061d7..7d51927845 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -766,16 +766,27 @@ int config_section_new(const char *filename, unsigned line, ConfigSection **ret) return 0; } -unsigned hashmap_find_free_section_line(Hashmap *hashmap) { +int hashmap_by_section_find_unused_line( + Hashmap *entries_by_section, + const char *filename, + unsigned *ret) { + ConfigSection *cs; unsigned n = 0; void *entry; - HASHMAP_FOREACH_KEY(entry, cs, hashmap) - if (n < cs->line) - n = cs->line; + HASHMAP_FOREACH_KEY(entry, cs, entries_by_section) { + if (filename && !streq(cs->filename, filename)) + continue; + n = MAX(n, cs->line); + } - return n + 1; + /* overflow? */ + if (n >= UINT_MAX) + return -EFBIG; + + *ret = n + 1; + return 0; } #define DEFINE_PARSER(type, vartype, conv_func) \ diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index 3fc434ef03..74943523b3 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -138,7 +138,10 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(ConfigSection*, config_section_free); int config_section_new(const char *filename, unsigned line, ConfigSection **ret); extern const struct hash_ops config_section_hash_ops; -unsigned hashmap_find_free_section_line(Hashmap *hashmap); +int hashmap_by_section_find_unused_line( + Hashmap *entries_by_section, + const char *filename, + unsigned *ret); static inline bool section_is_invalid(ConfigSection *section) { /* If this returns false, then it does _not_ mean the section is valid. */ From e63c6e9ffa146949ab8fb27f7e65b87bbbaf241e Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 8 Sep 2023 04:42:48 +0900 Subject: [PATCH 4/4] conf-parser: introduce ordered_hashmap_by_section_find_unused_line() --- src/shared/conf-parser.c | 6 +++--- src/shared/conf-parser.h | 16 ++++++++++++++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index 7d51927845..63030d4a2d 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -766,8 +766,8 @@ int config_section_new(const char *filename, unsigned line, ConfigSection **ret) return 0; } -int hashmap_by_section_find_unused_line( - Hashmap *entries_by_section, +int _hashmap_by_section_find_unused_line( + HashmapBase *entries_by_section, const char *filename, unsigned *ret) { @@ -775,7 +775,7 @@ int hashmap_by_section_find_unused_line( unsigned n = 0; void *entry; - HASHMAP_FOREACH_KEY(entry, cs, entries_by_section) { + HASHMAP_BASE_FOREACH_KEY(entry, cs, entries_by_section) { if (filename && !streq(cs->filename, filename)) continue; n = MAX(n, cs->line); diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index 74943523b3..140883969c 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -138,10 +138,22 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(ConfigSection*, config_section_free); int config_section_new(const char *filename, unsigned line, ConfigSection **ret); extern const struct hash_ops config_section_hash_ops; -int hashmap_by_section_find_unused_line( - Hashmap *entries_by_section, +int _hashmap_by_section_find_unused_line( + HashmapBase *entries_by_section, const char *filename, unsigned *ret); +static inline int hashmap_by_section_find_unused_line( + Hashmap *entries_by_section, + const char *filename, + unsigned *ret) { + return _hashmap_by_section_find_unused_line(HASHMAP_BASE(entries_by_section), filename, ret); +} +static inline int ordered_hashmap_by_section_find_unused_line( + OrderedHashmap *entries_by_section, + const char *filename, + unsigned *ret) { + return _hashmap_by_section_find_unused_line(HASHMAP_BASE(entries_by_section), filename, ret); +} static inline bool section_is_invalid(ConfigSection *section) { /* If this returns false, then it does _not_ mean the section is valid. */