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);
+ }
}
}
}