Blob Blame History Raw
diff --git a/src/apprentice.c b/src/apprentice.c
index b609dd1..21eac1e 100644
--- a/src/apprentice.c
+++ b/src/apprentice.c
@@ -423,7 +423,15 @@ add_mlist(struct mlist *mlp, struct magic_map *map, size_t idx)
 	ml->map = idx == 0 ? map : NULL;
 	ml->magic = map->magic[idx];
 	ml->nmagic = map->nmagic[idx];
-
+	if (ml->nmagic) {
+		ml->magic_rxcomp = CAST(file_regex_t **,
+		    calloc(ml->nmagic, sizeof(*ml->magic_rxcomp)));
+		if (ml->magic_rxcomp == NULL) {
+			free(ml);
+			return -1;
+		}
+	} else
+		ml->magic_rxcomp = NULL;
 	mlp->prev->next = ml;
 	ml->prev = mlp->prev;
 	ml->next = mlp;
@@ -607,8 +615,19 @@ mlist_free_all(struct magic_set *ms)
 private void
 mlist_free_one(struct mlist *ml)
 {
+	size_t i;
+
 	if (ml->map)
 		apprentice_unmap(CAST(struct magic_map *, ml->map));
+
+	for (i = 0; i < ml->nmagic; ++i) {
+		if (ml->magic_rxcomp[i]) {
+			file_regfree(ml->magic_rxcomp[i]);
+			free(ml->magic_rxcomp[i]);
+		}
+	}
+	free(ml->magic_rxcomp);
+	ml->magic_rxcomp = NULL;
 	free(ml);
 }
 
@@ -3492,16 +3511,16 @@ file_magicfind(struct magic_set *ms, const char *name, struct mlist *v)
 
 	for (ml = mlist->next; ml != mlist; ml = ml->next) {
 		struct magic *ma = ml->magic;
-		uint32_t nma = ml->nmagic;
-		for (i = 0; i < nma; i++) {
+		for (i = 0; i < ml->nmagic; i++) {
 			if (ma[i].type != FILE_NAME)
 				continue;
 			if (strcmp(ma[i].value.s, name) == 0) {
 				v->magic = &ma[i];
-				for (j = i + 1; j < nma; j++)
+				for (j = i + 1; j < ml->nmagic; j++)
 				    if (ma[j].cont_level == 0)
 					    break;
 				v->nmagic = j - i;
+				v->magic_rxcomp = ml->magic_rxcomp;
 				return 0;
 			}
 		}
diff --git a/src/file.h b/src/file.h
index 48f4b69..c0b5a7c 100644
--- a/src/file.h
+++ b/src/file.h
@@ -88,6 +88,10 @@
 /* Do this here and now, because struct stat gets re-defined on solaris */
 #include <sys/stat.h>
 #include <stdarg.h>
+#include <locale.h>
+#if defined(HAVE_XLOCALE_H)
+#include <xlocale.h>
+#endif
 
 #define ENABLE_CONDITIONALS
 
@@ -167,6 +171,19 @@
 #define FILE_COMPILE	2
 #define FILE_LIST	3
 
+typedef struct {
+	const char *pat;
+#if defined(HAVE_NEWLOCALE) && defined(HAVE_USELOCALE) && defined(HAVE_FREELOCALE)
+#define USE_C_LOCALE
+	locale_t old_lc_ctype;
+	locale_t c_lc_ctype;
+#else
+	char *old_lc_ctype;
+#endif
+	int rc;
+	regex_t rx;
+} file_regex_t;
+
 struct buffer {
 	int fd;
 	struct stat st;
@@ -394,7 +411,8 @@ struct magic {
 /* list of magic entries */
 struct mlist {
 	struct magic *magic;		/* array of magic entries */
-	uint32_t nmagic;		/* number of entries in array */
+	file_regex_t **magic_rxcomp;	/* array of compiled regexps */
+	size_t nmagic;			/* number of entries in array */
 	void *map;			/* internal resources used by entry */
 	struct mlist *next, *prev;
 };
@@ -554,23 +572,7 @@ protected void buffer_init(struct buffer *, int, const struct stat *,
 protected void buffer_fini(struct buffer *);
 protected int buffer_fill(const struct buffer *);
 
-#include <locale.h>
-#if defined(HAVE_XLOCALE_H)
-#include <xlocale.h>
-#endif
 
-typedef struct {
-	const char *pat;
-#if defined(HAVE_NEWLOCALE) && defined(HAVE_USELOCALE) && defined(HAVE_FREELOCALE)
-#define USE_C_LOCALE
-	locale_t old_lc_ctype;
-	locale_t c_lc_ctype;
-#else
-	char *old_lc_ctype;
-#endif
-	int rc;
-	regex_t rx;
-} file_regex_t;
 
 protected int file_regcomp(file_regex_t *, const char *, int);
 protected int file_regexec(file_regex_t *, const char *, size_t, regmatch_t *,
diff --git a/src/softmagic.c b/src/softmagic.c
index 95061e5..834dfe3 100644
--- a/src/softmagic.c
+++ b/src/softmagic.c
@@ -43,7 +43,7 @@ FILE_RCSID("@(#)$File: softmagic.c,v 1.299 2020/06/07 21:58:01 christos Exp $")
 #include <time.h>
 #include "der.h"
 
-private int match(struct magic_set *, struct magic *, uint32_t,
+private int match(struct magic_set *, struct magic *, file_regex_t **, uint32_t,
     const struct buffer *, size_t, int, int, int, uint16_t *,
     uint16_t *, int *, int *, int *, int *);
 private int mget(struct magic_set *, struct magic *, const struct buffer *,
@@ -52,7 +52,7 @@ private int mget(struct magic_set *, struct magic *, const struct buffer *,
     uint16_t *, int *, int *, int *, int *);
 private int msetoffset(struct magic_set *, struct magic *, struct buffer *,
     const struct buffer *, size_t, unsigned int);
-private int magiccheck(struct magic_set *, struct magic *);
+private int magiccheck(struct magic_set *, struct magic *, file_regex_t **);
 private int32_t mprint(struct magic_set *, struct magic *);
 private int moffset(struct magic_set *, struct magic *, const struct buffer *,
     int32_t *);
@@ -131,8 +131,8 @@ file_softmagic(struct magic_set *ms, const struct buffer *b,
 	}
 
 	for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next)
-		if ((rv = match(ms, ml->magic, ml->nmagic, b, 0, mode,
-		    text, 0, indir_count, name_count,
+		if ((rv = match(ms, ml->magic, ml->magic_rxcomp, ml->nmagic, b,
+		    0, mode, text, 0, indir_count, name_count,
 		    &printed_something, &need_separator, NULL, NULL)) != 0)
 			return rv;
 
@@ -191,8 +191,8 @@ file_fmtcheck(struct magic_set *ms, const char *desc, const char *def,
  *	so that higher-level continuations are processed.
  */
 private int
-match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
-    const struct buffer *b, size_t offset, int mode, int text,
+match(struct magic_set *ms, struct magic *magic, file_regex_t **magic_rxcomp,
+    uint32_t nmagic, const struct buffer *b, size_t offset, int mode, int text,
     int flip, uint16_t *indir_count, uint16_t *name_count,
     int *printed_something, int *need_separator, int *returnval,
     int *found_match)
@@ -220,6 +220,7 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
 	for (magindex = 0; magindex < nmagic; magindex++) {
 		int flush = 0;
 		struct magic *m = &magic[magindex];
+		file_regex_t **m_rxcomp = &magic_rxcomp[magindex];
 
 		if (m->type != FILE_NAME)
 		if ((IS_STRING(m->type) &&
@@ -257,7 +258,7 @@ flush:
 				*returnval = 1;
 			}
 
-			switch (magiccheck(ms, m)) {
+			switch (magiccheck(ms, m, m_rxcomp)) {
 			case -1:
 				return -1;
 			case 0:
@@ -317,6 +318,7 @@ flush:
 		while (magindex + 1 < nmagic &&
 		    magic[magindex + 1].cont_level != 0) {
 			m = &magic[++magindex];
+			m_rxcomp = &magic_rxcomp[magindex];
 			ms->line = m->lineno; /* for messages */
 
 			if (cont_level < m->cont_level)
@@ -370,7 +372,7 @@ flush:
 				break;
 			}
 
-			switch (flush ? 1 : magiccheck(ms, m)) {
+			switch (flush ? 1 : magiccheck(ms, m, m_rxcomp)) {
 			case -1:
 				return -1;
 			case 0:
@@ -1880,8 +1882,8 @@ mget(struct magic_set *ms, struct magic *m, const struct buffer *b,
 		oneed_separator = *need_separator;
 		if (m->flag & NOSPACE)
 			*need_separator = 0;
-		rv = match(ms, ml.magic, ml.nmagic, b, offset + o,
-		    mode, text, flip, indir_count, name_count,
+		rv = match(ms, ml.magic, ml.magic_rxcomp, ml.nmagic, b,
+		    offset + o, mode, text, flip, indir_count, name_count,
 		    printed_something, need_separator, returnval, found_match);
 		(*name_count)--;
 		if (rv != 1)
@@ -1989,8 +1991,31 @@ file_strncmp16(const char *a, const char *b, size_t len, size_t maxlen,
 	return file_strncmp(a, b, len, maxlen, flags);
 }
 
+private file_regex_t *
+alloc_regex(struct magic_set *ms, struct magic *m)
+{
+	int rc;
+	file_regex_t *rx = CAST(file_regex_t *, malloc(sizeof(*rx)));
+
+	if (rx == NULL) {
+		file_error(ms, errno, "can't allocate %" SIZE_T_FORMAT
+		    "u bytes", sizeof(*rx));
+		return NULL;
+	}
+
+	rc = file_regcomp(rx, m->value.s, REG_EXTENDED | REG_NEWLINE |
+	    ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0));
+	if (rc == 0)
+		return rx;
+
+	file_regerror(rx, rc, ms);
+	file_regfree(rx);
+	free(rx);
+	return NULL;
+}
+
 private int
-magiccheck(struct magic_set *ms, struct magic *m)
+magiccheck(struct magic_set *ms, struct magic *m, file_regex_t **m_cache)
 {
 	uint64_t l = m->value.q;
 	uint64_t v;
@@ -2068,8 +2093,8 @@ magiccheck(struct magic_set *ms, struct magic *m)
 			break;
 
 		default:
-			file_magerror(ms, "cannot happen with float: invalid relation `%c'",
-			    m->reln);
+			file_magerror(ms, "cannot happen with float: "
+			    "invalid relation `%c'", m->reln);
 			return -1;
 		}
 		return matched;
@@ -2101,7 +2126,8 @@ magiccheck(struct magic_set *ms, struct magic *m)
 			break;
 
 		default:
-			file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln);
+			file_magerror(ms, "cannot happen with double: "
+			    "invalid relation `%c'", m->reln);
 			return -1;
 		}
 		return matched;
@@ -2169,62 +2195,57 @@ magiccheck(struct magic_set *ms, struct magic *m)
 	}
 	case FILE_REGEX: {
 		int rc;
-		file_regex_t rx;
+		file_regex_t *rx = *m_cache;
 		const char *search;
+		regmatch_t pmatch;
+		size_t slen = ms->search.s_len;
+		char *copy;
 
 		if (ms->search.s == NULL)
 			return 0;
 
+		if (rx == NULL) {
+			rx = *m_cache = alloc_regex(ms, m);
+			if (rx == NULL)
+				return -1;
+		}
 		l = 0;
-		rc = file_regcomp(&rx, m->value.s,
-		    REG_EXTENDED|REG_NEWLINE|
-		    ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0));
-		if (rc) {
-			file_regerror(&rx, rc, ms);
-			v = CAST(uint64_t, -1);
+		if (slen != 0) {
+		    copy = CAST(char *, malloc(slen));
+		    if (copy == NULL)  {
+			file_error(ms, errno,
+			    "can't allocate %" SIZE_T_FORMAT "u bytes",
+			    slen);
+			return -1;
+		    }
+		    memcpy(copy, ms->search.s, slen);
+		    copy[--slen] = '\0';
+		    search = copy;
 		} else {
-			regmatch_t pmatch;
-			size_t slen = ms->search.s_len;
-			char *copy;
-			if (slen != 0) {
-			    copy = CAST(char *, malloc(slen));
-			    if (copy == NULL)  {
-				file_regfree(&rx);
-				file_error(ms, errno,
-				    "can't allocate %" SIZE_T_FORMAT "u bytes",
-				    slen);
-				return -1;
-			    }
-			    memcpy(copy, ms->search.s, slen);
-			    copy[--slen] = '\0';
-			    search = copy;
-			} else {
-			    search = CCAST(char *, "");
-			    copy = NULL;
-			}
-			rc = file_regexec(&rx, RCAST(const char *, search),
-			    1, &pmatch, 0);
-			free(copy);
-			switch (rc) {
-			case 0:
-				ms->search.s += CAST(int, pmatch.rm_so);
-				ms->search.offset += CAST(size_t, pmatch.rm_so);
-				ms->search.rm_len = CAST(size_t, 
-				    pmatch.rm_eo - pmatch.rm_so);
-				v = 0;
-				break;
+		    search = CCAST(char *, "");
+		    copy = NULL;
+		}
+		rc = file_regexec(rx, RCAST(const char *, search),
+		    1, &pmatch, 0);
+		free(copy);
+		switch (rc) {
+		case 0:
+			ms->search.s += CAST(int, pmatch.rm_so);
+			ms->search.offset += CAST(size_t, pmatch.rm_so);
+			ms->search.rm_len = CAST(size_t,
+			    pmatch.rm_eo - pmatch.rm_so);
+			v = 0;
+			break;
 
-			case REG_NOMATCH:
-				v = 1;
-				break;
+		case REG_NOMATCH:
+			v = 1;
+			break;
 
-			default:
-				file_regerror(&rx, rc, ms);
-				v = CAST(uint64_t, -1);
-				break;
-			}
+		default:
+			file_regerror(rx, rc, ms);
+			v = CAST(uint64_t, -1);
+			break;
 		}
-		file_regfree(&rx);
 		if (v == CAST(uint64_t, -1))
 			return -1;
 		break;