diff options
| author | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2018-08-30 23:54:34 +0200 |
|---|---|---|
| committer | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2018-09-01 08:42:30 +0200 |
| commit | 47da866ed7671944d66b1075f2beeb494e5fa924 (patch) | |
| tree | 01bb9e161dfa04f3bb387021da3026229892df97 | |
| parent | 5cf440518858ce0fb0b6e904bf4c5cbf0670ab48 (diff) | |
| download | sparse-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.c | 37 | ||||
| -rw-r--r-- | linearize.h | 6 |
2 files changed, 40 insertions, 3 deletions
@@ -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); |
