summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/doc-docbook/spec.xfpt10
-rw-r--r--doc/doc-txt/NewStuff4
-rw-r--r--doc/doc-txt/OptionLists.txt1
-rw-r--r--src/src/globals.c1
-rw-r--r--src/src/globals.h1
-rw-r--r--src/src/readconf.c1
-rw-r--r--src/src/store.c41
-rw-r--r--test/confs/00011
8 files changed, 41 insertions, 19 deletions
diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index c69e45c39..8b20910c1 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -13541,6 +13541,7 @@ listed in more than one group.
.section "Miscellaneous" "SECID96"
.table2
.row &%bi_command%& "to run for &%-bi%& command line option"
+.row &%debug_store%& "do extra internal checks"
.row &%disable_ipv6%& "do no IPv6 processing"
.row &%keep_malformed%& "for broken files &-- should not happen"
.row &%localhost_number%& "for unique message ids in clusters"
@@ -14429,6 +14430,15 @@ The CHUNKING extension (RFC3030) will be advertised in the EHLO message to
these hosts.
Hosts may use the BDAT command as an alternate to DATA.
+.new
+.option debug_store main boolean &`false`&
+.cindex debugging "memory corruption"
+.cindex memory debugging
+This option, when true, enables extra checking in Exim's internal memory
+management. For use when a memory corruption issue is being investigated,
+it should normally be left as default.
+.wen
+
.option daemon_smtp_ports main string &`smtp`&
.cindex "port" "for daemon"
.cindex "TCP/IP" "setting listening ports"
diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff
index ac876ed9f..2a8e520c6 100644
--- a/doc/doc-txt/NewStuff
+++ b/doc/doc-txt/NewStuff
@@ -18,6 +18,10 @@ Version 4.89
1. Allow relative config file names for ".include"
+ 2. A main-section config option "debug_store" to control the checks on
+ variable locations during store-reset. Normally false but can be enabled
+ when a memory corrution issue is suspected on a production system.
+
Version 4.88
------------
diff --git a/doc/doc-txt/OptionLists.txt b/doc/doc-txt/OptionLists.txt
index fc528518d..696b5f3fa 100644
--- a/doc/doc-txt/OptionLists.txt
+++ b/doc/doc-txt/OptionLists.txt
@@ -152,6 +152,7 @@ data_timeout time 5m smtp
debug_print string* unset authenticators 4.00
unset routers 4.00
unset transports 2.00
+debug_store boolean false main 4.90
delay_after_cutoff boolean true smtp
delay_warning time list 24h main
delay_warning_condition string* + main 1.73
diff --git a/src/src/globals.c b/src/src/globals.c
index 5e0fc2387..79ac37f92 100644
--- a/src/src/globals.c
+++ b/src/src/globals.c
@@ -599,6 +599,7 @@ bit_table debug_options[] = { /* must be in alphabetical order */
int debug_options_count = nelem(debug_options);
unsigned int debug_selector = 0;
+BOOL debug_store = FALSE;
int delay_warning[DELAY_WARNING_SIZE] = { DELAY_WARNING_SIZE, 1, 24*60*60 };
uschar *delay_warning_condition=
US"${if or {"
diff --git a/src/src/globals.h b/src/src/globals.h
index c2c69cf7c..340f1aecf 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -327,6 +327,7 @@ extern FILE *debug_file; /* Where to write debugging info */
extern int debug_notall[]; /* Debug options excluded from +all */
extern bit_table debug_options[]; /* Table of debug options */
extern int debug_options_count; /* Size of table */
+extern BOOL debug_store; /* Do extra checks on store_reset */
extern int delay_warning[]; /* Times between warnings */
extern uschar *delay_warning_condition; /* Condition string for warnings */
extern BOOL delivery_date_remove; /* Remove delivery-date headers */
diff --git a/src/src/readconf.c b/src/src/readconf.c
index 5efe7aa04..8b685c8fc 100644
--- a/src/src/readconf.c
+++ b/src/src/readconf.c
@@ -226,6 +226,7 @@ static optionlist optionlist_config[] = {
{ "dccifd_address", opt_stringptr, &dccifd_address },
{ "dccifd_options", opt_stringptr, &dccifd_options },
#endif
+ { "debug_store", opt_bool, &debug_store },
{ "delay_warning", opt_timelist, &delay_warning },
{ "delay_warning_condition", opt_stringptr, &delay_warning_condition },
{ "deliver_drop_privilege", opt_bool, &deliver_drop_privilege },
diff --git a/src/src/store.c b/src/src/store.c
index e88555cbf..8628954b5 100644
--- a/src/src/store.c
+++ b/src/src/store.c
@@ -144,39 +144,39 @@ if (size > yield_length[store_pool])
{
int length = (size <= STORE_BLOCK_SIZE)? STORE_BLOCK_SIZE : size;
int mlength = length + ALIGNED_SIZEOF_STOREBLOCK;
- storeblock *newblock = NULL;
+ storeblock * newblock = NULL;
/* Sometimes store_reset() may leave a block for us; check if we can use it */
- if (current_block[store_pool] != NULL &&
- current_block[store_pool]->next != NULL)
+ if ( (newblock = current_block[store_pool])
+ && (newblock = newblock->next)
+ && newblock->length < length
+ )
{
- newblock = current_block[store_pool]->next;
- if (newblock->length < length)
- {
- /* Give up on this block, because it's too small */
- store_free(newblock);
- newblock = NULL;
- }
+ /* Give up on this block, because it's too small */
+ store_free(newblock);
+ newblock = NULL;
}
/* If there was no free block, get a new one */
- if (newblock == NULL)
+ if (!newblock)
{
pool_malloc += mlength; /* Used in pools */
nonpool_malloc -= mlength; /* Exclude from overall total */
newblock = store_malloc(mlength);
newblock->next = NULL;
newblock->length = length;
- if (chainbase[store_pool] == NULL) chainbase[store_pool] = newblock;
- else current_block[store_pool]->next = newblock;
+ if (!chainbase[store_pool])
+ chainbase[store_pool] = newblock;
+ else
+ current_block[store_pool]->next = newblock;
}
current_block[store_pool] = newblock;
yield_length[store_pool] = newblock->length;
next_yield[store_pool] =
- (void *)((char *)current_block[store_pool] + ALIGNED_SIZEOF_STOREBLOCK);
+ (void *)(CS current_block[store_pool] + ALIGNED_SIZEOF_STOREBLOCK);
(void) VALGRIND_MAKE_MEM_NOACCESS(next_yield[store_pool], yield_length[store_pool]);
}
@@ -354,11 +354,14 @@ the released memory. */
newlength = bc + b->length - CS ptr;
#ifndef COMPILE_UTILITY
-if (running_in_test_harness)
+if (running_in_test_harness || debug_store)
{
assert_no_variables(ptr, newlength, filename, linenumber);
- (void) VALGRIND_MAKE_MEM_DEFINED(ptr, newlength);
- memset(ptr, 0xF0, newlength);
+ if (running_in_test_harness)
+ {
+ (void) VALGRIND_MAKE_MEM_DEFINED(ptr, newlength);
+ memset(ptr, 0xF0, newlength);
+ }
}
#endif
(void) VALGRIND_MAKE_MEM_NOACCESS(ptr, newlength);
@@ -376,7 +379,7 @@ if (yield_length[store_pool] < STOREPOOL_MIN_SIZE &&
{
b = b->next;
#ifndef COMPILE_UTILITY
- if (running_in_test_harness)
+ if (running_in_test_harness || debug_store)
assert_no_variables(b, b->length + ALIGNED_SIZEOF_STOREBLOCK,
filename, linenumber);
#endif
@@ -390,7 +393,7 @@ b->next = NULL;
while ((b = bb))
{
#ifndef COMPILE_UTILITY
- if (running_in_test_harness)
+ if (running_in_test_harness || debug_store)
assert_no_variables(b, b->length + ALIGNED_SIZEOF_STOREBLOCK,
filename, linenumber);
#endif
diff --git a/test/confs/0001 b/test/confs/0001
index b0f8f61e3..471c8f817 100644
--- a/test/confs/0001
+++ b/test/confs/0001
@@ -54,6 +54,7 @@ daemon_smtp_port =
daemon_smtp_ports =
daemon_startup_retries = 3
daemon_startup_sleep = 8s
+debug_store
delay_warning = 1d
delay_warning_condition = ${if match{$h_precedence:}{(?i)bulk|list}{no}{yes}}
deliver_drop_privilege