aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2018-08-30 23:54:34 +0200
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2018-09-01 08:42:30 +0200
commit47da866ed7671944d66b1075f2beeb494e5fa924 (patch)
tree01bb9e161dfa04f3bb387021da3026229892df97
parent5cf440518858ce0fb0b6e904bf4c5cbf0670ab48 (diff)
downloadsparse-dev-47da866ed7671944d66b1075f2beeb494e5fa924.tar.gz
ir-validate: add validation branch to dead BB
All branches must target an existing BB. Validate that it is the case for BR, CBR & SWITCH (COMPUTEDGOTO is left aside for the moment). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
-rw-r--r--ir.c37
-rw-r--r--linearize.h6
2 files changed, 40 insertions, 3 deletions
diff --git a/ir.c b/ir.c
index 1890eb13..533e8e23 100644
--- a/ir.c
+++ b/ir.c
@@ -82,7 +82,29 @@ static int check_user(struct instruction *insn, pseudo_t pseudo)
return 0;
}
-static int validate_insn(struct instruction *insn)
+static int check_branch(struct entrypoint *ep, struct instruction *insn, struct basic_block *bb)
+{
+ if (bb->ep && lookup_bb(ep->bbs, bb))
+ return 0;
+ sparse_error(insn->pos, "branch to dead BB: %s", show_instruction(insn));
+ return 1;
+}
+
+static int check_switch(struct entrypoint *ep, struct instruction *insn)
+{
+ struct multijmp *jmp;
+ int err = 0;
+
+ FOR_EACH_PTR(insn->multijmp_list, jmp) {
+ err = check_branch(ep, insn, jmp->target);
+ if (err)
+ return err;
+ } END_FOR_EACH_PTR(jmp);
+
+ return err;
+}
+
+static int validate_insn(struct entrypoint *ep, struct instruction *insn)
{
int err = 0;
@@ -104,6 +126,9 @@ static int validate_insn(struct instruction *insn)
break;
case OP_CBR:
+ err += check_branch(ep, insn, insn->bb_true);
+ err += check_branch(ep, insn, insn->bb_false);
+ /* fall through */
case OP_COMPUTEDGOTO:
err += check_user(insn, insn->cond);
break;
@@ -124,8 +149,14 @@ static int validate_insn(struct instruction *insn)
err += check_user(insn, insn->src);
break;
- case OP_ENTRY:
case OP_BR:
+ err += check_branch(ep, insn, insn->bb_true);
+ break;
+ case OP_SWITCH:
+ err += check_switch(ep, insn);
+ break;
+
+ case OP_ENTRY:
case OP_SETVAL:
default:
break;
@@ -147,7 +178,7 @@ int ir_validate(struct entrypoint *ep)
FOR_EACH_PTR(bb->insns, insn) {
if (!insn->bb)
continue;
- err += validate_insn(insn);
+ err += validate_insn(ep, insn);
} END_FOR_EACH_PTR(insn);
} END_FOR_EACH_PTR(bb);
diff --git a/linearize.h b/linearize.h
index 413bf013..25fc4ce9 100644
--- a/linearize.h
+++ b/linearize.h
@@ -335,6 +335,12 @@ static inline int bb_reachable(struct basic_block *bb)
return bb != NULL;
}
+static inline int lookup_bb(struct basic_block_list *list, struct basic_block *bb)
+{
+ return lookup_ptr_list_entry((struct ptr_list *)list, bb);
+}
+
+
static inline void add_pseudo_user_ptr(struct pseudo_user *user, struct pseudo_user_list **list)
{
add_ptr_list(list, user);