aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2018-09-01 21:20:46 +0200
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2018-09-01 21:45:42 +0200
commit4fd434fd65a494592fef81937254ba89c9ae6546 (patch)
tree1d1a86ae8df525df8d6f7edd406ad300752aedea
parent9059c1e96cba1fb20359cb161892e83688e259e1 (diff)
parenta5a8f8b9a1febfbae59751d1ce25a86ada8818ae (diff)
downloadsparse-dev-4fd434fd65a494592fef81937254ba89c9ae6546.tar.gz
Merge branch 'dead-switch' into tip
* fix linearization of unreachable switch + label
-rw-r--r--ir.c55
-rw-r--r--linearize.c11
-rw-r--r--linearize.h6
-rw-r--r--validation/linear/unreachable-label0.c19
4 files changed, 83 insertions, 8 deletions
diff --git a/ir.c b/ir.c
index 1890eb13..2e284c25 100644
--- a/ir.c
+++ b/ir.c
@@ -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
+ */