parts. It could also potentially affect tls_privatekeys. The underlyding
coding errors go back to 4.90 but were only exposed in 4.97.
+JH/20 Bug 3047: A recent (somewhere between 10.34 and 10.42) version of the
+ pcre2 library starting allocating 20kB rather than 112 bytes per match
+ call, which broke the 2GB total limitation on Exim's memory management
+ when a user had over 104207 messages stored and the appendfile
+ maildir_quota_directory_regex option is in use. Release the allocated
+ memory every thosand files to avoid this.
+
Exim version 4.97
-----------------
static void *
function_store_malloc(PCRE2_SIZE size, void * tag)
{
+if (size > INT_MAX)
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "excessive memory alloc request");
return store_malloc((int)size);
}
static void *
function_store_get(PCRE2_SIZE size, void * tag)
{
+if (size > INT_MAX)
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "excessive memory alloc request");
return store_get((int)size, GET_UNTAINTED); /* loses track of taint */
}
static void
function_store_nullfree(void * block, void * tag)
{
+/* We cannot free memory allocated using store_get() */
}
(!ob->quota_warn_threshold_is_percent || ob->quota_value > 0))
+/* Free memory allocated by PCRE2 every so often, because a recent version
+is now using 20kB for every match call */
+
+#define RESET_STORE_FILECNT 1000
/*************************************************
* Setup entry point *
off_t
check_dir_size(const uschar * dirname, int * countptr, const pcre2_code * re)
{
-DIR *dir;
+DIR * dir;
off_t sum = 0;
-int count = *countptr;
+int count = *countptr, lcount = RESET_STORE_FILECNT;
+rmark reset_point = store_mark();
if (!(dir = exim_opendir(dirname))) return 0;
-for (struct dirent *ent; ent = readdir(dir); )
+for (struct dirent * ent; ent = readdir(dir); )
{
uschar * path, * name = US ent->d_name;
struct stat statbuf;
if (Ustrcmp(name, ".") == 0 || Ustrcmp(name, "..") == 0) continue;
count++;
+ if (--lcount == 0)
+ {
+ store_reset(reset_point); reset_point = store_mark();
+ lcount = RESET_STORE_FILECNT;
+ }
/* If there's a regex, try to find the size using it */
debug_printf("check_dir_size: dir=%s sum=" OFF_T_FMT " count=%d\n", dirname,
sum, count);
+store_reset(reset_point);
*countptr = count;
return sum;
}