This is the third installment of my Perl threads experiments. Again, I have something I don't understand and seek advice before perl-bugging it.
The test program below crashes for me on both Linux and Windows when you use an external sort function -- but not if you use an inline sort block. I am using Perl 5.8.4. Any explanations?
#!/usr/bin/perl -w
use strict;
use threads;
$|=1;
sub mycmp { length($b) <=> length($a) }
sub do_one_thread {
my $kid = shift;
warn "kid $kid before sort\n";
my @list = ( 'x', 'yy', 'zzz', 'a', 'bb', 'ccc', 'aaaaa', 'z',
'hello', 's', 'thisisalongname', '1', '2', '3',
'abc', 'xyz', '1234567890', 'm', 'n', 'p' );
for my $j (1..1000) {
# This does not crash
# for my $k (sort { length($b) <=> length($a) } @list) {}
# Yet this does
for my $k (sort mycmp @list) {}
}
warn "kid $kid after sort\n";
}
sub do_threads {
my $nthreads = shift;
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";
$t->join();
warn "parent $$: thread exited\n";
}
}
# do_threads(1); # does not crash
do_threads(2); # crashes
It doesn't crash for me?
P:\test>perl -v
This is perl, v5.8.3 built for MSWin32-x86-multi-thread
(with 8 registered patches, see perl -V for more detail)
Copyright 1987-2003, Larry Wall
Binary build 809 provided by ActiveState Corp. http://www.ActiveState.com
ActiveState is a division of Sophos.
Built Feb 3 2004 00:28:51
Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.
Complete documentation for Perl, including FAQ lists, should be found on
this system using `man perl' or `perldoc perl'. If you have access to the
Internet, point your browser at http://www.perl.com/, the Perl Home Page.
P:\test>type 367162.pl
#!/usr/bin/perl -w
use strict;
use threads;
$|=1;
sub mycmp { length($b) <=> length($a) }
sub do_one_thread {
my $kid = shift;
warn "kid $kid before sort\n";
my @list = ( 'x', 'yy', 'zzz', 'a', 'bb', 'ccc', 'aaaaa', 'z',
'hello', 's', 'thisisalongname', '1', '2', '3',
'abc', 'xyz', '1234567890', 'm', 'n', 'p' );
for my $j (1..1000) {
# This does not crash
# for my $k (sort { length($b) <=> length($a) } @list) {}
# Yet this does
for my $k (sort mycmp @list) {}
}
warn "kid $kid after sort\n";
}
sub do_threads {
my $nthreads = shift;
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";
$t->join();
warn "parent $$: thread exited\n";
}
}
# do_threads(1); # does not crash
do_threads(2); # crashes
P:\test>367162
parent 320: continue
kid 1 before sort
kid 1 after sort
parent 320: continue
parent 320: waiting for join
parent 320: thread exited
parent 320: waiting for join
kid 2 before sort
kid 2 after sort
parent 320: thread exited
update: This is on v5.8.3 built for i386-linux-thread-multi. I just tried it again and I can't get your original version to crash. Weird.
I just re-built 5.8.4 from scratch and ran your test 100 times without failure.
Update: I can now reproduce the failure--reliably--with 5.8.4. This doesn't happen with 5.8.3/AS809.
The trick seems to be taking the focus away from the session running the test. If I bring up the task manager while running the loop below, every run will fail whilst the task manager has the focus and every run will complete if the cmd session has the focus.
A timing issue for sure.
P:\test>perl5.8.4 -v This is perl, v5.8.4 built for MSWin32-x86-multi-thread Copyright 1987-2004, Larry Wall Perl may be copied only under the terms of either the Artistic License or the GNU General Public License, which may be found in the Perl 5 source kit. Complete documentation for Perl, including FAQ lists, should be found on this system using `man perl' or `perldoc perl'. If you have access to the Internet, point your browser at http://www.perl.com/, the Perl Home Page. P:\test>for /l %i in (1,1,100) do perl5.8.4 367162.pl P:\test>perl5.8.4 367162.pl parent 1980: continue parent 1980: continue parent 1980: waiting for join kid 1 before sort kid 1 after sort parent 1980: thread exited parent 1980: waiting for join kid 2 before sort kid 2 after sort parent 1980: thread exited P:\test>perl5.8.4 367162.pl parent 1396: continue kid 1 before sort kid 1 after sort parent 1396: continue parent 1396: waiting for join kid 2 before sort kid 2 after sort parent 1396: thread exited parent 1396: waiting for join parent 1396: thread exited P:\test>perl5.8.4 367162.pl ...
Here's the disassembly of the segfault.
Disassembly of Function perl58.dll!sortcv (0x2807A60E) ;******************************************************************************** SYM:sortcv; pp_sort.c - Line 1634 ; ; static I32 ; sortcv(pTHX_ SV *a, SV *b) ; { 0x2807A60E: PUSH EBP 0x2807A60F: MOV EBP,ESP 0x2807A611: SUB ESP,0x10 ; pp_sort.c - Line 1635 ; I32 oldsaveix = PL_savestack_ix; 0x2807A614: MOV EAX,DWORD PTR [EBP+0x8] ; ARG:my_perl 0x2807A617: MOV EAX,DWORD PTR [EAX+0x24] 0x2807A61A: MOV DWORD PTR [EBP-0x8],EAX ; VAR:oldsaveix ; pp_sort.c - Line 1636 ; I32 oldscopeix = PL_scopestack_ix; 0x2807A61D: MOV EAX,DWORD PTR [EBP+0x8] ; ARG:my_perl 0x2807A620: MOV EAX,DWORD PTR [EAX+0x18] 0x2807A623: MOV DWORD PTR [EBP-0x4],EAX ; VAR:oldscopeix ; pp_sort.c - Line 1638 ; I32 result; ; GvSV(PL_firstgv) = a; 0x2807A626: MOV EAX,DWORD PTR [EBP+0x8] ; ARG:my_perl 0x2807A629: MOV EAX,DWORD PTR [EAX+0x1A4] > 0x2807A62F: MOV EAX,DWORD PTR [EAX] ; !!SEGFAULT (trap 5) OCCURS HERE!! 0x2807A631: MOV EAX,DWORD PTR [EAX+0x20] 0x2807A634: MOV ECX,DWORD PTR [EBP+0xC] ; ARG:a 0x2807A637: MOV DWORD PTR [EAX],ECX ; pp_sort.c - Line 1639 ; GvSV(PL_secondgv) = b; 0x2807A639: MOV EAX,DWORD PTR [EBP+0x8] ; ARG:my_perl 0x2807A63C: MOV EAX,DWORD PTR [EAX+0x1A8] 0x2807A642: MOV EAX,DWORD PTR [EAX] 0x2807A644: MOV EAX,DWORD PTR [EAX+0x20] 0x2807A647: MOV ECX,DWORD PTR [EBP+0x10] ; ARG:b 0x2807A64A: MOV DWORD PTR [EAX],ECX ; pp_sort.c - Line 1640 ; PL_stack_sp = PL_stack_base; 0x2807A64C: MOV EAX,DWORD PTR [EBP+0x8] ; ARG:my_perl 0x2807A64F: MOV ECX,DWORD PTR [EBP+0x8] ; ARG:my_perl 0x2807A652: MOV ECX,DWORD PTR [ECX+0xC] 0x2807A655: MOV DWORD PTR [EAX],ECX ; pp_sort.c - Line 1641 ; PL_op = PL_sortcop; 0x2807A657: MOV EAX,DWORD PTR [EBP+0x8] ; ARG:my_perl 0x2807A65A: MOV ECX,DWORD PTR [EBP+0x8] ; ARG:my_perl 0x2807A65D: MOV ECX,DWORD PTR [ECX+0x19C] 0x2807A663: MOV DWORD PTR [EAX+0x4],ECX ; pp_sort.c - Line 1642 ; CALLRUNOPS(aTHX); 0x2807A666: PUSH DWORD PTR [EBP+0x8] ; ARG:my_perl 0x2807A669: MOV EAX,DWORD PTR [EBP+0x8] ; ARG:my_perl 0x2807A66C: CALL DWORD PTR [EAX+0x86C] 0x2807A672: POP ECX ; pp_sort.c - Line 1643 ; if (PL_stack_sp != PL_stack_base + 1) 0x2807A673: MOV EAX,DWORD PTR [EBP+0x8] ; ARG:my_perl 0x2807A676: MOV EAX,DWORD PTR [EAX+0xC] 0x2807A679: ADD EAX,0x4 0x2807A67C: MOV ECX,DWORD PTR [EBP+0x8] ; ARG:my_perl 0x2807A67F: CMP DWORD PTR [ECX],EAX 0x2807A681: JZ 0x2807A692 ; (*+0x11) ; pp_sort.c - Line 1644 ; Perl_croak(aTHX_ "Sort subroutine didn't return single value"); 0x2807A683: PUSH 0x2811EE88 ; SYM:`string' ; DATA:Sort subroutine didn't return single value 0x2807A688: PUSH DWORD PTR [EBP+0x8] ; ARG:my_perl 0x2807A68B: CALL 0x280E6F94 ; SYM:Perl_croak 0x2807A690: POP ECX 0x2807A691: POP ECX ; pp_sort.c - Line 1645 ; if (!SvNIOKp(*PL_stack_sp)) 0x2807A692: MOV EAX,DWORD PTR [EBP+0x8] ; ARG:my_perl ; <==0x2807A681(*-0x11) 0x2807A695: MOV EAX,DWORD PTR [EAX] 0x2807A697: MOV EAX,DWORD PTR [EAX] 0x2807A699: MOV EAX,DWORD PTR [EAX+0x8] 0x2807A69C: AND EAX,0x3000000 0x2807A6A1: TEST EAX,EAX 0x2807A6A3: JNZ 0x2807A6B4 ; (*+0x11) ; pp_sort.c - Line 1646 ; Perl_croak(aTHX_ "Sort subroutine didn't return a numeric value"); 0x2807A6A5: PUSH 0x2811EE58 ; SYM:`string' ; DATA:Sort subroutine didn't return a numeric value 0x2807A6AA: PUSH DWORD PTR [EBP+0x8] ; ARG:my_perl 0x2807A6AD: CALL 0x280E6F94 ; SYM:Perl_croak 0x2807A6B2: POP ECX 0x2807A6B3: POP ECX ; pp_sort.c - Line 1647 ; result = SvIV(*PL_stack_sp); 0x2807A6B4: MOV EAX,DWORD PTR [EBP+0x8] ; ARG:my_perl ; <==0x2807A6A3(*-0x11) 0x2807A6B7: MOV EAX,DWORD PTR [EAX] 0x2807A6B9: MOV EAX,DWORD PTR [EAX] 0x2807A6BB: MOV EAX,DWORD PTR [EAX+0x8] 0x2807A6BE: AND EAX,0x10000 0x2807A6C3: TEST EAX,EAX 0x2807A6C5: JZ 0x2807A6D8 ; (*+0x13) 0x2807A6C7: MOV EAX,DWORD PTR [EBP+0x8] ; ARG:my_perl 0x2807A6CA: MOV EAX,DWORD PTR [EAX] 0x2807A6CC: MOV EAX,DWORD PTR [EAX] 0x2807A6CE: MOV EAX,DWORD PTR [EAX] 0x2807A6D0: MOV EAX,DWORD PTR [EAX+0xC] 0x2807A6D3: MOV DWORD PTR [EBP-0x10],EAX ; VAR:0x10 0x2807A6D6: JMP 0x2807A6EC ; (*+0x16) 0x2807A6D8: MOV EAX,DWORD PTR [EBP+0x8] ; ARG:my_perl ; <==0x2807A6C5(*-0x13) 0x2807A6DB: MOV EAX,DWORD PTR [EAX] 0x2807A6DD: PUSH DWORD PTR [EAX] 0x2807A6DF: PUSH DWORD PTR [EBP+0x8] ; ARG:my_perl 0x2807A6E2: CALL 0x280AA037 ; SYM:Perl_sv_2iv 0x2807A6E7: POP ECX 0x2807A6E8: POP ECX 0x2807A6E9: MOV DWORD PTR [EBP-0x10],EAX ; VAR:0x10 0x2807A6EC: MOV EAX,DWORD PTR [EBP-0x10] ; VAR:0x10; <==0x2807A6D6(*-0x16) 0x2807A6EF: MOV DWORD PTR [EBP-0xC],EAX ; VAR:result ; pp_sort.c - Line 1648 ; while (PL_scopestack_ix > oldscopeix) { 0x2807A6F2: MOV EAX,DWORD PTR [EBP+0x8] ; ARG:my_perl ; <==0x2807A706(*+0x14) 0x2807A6F5: MOV EAX,DWORD PTR [EAX+0x18] 0x2807A6F8: CMP EAX,DWORD PTR [EBP-0x4] ; VAR:oldscopeix 0x2807A6FB: JLE 0x2807A708 ; (*+0xD) ; pp_sort.c - Line 1649 ; LEAVE; 0x2807A6FD: PUSH DWORD PTR [EBP+0x8] ; ARG:my_perl 0x2807A700: CALL 0x280A4E0E ; SYM:Perl_pop_scope 0x2807A705: POP ECX ; pp_sort.c - Line 1650 ; } 0x2807A706: JMP 0x2807A6F2 ; (*-0x14) ; pp_sort.c - Line 1651 ; leave_scope(oldsaveix); 0x2807A708: PUSH DWORD PTR [EBP-0x8] ; VAR:oldsaveix ; <==0x2807A6FB(*-0xD) 0x2807A70B: PUSH DWORD PTR [EBP+0x8] ; ARG:my_perl 0x2807A70E: CALL 0x280A6A9D ; SYM:Perl_leave_scope 0x2807A713: POP ECX 0x2807A714: POP ECX ; pp_sort.c - Line 1652 ; return result; 0x2807A715: MOV EAX,DWORD PTR [EBP-0xC] ; VAR:result ; pp_sort.c - Line 1653 ; } 0x2807A718: LEAVE 0x2807A719: RET ;********************************************************************************
#0 sortcv (my_perl=0x9a4c7a0, a=0x0, b=0x0) at pp_sort.c:1591 1591 pp_sort.c: No such file or directory.Running it under the debugger worked a few times, and then crashed with a SEGV, at the same location.
perl 5.8.3 i386-linux-thread-multi.
Michael
In the test program, I found it useful to change this line in do_one_thread():
for my $j (1..1000) {
to:
for my $j (1..99999999) {
to demonstrate that the crash is not related to thread destruction.
As reported by others, the crash occurs when sortcv attempts to read memory at address zero. WinDbg spew of crash follows (perl 5.8.4):
0:002> ~* kv 0 Id: 2c48.2ad4 Suspend: 1 Teb: 7ffde000 Unfrozen ChildEBP RetAddr Args to Child 0140fbf4 77f5c534 77e7a62d 000007c0 00000000 SharedUserData!SystemCallStub+0x4 (FPO: [0,0,0]) 0140fbf8 77e7a62d 000007c0 00000000 00000000 ntdll!NtWaitForSingleObject+0xc (FPO: [3,0,0]) 0140fc5c 77e7ac21 000007c0 ffffffff 00000000 kernel32!WaitForSingleObjectEx+0xa8 (FPO: [Non-Fpo]) *** WARNING: Unable to verify checksum for c:\pperl\lib\auto\threads\threads.dll 0140fc6c 10002335 000007c0 ffffffff 00224ff8 kernel32!WaitForSingleObject+0xf (FPO: [2,0,0]) 0140fca8 10002de8 00224fec 00225fa4 00000000 threads!Perl_ithread_join+0xa5 (CONV: cdecl) [threads.xs @ 573] 0140fce8 280a1cc2 00224fec 01834f20 018e8bc4 threads!XS_threads_join+0xc0 (CONV: cdecl) [threads.xs @ 700] 0140fd80 2801d44f 00224fec 0140fda0 28059e3a perl58!Perl_pp_entersub+0x748 (CONV: cdecl) [..\pp_hot.c @ 2854] 0140fd8c 28059e3a 00224fec 00000001 0140fdd8 perl58!Perl_runops_debug+0x1c0 (CONV: cdecl) [..\dump.c @ 1442] 0140fda0 2805989c 00224fec 00000001 00000ff0 perl58!S_run_body+0x250 (CONV: cdecl) [..\perl.c @ 1921] 0140fe1c 2815d038 00224fec 00224fec 00000000 perl58!perl_run+0xb5 (CONV: cdecl) [..\perl.c @ 1840] *** WARNING: Unable to verify checksum for perl.exe 0140ff38 00401025 00000002 00224e60 00223200 perl58!RunPerl+0xc6 (CONV: cdecl) [perllib.c @ 202] 0140ff4c 00401113 00000002 00224e60 00223200 perl!main+0x15 (CONV: cdecl) [perlmain.c @ 18] 0140ffc0 77e814c7 00000000 00000000 7ffdf000 perl!mainCRTStartup+0xe3 0140fff0 00000000 00401030 00000000 00000000 kernel32!BaseProcessStart+0x23 (FPO: [Non-Fpo]) 1 Id: 2c48.2ed8 Suspend: 1 Teb: 7ffdd000 Unfrozen ChildEBP RetAddr Args to Child 02b1fd70 28100a8f 018d9914 0197e934 00000001 perl58!Perl_sv_grow+0x187 (CONV: cdecl) [..\sv.c @ 1642] 02b1fdd8 281072c8 018d9914 0197e934 018da290 perl58!Perl_sv_setsv_flags+0x16c8 (CONV: cdecl) [..\sv.c @ 4019] 02b1fdf4 2808a343 018d9914 018da290 00000001 perl58!Perl_sv_mortalcopy+0x8c (CONV: cdecl) [..\sv.c @ 6746] 02b1fe3c 2801d44f 018d9914 02b1fe54 2805ad46 perl58!Perl_pp_leaveloop+0x1d5 (CONV: cdecl) [..\pp_ctl.c @ 1774] 02b1fe48 2805ad46 018d9914 02b1ff54 2805a896 perl58!Perl_runops_debug+0x1c0 (CONV: cdecl) [..\dump.c @ 1442] 02b1fe54 2805a896 018d9914 02b1ff1c 00000000 perl58!S_call_body+0x50 (CONV: cdecl) [..\perl.c @ 2285] 02b1ff54 10001832 018d9914 0197e7cc 00000004 perl58!Perl_call_sv+0x701 (CONV: cdecl) [..\perl.c @ 2203] 02b1ffb4 77e7d33b 0022e28c 018dd550 0101000b threads!Perl_ithread_run+0x219 (CONV: stdcall) [threads.xs @ 300] 02b1ffec 00000000 1000106e 0022e28c 00000000 kernel32!BaseThreadStart+0x37 (FPO: [Non-Fpo]) # 2 Id: 2c48.1ce4 Suspend: 1 Teb: 7ffdc000 Unfrozen ChildEBP RetAddr Args to Child 03b1f794 280aee43 0193412c 019ef8a0 019ef888 perl58!sortcv+0x21 (CONV: cdecl) [..\pp_sort.c @ 1638] 03b1fd08 280aebae 0193412c 019ea658 00000014 perl58!S_mergesortsv+0x28e (CONV: cdecl) [..\pp_sort.c @ 424] 03b1fd34 280b1245 0193412c 019ea658 00000014 perl58!Perl_sortsv+0xae (CONV: cdecl) [..\pp_sort.c @ 1410] 03b1fe3c 2801d44f 0193412c 03b1fe54 2805ad46 perl58!Perl_pp_sort+0xcde (CONV: cdecl) [..\pp_sort.c @ 1577] 03b1fe48 2805ad46 0193412c 03b1ff54 2805a896 perl58!Perl_runops_debug+0x1c0 (CONV: cdecl) [..\dump.c @ 1442] 03b1fe54 2805a896 0193412c 03b1ff1c 00000000 perl58!S_call_body+0x50 (CONV: cdecl) [..\perl.c @ 2285] 03b1ff54 10001832 0193412c 019ef7bc 00000004 perl58!Perl_call_sv+0x701 (CONV: cdecl) [..\perl.c @ 2203] 03b1ffb4 77e7d33b 01950fac 018e7050 0101000b threads!Perl_ithread_run+0x219 (CONV: stdcall) [threads.xs @ 300] 03b1ffec 00000000 1000106e 01950fac 00000000 kernel32!BaseThreadStart+0x37 (FPO: [Non-Fpo]) 0:002> u eip perl58!sortcv+0x21 [..\pp_sort.c @ 1638]: 280b1932 8b02 mov eax,[edx] 280b1934 8b4820 mov ecx,[eax+0x20] 280b1937 8b550c mov edx,[ebp+0xc] 280b193a 8911 mov [ecx],edx 280b193c 8b4508 mov eax,[ebp+0x8] 280b193f 8b88a8010000 mov ecx,[eax+0x1a8] 280b1945 8b11 mov edx,[ecx] 280b1947 8b4220 mov eax,[edx+0x20] 0:002> .exr -1 ExceptionAddress: 280b1932 (perl58!sortcv+0x00000021) ExceptionCode: c0000005 (Access violation) ExceptionFlags: 00000000 NumberParameters: 2 Parameter[0]: 00000000 Parameter[1]: 00000000 Attempt to read from address 00000000
I hacked the thread-id into deb.c/Perl_vdeb() so that perl -Dt also prints thread-id. The crashes seem to occur when one thread does a POPBLOCK/LEAVE as a sort finishes inside the for(). I further noticed that when I change:
for my $k (sort mycmp @list) {}
to simply:
sort mycmp @list;
the crashes go away. Edited perl -Dtlsv output follows:
4440: (p5-5A.pl:7) gvsv(main::a) 4440: (p5-5A.pl:7) length 4440: (p5-5A.pl:7) ncmp 4440: (p5-5A.pl:7) leavesub 4440: (p5-5A.pl:7) nextstate 4440: (p5-5A.pl:7) gvsv(main::b) 4440: (p5-5A.pl:7) length 4440: (p5-5A.pl:7) gvsv(main::a) 4440: (p5-5A.pl:7) length 9432: (p5-5A.pl:7) length 9432: (p5-5A.pl:7) ncmp 9432: (p5-5A.pl:7) leavesub 9432: (p5-5A.pl:7) nextstate 9432: (p5-5A.pl:7) gvsv(main::b) 9432: (p5-5A.pl:7) length 9432: (p5-5A.pl:7) gvsv(main::a) 9432: (p5-5A.pl:7) length 9432: (p5-5A.pl:7) ncmp 4440: (p5-5A.pl:7) ncmp 4440: (p5-5A.pl:7) leavesub 4440: (p5-5A.pl:7) nextstate 4440: (p5-5A.pl:7) gvsv(main::b) 4440: (p5-5A.pl:7) length 4440: (p5-5A.pl:7) gvsv(main::a) 4440: (p5-5A.pl:7) length 4440: (p5-5A.pl:7) ncmp *** tid=4440 crashed around here *** 9432: (p5-5A.pl:7) leavesub 9432: (p5-5A.pl:19) POPBLOCK scope 7 at ..\pp_sort.c:1579 9432: (p5-5A.pl:19) LEAVE scope 7 at ..\pp_sort.c:1627 9432: (p5-5A.pl:19) enteriter 9432: (p5-5A.pl:19) ENTER scope 7 at ..\pp_ctl.c:1666 9432: (p5-5A.pl:19) ENTER scope 8 at ..\pp_ctl.c:1697 9432: (p5-5A.pl:19) iter 9432: (p5-5A.pl:19) and (tid=9432 continues on)
perlmonks.org content © perlmonks.org and BrowserUk, eyepopslikeamosquito, mpeppler, PodMaster
prlmnks.org © 2006 edmund von der burg (eccles & toad)
v 0.03