Fix ${filter } for conditions modifying $value
authorJeremy Harris <jgh146exb@wizmail.org>
Thu, 22 Sep 2022 14:09:07 +0000 (15:09 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Thu, 22 Sep 2022 14:42:58 +0000 (15:42 +0100)
doc/doc-docbook/spec.xfpt
doc/doc-txt/ChangeLog
src/src/expand.c
test/scripts/0000-Basic/0002
test/stdout/0002

index 4e41acf42a295678485199128a5eae94e2705550..8c54931fe65038c584bd7ed58f2897d9c04a8dbe 100644 (file)
@@ -9907,7 +9907,11 @@ After expansion, <&'string'&> is interpreted as a list, colon-separated by
 default, but the separator can be changed in the usual way (&<<SECTlistsepchange>>&).
 For each item
 in this list, its value is place in &$item$&, and then the condition is
-evaluated. If the condition is true, &$item$& is added to the output as an
+evaluated.
+.new
+Any modification of &$value$& by this evaluation is discarded.
+.wen
+If the condition is true, &$item$& is added to the output as an
 item in a new list; if the condition is false, the item is discarded. The
 separator used for the output list is the same as the one used for the
 input, but a separator setting is not included in the output. For example:
@@ -9915,7 +9919,8 @@ input, but a separator setting is not included in the output. For example:
 ${filter{a:b:c}{!eq{$item}{b}}}
 .endd
 yields &`a:c`&. At the end of the expansion, the value of &$item$& is restored
-to what it was before. See also the &%map%& and &%reduce%& expansion items.
+to what it was before.
+See also the &%map%& and &%reduce%& expansion items.
 
 
 .vitem &*${hash{*&<&'string1'&>&*}{*&<&'string2'&>&*}{*&<&'string3'&>&*}}*&
index ba5bd23d9f1a4d5c686f27f40ec615b7d707eb55..2720fb8192fb61317eb7bd6269b28d6005e4167f 100644 (file)
@@ -23,10 +23,10 @@ JH/05 Follow symlinks for placing a watch on TLS creds files.  This means
       it would be the dir with the first symlink.  We still do not monitor
       the entire path.
 
-JH/06 Check for bad chars in rDNS for sender_host_name. The OpenBSD (at least)
+JH/06 Check for bad chars in rDNS for sender_host_name.  The OpenBSD (at least)
       dn_expand() is happy to pass them through.
 
-JH/07 OpenSSL Fix auto-reload of changed server OCSP proof. Previously, if
+JH/07 OpenSSL Fix auto-reload of changed server OCSP proof.  Previously, if
       the file with the proof had an unchanged name, the new proof(s) were
       loaded on top of the old ones (and nover used; the old ones were stapled).
 
@@ -36,6 +36,10 @@ JH/08 Bug 2915: Fix use-after-free for $regex<n> variables. Previously when
       These variables were introduced in Exim 4.87.
       Debug help from Graeme Fowler.
 
+JH/09 Fix ${filter } for conditions that modify $value.  Previously the
+      modified version would be used in construction the result, and a memory
+      error would occur.
+
 
 Exim version 4.96
 -----------------
index 831ca2b759f877c5b9138653e656ebed8970e6f9..ff0b4d6003c534df3bc45cee0c57efe3836cb345 100644 (file)
@@ -6544,6 +6544,9 @@ while (*s)
         if (item_type == EITEM_FILTER)
           {
           BOOL condresult;
+         /* the condition could modify $value, as a side-effect */
+         uschar * save_value = lookup_value;
+
           if (!eval_condition(expr, &resetok, &condresult))
             {
             iterate_item = save_iterate_item;
@@ -6552,6 +6555,7 @@ while (*s)
               expand_string_message, name);
             goto EXPAND_FAILED;
             }
+         lookup_value = save_value;
           DEBUG(D_expand) debug_printf_indent("%s: condition is %s\n", name,
             condresult? "true":"false");
           if (condresult)
@@ -6560,14 +6564,12 @@ while (*s)
             continue;               /* FALSE => skip this item */
           }
 
-        /* EITEM_MAP and EITEM_REDUCE */
-
-        else
+        else                   /* EITEM_MAP and EITEM_REDUCE */
           {
+         /* the expansion could modify $value, as a side-effect */
          uschar * t = expand_string_internal(expr,
            ESI_BRACE_ENDS | ESI_HONOR_DOLLAR | flags, NULL, &resetok, NULL);
-          temp = t;
-          if (!temp)
+          if (!(temp = t))
             {
             iterate_item = save_iterate_item;
             expand_string_message = string_sprintf("%s inside \"%s\" item",
index d169518b6e7e3dc827c3844ae57c081b71a30a85..898f3b6bcf1bea9af174d652940a2ab78a346cca 100644 (file)
@@ -90,6 +90,8 @@ filter: ${filter{a:b:c}{!eq{$item}{b}}}
 filter: ${filter{<' a'b'c}{!eq{$item}{b}}}
 filter: ${filter{<' ''a'b' ''c}{!eq{$item}{b}}}
 filter: "${filter{}{!eq{$item}{b}}}"
+# check operation when the condition modifies the 'value' variable
+${filter {E} {inlisti{$item}{ e }}}
 
 map: "${map{}{$item}}"
 map: ${map{a:b:c}{$item}}
index 74219a6f320f401ea59f3575530420cc8ea25ce0..9232089f6c4812a0e4344911ed7de92503c2af13 100644 (file)
@@ -79,6 +79,8 @@
 > filter: a'c
 > filter: ''a' ''c
 > filter: ""
+> # check operation when the condition modifies the 'value' variable
+> E
 > 
 > map: ""
 > map: a:b:c