Skip Menu |

This queue is for tickets about the Kavorka CPAN distribution.

Report information
The Basics
Id: 94015
Status: resolved
Priority: 0/
Queue: Kavorka

People
Owner: Nobody in particular
Requestors: ajt [...] thermeon.com
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: (no value)



Subject: segfault on joining multiple threads using Kavorka
Date: Wed, 19 Mar 2014 20:24:47 +0000
To: bug-Kavorka [...] rt.cpan.org
From: Aaron Trevena <ajt [...] thermeon.com>
Using kavorka in threaded code is crashing very hard.. even managing to make my terminal hang, quite impressive for a relatively innocuous test case .. test script: use strict; use Test::More; use threads; { package ThreadedExample; use Kavorka; use Moose; method foo { return { '$self' => $self, '@_' => \@_ }; } } my $subref = sub { my $id = shift; warn "id : $id"; # sleep 1; return $id; }; my @threads; foreach my $foo_id (qw/bar1 bar2 bar3 bar4 bar5 bar6/){ push @threads, threads->create($subref, $foo_id); # sleep 1; # push @threads, threads->create($subref, $foo_id . 'A'); } my @results; for my $thread (@threads){ warn "joining thread $thread"; push @results, $thread->join; } ok(1); # didn't explode! done_testing; output : perl -w kavorka_thread.t id : bar1 at kavorka_thread.t line 16. id : bar2 at kavorka_thread.t line 16. id : bar3 at kavorka_thread.t line 16. id : bar4 at kavorka_thread.t line 16. id : bar5 at kavorka_thread.t line 16. joining thread threads=SCALAR(0x941b3b8) at kavorka_thread.t line 30. id : bar6 at kavorka_thread.t line 16. joining thread threads=SCALAR(0x941b3d8) at kavorka_thread.t line 30. joining thread threads=SCALAR(0x941b3f8) at kavorka_thread.t line 30. *** glibc detected *** perl: malloc(): smallbin double linked list corrupted: 0x0b501738 *** ^C Sometimes will get segfault and dumped core, using in a Moose::Role will almost always give a segfault rather than the double link list corruption. We've also seen the same error message happen in the same place with Moops, so it's some trick that they're both doing that fails in this way

Message body is not shown because it is too large.

Test case passes on my (32-bit) machine with threaded Perl 5.16.2, but fails on (64-bit) Travis Perl 5.14.2, 5.16.2 and 5.18.2 builds. It passes on an non-threaded Perl using the very awesome forks.pm module (that emulates threads using fork). Here's the link to the Travis build: https://travis-ci.org/tobyink/p5-kavorka/builds/21172617 As an aside, here's an interesting quote from the Perl 5.19.10 perldelta pod: https://metacpan.org/pod/release/ARC/perl-5.19.10/pod/perldelta.pod#Discouraged-features | The "interpreter-based threads" provided by | Perl are not the fast, lightweight system for | multitasking that one might expect or hope | for. Threads are implemented in a way that | make them easy to misuse. Few people know how | to use them correctly or will be able to | provide help. The use of interpreter-based | threads in perl is officially discouraged. I consider this a bug that does need to be fixed, but I'll need to find a box that I can replicate the issue on. (Other than Travis, because I can't exactly SSH into that.)
You and Travis both seem to be using glibc 2.15; I'm using 2.17. I wonder if that makes a difference?
I've done a bit if tweaking of the 99thread.t in the git repo and it seems that if I have: { package ThreadedExample; use Kavorka () } as the block that uses Kavorka, the join happens successfully, but if I do: { package ThreadedExample; use Kavorka(fun) } we blow up at join time, so we're getting the problem set up by something that gets done as a result of Kavorka->import. My immediate thought was that it was likely to be something to do with Parse::Keyword::install_keyword_handler, but if I comment out the call to that, the test still fails. This makes me wonder if the problem might be with Exporter::Tiny. I'm going to keep hollowing out Kavorka::_exporter_fail and see what happens.
And... we have a winner. If I adjust Kavorka so that _exporter_fail looks like this: sub _exporter_fail { my $me = shift; my ($name, $args, $globals) = @_; Module::Runtime::use_package_optimistically('Kavorka::Sub::Fun'); return ($name => sub { "Sub $name" }; } Then the join blows up. If I comment out the call to use_package_optimistically, all is well.
I think we've unearthed a glib bug. Because when I replace the Module::Runtime::use_package_optimistically with what it eventually reduces to: eval "require $implementation"; the join blows up. That's not a Kavorka bug. That's something very wrong with either our Perl build (unlikely) or the glib that's doing the complaining.
Forget that last. Replaced 'eval "require $implementation"' with 'require Kavorka::Sub::Fun' and we're back to blowing up.
More narrowing. In the test, if I do: { package ThreadedExample; use Devel::Pragma } Then we blow up at the join.
It turns out that, if you roll Devel::Pragma back to version 0.54, the problem goes away on 64-bit threaded perl, in case anyone else is experiencing this issue.
Thanks for tracking down the source of the bug, and for your pull request. I'll upload a new release in a few minutes.