/*
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
*/
static uschar *
-eval_condition(uschar *s, BOOL *yield)
+eval_condition(uschar *s, BOOL *canfree, BOOL *yield)
{
BOOL testfor = TRUE;
BOOL tempcond, combined_cond;
const pcre *re;
const uschar *rerror;
+*canfree = TRUE;
+
for (;;)
{
while (isspace(*s)) s++;
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:
case 3: return NULL;
}
+ *canfree = FALSE;
if (yield != NULL) switch(eval_acl(sub, sizeof(sub)/sizeof(*sub), &user_msg))
{
case OK:
for (;;)
{
+ BOOL local_canfree;
while (isspace(*s)) s++;
/* {-for-text-editors */
if (*s == '}') break;
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",
{
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 */
"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",
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);
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)
/* 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;
}
/* Handle list operations */
+ /* These do not see to free any excess memory. Why not? */
case EITEM_FILTER:
case EITEM_MAP:
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;
if (item_type == EITEM_FILTER)
{
- temp = eval_condition(expr, NULL);
+ temp = eval_condition(expr, &dummy, NULL);
if (temp != NULL) s = temp;
}
else
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;