Random segfaults when using AnyEvent::HTTP

Yuriy Ustushenko yoreek at yahoo.com
Fri Dec 11 22:29:54 CET 2015


Hi all!

I have script below to reproduce the problem (for testing you need some 
HTTP server):
#!/usr/bin/perl

use warnings;
use strict;
use AnyEvent::HTTP;
use EV;

my $url                = $ARGV[0] || 'http://google.com';
my $max_pending_reqs   = $ARGV[1] || 100;
my $max_completed_reqs = $ARGV[2] || 1;

print "AnyEvent::VERSION:            $AnyEvent::VERSION\n";
print "EV::VERSION:                  $EV::VERSION\n";
print "AnyEvent::HTTP::VERSION:      $AnyEvent::HTTP::VERSION\n";
print "AnyEvent::HTTP::MAX_PER_HOST: $AnyEvent::HTTP::MAX_PER_HOST\n";

my $cv = AnyEvent->condvar();
$cv->begin();
my $completed = 0;

for (1 .. $max_pending_reqs) {
     $cv->begin();
     http_request GET => $url, sub {
         $completed++;
         print "completed: $completed\n";
         if ($completed == $max_completed_reqs) {
             # break
             $cv->send();
             return;
         }
         # some work
         $cv->end();
     };
}

$cv->end();
$cv->recv();

Debugger output:
(gdb) run ./ae_http_test.pl http://192.168.1.1
Starting program: /usr/bin/perl ./ae_http_test.pl http://192.168.1.1
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
AnyEvent::VERSION:            7.04
EV::VERSION:                  4.18
AnyEvent::HTTP::VERSION:      2.22
AnyEvent::HTTP::MAX_PER_HOST: 4
completed: 1
OK

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff66810f4 in XS_EV_timer (my_perl=<optimized out>, 
cv=<optimized out>) at EV.xs:686

This bug reproduce when $AnyEvent::HTTP::MAX_PER_HOST is smaller than 
the total pending requests.

After investigating the problem, I think it is due to use the guard that 
executes a callback
during global destruction, but at this point some objects have been 
destroyed.
So in this case, the object EV::Loop has already been destroyed and when 
we try to create a timer
we get an error.


After debugging EV module(EV.xs) and tracking default_loop_sv I got the 
following results:
e_new loop: cc65c8 SvRV(loop): cc65b0
default_loop_sv at ae/AnyEvent-7.11/blib/lib/AnyEvent/Socket.pm line 
1062 during global destruction.
SV = IV(0xcc65b8) at 0xcc65c8
   REFCNT = 1
   FLAGS = (ROK,READONLY)
   RV = 0xcc65b0
     SV = PVMG(0x13cf7a8) at 0xcc65b0
       REFCNT = 10
       FLAGS = (OBJECT,IOK,READONLY,pIOK)
       IV = 139917662998016
       NV = 0
       PV = 0
       STASH = 0x14f9a88	"EV::Loop"
...

e_new loop: cc65c8 SvRV(loop): 0
default_loop_sv at ae/AnyEvent-7.11/blib/lib/AnyEvent/Socket.pm line 
1018 during global destruction.
SV = IV(0xcc65b8) at 0xcc65c8
   REFCNT = 1
   FLAGS = (READONLY)
   IV = 0
In the last case, EV::Loop object has already been destroyed, and we'll 
get an error.


To more easily reproduce the problem you can use a script below:
#!/usr/bin/perl

use warnings;
use strict;
use AnyEvent;
use AnyEvent::Util;

AnyEvent->condvar();

our @stash;
push @stash, AnyEvent::Util::guard {
     my $w; $w = AnyEvent->timer(after => 1, cb => sub {
         warn "timer activated";
         undef $w;
     });
};


Maybe it's not a bug? Maybe it's a feature ?

-- 
Yuriy Ustushenko



More information about the anyevent mailing list