aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2017-07-04 21:40:13 +0200
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2017-07-31 17:25:51 +0200
commitd254b816c4b6b8a692507567ad9127ca9991596d (patch)
treee538b707b12238bf345e8e98ca4c258ce64cc0ff
parentec3f72e981792a86a9e002471a06d61ecd5c6675 (diff)
downloadsparse-dev-d254b816c4b6b8a692507567ad9127ca9991596d.tar.gz
fix ptrlist corruption while killing unreachable BBs
In commit (51cfbc90a5 "fix: kill unreachable BBs after killing a child") kill_unreachable_bbs() was called during simplification in order to avoid creating fake cycles between phis and issuing bogus "crazy programmer" warnings. However, simplification is done via cse.c:clean_up_insns() which is looping over all BBs while kill_unreachable_bbs() loops over all BBs *and* can delete some of them which may corrupt the looping in clean_up_insns(). Fix this by: 1) refuse to emit the "crazy programmer" warning if there is a potential dead BB 2) move kill_unreachable_bbs() in the main cleanup loop which will avoid nested ep->bbs loop. Note: this solution is preferable to some others because the "crazy programmer" condition happens very rarely. It this thus better to delay this check than to call kill_unreachable_bbs() preventively. Note: the reproducer is one with very broken syntax but nothing forbid the same situation to happen with a valid program. Fixes: 51cfbc90a5e1462fcd624a1598ecd985a508a5d6 Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
-rw-r--r--cse.c2
-rw-r--r--flow.c2
-rw-r--r--linearize.c3
-rw-r--r--simplify.c9
-rw-r--r--validation/crash-ptrlist.c23
-rw-r--r--validation/crazy02-not-so.c18
6 files changed, 52 insertions, 5 deletions
diff --git a/cse.c b/cse.c
index 0d3815c5..17b3da01 100644
--- a/cse.c
+++ b/cse.c
@@ -364,6 +364,8 @@ void cleanup_and_cse(struct entrypoint *ep)
repeat:
repeat_phase = 0;
clean_up_insns(ep);
+ if (repeat_phase & REPEAT_CFG_CLEANUP)
+ kill_unreachable_bbs(ep);
for (i = 0; i < INSN_HASH_SIZE; i++) {
struct instruction_list **list = insn_hash_table + i;
if (*list) {
diff --git a/flow.c b/flow.c
index c7161d47..fce8bde2 100644
--- a/flow.c
+++ b/flow.c
@@ -840,8 +840,6 @@ void kill_unreachable_bbs(struct entrypoint *ep)
DELETE_CURRENT_PTR(bb);
} END_FOR_EACH_PTR(bb);
PACK_PTR_LIST(&ep->bbs);
-
- repeat_phase &= ~REPEAT_CFG_CLEANUP;
}
static int rewrite_parent_branch(struct basic_block *bb, struct basic_block *old, struct basic_block *new)
diff --git a/linearize.c b/linearize.c
index 7313e72d..a3672077 100644
--- a/linearize.c
+++ b/linearize.c
@@ -671,9 +671,6 @@ void insert_branch(struct basic_block *bb, struct instruction *jmp, struct basic
remove_parent(child, bb);
} END_FOR_EACH_PTR(child);
PACK_PTR_LIST(&bb->children);
-
- if (repeat_phase & REPEAT_CFG_CLEANUP)
- kill_unreachable_bbs(bb->ep);
}
diff --git a/simplify.c b/simplify.c
index a141ddd4..03ff9c94 100644
--- a/simplify.c
+++ b/simplify.c
@@ -879,6 +879,15 @@ offset:
if (new == orig) {
if (new == VOID)
return 0;
+ /*
+ * If some BB have been removed it is possible that this
+ * memop is in fact part of a dead BB. In this case
+ * we must not warn since nothing is wrong.
+ * If not part of a dead BB this will be redone after
+ * the BBs have been cleaned up.
+ */
+ if (repeat_phase & REPEAT_CFG_CLEANUP)
+ return 0;
new = VOID;
warning(insn->pos, "crazy programmer");
}
diff --git a/validation/crash-ptrlist.c b/validation/crash-ptrlist.c
new file mode 100644
index 00000000..8e9b5cb5
--- /dev/null
+++ b/validation/crash-ptrlist.c
@@ -0,0 +1,23 @@
+a;
+char b;
+c() {
+ while () {
+ int *d;
+ while () {
+ char *e = &b;
+ if (a ?: (*d = f || *0) || g) {
+ if
+ ;
+ } else {
+ int h = 0;
+ if (j) {
+ char **i = &e;
+ if (0 ? 0 : 0 ?: (**i = 1 || 0 && 0)) h ?: (*e = i && &h
+
+/*
+ * check-name: crash ptrlist
+ * check-command: test-linearize $file
+ *
+ * check-error-ignore
+ * check-output-ignore
+ */
diff --git a/validation/crazy02-not-so.c b/validation/crazy02-not-so.c
index fe713358..19ee2529 100644
--- a/validation/crazy02-not-so.c
+++ b/validation/crazy02-not-so.c
@@ -16,6 +16,24 @@ int foo(int *ptr, int i)
return 1;
}
+int bar(int *ptr, int i)
+{
+ int *p;
+
+ switch (i - i) { // will be optimized to 0
+ case 0:
+ return 0;
+ case 1: // will be optimized away
+ // p is uninitialized
+ do { // will be an unreachable loop
+ *p++ = 123;
+ } while (--i);
+ break;
+ }
+
+ return 1;
+}
+
/*
* check-name: crazy02-not-so.c
* check-command: sparse -Wno-decl $file