]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
basic/set: add set_ensure_consume()
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 4 Jun 2020 17:46:14 +0000 (19:46 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 24 Jun 2020 08:38:15 +0000 (10:38 +0200)
This combines set_ensure_allocated() with set_consume(). The cool thing is that
because we know the hash ops, we can correctly free the item if appropriate.
Similarly to set_consume(), the goal is to simplify handling of the case where
the item needs to be freed on error and if already present in the set.

src/basic/hashmap.c
src/basic/set.h
src/test/test-set.c
test/fuzz/fuzz-network-parser/dns-trust-anchor-duplicate.network [new file with mode: 0644]

index c876662a0bf3c87f9249834497c3f4e1d49b0314..ae3235d51856637599ef6568cbd342378de98b22 100644 (file)
@@ -1257,6 +1257,20 @@ int _set_ensure_put(Set **s, const struct hash_ops *hash_ops, const void *key  H
         return set_put(*s, key);
 }
 
+int _set_ensure_consume(Set **s, const struct hash_ops *hash_ops, void *key  HASHMAP_DEBUG_PARAMS) {
+        int r;
+
+        r = _set_ensure_put(s, hash_ops, key  HASHMAP_DEBUG_PASS_ARGS);
+        if (r <= 0) {
+                if (hash_ops && hash_ops->free_key)
+                        hash_ops->free_key(key);
+                else
+                        free(key);
+        }
+
+        return r;
+}
+
 int hashmap_replace(Hashmap *h, const void *key, void *value) {
         struct swap_entries swap;
         struct plain_hashmap_entry *e;
index cdc4abaa42ff9980c78311853baf736af39004f8..3684a00f78c303514d883ed7f4da818cdb59d3d8 100644 (file)
@@ -123,6 +123,9 @@ static inline char **set_get_strv(Set *s) {
 int _set_ensure_put(Set **s, const struct hash_ops *hash_ops, const void *key  HASHMAP_DEBUG_PARAMS);
 #define set_ensure_put(s, hash_ops, key) _set_ensure_put(s, hash_ops, key  HASHMAP_DEBUG_SRC_ARGS)
 
+int _set_ensure_consume(Set **s, const struct hash_ops *hash_ops, void *key  HASHMAP_DEBUG_PARAMS);
+#define set_ensure_consume(s, hash_ops, key) _set_ensure_consume(s, hash_ops, key  HASHMAP_DEBUG_SRC_ARGS)
+
 int set_consume(Set *s, void *value);
 int set_put_strdup(Set **s, const char *p);
 int set_put_strdupv(Set **s, char **l);
index 7213abda01cbb76eff755b5c52378652b2bc8dd7..d3e6de79789c685b3a4ef06914ecab3f96792dce 100644 (file)
@@ -128,6 +128,28 @@ static void test_set_ensure_put(void) {
         assert_se(set_size(m) == 2);
 }
 
+static void test_set_ensure_consume(void) {
+        _cleanup_set_free_ Set *m = NULL;
+        char *s, *t;
+
+        assert_se(s = strdup("a"));
+        assert_se(set_ensure_consume(&m, &string_hash_ops_free, s) == 1);
+
+        assert_se(t = strdup("a"));
+        assert_se(set_ensure_consume(&m, &string_hash_ops_free, t) == 0);
+
+        assert_se(t = strdup("a"));
+        assert_se(set_ensure_consume(&m, &string_hash_ops_free, t) == 0);
+
+        assert_se(t = strdup("b"));
+        assert_se(set_ensure_consume(&m, &string_hash_ops_free, t) == 1);
+
+        assert_se(t = strdup("b"));
+        assert_se(set_ensure_consume(&m, &string_hash_ops_free, t) == 0);
+
+        assert_se(set_size(m) == 2);
+}
+
 int main(int argc, const char *argv[]) {
         test_set_steal_first();
         test_set_free_with_destructor();
@@ -137,6 +159,7 @@ int main(int argc, const char *argv[]) {
         test_set_put_strdupv();
         test_set_ensure_allocated();
         test_set_ensure_put();
+        test_set_ensure_consume();
 
         return 0;
 }
diff --git a/test/fuzz/fuzz-network-parser/dns-trust-anchor-duplicate.network b/test/fuzz/fuzz-network-parser/dns-trust-anchor-duplicate.network
new file mode 100644 (file)
index 0000000..ed7bdab
--- /dev/null
@@ -0,0 +1,2 @@
+[Network]
+DNSSECNegativeTrustAnchors=i i
\ No newline at end of file