Skip Menu |

Preferred bug tracker

Please visit the preferred bug tracker to report your issue.

This queue is for tickets about the Test-Simple CPAN distribution.

Report information
The Basics
Id: 6782
Status: resolved
Priority: 0/
Queue: Test-Simple

People
Owner: Nobody in particular
Requestors: ajsavige [...] yahoo.com.au
Cc:
AdminCc:

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



Subject: Test::More not thread safe due to perl sort bug
Test-Simple-0.47. perl version 5.8.4. As described in perl bug #30333 "threads sort crashes with sort subroutine (but not with sort block)" using sort subroutines is not thread safe. Because this perl bug presumably goes way back to many earlier perl versions, it seems best to work around it in Test/More.pm. I did a search of all perl core code and the only place that uses a sort subroutine is Test/More.pm. In More.pm, the _bogus_sort subroutine is used in only two places (both as a sort subroutine). The attached patch inlines _bogus_sort as a sort block to work around perl bug #30333. /-\
--- More.pm 2004-06-29 13:27:05.000000000 +1000 +++ More.pm.orig 2004-06-29 13:25:24.000000000 +1000 @@ -1117,15 +1117,14 @@ # We must make sure that references are treated neutrally. It really # doesn't matter how we sort them, as long as both arrays are sorted # with the same algorithm. -# Inlined _bogus_sort twice in eq_set below to work around perl threading bug #30333. -# sub _bogus_sort { local $^W = 0; ref $a ? 0 : $a cmp $b } +sub _bogus_sort { local $^W = 0; ref $a ? 0 : $a cmp $b } sub eq_set { my($a1, $a2) = @_; return 0 unless @$a1 == @$a2; # There's faster ways to do this, but this is easiest. - return eq_array( [sort { local $^W = 0; ref $a ? 0 : $a cmp $b } @$a1], [sort { local $^W = 0; ref $a ? 0 : $a cmp $b } @$a2] ); + return eq_array( [sort _bogus_sort @$a1], [sort _bogus_sort @$a2] ); } =back
[guest - Mon Jun 28 23:34:41 2004]: Show quoted text
> In More.pm, the _bogus_sort subroutine is used in only two places > (both as a sort subroutine). The attached patch inlines _bogus_sort > as a sort block to work around perl bug #30333.
Could you provide some Test::More code where this causes problems? PS I think you got the patch backwards.
[MSCHWERN - Wed Nov 24 16:46:48 2004]: Show quoted text
> [guest - Mon Jun 28 23:34:41 2004]:
> > In More.pm, the _bogus_sort subroutine is used in only two places > > (both as a sort subroutine). The attached patch inlines _bogus_sort > > as a sort block to work around perl bug #30333.
> > Could you provide some Test::More code where this causes problems? > > PS I think you got the patch backwards.
Since the core sort construct in question is "deeply, deeply, not thread-safe" (D. Mitchell) there are doubtless many ways to demonstrate a crash in any Perl module that uses it. The following test program demonstrates the bug for both Test-Simple-0.47 and Test-Simple-0.51. I tested with Perl version 5.8.4/5.8.5 (with ithreads) on both Linux and Windows. (If you want me to improve this test program for addition to the Test-Simple test suite, please let me know). #!/usr/bin/perl -w # Crash Test::More due to thread-hostile perl sort #30333 bug. use strict; use threads; # Passes with $nthreads = 1 and with eq_set(). # Passes with $nthreads = 2 and with eq_array(). # Fails with $nthreads = 2 and with eq_set(). my $nthreads = 2; use Test::More; plan tests => $nthreads; sub do_one_thread { my $kid = shift; my @list = ( 'x', 'yy', 'zzz', 'a', 'bb', 'ccc', 'aaaaa', 'z', 'hello', 's', 'thisisalongname', '1', '2', '3', 'abc', 'xyz', '1234567890', 'm', 'n', 'p' ); my @list2 = @list; warn "# kid $kid before eq_set\n"; sleep(1); for my $j (1..9999) { # With eq_set, either crashes or get: # "thread failed to start: panic: pp_iter at .../More.pm line 1127". # (Test-Simple-0.47) or line 1176 (Test-Simple-0.51). # Replace eq_set() with eq_array() and the panic goes away. eq_set(\@list, \@list2); # eq_array(\@list, \@list2); } warn "# kid $kid exit\n"; return 42; } my @kids = (); for my $i (1..$nthreads) { my $t = threads->new(\&do_one_thread, $i); warn "# parent $$: continue\n"; push(@kids, $t); } for my $t (@kids) { warn "# parent $$: waiting for join\n"; my $rc = $t->join(); cmp_ok( $rc, '==', 42, "threads exit status is $rc" ); }