From b4fa2a49f3d386c6e92e77d3c0d427fb9c15888d Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Sat, 11 Feb 2017 16:36:23 +0000 Subject: [PATCH] Memory Managment: new main-section config option "debug_store" to control extra internal checking (cherry picked from commit 10919584f8ad580434442c7d971083f91c315bc0) Signed-off-by: Phil Pennock --- doc/doc-docbook/spec.xfpt | 10 +++++++++ doc/doc-txt/NewStuff | 4 ++++ doc/doc-txt/OptionLists.txt | 1 + src/src/globals.c | 1 + src/src/globals.h | 1 + src/src/readconf.c | 1 + src/src/store.c | 41 ++++++++++++++++++++----------------- test/confs/0001 | 1 + 8 files changed, 41 insertions(+), 19 deletions(-) diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index 919b36a14..19227beef 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -13535,6 +13535,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" @@ -14423,6 +14424,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 dd70201e5..9d9c81796 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -11,6 +11,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 4ebfca19b..790f07317 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 -- 2.30.2