summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGuillem Jover <guillem@debian.org>2014-09-26 05:43:56 +0200
committerGuillem Jover <guillem@debian.org>2014-10-06 02:08:04 +0200
commit67c4ac7e7a9c8a8c20d0796b5a58e8f4797c3d7b (patch)
tree631e770e071e0ffa08bd02fe71fceb6de06a381c /src
parentc8cd4cc0c17b43fec77595324f64e22dcc15f3e1 (diff)
downloaddpkg-67c4ac7e7a9c8a8c20d0796b5a58e8f4797c3d7b.tar.gz
dpkg: Switch the filesdb module to use the FNV hash function
Use it instead of what seems to be a custom hash function. This seems to reduce dispersion somewhat. As a side effect this fixes an integer overflow. Addresses: #760741 Warned-by: ASan Reported-by: Bálint Réczey <balint@balintreczey.hu>
Diffstat (limited to 'src')
-rw-r--r--src/filesdb.c15
1 files changed, 5 insertions, 10 deletions
diff --git a/src/filesdb.c b/src/filesdb.c
index af1e466bb..9c8780e46 100644
--- a/src/filesdb.c
+++ b/src/filesdb.c
@@ -44,6 +44,7 @@
#include <dpkg/i18n.h>
#include <dpkg/dpkg.h>
#include <dpkg/dpkg-db.h>
+#include <dpkg/string.h>
#include <dpkg/path.h>
#include <dpkg/dir.h>
#include <dpkg/fdio.h>
@@ -523,9 +524,9 @@ struct fileiterator {
int nbinn;
};
-/* This must always be a power of two. If you change it consider changing
- * the per-character hashing factor (currently 1785 = 137 * 13) too. */
-#define BINS (1 << 17)
+/* This must always be a prime for optimal performance.
+ * This is the closest one to 2^17 (131072). */
+#define BINS 131071
static struct filenamenode *bins[BINS];
@@ -576,12 +577,6 @@ void filesdbinit(void) {
}
}
-static int hash(const char *name) {
- int v= 0;
- while (*name) { v *= 1787; v += *name; name++; }
- return v;
-}
-
struct filenamenode *findnamenode(const char *name, enum fnnflags flags) {
struct filenamenode **pointerp, *newnode;
const char *orig_name = name;
@@ -590,7 +585,7 @@ struct filenamenode *findnamenode(const char *name, enum fnnflags flags) {
* leading slash. */
name = path_skip_slash_dotslash(name);
- pointerp= bins + (hash(name) & (BINS-1));
+ pointerp = bins + (str_fnv_hash(name) % (BINS));
while (*pointerp) {
/* XXX: Why is the assert needed? It's checking already added entries. */
assert((*pointerp)->name[0] == '/');