linearize.c | 24 ++++++++++++++++++++++-- validation/context.c | 15 +++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/linearize.c b/linearize.c index d9aed61b..8dd005af 100644 --- a/linearize.c +++ b/linearize.c @@ -1537,6 +1537,8 @@ static pseudo_t linearize_call_expression(struct entrypoint *ep, struct expressi add_one_insn(ep, insn); if (ctype) { + struct basic_block *post_call = NULL; + FOR_EACH_PTR(ctype->contexts, context) { int in = context->in; int out = context->out; @@ -1547,8 +1549,21 @@ static pseudo_t linearize_call_expression(struct entrypoint *ep, struct expressi in = 0; } if (out < 0) { - check = 0; - out = 0; + struct basic_block *set_context; + if (retval == VOID) { + warning(expr->pos, "nonsensical conditional output context with no condition"); + break; + } + if (check || in) { + warning(expr->pos, "nonsensical conditional input context"); + break; + } + if (!post_call) + post_call = alloc_basic_block(ep, expr->pos); + set_context = alloc_basic_block(ep, expr->pos); + add_branch(ep, retval, set_context, post_call); + set_activeblock(ep, set_context); + out = -out; } context_diff = out - in; if (check || context_diff) { @@ -1560,6 +1575,11 @@ static pseudo_t linearize_call_expression(struct entrypoint *ep, struct expressi } } END_FOR_EACH_PTR(context); + if (post_call) { + add_goto(ep, post_call); + set_activeblock(ep, post_call); + } + if (ctype->modifiers & MOD_NORETURN) add_unreachable(ep); } diff --git a/validation/context.c b/validation/context.c index b9500dc7..f8962f19 100644 --- a/validation/context.c +++ b/validation/context.c @@ -10,6 +10,10 @@ static void r(void) __attribute__((context(1,0))) __context__(-1); } +// Negative output means "conditional positive output" +extern int cond_get(void) __attribute((context(0,-1))); +extern void nonsensical_cond_get(void) __attribute((context(0,-1))); + extern int _ca(int fail); #define ca(fail) __cond_lock(_ca(fail)) @@ -19,6 +23,17 @@ static void good_paired1(void) r(); } +static void good_conditional(void) +{ + if (cond_get()) + r(); +} + +static void nonsensical_conditional(void) +{ + nonsensical_cond_get(); +} + static void good_paired2(void) { a();