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