I might be missing something, but isn't that what is supposed to happen? If `RtwqInvokeCallback()` fails (and `tracked_result` is then released), then nobody will ever pick the sample up again, so it is appropriate to have it freed, isn't it?
As you say, after `SetAllocator()` is called `refcount == 2` (one reference is the client, the other is the object self-reference itself) and `tracked_refcount == 1` (the self-reference again). Once the client code is done, it calls `Release()` and `refcount` drops to 1, so the callback is called.
* If the callback succeeds, presumably the client (specifically, the sample allocator, I believe) code will take a reference to the sample again, so `refcount` will become 2 again. After the async result is released and presumably freed, it will release the self-reference to the sample, so `refcount` will go to 1 again. And of course `tracked_refcount` is set to zero. This seems to be correct: at the end of the process there is precisely a reference to the sample, by the sample allocator.
* If the callback fails, the client will never recover a reference to the sample, so `refcount` will remain at 1, just to drop to zero once the async result is freed. This is correct: nobody holds a reference to the sample any more, and then it's correct to free it.
So I don't understand what is the problem that you're seeing.