Fix a mismatched new/delete ASAN error #563
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
We discovered a bug in the tear-down of
any_sender_of<>
that ASAN reports as a mismatched new/delete. I'm not certain what's required to repro the problem, but this is sort of what our repro looks like:I don't know whether the
get_scheduler
customization is necessary, or if the problem would repro with a standardany_scheduler_of<...>
.The Sender constructed (and spawned) by the above code looks like this:
When we destroy the resulting operation state, the outer
then
op state (numbered 1, above) tries to destroy the op state for theany_scheduled_sender_of<Container>
, which, through a few layers of indirection, correctly invokes thetag_invoke(_deallocate_cpo{}, ...)
implementation of_deallocate_cpo
[1]. However, thetag_invoke
overload that's found is the forwarding implementation onany_sender_of<>
's_op_for
[2], which is intended to only forward receiver queries. Since the receiver in question doesn't customize_deallocate_cpo
, we end up invokingdelete &receiver
, which is, coincidentally, stored at the beginning of the operation state forthen (2)
, leading ASAN to believe we're deleting a pointer that was new'd but with the wrong type. In fact, we're deleting an object that was never new'd because we've selected the wrongtag_invoke
overload.I believe that
_deallocate_cpo
is expecting that the only customizations will be the one provided inany_unique.hpp
[3] but, because_deallocate_cpo
matches theis_receiver_query_cpo_v
predicate, and because we've somehow goofed up how we build thetag_invoke
overload set forany_sender_of<>
's operation state, we select a different one that matches better.This diff fixes the problem by explicitly defining
is_receiver_query_cpo_v<_deallocate_cpo>
tofalse
, thus making the erroneoustag_invoke
overload a non-match. Once the undesired overload is excluded, overload resolution finds the correct one and we delete the correct object.In the future, we should probably make "is this CPO a receiver query?" an explicit opt-in somehow, rather than answering "yes" to every CPO that is not one of
set_value
,set_error
,set_done
, orconnect
.