diff --git a/librz/il/il_validate.c b/librz/il/il_validate.c index 66705905ba..1f7fd30fba 100644 --- a/librz/il/il_validate.c +++ b/librz/il/il_validate.c @@ -621,6 +621,7 @@ RZ_API bool rz_il_validate_pure(RZ_NULLABLE RzILOpPure *op, RZ_NONNULL RzILValid // clang-format off #define VALIDATOR_EFFECT_ARGS \ RZ_NULLABLE RzILOpEffect *op, \ + RZ_NONNULL RzILTypeEffect *type_out, \ RZ_NONNULL RzStrBuf *report_builder, \ RZ_NONNULL LocalContext *ctx // clang-format on @@ -636,14 +637,15 @@ typedef bool (*ValidateEffectFn)(VALIDATOR_EFFECT_ARGS); return false; \ } \ } while (0) -#define VALIDATOR_DESCEND_EFFECT(op, ectx, cleanup) \ +#define VALIDATOR_DESCEND_EFFECT(op, etype, ectx, cleanup) \ do { \ - if (!validate_effect(op, report_builder, ectx)) { \ + if (!validate_effect(op, etype, report_builder, ectx)) { \ cleanup return false; \ } \ } while (0) VALIDATOR_EFFECT(nop) { + *type_out = RZ_IL_TYPE_EFFECT_NONE; return true; } @@ -664,6 +666,7 @@ VALIDATOR_EFFECT(store) { VALIDATOR_ASSERT(sv.type == RZ_IL_TYPE_PURE_BITVECTOR, "Value operand of store op is not a bitvector.\n"); VALIDATOR_ASSERT(sv.props.bv.length == val_len, "Length of value operand (%u) of store op is not equal to value length %u of mem %u.\n", (unsigned int)sv.props.bv.length, (unsigned int)val_len, (unsigned int)args->mem); + *type_out = RZ_IL_TYPE_EFFECT_DATA; return true; } @@ -681,6 +684,7 @@ VALIDATOR_EFFECT(storew) { RzILSortPure sv; VALIDATOR_DESCEND_PURE(args->value, &sv); VALIDATOR_ASSERT(sv.type == RZ_IL_TYPE_PURE_BITVECTOR, "Value operand of storew op is not a bitvector.\n"); + *type_out = RZ_IL_TYPE_EFFECT_DATA; return true; } @@ -713,6 +717,7 @@ VALIDATOR_EFFECT(set) { } ht_pp_update(ctx->local_vars_available, args->v, sort); } + *type_out = RZ_IL_TYPE_EFFECT_DATA; return true; } @@ -724,6 +729,7 @@ VALIDATOR_EFFECT(jmp) { VALIDATOR_ASSERT(sd.props.bv.length == ctx->global_ctx->pc_len, "Length of dst operand (%u) of jmp op is not equal to pc length %u.\n", (unsigned int)sd.props.bv.length, (unsigned int)ctx->global_ctx->pc_len); + *type_out = RZ_IL_TYPE_EFFECT_CTRL; return true; } @@ -731,21 +737,35 @@ VALIDATOR_EFFECT(goto) { RzILOpArgsGoto *args = &op->op.goto_; VALIDATOR_ASSERT(args->lbl, "Label of goto op is NULL.\n"); // So far, no restrictions on goto because labels are dynamically created. This might change in the future. + *type_out = RZ_IL_TYPE_EFFECT_CTRL; return true; } VALIDATOR_EFFECT(seq) { RzILOpArgsSeq *args = &op->op.seq; - VALIDATOR_DESCEND_EFFECT(args->x, ctx, {}); - VALIDATOR_DESCEND_EFFECT(args->y, ctx, {}); + RzILTypeEffect tx; + VALIDATOR_DESCEND_EFFECT(args->x, &tx, ctx, {}); + RzILTypeEffect ty; + VALIDATOR_DESCEND_EFFECT(args->y, &ty, ctx, {}); + // Code after a jmp/goto makes no sense because the jmp naturally jumps somewhere else already. + // Intuitively, this could be considered just dead code and valid, but because it is not practically useful, + // we reject such code completely for now, which gives us more freedom if in the future we do want to define + // semantics for code after ctrl in some way. + VALIDATOR_ASSERT(!(tx & RZ_IL_TYPE_EFFECT_CTRL) || !ty, "Encountered further effects after a ctrl effect in seq op."); + *type_out = tx | ty; return true; } VALIDATOR_EFFECT(blk) { RzILOpArgsBlk *args = &op->op.blk; // Semantics of blk are still somewhat undefined in RzIL - VALIDATOR_DESCEND_EFFECT(args->data_eff, ctx, {}); - VALIDATOR_DESCEND_EFFECT(args->ctrl_eff, ctx, {}); + RzILTypeEffect td; + VALIDATOR_DESCEND_EFFECT(args->data_eff, &td, ctx, {}); + VALIDATOR_ASSERT((td | RZ_IL_TYPE_EFFECT_DATA) == RZ_IL_TYPE_EFFECT_DATA, "Data effect operand of blk op does not only perform data effects."); + RzILTypeEffect tc; + VALIDATOR_DESCEND_EFFECT(args->ctrl_eff, &tc, ctx, {}); + VALIDATOR_ASSERT((tc | RZ_IL_TYPE_EFFECT_CTRL) == RZ_IL_TYPE_EFFECT_CTRL, "Control effect operand of blk op does not only perform control effects."); + *type_out = td | tc; return true; } @@ -758,9 +778,14 @@ VALIDATOR_EFFECT(repeat) { if (!local_context_copy(&loop_ctx, ctx)) { return false; } - VALIDATOR_DESCEND_EFFECT(args->data_eff, ctx, { local_context_fini(&loop_ctx); }); + RzILTypeEffect t; + VALIDATOR_DESCEND_EFFECT(args->data_eff, &t, ctx, { local_context_fini(&loop_ctx); }); + // Enforce (by overapproximation) that there are no effects after a ctrl effect, like in seq. + // In a loop, we just reject ctrl completely. This also matches BAP's `repeat : bool -> data eff -> data eff`. + VALIDATOR_ASSERT((t | RZ_IL_TYPE_EFFECT_DATA) == RZ_IL_TYPE_EFFECT_DATA, "Body operand of repeat op does not only perform data effects."); bool val = local_context_meet(ctx, &loop_ctx, report_builder, "repeat"); local_context_fini(&loop_ctx); + *type_out = t; return val; } @@ -773,10 +798,13 @@ VALIDATOR_EFFECT(branch) { if (!local_context_copy(&false_ctx, ctx)) { return false; } - VALIDATOR_DESCEND_EFFECT(args->true_eff, ctx, { local_context_fini(&false_ctx); }); - VALIDATOR_DESCEND_EFFECT(args->false_eff, &false_ctx, { local_context_fini(&false_ctx); }); + RzILTypeEffect tt; + VALIDATOR_DESCEND_EFFECT(args->true_eff, &tt, ctx, { local_context_fini(&false_ctx); }); + RzILTypeEffect tf; + VALIDATOR_DESCEND_EFFECT(args->false_eff, &tf, &false_ctx, { local_context_fini(&false_ctx); }); bool val = local_context_meet(ctx, &false_ctx, report_builder, "branch"); local_context_fini(&false_ctx); + *type_out = tt | tf; return val; } @@ -797,7 +825,7 @@ static bool validate_effect(VALIDATOR_EFFECT_ARGS) { VALIDATOR_ASSERT(op, "Encountered NULL for effect op.\n"); ValidateEffectFn validator = validate_effect_table[op->code]; rz_return_val_if_fail(validator, false); - return validator(op, report_builder, ctx); + return validator(op, type_out, report_builder, ctx); } /** @@ -805,11 +833,13 @@ static bool validate_effect(VALIDATOR_EFFECT_ARGS) { * \p op the op to be checked. May be null, which will always be reported as invalid. * \p ctx global context, defining available global vars and mems * \p local_var_sorts_out optionally returns a map of local variable names defined in the effect to their sorts + * \p type_put optionally returns the type of effects that the ops perform, i.e. ctrl, data, both or none * \p report_out optionally returns a readable report containing details about why the validation failed * \return whether the given op is valid under \p ctx */ RZ_API bool rz_il_validate_effect(RZ_NULLABLE RzILOpEffect *op, RZ_NONNULL RzILValidateGlobalContext *ctx, RZ_NULLABLE RZ_OUT HtPP /* */ **local_var_sorts_out, + RZ_NULLABLE RZ_OUT RzILTypeEffect *type_out, RZ_NULLABLE RZ_OUT RzILValidateReport *report_out) { LocalContext local_ctx; if (!local_context_init(&local_ctx, ctx)) { @@ -818,14 +848,18 @@ RZ_API bool rz_il_validate_effect(RZ_NULLABLE RzILOpEffect *op, RZ_NONNULL RzILV } return false; } + RzILTypeEffect type = RZ_IL_TYPE_EFFECT_NONE; RzStrBuf report_builder; rz_strbuf_init(&report_builder); - bool valid = validate_effect(op, &report_builder, &local_ctx); + bool valid = validate_effect(op, &type, &report_builder, &local_ctx); if (valid && local_var_sorts_out) { *local_var_sorts_out = local_ctx.local_vars_known; local_ctx.local_vars_known = NULL; } local_context_fini(&local_ctx); + if (type_out) { + *type_out = type; + } if (report_out) { *report_out = rz_strbuf_is_empty(&report_builder) ? NULL : rz_str_trim_tail(rz_strbuf_drain_nofree(&report_builder)); } diff --git a/librz/include/rz_il/definitions/sort.h b/librz/include/rz_il/definitions/sort.h index 0600a58c78..dc810f5f23 100644 --- a/librz/include/rz_il/definitions/sort.h +++ b/librz/include/rz_il/definitions/sort.h @@ -61,6 +61,12 @@ static inline RzILSortPure rz_il_sort_pure_bv(ut32 length) { RZ_API RZ_OWN char *rz_il_sort_pure_stringify(RzILSortPure sort); +typedef enum { + RZ_IL_TYPE_EFFECT_NONE = 0, ///< nop + RZ_IL_TYPE_EFFECT_DATA = (1 << 0), ///< mutating mems, vars, etc. + RZ_IL_TYPE_EFFECT_CTRL = (1 << 1) ///< jmp/goto +} RzILTypeEffect; + #ifdef __cplusplus } #endif diff --git a/librz/include/rz_il/rz_il_validate.h b/librz/include/rz_il/rz_il_validate.h index b8a6868e32..7b42b12e10 100644 --- a/librz/include/rz_il/rz_il_validate.h +++ b/librz/include/rz_il/rz_il_validate.h @@ -36,6 +36,7 @@ RZ_API bool rz_il_validate_pure(RZ_NULLABLE RzILOpPure *op, RZ_NONNULL RzILValid RZ_NULLABLE RZ_OUT RzILSortPure *sort_out, RZ_NULLABLE RZ_OUT RzILValidateReport *report_out); RZ_API bool rz_il_validate_effect(RZ_NULLABLE RzILOpEffect *op, RZ_NONNULL RzILValidateGlobalContext *ctx, RZ_NULLABLE RZ_OUT HtPP /* */ **local_var_sorts_out, + RZ_NULLABLE RZ_OUT RzILTypeEffect *type_out, RZ_NULLABLE RZ_OUT RzILValidateReport *report_out); #ifdef __cplusplus diff --git a/librz/main/rz-asm.c b/librz/main/rz-asm.c index d74325b06a..05312808ba 100644 --- a/librz/main/rz-asm.c +++ b/librz/main/rz-asm.c @@ -253,7 +253,7 @@ static bool print_and_check_il(RzAsmState *as, RzAnalysisOp *op) { rz_strbuf_fini(&sb); } char *report; - if (!rz_il_validate_effect(il_op, ctx, NULL, &report)) { + if (!rz_il_validate_effect(il_op, ctx, NULL, NULL, &report)) { ret = false; eprintf("IL Validation failed%c\n", report ? ':' : '.'); } diff --git a/test/unit/test_il_validate.c b/test/unit/test_il_validate.c index 6c20773346..76d8112fc4 100644 --- a/test/unit/test_il_validate.c +++ b/test/unit/test_il_validate.c @@ -184,8 +184,10 @@ static bool test_il_validate_pure_var() { RzILOpEffect *eop = rz_il_op_new_seq( rz_il_op_new_set("y", true, rz_il_op_new_bitv_from_ut64(24, 0x1234)), rz_il_op_new_jmp(rz_il_op_new_var("y", RZ_IL_VAR_KIND_LOCAL))); - val = rz_il_validate_effect(eop, ctx, NULL, &report); + RzILTypeEffect t; + val = rz_il_validate_effect(eop, ctx, NULL, &t, &report); mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_DATA | RZ_IL_TYPE_EFFECT_CTRL, "effect type"); mu_assert_null(report, "no report"); rz_il_op_effect_free(eop); @@ -204,7 +206,7 @@ static bool test_il_validate_pure_var() { eop = rz_il_op_new_seq( rz_il_op_new_set("y", true, rz_il_op_new_bitv_from_ut64(23, 0x1234)), rz_il_op_new_jmp(rz_il_op_new_var("y", RZ_IL_VAR_KIND_LOCAL))); - val = rz_il_validate_effect(eop, ctx, NULL, &report); + val = rz_il_validate_effect(eop, ctx, NULL, &t, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Length of dst operand (23) of jmp op is not equal to pc length 24.", "report"); rz_il_op_effect_free(eop); @@ -581,7 +583,7 @@ static bool test_il_validate_effect_null() { RzILValidateGlobalContext *ctx = rz_il_validate_global_context_new_empty(24); RzILValidateReport report; - bool val = rz_il_validate_effect(NULL, ctx, NULL, &report); + bool val = rz_il_validate_effect(NULL, ctx, NULL, NULL, &report); mu_assert_false(val, "valid"); mu_assert_streq_free(report, "Encountered NULL for effect op.", "no report"); @@ -594,8 +596,10 @@ static bool test_il_validate_effect_nop() { RzILOpEffect *op = rz_il_op_new_nop(); RzILValidateReport report; - bool val = rz_il_validate_effect(op, ctx, NULL, &report); + RzILTypeEffect t; + bool val = rz_il_validate_effect(op, ctx, NULL, &t, &report); mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_NONE, "effect type"); mu_assert_null(report, "no report"); rz_il_op_effect_free(op); @@ -611,15 +615,17 @@ static bool test_il_validate_effect_store() { rz_il_op_new_bitv_from_ut64(16, 123), rz_il_op_new_bitv_from_ut64(9, 42)); RzILValidateReport report; - bool val = rz_il_validate_effect(op, ctx, NULL, &report); + RzILTypeEffect t; + bool val = rz_il_validate_effect(op, ctx, NULL, &t, &report); mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_DATA, "effect type"); mu_assert_null(report, "no report"); rz_il_op_effect_free(op); op = rz_il_op_new_store(0, rz_il_op_new_bitv_from_ut64(16, 123), rz_il_op_new_bitv_from_ut64(9, 42)); - val = rz_il_validate_effect(op, ctx, NULL, &report); + val = rz_il_validate_effect(op, ctx, NULL, &t, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Mem 0 referenced by store op does not exist.", "report"); rz_il_op_effect_free(op); @@ -627,7 +633,7 @@ static bool test_il_validate_effect_store() { op = rz_il_op_new_store(1, rz_il_op_new_bitv_from_ut64(12, 123), rz_il_op_new_bitv_from_ut64(9, 42)); - val = rz_il_validate_effect(op, ctx, NULL, &report); + val = rz_il_validate_effect(op, ctx, NULL, NULL, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Length of key operand (12) of store op is not equal to key length 16 of mem 1.", "report"); rz_il_op_effect_free(op); @@ -635,7 +641,7 @@ static bool test_il_validate_effect_store() { op = rz_il_op_new_store(1, rz_il_op_new_b0(), rz_il_op_new_bitv_from_ut64(9, 42)); - val = rz_il_validate_effect(op, ctx, NULL, &report); + val = rz_il_validate_effect(op, ctx, NULL, NULL, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Key operand of store op is not a bitvector.", "report"); rz_il_op_effect_free(op); @@ -643,7 +649,7 @@ static bool test_il_validate_effect_store() { op = rz_il_op_new_store(1, rz_il_op_new_bitv_from_ut64(16, 123), rz_il_op_new_bitv_from_ut64(8, 42)); - val = rz_il_validate_effect(op, ctx, NULL, &report); + val = rz_il_validate_effect(op, ctx, NULL, NULL, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Length of value operand (8) of store op is not equal to value length 9 of mem 1.", "report"); rz_il_op_effect_free(op); @@ -651,7 +657,7 @@ static bool test_il_validate_effect_store() { op = rz_il_op_new_store(1, rz_il_op_new_bitv_from_ut64(16, 123), rz_il_op_new_b0()); - val = rz_il_validate_effect(op, ctx, NULL, &report); + val = rz_il_validate_effect(op, ctx, NULL, NULL, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Value operand of store op is not a bitvector.", "report"); rz_il_op_effect_free(op); @@ -668,15 +674,17 @@ static bool test_il_validate_effect_storew() { rz_il_op_new_bitv_from_ut64(16, 123), rz_il_op_new_bitv_from_ut64(42, 42)); RzILValidateReport report; - bool val = rz_il_validate_effect(op, ctx, NULL, &report); + RzILTypeEffect t; + bool val = rz_il_validate_effect(op, ctx, NULL, &t, &report); mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_DATA, "effect type"); mu_assert_null(report, "no report"); rz_il_op_effect_free(op); op = rz_il_op_new_storew(0, rz_il_op_new_bitv_from_ut64(16, 123), rz_il_op_new_bitv_from_ut64(9, 42)); - val = rz_il_validate_effect(op, ctx, NULL, &report); + val = rz_il_validate_effect(op, ctx, NULL, &t, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Mem 0 referenced by storew op does not exist.", "report"); rz_il_op_effect_free(op); @@ -684,7 +692,7 @@ static bool test_il_validate_effect_storew() { op = rz_il_op_new_storew(1, rz_il_op_new_bitv_from_ut64(12, 123), rz_il_op_new_bitv_from_ut64(9, 42)); - val = rz_il_validate_effect(op, ctx, NULL, &report); + val = rz_il_validate_effect(op, ctx, NULL, NULL, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Length of key operand (12) of storew op is not equal to key length 16 of mem 1.", "report"); rz_il_op_effect_free(op); @@ -692,7 +700,7 @@ static bool test_il_validate_effect_storew() { op = rz_il_op_new_storew(1, rz_il_op_new_b0(), rz_il_op_new_bitv_from_ut64(9, 42)); - val = rz_il_validate_effect(op, ctx, NULL, &report); + val = rz_il_validate_effect(op, ctx, NULL, NULL, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Key operand of storew op is not a bitvector.", "report"); rz_il_op_effect_free(op); @@ -700,7 +708,7 @@ static bool test_il_validate_effect_storew() { op = rz_il_op_new_storew(1, rz_il_op_new_bitv_from_ut64(16, 123), rz_il_op_new_b0()); - val = rz_il_validate_effect(op, ctx, NULL, &report); + val = rz_il_validate_effect(op, ctx, NULL, NULL, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Value operand of storew op is not a bitvector.", "report"); rz_il_op_effect_free(op); @@ -716,26 +724,28 @@ static bool test_il_validate_effect_set() { // global RzILOpEffect *op = rz_il_op_new_set("x", false, rz_il_op_new_bitv_from_ut64(42, 0)); RzILValidateReport report; - bool val = rz_il_validate_effect(op, ctx, NULL, &report); + RzILTypeEffect t; + bool val = rz_il_validate_effect(op, ctx, NULL, &t, &report); mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_DATA, "effect type"); mu_assert_null(report, "no report"); rz_il_op_effect_free(op); op = rz_il_op_new_set("y", false, rz_il_op_new_bitv_from_ut64(42, 0)); - val = rz_il_validate_effect(op, ctx, NULL, &report); + val = rz_il_validate_effect(op, ctx, NULL, &t, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Global variable \"y\" referenced by set op does not exist.", "report"); rz_il_op_effect_free(op); op = rz_il_op_new_set("x", false, rz_il_op_new_bitv_from_ut64(41, 0)); - val = rz_il_validate_effect(op, ctx, NULL, &report); + val = rz_il_validate_effect(op, ctx, NULL, NULL, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Types of global variable \"x\" and set op do not agree: bitvector:42 vs. bitvector:41.", "report"); rz_il_op_effect_free(op); // local op = rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(20, 0)); - val = rz_il_validate_effect(op, ctx, NULL, &report); + val = rz_il_validate_effect(op, ctx, NULL, NULL, &report); mu_assert_true(val, "valid"); mu_assert_null(report, "no report"); rz_il_op_effect_free(op); @@ -743,7 +753,7 @@ static bool test_il_validate_effect_set() { op = rz_il_op_new_seq( rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(22, 0)), rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(22, 42))); - val = rz_il_validate_effect(op, ctx, NULL, &report); + val = rz_il_validate_effect(op, ctx, NULL, NULL, &report); mu_assert_true(val, "valid"); mu_assert_null(report, "no report"); rz_il_op_effect_free(op); @@ -751,7 +761,7 @@ static bool test_il_validate_effect_set() { op = rz_il_op_new_seq( rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(22, 0)), rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(21, 42))); - val = rz_il_validate_effect(op, ctx, NULL, &report); + val = rz_il_validate_effect(op, ctx, NULL, NULL, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Types of local variable \"x\" and set op do not agree: bitvector:22 vs. bitvector:21.", "report"); rz_il_op_effect_free(op); @@ -765,19 +775,21 @@ static bool test_il_validate_effect_jmp() { RzILOpEffect *op = rz_il_op_new_jmp(rz_il_op_new_bitv_from_ut64(24, 0x1000)); RzILValidateReport report; - bool val = rz_il_validate_effect(op, ctx, NULL, &report); + RzILTypeEffect t; + bool val = rz_il_validate_effect(op, ctx, NULL, &t, &report); mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_CTRL, "effect type"); mu_assert_null(report, "no report"); rz_il_op_effect_free(op); op = rz_il_op_new_jmp(rz_il_op_new_bitv_from_ut64(42, 0x1000)); - val = rz_il_validate_effect(op, ctx, NULL, &report); + val = rz_il_validate_effect(op, ctx, NULL, &t, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Length of dst operand (42) of jmp op is not equal to pc length 24.", "report"); rz_il_op_effect_free(op); op = rz_il_op_new_jmp(rz_il_op_new_b0()); - val = rz_il_validate_effect(op, ctx, NULL, &report); + val = rz_il_validate_effect(op, ctx, NULL, NULL, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Dst operand of jmp op is not a bitvector.", "report"); rz_il_op_effect_free(op); @@ -791,8 +803,10 @@ static bool test_il_validate_effect_goto() { RzILOpEffect *op = rz_il_op_new_goto("beach"); RzILValidateReport report; - bool val = rz_il_validate_effect(op, ctx, NULL, &report); + RzILTypeEffect t; + bool val = rz_il_validate_effect(op, ctx, NULL, &t, &report); mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_CTRL, "effect type"); mu_assert_null(report, "no report"); rz_il_op_effect_free(op); @@ -805,23 +819,67 @@ static bool test_il_validate_effect_seq() { RzILOpEffect *op = rz_il_op_new_seq(rz_il_op_new_nop(), rz_il_op_new_nop()); RzILValidateReport report; - bool val = rz_il_validate_effect(op, ctx, NULL, &report); + RzILTypeEffect t; + bool val = rz_il_validate_effect(op, ctx, NULL, &t, &report); mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_NONE, "effect type"); mu_assert_null(report, "no report"); rz_il_op_effect_free(op); op = rz_il_op_new_seq(rz_il_op_new_set("nexist", false, rz_il_op_new_b0()), rz_il_op_new_nop()); - val = rz_il_validate_effect(op, ctx, NULL, &report); + val = rz_il_validate_effect(op, ctx, NULL, &t, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Global variable \"nexist\" referenced by set op does not exist.", "report"); rz_il_op_effect_free(op); op = rz_il_op_new_seq(rz_il_op_new_nop(), rz_il_op_new_set("nexist", false, rz_il_op_new_b0())); - val = rz_il_validate_effect(op, ctx, NULL, &report); + val = rz_il_validate_effect(op, ctx, NULL, NULL, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Global variable \"nexist\" referenced by set op does not exist.", "report"); rz_il_op_effect_free(op); + // effect type handling + op = rz_il_op_new_seq(rz_il_op_new_set("x", true, rz_il_op_new_b0()), rz_il_op_new_nop()); + val = rz_il_validate_effect(op, ctx, NULL, &t, &report); + mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_DATA, "effect type"); + mu_assert_null(report, "no report"); + rz_il_op_effect_free(op); + + op = rz_il_op_new_seq(rz_il_op_new_set("x", true, rz_il_op_new_b0()), rz_il_op_new_jmp(rz_il_op_new_bitv_from_ut64(24, 0x100))); + val = rz_il_validate_effect(op, ctx, NULL, &t, &report); + mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_DATA | RZ_IL_TYPE_EFFECT_CTRL, "effect type"); + mu_assert_null(report, "no report"); + rz_il_op_effect_free(op); + + op = rz_il_op_new_seq(rz_il_op_new_jmp(rz_il_op_new_bitv_from_ut64(24, 0x100)), rz_il_op_new_set("x", true, rz_il_op_new_b0())); + val = rz_il_validate_effect(op, ctx, NULL, &t, &report); + mu_assert_false(val, "invalid"); + mu_assert_streq_free(report, "Encountered further effects after a ctrl effect in seq op.", "report"); + rz_il_op_effect_free(op); + + op = rz_il_op_new_seq(rz_il_op_new_jmp(rz_il_op_new_bitv_from_ut64(24, 0x100)), rz_il_op_new_nop()); + val = rz_il_validate_effect(op, ctx, NULL, &t, &report); + mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_CTRL, "effect type"); + mu_assert_null(report, "no report"); + rz_il_op_effect_free(op); + + op = rz_il_op_new_seq(rz_il_op_new_nop(), rz_il_op_new_jmp(rz_il_op_new_bitv_from_ut64(24, 0x100))); + val = rz_il_validate_effect(op, ctx, NULL, &t, &report); + mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_CTRL, "effect type"); + mu_assert_null(report, "no report"); + rz_il_op_effect_free(op); + + op = rz_il_op_new_seq(rz_il_op_new_nop(), rz_il_op_new_set("x", true, rz_il_op_new_b0())); + val = rz_il_validate_effect(op, ctx, NULL, &t, &report); + mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_DATA, "effect type"); + mu_assert_null(report, "no report"); + rz_il_op_effect_free(op); + rz_il_validate_global_context_free(ctx); mu_end; } @@ -831,15 +889,17 @@ static bool test_il_validate_effect_blk() { RzILOpEffect *op = rz_il_op_new_blk(NULL, rz_il_op_new_nop(), rz_il_op_new_jmp(rz_il_op_new_bitv_from_ut64(24, 0x1000))); RzILValidateReport report; - bool val = rz_il_validate_effect(op, ctx, NULL, &report); + RzILTypeEffect t; + bool val = rz_il_validate_effect(op, ctx, NULL, &t, &report); mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_CTRL, "effect type"); mu_assert_null(report, "no report"); rz_il_op_effect_free(op); op = rz_il_op_new_blk(NULL, rz_il_op_new_set("nexist", false, rz_il_op_new_b0()), rz_il_op_new_jmp(rz_il_op_new_bitv_from_ut64(24, 0x1000))); - val = rz_il_validate_effect(op, ctx, NULL, &report); + val = rz_il_validate_effect(op, ctx, NULL, &t, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Global variable \"nexist\" referenced by set op does not exist.", "report"); rz_il_op_effect_free(op); @@ -847,11 +907,46 @@ static bool test_il_validate_effect_blk() { op = rz_il_op_new_blk(NULL, rz_il_op_new_nop(), rz_il_op_new_jmp(rz_il_op_new_bitv_from_ut64(23, 0x1000))); - val = rz_il_validate_effect(op, ctx, NULL, &report); + val = rz_il_validate_effect(op, ctx, NULL, NULL, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Length of dst operand (23) of jmp op is not equal to pc length 24.", "report"); rz_il_op_effect_free(op); + // effect type handling + op = rz_il_op_new_blk(NULL, + rz_il_op_new_set("x", true, rz_il_op_new_b0()), + rz_il_op_new_jmp(rz_il_op_new_bitv_from_ut64(24, 0x1000))); + val = rz_il_validate_effect(op, ctx, NULL, &t, &report); + mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_DATA | RZ_IL_TYPE_EFFECT_CTRL, "effect type"); + mu_assert_null(report, "no report"); + rz_il_op_effect_free(op); + + op = rz_il_op_new_blk(NULL, + rz_il_op_new_set("x", true, rz_il_op_new_b0()), + rz_il_op_new_nop()); + val = rz_il_validate_effect(op, ctx, NULL, &t, &report); + mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_DATA, "effect type"); + mu_assert_null(report, "no report"); + rz_il_op_effect_free(op); + + op = rz_il_op_new_blk(NULL, + rz_il_op_new_nop(), + rz_il_op_new_set("x", true, rz_il_op_new_b0())); + val = rz_il_validate_effect(op, ctx, NULL, NULL, &report); + mu_assert_false(val, "invalid"); + mu_assert_streq_free(report, "Control effect operand of blk op does not only perform control effects.", "report"); + rz_il_op_effect_free(op); + + op = rz_il_op_new_blk(NULL, + rz_il_op_new_jmp(rz_il_op_new_bitv_from_ut64(24, 0x1000)), + rz_il_op_new_nop()); + val = rz_il_validate_effect(op, ctx, NULL, NULL, &report); + mu_assert_false(val, "invalid"); + mu_assert_streq_free(report, "Data effect operand of blk op does not only perform data effects.", "report"); + rz_il_op_effect_free(op); + rz_il_validate_global_context_free(ctx); mu_end; } @@ -861,19 +956,21 @@ static bool test_il_validate_effect_repeat() { RzILOpEffect *op = rz_il_op_new_repeat(rz_il_op_new_b0(), rz_il_op_new_nop()); RzILValidateReport report; - bool val = rz_il_validate_effect(op, ctx, NULL, &report); + RzILTypeEffect t; + bool val = rz_il_validate_effect(op, ctx, NULL, &t, &report); mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_NONE, "effect type"); mu_assert_null(report, "no report"); rz_il_op_effect_free(op); op = rz_il_op_new_repeat(rz_il_op_new_bitv_from_ut64(16, 0), rz_il_op_new_nop()); - val = rz_il_validate_effect(op, ctx, NULL, &report); + val = rz_il_validate_effect(op, ctx, NULL, &t, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Condition of repeat op is not boolean.", "report"); rz_il_op_effect_free(op); op = rz_il_op_new_repeat(rz_il_op_new_b0(), rz_il_op_new_set("nexist", false, rz_il_op_new_b0())); - val = rz_il_validate_effect(op, ctx, NULL, &report); + val = rz_il_validate_effect(op, ctx, NULL, NULL, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Global variable \"nexist\" referenced by set op does not exist.", "report"); rz_il_op_effect_free(op); @@ -884,8 +981,9 @@ static bool test_il_validate_effect_repeat() { // types remembered from the loop op = rz_il_op_new_repeat(rz_il_op_new_b0(), rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(14, 0))); HtPP *local_var_sorts; - val = rz_il_validate_effect(op, ctx, &local_var_sorts, &report); + val = rz_il_validate_effect(op, ctx, &local_var_sorts, &t, &report); mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_DATA, "effect type"); mu_assert_null(report, "no report"); mu_assert_notnull(local_var_sorts, "local var sorts"); mu_assert_eq(local_var_sorts->count, 1, "local var sorts count"); @@ -901,7 +999,7 @@ static bool test_il_validate_effect_repeat() { rz_il_op_new_set("y", true, rz_il_op_new_b0()), rz_il_op_new_repeat(rz_il_op_new_b0(), rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(14, 0))), rz_il_op_new_set("y", true, rz_il_op_new_ite(rz_il_op_new_var("y", RZ_IL_VAR_KIND_LOCAL), rz_il_op_new_b0(), rz_il_op_new_b1()))); - val = rz_il_validate_effect(op, ctx, &local_var_sorts, &report); + val = rz_il_validate_effect(op, ctx, &local_var_sorts, NULL, &report); mu_assert_true(val, "valid"); mu_assert_null(report, "no report"); mu_assert_notnull(local_var_sorts, "local var sorts"); @@ -921,7 +1019,7 @@ static bool test_il_validate_effect_repeat() { rz_il_op_new_set("y", true, rz_il_op_new_b0()), rz_il_op_new_repeat(rz_il_op_new_b0(), rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(14, 0))), rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(14, 32))); - val = rz_il_validate_effect(op, ctx, &local_var_sorts, &report); + val = rz_il_validate_effect(op, ctx, &local_var_sorts, NULL, &report); mu_assert_true(val, "valid"); mu_assert_null(report, "no report"); mu_assert_notnull(local_var_sorts, "local var sorts"); @@ -941,7 +1039,7 @@ static bool test_il_validate_effect_repeat() { rz_il_op_new_set("y", true, rz_il_op_new_b0()), rz_il_op_new_repeat(rz_il_op_new_b0(), rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(14, 0))), rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(13, 32))); - val = rz_il_validate_effect(op, ctx, &local_var_sorts, &report); + val = rz_il_validate_effect(op, ctx, &local_var_sorts, &t, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Types of local variable \"x\" and set op do not agree: bitvector:14 vs. bitvector:13.", "report"); rz_il_op_effect_free(op); @@ -951,11 +1049,27 @@ static bool test_il_validate_effect_repeat() { rz_il_op_new_set("y", true, rz_il_op_new_b0()), rz_il_op_new_repeat(rz_il_op_new_b0(), rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(14, 0))), rz_il_op_new_set("x", true, rz_il_op_new_var("x", RZ_IL_VAR_KIND_LOCAL))); - val = rz_il_validate_effect(op, ctx, &local_var_sorts, &report); + val = rz_il_validate_effect(op, ctx, &local_var_sorts, NULL, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Local variable \"x\" is not available at var op.", "report"); rz_il_op_effect_free(op); + ////////////////////////// + // effect type handling + + op = rz_il_op_new_repeat(rz_il_op_new_b0(), rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(14, 0))); + val = rz_il_validate_effect(op, ctx, NULL, &t, &report); + mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_DATA, "effect type"); + mu_assert_null(report, "no report"); + rz_il_op_effect_free(op); + + op = rz_il_op_new_repeat(rz_il_op_new_b0(), rz_il_op_new_jmp(rz_il_op_new_bitv_from_ut64(24, 0x100))); + val = rz_il_validate_effect(op, ctx, &local_var_sorts, &t, &report); + mu_assert_false(val, "invalid"); + mu_assert_streq_free(report, "Body operand of repeat op does not only perform data effects.", "report"); + rz_il_op_effect_free(op); + rz_il_validate_global_context_free(ctx); mu_end; } @@ -965,25 +1079,27 @@ static bool test_il_validate_effect_branch() { RzILOpEffect *op = rz_il_op_new_branch(rz_il_op_new_b0(), rz_il_op_new_nop(), rz_il_op_new_nop()); RzILValidateReport report; - bool val = rz_il_validate_effect(op, ctx, NULL, &report); + RzILTypeEffect t; + bool val = rz_il_validate_effect(op, ctx, NULL, &t, &report); mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_NONE, "effect type"); mu_assert_null(report, "no report"); rz_il_op_effect_free(op); op = rz_il_op_new_branch(rz_il_op_new_bitv_from_ut64(8, 0), rz_il_op_new_nop(), rz_il_op_new_nop()); - val = rz_il_validate_effect(op, ctx, NULL, &report); + val = rz_il_validate_effect(op, ctx, NULL, &t, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Condition of branch op is not boolean.", "report"); rz_il_op_effect_free(op); op = rz_il_op_new_branch(rz_il_op_new_b0(), rz_il_op_new_set("nexist", false, rz_il_op_new_b0()), rz_il_op_new_nop()); - val = rz_il_validate_effect(op, ctx, NULL, &report); + val = rz_il_validate_effect(op, ctx, NULL, &t, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Global variable \"nexist\" referenced by set op does not exist.", "report"); rz_il_op_effect_free(op); op = rz_il_op_new_branch(rz_il_op_new_b0(), rz_il_op_new_nop(), rz_il_op_new_set("nexist", false, rz_il_op_new_b0())); - val = rz_il_validate_effect(op, ctx, NULL, &report); + val = rz_il_validate_effect(op, ctx, NULL, &t, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Global variable \"nexist\" referenced by set op does not exist.", "report"); rz_il_op_effect_free(op); @@ -996,7 +1112,7 @@ static bool test_il_validate_effect_branch() { rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(14, 0)), rz_il_op_new_set("y", true, rz_il_op_new_b0())); HtPP *local_var_sorts; - val = rz_il_validate_effect(op, ctx, &local_var_sorts, &report); + val = rz_il_validate_effect(op, ctx, &local_var_sorts, &t, &report); mu_assert_true(val, "valid"); mu_assert_null(report, "no report"); mu_assert_notnull(local_var_sorts, "local var sorts"); @@ -1016,8 +1132,9 @@ static bool test_il_validate_effect_branch() { rz_il_op_new_set("y", true, rz_il_op_new_b0()), rz_il_op_new_branch(rz_il_op_new_b0(), rz_il_op_new_nop(), rz_il_op_new_nop()), rz_il_op_new_set("y", true, rz_il_op_new_ite(rz_il_op_new_var("y", RZ_IL_VAR_KIND_LOCAL), rz_il_op_new_b0(), rz_il_op_new_b1()))); - val = rz_il_validate_effect(op, ctx, &local_var_sorts, &report); + val = rz_il_validate_effect(op, ctx, &local_var_sorts, &t, &report); mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_DATA, "effect type"); mu_assert_null(report, "no report"); mu_assert_notnull(local_var_sorts, "local var sorts"); mu_assert_eq(local_var_sorts->count, 1, "local var sorts count"); @@ -1033,7 +1150,7 @@ static bool test_il_validate_effect_branch() { rz_il_op_new_set("y", true, rz_il_op_new_b0()), rz_il_op_new_branch(rz_il_op_new_b0(), rz_il_op_new_nop(), rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(14, 0))), rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(14, 32))); - val = rz_il_validate_effect(op, ctx, &local_var_sorts, &report); + val = rz_il_validate_effect(op, ctx, &local_var_sorts, NULL, &report); mu_assert_true(val, "valid"); mu_assert_null(report, "no report"); mu_assert_notnull(local_var_sorts, "local var sorts"); @@ -1052,7 +1169,7 @@ static bool test_il_validate_effect_branch() { rz_il_op_new_set("y", true, rz_il_op_new_b0()), rz_il_op_new_branch(rz_il_op_new_b0(), rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(14, 0)), rz_il_op_new_nop()), rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(14, 32))); - val = rz_il_validate_effect(op, ctx, &local_var_sorts, &report); + val = rz_il_validate_effect(op, ctx, &local_var_sorts, NULL, &report); mu_assert_true(val, "valid"); mu_assert_null(report, "no report"); mu_assert_notnull(local_var_sorts, "local var sorts"); @@ -1074,7 +1191,7 @@ static bool test_il_validate_effect_branch() { rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(14, 0)), rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(14, 42))), rz_il_op_new_set("x", true, rz_il_op_new_var("x", RZ_IL_VAR_KIND_LOCAL))); - val = rz_il_validate_effect(op, ctx, &local_var_sorts, &report); + val = rz_il_validate_effect(op, ctx, &local_var_sorts, NULL, &report); mu_assert_true(val, "valid"); mu_assert_null(report, "no report"); mu_assert_notnull(local_var_sorts, "local var sorts"); @@ -1094,7 +1211,7 @@ static bool test_il_validate_effect_branch() { rz_il_op_new_set("y", true, rz_il_op_new_b0()), rz_il_op_new_branch(rz_il_op_new_b0(), rz_il_op_new_nop(), rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(14, 0))), rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(13, 32))); - val = rz_il_validate_effect(op, ctx, &local_var_sorts, &report); + val = rz_il_validate_effect(op, ctx, &local_var_sorts, NULL, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Types of local variable \"x\" and set op do not agree: bitvector:14 vs. bitvector:13.", "report"); rz_il_op_effect_free(op); @@ -1103,7 +1220,7 @@ static bool test_il_validate_effect_branch() { rz_il_op_new_set("y", true, rz_il_op_new_b0()), rz_il_op_new_branch(rz_il_op_new_b0(), rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(14, 0)), rz_il_op_new_nop()), rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(13, 32))); - val = rz_il_validate_effect(op, ctx, &local_var_sorts, &report); + val = rz_il_validate_effect(op, ctx, &local_var_sorts, NULL, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Types of local variable \"x\" and set op do not agree: bitvector:14 vs. bitvector:13.", "report"); rz_il_op_effect_free(op); @@ -1113,7 +1230,7 @@ static bool test_il_validate_effect_branch() { rz_il_op_new_set("y", true, rz_il_op_new_b0()), rz_il_op_new_branch(rz_il_op_new_b0(), rz_il_op_new_nop(), rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(14, 0))), rz_il_op_new_set("x", true, rz_il_op_new_var("x", RZ_IL_VAR_KIND_LOCAL))); - val = rz_il_validate_effect(op, ctx, &local_var_sorts, &report); + val = rz_il_validate_effect(op, ctx, &local_var_sorts, NULL, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Local variable \"x\" is not available at var op.", "report"); rz_il_op_effect_free(op); @@ -1122,7 +1239,7 @@ static bool test_il_validate_effect_branch() { rz_il_op_new_set("y", true, rz_il_op_new_b0()), rz_il_op_new_branch(rz_il_op_new_b0(), rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(14, 0)), rz_il_op_new_nop()), rz_il_op_new_set("x", true, rz_il_op_new_var("x", RZ_IL_VAR_KIND_LOCAL))); - val = rz_il_validate_effect(op, ctx, &local_var_sorts, &report); + val = rz_il_validate_effect(op, ctx, &local_var_sorts, NULL, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Local variable \"x\" is not available at var op.", "report"); rz_il_op_effect_free(op); @@ -1134,12 +1251,52 @@ static bool test_il_validate_effect_branch() { rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(13, 0)), rz_il_op_new_set("x", true, rz_il_op_new_bitv_from_ut64(14, 42))), rz_il_op_new_set("x", true, rz_il_op_new_var("x", RZ_IL_VAR_KIND_LOCAL))); - val = rz_il_validate_effect(op, ctx, &local_var_sorts, &report); + val = rz_il_validate_effect(op, ctx, &local_var_sorts, NULL, &report); mu_assert_false(val, "invalid"); mu_assert_streq_free(report, "Control flow paths from branch op do not agree on the type of local variable \"x\": bitvector:14 vs. bitvector:13.", "report"); rz_il_op_effect_free(op); + ////////////////////////// + // effect type handling + + op = rz_il_op_new_branch(rz_il_op_new_b0(), rz_il_op_new_set("x", true, rz_il_op_new_b0()), rz_il_op_new_nop()); + val = rz_il_validate_effect(op, ctx, NULL, &t, &report); + mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_DATA, "effect type"); + mu_assert_null(report, "no report"); + rz_il_op_effect_free(op); + + op = rz_il_op_new_branch(rz_il_op_new_b0(), rz_il_op_new_nop(), rz_il_op_new_set("x", true, rz_il_op_new_b0())); + val = rz_il_validate_effect(op, ctx, NULL, &t, &report); + mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_DATA, "effect type"); + mu_assert_null(report, "no report"); + rz_il_op_effect_free(op); + + op = rz_il_op_new_branch(rz_il_op_new_b0(), rz_il_op_new_nop(), rz_il_op_new_jmp(rz_il_op_new_bitv_from_ut64(24, 0x100))); + val = rz_il_validate_effect(op, ctx, NULL, &t, &report); + mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_CTRL, "effect type"); + mu_assert_null(report, "no report"); + rz_il_op_effect_free(op); + + op = rz_il_op_new_branch(rz_il_op_new_b0(), rz_il_op_new_jmp(rz_il_op_new_bitv_from_ut64(24, 0x100)), rz_il_op_new_nop()); + val = rz_il_validate_effect(op, ctx, NULL, &t, &report); + mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_CTRL, "effect type"); + mu_assert_null(report, "no report"); + rz_il_op_effect_free(op); + + op = rz_il_op_new_branch(rz_il_op_new_b0(), + rz_il_op_new_jmp(rz_il_op_new_bitv_from_ut64(24, 0x100)), + rz_il_op_new_set("x", true, rz_il_op_new_b0())); + val = rz_il_validate_effect(op, ctx, NULL, &t, &report); + mu_assert_true(val, "valid"); + mu_assert_eq(t, RZ_IL_TYPE_EFFECT_DATA | RZ_IL_TYPE_EFFECT_CTRL, "effect type"); + mu_assert_null(report, "no report"); + rz_il_op_effect_free(op); + rz_il_validate_global_context_free(ctx); mu_end; }