Memory management: when running under the testsuite, check every string variable...
[exim.git] / src / src / expand.c
index fd55436a24a925df20ccdad83dab403e1b720247..d35bf99018dee942bcefc1df263d72d100b750bf 100644 (file)
@@ -46,7 +46,7 @@ the first 8 characters of the password using a 20-round version of crypt
 (standard crypt does 25 rounds).  It then crypts the next 8 characters,
 or an empty block if the password is less than 9 characters, using a
 20-round version of crypt and the same salt as was used for the first
-block.  Charaters after the first 16 are ignored.  It always generates
+block.  Characters after the first 16 are ignored.  It always generates
 a 16-byte hash, which is expressed together with the salt as a string
 of 24 base 64 digits.  Here are some links to peruse:
 
@@ -1589,7 +1589,7 @@ for (i = 0; i < 2; i++)
 
         size += ilen + comma + 1;  /* +1 for the newline */
 
-        /* Second pass - concatentate the data, up to a maximum. Note that
+        /* Second pass - concatenate the data, up to a maximum. Note that
         the loop stops when size hits the limit. */
 
         if (i != 0)
@@ -1966,6 +1966,7 @@ return;          /* Unknown variable name, fail silently */
 
 
 
+
 /*************************************************
 *           Read and expand substrings           *
 *************************************************/
@@ -3050,6 +3051,8 @@ switch(cond_type)
        "value \"%s\"", t);
       return NULL;
       }
+    DEBUG(D_expand) debug_printf("%s: condition evaluated to %s\n", ourname,
+        boolvalue? "true":"false");
     if (yield != NULL) *yield = (boolvalue == testfor);
     return s;
     }
@@ -3633,7 +3636,7 @@ if (*error == NULL)
     /* SIGFPE both on div/mod by zero and on INT_MIN / -1, which would give
      * a value of INT_MAX+1. Note that INT_MIN * -1 gives INT_MIN for me, which
      * is a bug somewhere in [gcc 4.2.1, FreeBSD, amd64].  In fact, -N*-M where
-     * -N*M is INT_MIN will yielf INT_MIN.
+     * -N*M is INT_MIN will yield INT_MIN.
      * Since we don't support floating point, this is somewhat simpler.
      * Ideally, we'd return an error, but since we overflow for all other
      * arithmetic, consistency suggests otherwise, but what's the correct value
@@ -3811,7 +3814,7 @@ them here in detail any more.
 We use an internal routine recursively to handle embedded substrings. The
 external function follows. The yield is NULL if the expansion failed, and there
 are two cases: if something collapsed syntactically, or if "fail" was given
-as the action on a lookup failure. These can be distinguised by looking at the
+as the action on a lookup failure. These can be distinguished by looking at the
 variable expand_string_forcedfail, which is TRUE in the latter case.
 
 The skipping flag is set true when expanding a substring that isn't actually
@@ -4110,7 +4113,7 @@ while (*s != 0)
         save_expand_strings(save_expand_nstring, save_expand_nlength);
 
       while (isspace(*s)) s++;
-      next_s = eval_condition(s, &resetok, skipping? NULL : &cond);
+      next_s = eval_condition(s, &resetok, skipping ? NULL : &cond);
       if (next_s == NULL) goto EXPAND_FAILED;  /* message already set */
 
       DEBUG(D_expand)
@@ -4174,11 +4177,13 @@ while (*s != 0)
        goto EXPAND_FAILED;
        }
 
-      if (!(encoded = imap_utf7_encode(sub_arg[0], headers_charset,
-                         sub_arg[1][0], sub_arg[2], &expand_string_message)))
-       goto EXPAND_FAILED;
       if (!skipping)
+       {
+       if (!(encoded = imap_utf7_encode(sub_arg[0], headers_charset,
+                           sub_arg[1][0], sub_arg[2], &expand_string_message)))
+         goto EXPAND_FAILED;
        yield = string_cat(yield, &size, &ptr, encoded);
+       }
       continue;
       }
 #endif
@@ -4656,7 +4661,6 @@ while (*s != 0)
         prvscheck_keynum = NULL;
         }
       else
-        {
         /* Does not look like a prvs encoded address, return the empty string.
            We need to make sure all subs are expanded first, so as to skip over
            the entire item. */
@@ -4667,7 +4671,6 @@ while (*s != 0)
           case 2:
           case 3: goto EXPAND_FAILED;
           }
-        }
 
       continue;
       }
@@ -5384,7 +5387,7 @@ while (*s != 0)
 
       /* While skipping we cannot rely on the data for expansions being
       available (eg. $item) hence cannot decide on numeric vs. keyed.
-      Read a maximum of 5 arguments (inclding the yes/no) */
+      Read a maximum of 5 arguments (including the yes/no) */
 
       if (skipping)
        {
@@ -6438,7 +6441,11 @@ while (*s != 0)
          blob b;
          char st[3];
 
-         exim_sha_init(&h, HASH_SHA256);
+         if (!exim_sha_init(&h, HASH_SHA256))
+           {
+           expand_string_message = US"unrecognised sha256 variant";
+           goto EXPAND_FAILED;
+           }
          exim_sha_update(&h, sub, Ustrlen(sub));
          exim_sha_finish(&h, &b);
          while (b.len-- > 0)
@@ -6465,13 +6472,12 @@ while (*s != 0)
          : Ustrcmp(arg, "512") == 0 ? HASH_SHA3_512
          : HASH_BADTYPE;
 
-       if (m == HASH_BADTYPE)
+       if (m == HASH_BADTYPE || !exim_sha_init(&h, m))
          {
          expand_string_message = US"unrecognised sha3 variant";
          goto EXPAND_FAILED;
          }
 
-       exim_sha_init(&h, m);
        exim_sha_update(&h, sub, Ustrlen(sub));
        exim_sha_finish(&h, &b);
        while (b.len-- > 0)
@@ -7121,7 +7127,7 @@ while (*s != 0)
        const uschar * s = sub;
        uschar c;
 
-       for (s = sub; c = *s; s++)
+       for (s = sub; (c = *s); s++)
          yield = c < 127 && c != '\\'
            ? string_catn(yield, &size, &ptr, s, 1)
            : string_catn(yield, &size, &ptr, string_sprintf("\\%03o", c), 4);
@@ -7771,6 +7777,55 @@ return (  (  Ustrstr(s, "failed to expand") != NULL
 
 
 
+/*************************************************
+* Error-checking for testsuite                   *
+*************************************************/
+typedef struct {
+  const char * filename;
+  int          linenumber;
+  uschar *     region_start;
+  uschar *     region_end;
+  const uschar *var_name;
+} err_ctx;
+
+static void
+assert_variable_notin(uschar * var_name, uschar * var_data, void * ctx)
+{
+err_ctx * e = ctx;
+if (var_data >= e->region_start  &&  var_data < e->region_end)
+  e->var_name = CUS var_name;
+}
+
+void
+assert_no_variables(void * ptr, int len, const char * filename, int linenumber)
+{
+err_ctx e = {filename, linenumber, ptr, US ptr + len, NULL };
+int i;
+var_entry * v;
+
+/* check acl_ variables */
+tree_walk(acl_var_c, assert_variable_notin, &e);
+tree_walk(acl_var_m, assert_variable_notin, &e);
+
+/* check auth<n> variables */
+for (i = 0; i < AUTH_VARS; i++) if (auth_vars[i])
+  assert_variable_notin(US"auth<n>", auth_vars[i], &e);
+
+/* check regex<n> variables */
+for (i = 0; i < REGEX_VARS; i++) if (regex_vars[i])
+  assert_variable_notin(US"regex<n>", regex_vars[i], &e);
+
+/* check known-name variables */
+for (v = var_table; v < var_table + var_table_size; v++)
+  if (v->type == vtype_stringptr)
+    assert_variable_notin(US v->name, *(USS v->value), &e);
+
+if (e.var_name)
+  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "live variable '%s' destroyed by reset_store"
+    " at %s:%d\n", e.var_name, e.filename, e.linenumber);
+}
+
+
 
 /*************************************************
 **************************************************