aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2026-01-11 09:51:51 +0100
committerlemon <lsof@mailbox.org>2026-01-11 09:51:51 +0100
commitd42a6b1a5d14f1d1d0d19b222e3b0ce11d009c4e (patch)
treeebbe0d8f5bd5d56ed8d38f3b2019f1507391b25e
parent0705d7578247cdc55b3bff9776bfd25661782dbd (diff)
io: fix hashtable lookup of builtin include files
It would break if there were hash collisions.
-rw-r--r--io.c20
1 files changed, 15 insertions, 5 deletions
diff --git a/io.c b/io.c
index 14e753a..9e7cba7 100644
--- a/io.c
+++ b/io.c
@@ -793,7 +793,11 @@ _assertfmt(const char *file, int line, const char *func, const char *expr)
}
struct fileuid {
- long dev, ino;
+ long dev;
+ union {
+ long ino;
+ const char *str;
+ };
};
/* one entry per #line */
@@ -852,22 +856,28 @@ openfile(const char **err, struct memfile **pf, const char *path)
struct stat st;
struct file *f;
struct fileuid uid;
- uint h, id, n = countof(fileht);
+ size_t h, id, n = countof(fileht);
if (*path == '@' && path[1] == ':') {
+ /* fast path to rule out filenames we know for sure aren't builtin */
+ /* !KEEP SYNC with embedfilesdir */
+ if (path[2] != 's' /* std*.h */
+ && path[2] != 'f' /* float.h */) return -1;
uid.dev = -1;
- uid.ino = hashs(0, path+2);
+ uid.str = path;
+ h = hashs(0, path+2);
} else {
if (stat(path, &st) != 0) {
*err = strerror(errno);
return -1;
}
uid.dev = st.st_dev, uid.ino = st.st_ino;
+ h = uid.dev ^ uid.ino;
}
- for (id = h = uid.dev ^ uid.ino;; ++id) {
+ for (id = h;; ++id) {
id &= countof(fileht) - 1;
f = fileht[id];
- if (f && f->uid.dev == uid.dev && f->uid.ino == uid.ino) {
+ if (f && f->uid.dev == uid.dev && (uid.dev >= 0 ? f->uid.ino == uid.ino : !strcmp(f->uid.str, uid.str))) {
break;
} else if (!f) {
struct memfile m;