hash table BUGFIX invalid length when resizing dict

Refs #1045
Refs #1093
diff --git a/src/hash_table.c b/src/hash_table.c
index 5f1af01..cc6fbd0 100644
--- a/src/hash_table.c
+++ b/src/hash_table.c
@@ -130,6 +130,30 @@
     return dict_hash_multi(hash, NULL, len);
 }
 
+static ly_bool
+lydict_resize_val_eq(void *val1_p, void *val2_p, ly_bool mod, void *cb_data)
+{
+    LY_CHECK_ARG_RET(NULL, val1_p, val2_p, 0);
+
+    const char *str1 = ((struct dict_rec *)val1_p)->value;
+    const char *str2 = ((struct dict_rec *)val2_p)->value;
+
+    LY_CHECK_ERR_RET(!str1, LOGARG(NULL, val1_p), 0);
+    LY_CHECK_ERR_RET(!str2, LOGARG(NULL, val2_p), 0);
+
+    if (mod) {
+        /* used when inserting new values */
+        if (strcmp(str1, str2) == 0) {
+            return 1;
+        }
+    } else {
+        /* used when finding the original value again in the resized table */
+        return lydict_val_eq(val1_p, val2_p, mod, cb_data);
+    }
+
+    return 0;
+}
+
 API void
 lydict_remove(const struct ly_ctx *ctx, const char *value)
 {
@@ -168,7 +192,7 @@
              * free it after it is removed from hash table
              */
             val_p = match->value;
-            ret = lyht_remove(ctx->dict.hash_tab, &rec, hash);
+            ret = lyht_remove_with_resize_cb(ctx->dict.hash_tab, &rec, hash, lydict_resize_val_eq);
             free(val_p);
             LY_CHECK_ERR_GOTO(ret, LOGINT(ctx), finish);
         }
@@ -193,7 +217,7 @@
     rec.refcount = 1;
 
     LOGDBG(LY_LDGDICT, "inserting \"%s\"", rec.value);
-    ret = lyht_insert(ctx->dict.hash_tab, (void *)&rec, hash, (void **)&match);
+    ret = lyht_insert_with_resize_cb(ctx->dict.hash_tab, (void *)&rec, hash, lydict_resize_val_eq, (void **)&match);
     if (ret == LY_EEXIST) {
         match->refcount++;
         if (zerocopy) {
@@ -688,12 +712,13 @@
 }
 
 LY_ERR
-lyht_remove(struct hash_table *ht, void *val_p, uint32_t hash)
+lyht_remove_with_resize_cb(struct hash_table *ht, void *val_p, uint32_t hash, values_equal_cb resize_val_equal)
 {
     struct ht_rec *rec, *crec;
     int32_t i;
     ly_bool first_matched = 0;
     LY_ERR r, ret = LY_SUCCESS;
+    values_equal_cb old_val_equal;
 
     LY_CHECK_ERR_RET(lyht_find_first(ht, hash, &rec), LOGARG(NULL, hash), LY_ENOTFOUND); /* hash not found */
 
@@ -737,10 +762,24 @@
     if (ht->resize == 2) {
         r = (ht->used * 100) / ht->size;
         if ((r < LYHT_SHRINK_PERCENTAGE) && (ht->size > LYHT_MIN_SIZE)) {
+            if (resize_val_equal) {
+                old_val_equal = lyht_set_cb(ht, resize_val_equal);
+            }
+
             /* shrink */
             ret = lyht_resize(ht, 0);
+
+            if (resize_val_equal) {
+                lyht_set_cb(ht, old_val_equal);
+            }
         }
     }
 
     return ret;
 }
+
+LY_ERR
+lyht_remove(struct hash_table *ht, void *val_p, uint32_t hash)
+{
+    return lyht_remove_with_resize_cb(ht, val_p, hash, NULL);
+}
diff --git a/src/hash_table.h b/src/hash_table.h
index 91c3da2..575bc9f 100644
--- a/src/hash_table.h
+++ b/src/hash_table.h
@@ -223,12 +223,28 @@
  * @brief Remove a value from a hash table.
  *
  * @param[in] ht Hash table to remove from.
- * @param[in] value_p Pointer to value to be removed. Be careful, if the values stored in the hash table
- * are pointers, \p value_p must be a pointer to a pointer.
+ * @param[in] val_p Pointer to value to be removed. Be careful, if the values stored in the hash table
+ * are pointers, \p val_p must be a pointer to a pointer.
  * @param[in] hash Hash of the stored value.
  * @return LY_SUCCESS on success,
  * @return LY_ENOTFOUND if value was not found.
  */
 LY_ERR lyht_remove(struct hash_table *ht, void *val_p, uint32_t hash);
 
+/**
+ * @brief Remove a value from a hash table. Same functionality as lyht_remove()
+ * but allows to specify a temporary val equal callback to be used in case the hash table
+ * will be resized after successful removal.
+ *
+ * @param[in] ht Hash table to remove from.
+ * @param[in] val_p Pointer to value to be removed. Be careful, if the values stored in the hash table
+ * are pointers, \p val_p must be a pointer to a pointer.
+ * @param[in] hash Hash of the stored value.
+ * @param[in] resize_val_equal Val equal callback to use for resizing.
+ * @return LY_SUCCESS on success,
+ * @return LY_ENOTFOUND if value was not found.
+ */
+LY_ERR lyht_remove_with_resize_cb(struct hash_table *ht, void *val_p, uint32_t hash, values_equal_cb resize_val_equal);
+
+
 #endif /* LY_HASH_TABLE_H_ */
diff --git a/tests/utests/test_hash_table.c b/tests/utests/test_hash_table.c
index bf40371..57e0de0 100644
--- a/tests/utests/test_hash_table.c
+++ b/tests/utests/test_hash_table.c
@@ -150,7 +150,7 @@
     assert_int_equal(LY_SUCCESS, lyht_remove(ht, &i, i));
     assert_int_equal(LY_ENOTFOUND, lyht_find(ht, &i, i, NULL));
     assert_int_equal(LY_ENOTFOUND, lyht_remove(ht, &i, i));
-    logbuf_assert("Invalid argument hash (lyht_remove()).");
+    logbuf_assert("Invalid argument hash (lyht_remove_with_resize_cb()).");
 
     lyht_free(ht);
 }
@@ -192,7 +192,7 @@
     for (i = 0; i < 2; ++i) {
         logbuf_clean();
         assert_int_equal(LY_ENOTFOUND, lyht_remove(ht, &i, i));
-        logbuf_assert("Invalid argument hash (lyht_remove()).");
+        logbuf_assert("Invalid argument hash (lyht_remove_with_resize_cb()).");
     }
     /* removing present data, resize should happened
      * when we are below 25% of the table filled, so with 3 records left */