diff options
| author | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2018-09-01 21:20:46 +0200 |
|---|---|---|
| committer | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2018-09-01 21:45:42 +0200 |
| commit | 4fd434fd65a494592fef81937254ba89c9ae6546 (patch) | |
| tree | 1d1a86ae8df525df8d6f7edd406ad300752aedea | |
| parent | 9059c1e96cba1fb20359cb161892e83688e259e1 (diff) | |
| parent | a5a8f8b9a1febfbae59751d1ce25a86ada8818ae (diff) | |
| download | sparse-dev-4fd434fd65a494592fef81937254ba89c9ae6546.tar.gz | |
Merge branch 'dead-switch' into tip
* fix linearization of unreachable switch + label
| -rw-r--r-- | ir.c | 55 | ||||
| -rw-r--r-- | linearize.c | 11 | ||||
| -rw-r--r-- | linearize.h | 6 | ||||
| -rw-r--r-- | validation/linear/unreachable-label0.c | 19 |
4 files changed, 83 insertions, 8 deletions
@@ -29,6 +29,9 @@ static int check_phi_node(struct instruction *insn) pseudo_t phi; int err = 0; + if (!has_users(insn->target)) + return err; + if (bb_list_size(insn->bb->parents) != nbr_phi_operands(insn)) { sparse_error(insn->pos, "bad number of phi operands in:\n\t%s", show_instruction(insn)); @@ -82,7 +85,40 @@ 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 check_return(struct instruction *insn) +{ + struct symbol *ctype = insn->type; + + if (ctype && ctype->bit_size > 0 && insn->src == VOID) { + sparse_error(insn->pos, "return without value"); + return 1; + } + return 0; +} + +static int validate_insn(struct entrypoint *ep, struct instruction *insn) { int err = 0; @@ -104,6 +140,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 +163,18 @@ static int validate_insn(struct instruction *insn) err += check_user(insn, insn->src); break; - case OP_ENTRY: + case OP_RET: + err += check_return(insn); + break; + 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 +196,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.c b/linearize.c index 3ef44227..c74561c9 100644 --- a/linearize.c +++ b/linearize.c @@ -2175,13 +2175,14 @@ static pseudo_t linearize_switch(struct entrypoint *ep, struct statement *stmt) struct multijmp *jmp; pseudo_t pseudo; + if (!expr || !expr->ctype) + return VOID; pseudo = linearize_expression(ep, expr); - if (pseudo == VOID) - return pseudo; - active = ep->active; - if (!bb_reachable(active)) - return VOID; + if (!active) { + active = alloc_basic_block(ep, stmt->pos); + set_activeblock(ep, active); + } switch_ins = alloc_typed_instruction(OP_SWITCH, expr->ctype); use_pseudo(switch_ins, pseudo, &switch_ins->cond); diff --git a/linearize.h b/linearize.h index 69537ee1..d4973677 100644 --- a/linearize.h +++ b/linearize.h @@ -220,6 +220,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); diff --git a/validation/linear/unreachable-label0.c b/validation/linear/unreachable-label0.c new file mode 100644 index 00000000..695e5cb0 --- /dev/null +++ b/validation/linear/unreachable-label0.c @@ -0,0 +1,19 @@ +static int foo(int a) +{ + goto label; + switch(a) { + default: +label: + break; + } + return 0; +} + +/* + * check-name: unreachable-label0 + * check-command: test-linearize $file + * + * check-output-ignore + * check-output-contains: ret\\. + * check-output-excludes: END + */ |
