<div dir="ltr"><div>Hi,</div><div><br></div><div>Following is a test case which makes Perl > 5.22 crash.</div><div>I tested it on Perl 34, 38 and 42.</div><div><br></div><div>The corruptions usually segfault, or can generate scope errors like:<br>      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.</div><div>or ref errors like:<br>      Attempt to free unreferenced scalar: SV 0x55cc1a8d90 at /usr/local/perl/lib/site_perl/5.38.2/aarch64-linux/Coro/AnyEvent.pm line 357.<br><br></div><div>And sometimes, the test passes.</div><div><br></div><div>The Coro/AnyEvent.pm line 357 is outline below:</div><div><pre id="gmail-metacpan_source" class="gmail-line-numbers gmail-pod-toggle gmail-pod-hidden" style="margin-left:40px"><div class="gmail-line gmail-number353 gmail-index352 gmail-alt2"><code class="gmail-perl gmail-keyword">sub</code> <code class="gmail-perl gmail-plain">Coro::AnyEvent::CondVar::_wait {</code></div><div class="gmail-line gmail-number354 gmail-index353 gmail-alt1"><code class="gmail-perl gmail-spaces">   </code><code class="gmail-perl gmail-keyword">until</code> <code class="gmail-perl gmail-plain">(</code><code class="gmail-perl gmail-variable">$_</code><code class="gmail-perl gmail-plain">[0]{_ae_sent}) {</code></div><div class="gmail-line gmail-number355 gmail-index354 gmail-alt2"><code class="gmail-perl gmail-spaces">      </code><code class="gmail-perl gmail-variable">$AnyEvent::CondVar::Base::WAITING</code> <code class="gmail-perl gmail-plain">= 0; </code><code class="gmail-perl gmail-comments"># avoid recursive check by AnyEvent</code></div><div class="gmail-line gmail-number356 gmail-index355 gmail-alt1"><code class="gmail-perl gmail-spaces">      </code><code class="gmail-perl gmail-keyword">local</code> <code class="gmail-perl gmail-variable">$_</code><code class="gmail-perl gmail-plain">[0]{_ae_coro} = </code><code class="gmail-perl gmail-variable">$Coro::current</code><code class="gmail-perl gmail-plain">;</code></div><div class="gmail-line gmail-number357 gmail-index356 gmail-alt2"><code class="gmail-perl gmail-spaces">      </code><code class="gmail-perl gmail-plain">Coro::schedule; # <<<<<< Line 357</code></div><div class="gmail-line gmail-number358 gmail-index357 gmail-alt1"><code class="gmail-perl gmail-spaces">   </code><code class="gmail-perl gmail-plain">}</code></div><div class="gmail-line gmail-number359 gmail-index358 gmail-alt2"><code class="gmail-perl gmail-plain">};</code></div></pre>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".<br></div><div>It says the ref-cycle created by $_[0]{_ae_coro} = $Coro::current could also be problematic.</div><div><br></div><div>The suggested fix is to not use local in this case (and to break the ref cycle, but that's not strictly necessary):</div><div><div style="margin-left:40px">sub Coro::AnyEvent::CondVar::_wait {<br>   my $self = shift;<br>   until ($self->{_ae_sent}) {<br>      $AnyEvent::CondVar::Base::WAITING = 0; # avoid recursive check by AnyEvent<br><br>      # Prevent stack corruption with local+refcycles+strong ref on CV.<br>      # Set the coro reference manually (No 'local')<br>      # Weaken ensures there is no ref-cycle (coro->cv->coro).<br>      weaken($self->{_ae_coro} = $Coro::current);<br><br>      # Use a lexical guard to guarantee cleanup during exception unwinding<br>      scope_guard {<br>         delete $self->{_ae_coro};<br>      };<br><br>      Coro::schedule;<br>   }<br>};<br></div><br></div><div>At least, this fix lets the test pass.</div><div><br></div><div><br></div><div>The test follows:</div><div><br></div><div><br></div><div>$|=1;<br>print "1..10\n";<br><br>use EV;<br>use AnyEvent;<br>use Coro;<br>use Guard;<br><br>my $wakeup = AE::cv;<br>my $lock = AE::cv;<br>my $ref;<br>my $coro = async {<br>  my $guard = guard {<br>    print "ok 6 - guard called\n";<br>  };<br>  # Somehow, necessary to reproduce the problem.<br>  # We've seen refcnt errors as well... so maybe related.<br>  $ref = $wakeup;<br><br>  my $timer = AE::timer 1, 0, sub { $wakeup->(1); };<br>  print "ok 2 - coro waiting\n";<br>  $wakeup->recv;<br>  print "notok 10 - coro cancelled\n";<br>  exit 1;<br>};<br>$coro->on_destroy(sub {<br>  print "ok 7 - enter destroy\n";<br>  $lock->send;<br>  print "ok 8 - leave destroy\n";<br>});<br><br>print "ok 1 - coro created\n";<br><br>Coro::cede;<br>print "ok 3 - coro ready\n";<br><br>$coro->safe_cancel();<br>print "ok 4 - coro cancelled\n";<br><br>$coro->join();<br>print "ok 5 - coro joined\n";<br><br># Segfault here.<br>$lock->recv;<br>print "ok 9 - coro destroyed notified\n";<br><br>$coro = undef;<br>print "ok 10 - coro freed\n";<br><br></div></div>