passes: zero ambiguously lived slots at kill sites

Consider the following control flow:

for ... {
	statepoint1 // x is not live here
	{ // inner scope, probably due to inlining
		lifetime_start(x)
		if ... {
			x = ...
			use(&x)
		}
		statepoint2 // x is live here
		lifetime_end(x)
	}
}

Here, x is defined in the inner if block, and has its address
taken. It also has bounded lifetime (e.g. due to inlining). x is
live at statepoint2, as its address may still be used, then it
is killed. At next iteration x is not live at statepoint1, so
its referenced object could be collected there. Then it goes to
the inner scope, and the if branch is not taken, at statepoint2,
x is still holding the old value, which comes back to live
again, which is bad.

To prevent this, we need to zero x at the kill site, so the GC
won't see the old value of x once it is killed.

Change-Id: Iaf6a6d0002e24aa3576d52adb162aae47973d27f
Reviewed-on: https://go-review.googlesource.com/c/156557
Reviewed-by: Than McIntosh <thanm@google.com>
diff --git a/passes/GoStatepoints.cpp b/passes/GoStatepoints.cpp
index 6b22e10..ccd8501 100644
--- a/passes/GoStatepoints.cpp
+++ b/passes/GoStatepoints.cpp
@@ -1588,6 +1588,12 @@
   }
 }
 
+// Zero ambigously lived stack slots. We insert zeroing at lifetime
+// start (or the entry block), so the GC won't see uninitialized
+// content. We also insert zeroing at kill sites, to ensure the GC
+// won't see a dead slot come back to life.
+// We also conservatively extend the lifetime of address-taken slots,
+// to prevent the slot being reused while it is still recorded live.
 static void
 zeroAmbiguouslyLiveSlots(Function &F, SetVector<Value *> &ToZero,
                          SetVector<Value *> &AddrTakenAllocas) {
@@ -1620,8 +1626,14 @@
           }
         } else if (Fn->getIntrinsicID() == Intrinsic::lifetime_end) {
           Value *V = I.getOperand(1)->stripPointerCasts();
-          if (ToZero.count(V) != 0 && AddrTakenAllocas.count(V) != 0)
+          if (ToZero.count(V) != 0 && AddrTakenAllocas.count(V) != 0) {
+            if (!succ_empty(I.getParent())) { // no need to zero at exit block
+              IRBuilder<> Builder(&I);
+              Value *Zero = Constant::getNullValue(V->getType()->getPointerElementType());
+              Builder.CreateStore(Zero, V);
+            }
             InstToDelete.push_back(&I);
+          }
         }
       }
   }