Memory Managment: new main-section config option "debug_store" to control extra inter... exim-4_89_RC6
authorJeremy Harris <jgh146exb@wizmail.org>
Sat, 11 Feb 2017 16:36:23 +0000 (16:36 +0000)
committerPhil Pennock <pdp@exim.org>
Wed, 22 Feb 2017 17:27:36 +0000 (12:27 -0500)
(cherry picked from commit 10919584f8ad580434442c7d971083f91c315bc0)
Signed-off-by: Phil Pennock <pdp@exim.org>
doc/doc-docbook/spec.xfpt
doc/doc-txt/NewStuff
doc/doc-txt/OptionLists.txt
src/src/globals.c
src/src/globals.h
src/src/readconf.c
src/src/store.c
test/confs/0001

index 919b36a146d5260aa27baa6594e6dd31da39f13c..19227beef0868a2e78465ba5981ca6abe3e5b76a 100644 (file)
@@ -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"
index dd70201e5e22a01b7b995725b6c63722a33c7dbb..9d9c817967d433ed3f127a972a454f9f5ad641ff 100644 (file)
@@ -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
 ------------
index fc528518d0d72ce8ad74b56b3829c9bccf6a0903..696b5f3fa99f0413d5653ca0535353c394b423f2 100644 (file)
@@ -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
index 5e0fc2387bbac923f4e74b482031ccad77a78966..79ac37f92acf684a2125a8ddf6871364cbc8afb9 100644 (file)
@@ -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 {"
index c2c69cf7ccd6fb6fdfe6cb9dac8151298f1eaedd..340f1aecfa142a769e55a7cd3cebad0aab31cbbc 100644 (file)
@@ -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 */
index 4ebfca19ba4b18a530b2b46694eedb548d12931d..790f073174846d8aa192167a7b59c2452aeea355 100644 (file)
@@ -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 },
index e88555cbf6180b2112ffbe719cb379a220ed7e8c..8628954b5b2eec784aea7ddbb2456e04b8e3ca87 100644 (file)
@@ -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
index b0f8f61e35097e456df33d9b90c1258500967571..471c8f817257534c08b884b934d334300a2e3d14 100644 (file)
@@ -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