Gitweb:
http://git.exim.org/exim.git/commitdiff/fd5dad68368034fb9e5850322e66906a2d346ac1
Commit: fd5dad68368034fb9e5850322e66906a2d346ac1
Parent: 2e23003a9d8ac16da9e7599d4e4090dcfde1b242
Author: Jeremy Harris <jgh146exb@???>
AuthorDate: Sun Nov 10 21:31:17 2013 +0000
Committer: Jeremy Harris <jgh146exb@???>
CommitDate: Sun Nov 10 22:42:44 2013 +0000
Fix memory management vs. acl-as-conditional
---
doc/doc-txt/ChangeLog | 3 +++
src/src/expand.c | 36 +++++++++++++++++++++++++++---------
2 files changed, 30 insertions(+), 9 deletions(-)
diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog
index 6b8405d..cc9238e 100644
--- a/doc/doc-txt/ChangeLog
+++ b/doc/doc-txt/ChangeLog
@@ -17,6 +17,9 @@ TF/01 Correctly close the server side of TLS when forking for delivery.
TF/02 Portability fix for building lookup modules on Solaris when the xpg4
utilities have not been installed.
+JH/01 Fix memory-handling in use of acl as a conditional; avoid free of
+ temporary space as the ACL may create new global variables.
+
Exim version 4.82
-----------------
diff --git a/src/src/expand.c b/src/src/expand.c
index c5aadea..e610c99 100644
--- a/src/src/expand.c
+++ b/src/src/expand.c
@@ -1931,6 +1931,8 @@ return ret;
/*
Arguments:
s points to the start of the condition text
+ canfree points to a BOOL to sinal if it safe to free memory. Certain condition types (acl)
+ may have side-effect allocation which must be preserved.
yield points to a BOOL to hold the result of the condition test;
if NULL, we are just reading through a condition that is
part of an "or" combination to check syntax, or in a state
@@ -1941,7 +1943,7 @@ Returns: a pointer to the first character after the condition, or
*/
static uschar *
-eval_condition(uschar *s, BOOL *yield)
+eval_condition(uschar *s, BOOL *canfree, BOOL *yield)
{
BOOL testfor = TRUE;
BOOL tempcond, combined_cond;
@@ -1956,6 +1958,8 @@ uschar *sub[10];
const pcre *re;
const uschar *rerror;
+*canfree = TRUE;
+
for (;;)
{
while (isspace(*s)) s++;
@@ -2164,6 +2168,8 @@ switch(cond_type)
like the saslauthd condition does, to permit a variable number of args.
See also the expansion-item version EITEM_ACL and the traditional
acl modifier ACLC_ACL.
+ Since the ACL may allocate new global variables, tell our caller to not
+ reclaim memory.
*/
case ECOND_ACL:
@@ -2186,6 +2192,7 @@ switch(cond_type)
case 3: return NULL;
}
+ *canfree = FALSE;
if (yield != NULL) switch(eval_acl(sub, sizeof(sub)/sizeof(*sub), &user_msg))
{
case OK:
@@ -2655,6 +2662,7 @@ switch(cond_type)
for (;;)
{
+ BOOL local_canfree;
while (isspace(*s)) s++;
/* {-for-text-editors */
if (*s == '}') break;
@@ -2665,7 +2673,8 @@ switch(cond_type)
return NULL;
}
- s = eval_condition(s+1, subcondptr);
+ s = eval_condition(s+1, &local_canfree, subcondptr);
+ if (!local_canfree) *canfree = FALSE;
if (s == NULL)
{
expand_string_message = string_sprintf("%s inside \"%s{...}\" condition",
@@ -2709,6 +2718,7 @@ switch(cond_type)
{
int sep = 0;
uschar *save_iterate_item = iterate_item;
+ BOOL local_canfree;
while (isspace(*s)) s++;
if (*s++ != '{') goto COND_FAILED_CURLY_START; /* }-for-text-editors */
@@ -2726,7 +2736,8 @@ switch(cond_type)
"false" part). This allows us to find the end of the condition, because if
the list it empty, we won't actually evaluate the condition for real. */
- s = eval_condition(sub[1], NULL);
+ s = eval_condition(sub[1], &local_canfree, NULL);
+ if (!local_canfree) *canfree = FALSE;
if (s == NULL)
{
expand_string_message = string_sprintf("%s inside \"%s\" condition",
@@ -2747,8 +2758,11 @@ switch(cond_type)
if (yield != NULL) *yield = !testfor;
while ((iterate_item = string_nextinlist(&sub[0], &sep, NULL, 0)) != NULL)
{
+ uschar *s1;
DEBUG(D_expand) debug_printf("%s: $item = \"%s\"\n", name, iterate_item);
- if (eval_condition(sub[1], &tempcond) == NULL)
+ s1 = eval_condition(sub[1], &local_canfree, &tempcond);
+ if (!local_canfree) *canfree = FALSE;
+ if (!s1)
{
expand_string_message = string_sprintf("%s inside \"%s\" condition",
expand_string_message, name);
@@ -3857,9 +3871,10 @@ while (*s != 0)
uschar *next_s;
int save_expand_nmax =
save_expand_strings(save_expand_nstring, save_expand_nlength);
+ BOOL local_canfree;
while (isspace(*s)) s++;
- next_s = eval_condition(s, skipping? NULL : &cond);
+ next_s = eval_condition(s, &local_canfree, skipping? NULL : &cond);
if (next_s == NULL) goto EXPAND_FAILED; /* message already set */
DEBUG(D_expand)
@@ -3888,8 +3903,9 @@ while (*s != 0)
/* Restore external setting of expansion variables for continuation
at this level. */
- restore_expand_strings(save_expand_nmax, save_expand_nstring,
- save_expand_nlength);
+ if (local_canfree)
+ restore_expand_strings(save_expand_nmax, save_expand_nstring,
+ save_expand_nlength);
continue;
}
@@ -5212,6 +5228,7 @@ while (*s != 0)
/* Handle list operations */
+ /* These do not see to free any excess memory. Why not? */
case EITEM_FILTER:
case EITEM_MAP:
@@ -5223,6 +5240,7 @@ while (*s != 0)
uschar *list, *expr, *temp;
uschar *save_iterate_item = iterate_item;
uschar *save_lookup_value = lookup_value;
+ BOOL dummy;
while (isspace(*s)) s++;
if (*s++ != '{') goto EXPAND_FAILED_CURLY;
@@ -5254,7 +5272,7 @@ while (*s != 0)
if (item_type == EITEM_FILTER)
{
- temp = eval_condition(expr, NULL);
+ temp = eval_condition(expr, &dummy, NULL);
if (temp != NULL) s = temp;
}
else
@@ -5298,7 +5316,7 @@ while (*s != 0)
if (item_type == EITEM_FILTER)
{
BOOL condresult;
- if (eval_condition(expr, &condresult) == NULL)
+ if (eval_condition(expr, &dummy, &condresult) == NULL)
{
iterate_item = save_iterate_item;
lookup_value = save_lookup_value;