Stack corruption with Coro and AE::cv
Laurent
laurent.aml at gmail.com
Wed May 27 00:59:30 CEST 2026
Hi,
Following is a test case which makes Perl > 5.22 crash.
I tested it on Perl 34, 38 and 42.
The corruptions usually segfault, or can generate scope errors like:
perl: scope.c:1247: Perl_leave_scope: Assertion `!((((sv)->sv_flags &
(0x00004000|0x00008000)) == 0x00008000) && (((svtype)((sv)->sv_flags &
0xff)) == SVt_PVGV || ((svtype)((sv)->sv_flags & 0xff)) == SVt_PVLV))'
failed.
or ref errors like:
Attempt to free unreferenced scalar: SV 0x55cc1a8d90 at
/usr/local/perl/lib/site_perl/5.38.2/aarch64-linux/Coro/AnyEvent.pm line
357.
And sometimes, the test passes.
The Coro/AnyEvent.pm line 357 is outline below:
sub Coro::AnyEvent::CondVar::_wait {
until ($_[0]{_ae_sent}) {
$AnyEvent::CondVar::Base::WAITING = 0; # avoid recursive check by AnyEvent
local $_[0]{_ae_coro} = $Coro::current;
Coro::schedule; # <<<<<< Line 357
}
};
An AI suggestion is that this is due to the savestack being modified,
because of the $ref reference, so that unwinding the "local
$_[0]{_ae_coro}" at cancel time somehow fails to properly clean up
$_[0]{_ae_coro}, leaving it with an "unreferenced scalar".
It says the ref-cycle created by $_[0]{_ae_coro} = $Coro::current could
also be problematic.
The suggested fix is to not use local in this case (and to break the ref
cycle, but that's not strictly necessary):
sub Coro::AnyEvent::CondVar::_wait {
my $self = shift;
until ($self->{_ae_sent}) {
$AnyEvent::CondVar::Base::WAITING = 0; # avoid recursive check by
AnyEvent
# Prevent stack corruption with local+refcycles+strong ref on CV.
# Set the coro reference manually (No 'local')
# Weaken ensures there is no ref-cycle (coro->cv->coro).
weaken($self->{_ae_coro} = $Coro::current);
# Use a lexical guard to guarantee cleanup during exception unwinding
scope_guard {
delete $self->{_ae_coro};
};
Coro::schedule;
}
};
At least, this fix lets the test pass.
The test follows:
$|=1;
print "1..10\n";
use EV;
use AnyEvent;
use Coro;
use Guard;
my $wakeup = AE::cv;
my $lock = AE::cv;
my $ref;
my $coro = async {
my $guard = guard {
print "ok 6 - guard called\n";
};
# Somehow, necessary to reproduce the problem.
# We've seen refcnt errors as well... so maybe related.
$ref = $wakeup;
my $timer = AE::timer 1, 0, sub { $wakeup->(1); };
print "ok 2 - coro waiting\n";
$wakeup->recv;
print "notok 10 - coro cancelled\n";
exit 1;
};
$coro->on_destroy(sub {
print "ok 7 - enter destroy\n";
$lock->send;
print "ok 8 - leave destroy\n";
});
print "ok 1 - coro created\n";
Coro::cede;
print "ok 3 - coro ready\n";
$coro->safe_cancel();
print "ok 4 - coro cancelled\n";
$coro->join();
print "ok 5 - coro joined\n";
# Segfault here.
$lock->recv;
print "ok 9 - coro destroyed notified\n";
$coro = undef;
print "ok 10 - coro freed\n";
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.schmorp.de/pipermail/anyevent/attachments/20260526/4f5b9fe0/attachment.htm>
More information about the anyevent
mailing list