When two or more arguments in one argument list are calls whose return type is a Managed
class, one of the returned objects is destroyed BEFORE the callee returns — even though the
callee stores it in a ref field and therefore owns it.
The ref field is left pointing at a block that is already back in the free list, so the block
is live and free at the same time. The allocator hands it out again while it is still
referenced, and the heap is corrupted from there on.
The trigger is a CALL: inlining new in the same position is handled correctly, and a single
Managed-returning call in an argument list is fine too — it takes two.
Measured with a destructor that counts objects dying between the start and the end of the call
under test (local = an ARC_Leaf assigned on a previous line):
new ARC_Pair(local, local) -> 0 ok
new ARC_Pair(new ARC_Leaf(), new ARC_Leaf()) -> 0 ok, inline new unaffected
new ARC_Pair(local, ARC_Leaf.Make()) -> 0 ok, one call
new ARC_Pair(ARC_Leaf.Make(), local) -> 0 ok, one call
ARC_Box.Of(ARC_Leaf.Make())
new ARC_Pair(ARC_Leaf.Make(), ARC_Leaf.Make()) -> 1 BUG
Skin(ARC_Leaf.Make(), ARC_Leaf.Make()) -> 1 BUG
array<ref ARC_Leaf> x = { ARC_Leaf.Make(), ARC_Leaf.Make() }; -> 1 BUG