Skip Menu |
Report information
Id: 128870
Status: open
Priority: 0/
Queue: perl6

Owner: jnthn [at] jnthn.net
Requestors: alex.jakimenko [at] gmail.com
Cc:
AdminCc:

Severity: (no value)
Tag: (no value)
Platform: (no value)
Patch Status: (no value)
VM: (no value)



Subject: [SEGV] Pushing into the same array from two threads segfaults reliably
While it is probably a bad idea to push values into the same array from two threads, if I recall correctly rakudo is supposed to not crash like that no matter what.

Code:
my @a;
start loop { @a.push: rand };
start loop { @a.push: rand };
sleep 1

Result:
“corrupted double-linked list”, or “double free or corruption”, or “.realloc(): invalid next size”, etc. Usually with memory map dumped.
Subject: Re: [perl #128870] [SEGV] Pushing into the same array from two threads segfaults reliably
To: perl6-compiler [...] perl.org
Date: Mon, 8 Aug 2016 11:16:49 +0100
From: Nicholas Clark <nick [...] ccl4.org>
Download (untitled) / with headers
text/plain 3.9k
On Mon, Aug 08, 2016 at 12:25:52AM -0700, Aleks-Daniel Jakimenko-Aleksejev wrote: Show quoted text
> While it is probably a bad idea to push values into the same array from two > threads, if I recall correctly rakudo is supposed to not crash like that no > matter what. > > Code: > my @a; > start loop { @a.push: rand }; > start loop { @a.push: rand }; > sleep 1 > > Result: > “corrupted double-linked list”, or “double free or corruption”, or “.realloc(): > invalid next size”, etc. Usually with memory map dumped.
Thanks for the report. Yes, I also don't think that it should crash at a VM level. Ugly stuff like that is potentially exploitable. ASAN seems to be pretty consistent: $ ./perl6-m -Ilib -e 'my @a; start loop { @a.push: rand }; start loop { @a.push: rand }; sleep 1' ================================================================= ==25229==ERROR: AddressSanitizer: attempting double-free on 0x60c000173740 in thread T1: #0 0x7fb80293b8e6 in __interceptor_realloc ../../.././libsanitizer/asan/asan_malloc_linux.cc:93 #1 0x7fb801e6de7e in MVM_realloc src/core/alloc.h:20 #2 0x7fb801e70c67 in set_size_internal src/6model/reprs/MVMArray.c:334 #3 0x7fb801e71b77 in push src/6model/reprs/MVMArray.c:437 #4 0x7fb801d385ee in MVM_interp_run src/core/interp.c:2163 #5 0x7fb801dbd862 in start_thread src/core/threads.c:77 #6 0x7fb80208460d in uv__thread_start 3rdparty/libuv/src/unix/thread.c:49 #7 0x7fb80111daa0 in start_thread (/lib64/libpthread.so.0+0x7aa0) #8 0x7fb801623aac in __clone (/lib64/libc.so.6+0xe8aac) 0x60c000173740 is located 0 bytes inside of 128-byte region [0x60c000173740,0x60c0001737c0) freed by thread T2 here: #0 0x7fb80293b8e6 in __interceptor_realloc ../../.././libsanitizer/asan/asan_malloc_linux.cc:93 #1 0x7fb801e6de7e in MVM_realloc src/core/alloc.h:20 #2 0x7fb801e70c67 in set_size_internal src/6model/reprs/MVMArray.c:334 #3 0x7fb801e71b77 in push src/6model/reprs/MVMArray.c:437 #4 0x7fb801d385ee in MVM_interp_run src/core/interp.c:2163 #5 0x7fb801dbd862 in start_thread src/core/threads.c:77 #6 0x7fb80208460d in uv__thread_start 3rdparty/libuv/src/unix/thread.c:49 #7 0x7fb80111daa0 in start_thread (/lib64/libpthread.so.0+0x7aa0) previously allocated by thread T1 here: #0 0x7fb80293b8e6 in __interceptor_realloc ../../.././libsanitizer/asan/asan_malloc_linux.cc:93 #1 0x7fb801e6de7e in MVM_realloc src/core/alloc.h:20 #2 0x7fb801e70c67 in set_size_internal src/6model/reprs/MVMArray.c:334 #3 0x7fb801e71b77 in push src/6model/reprs/MVMArray.c:437 #4 0x7fb801d385ee in MVM_interp_run src/core/interp.c:2163 #5 0x7fb801dbd862 in start_thread src/core/threads.c:77 #6 0x7fb80208460d in uv__thread_start 3rdparty/libuv/src/unix/thread.c:49 #7 0x7fb80111daa0 in start_thread (/lib64/libpthread.so.0+0x7aa0) Thread T1 created by T0 here: #0 0x7fb80290a6ea in __interceptor_pthread_create ../../.././libsanitizer/asan/asan_interceptors.cc:183 #1 0x7fb802084712 in uv_thread_create 3rdparty/libuv/src/unix/thread.c:66 #2 0x7fb801dbdc13 in MVM_thread_run src/core/threads.c:129 #3 0x7fb801d63435 in MVM_interp_run src/core/interp.c:3964 #4 0x7fb802018c7c in MVM_vm_run_file src/moar.c:304 #5 0x401a4f in main src/main.c:191 #6 0x7fb801559d1c in __libc_start_main (/lib64/libc.so.6+0x1ed1c) Thread T2 created by T0 here: #0 0x7fb80290a6ea in __interceptor_pthread_create ../../.././libsanitizer/asan/asan_interceptors.cc:183 #1 0x7fb802084712 in uv_thread_create 3rdparty/libuv/src/unix/thread.c:66 #2 0x7fb801dbdc13 in MVM_thread_run src/core/threads.c:129 #3 0x7fb801d63435 in MVM_interp_run src/core/interp.c:3964 #4 0x7fb802018c7c in MVM_vm_run_file src/moar.c:304 #5 0x401a4f in main src/main.c:191 #6 0x7fb801559d1c in __libc_start_main (/lib64/libc.so.6+0x1ed1c) SUMMARY: AddressSanitizer: double-free ../../.././libsanitizer/asan/asan_malloc_linux.cc:93 __interceptor_realloc ==25229==ABORTING Nicholas Clark
Date: Mon, 8 Aug 2016 13:08:36 +0200
From: Elizabeth Mattijsen <liz [...] dijkmat.nl>
Subject: Re: [perl #128870] [SEGV] Pushing into the same array from two threads segfaults reliably
To: perl6-compiler [...] perl.org
Download (untitled) / with headers
text/plain 4.6k
As far as I understand Jonathan’s position on this, is that you shouldn’t do that. If you want to push to an array from multiple threads, you probably should use a Channel, or use Supplies with an .act block. As to the security implications of this behaviour, I must admit I haven’t thought about that in this context myself yet. In any case, having any array automatically work correctly when being pushed to from multiple threads, is a ticket to deadlock hell (if I remember Jonathan’s wording on this subject correctly). Liz ===================== Show quoted text
> On 08 Aug 2016, at 12:16, Nicholas Clark <nick@ccl4.org> wrote: > > On Mon, Aug 08, 2016 at 12:25:52AM -0700, Aleks-Daniel Jakimenko-Aleksejev wrote: >
>> While it is probably a bad idea to push values into the same array from two >> threads, if I recall correctly rakudo is supposed to not crash like that no >> matter what. >> >> Code: >> my @a; >> start loop { @a.push: rand }; >> start loop { @a.push: rand }; >> sleep 1 >> >> Result: >> “corrupted double-linked list”, or “double free or corruption”, or “.realloc(): >> invalid next size”, etc. Usually with memory map dumped.
> > Thanks for the report. Yes, I also don't think that it should crash at a VM > level. Ugly stuff like that is potentially exploitable. > > ASAN seems to be pretty consistent: > > $ ./perl6-m -Ilib -e 'my @a; start loop { @a.push: rand }; start loop { @a.push: rand }; sleep 1' > ================================================================= > ==25229==ERROR: AddressSanitizer: attempting double-free on 0x60c000173740 in thread T1: > #0 0x7fb80293b8e6 in __interceptor_realloc ../../.././libsanitizer/asan/asan_malloc_linux.cc:93 > #1 0x7fb801e6de7e in MVM_realloc src/core/alloc.h:20 > #2 0x7fb801e70c67 in set_size_internal src/6model/reprs/MVMArray.c:334 > #3 0x7fb801e71b77 in push src/6model/reprs/MVMArray.c:437 > #4 0x7fb801d385ee in MVM_interp_run src/core/interp.c:2163 > #5 0x7fb801dbd862 in start_thread src/core/threads.c:77 > #6 0x7fb80208460d in uv__thread_start 3rdparty/libuv/src/unix/thread.c:49 > #7 0x7fb80111daa0 in start_thread (/lib64/libpthread.so.0+0x7aa0) > #8 0x7fb801623aac in __clone (/lib64/libc.so.6+0xe8aac) > > 0x60c000173740 is located 0 bytes inside of 128-byte region [0x60c000173740,0x60c0001737c0) > freed by thread T2 here: > #0 0x7fb80293b8e6 in __interceptor_realloc ../../.././libsanitizer/asan/asan_malloc_linux.cc:93 > #1 0x7fb801e6de7e in MVM_realloc src/core/alloc.h:20 > #2 0x7fb801e70c67 in set_size_internal src/6model/reprs/MVMArray.c:334 > #3 0x7fb801e71b77 in push src/6model/reprs/MVMArray.c:437 > #4 0x7fb801d385ee in MVM_interp_run src/core/interp.c:2163 > #5 0x7fb801dbd862 in start_thread src/core/threads.c:77 > #6 0x7fb80208460d in uv__thread_start 3rdparty/libuv/src/unix/thread.c:49 > #7 0x7fb80111daa0 in start_thread (/lib64/libpthread.so.0+0x7aa0) > > previously allocated by thread T1 here: > #0 0x7fb80293b8e6 in __interceptor_realloc ../../.././libsanitizer/asan/asan_malloc_linux.cc:93 > #1 0x7fb801e6de7e in MVM_realloc src/core/alloc.h:20 > #2 0x7fb801e70c67 in set_size_internal src/6model/reprs/MVMArray.c:334 > #3 0x7fb801e71b77 in push src/6model/reprs/MVMArray.c:437 > #4 0x7fb801d385ee in MVM_interp_run src/core/interp.c:2163 > #5 0x7fb801dbd862 in start_thread src/core/threads.c:77 > #6 0x7fb80208460d in uv__thread_start 3rdparty/libuv/src/unix/thread.c:49 > #7 0x7fb80111daa0 in start_thread (/lib64/libpthread.so.0+0x7aa0) > > Thread T1 created by T0 here: > #0 0x7fb80290a6ea in __interceptor_pthread_create ../../.././libsanitizer/asan/asan_interceptors.cc:183 > #1 0x7fb802084712 in uv_thread_create 3rdparty/libuv/src/unix/thread.c:66 > #2 0x7fb801dbdc13 in MVM_thread_run src/core/threads.c:129 > #3 0x7fb801d63435 in MVM_interp_run src/core/interp.c:3964 > #4 0x7fb802018c7c in MVM_vm_run_file src/moar.c:304 > #5 0x401a4f in main src/main.c:191 > #6 0x7fb801559d1c in __libc_start_main (/lib64/libc.so.6+0x1ed1c) > > Thread T2 created by T0 here: > #0 0x7fb80290a6ea in __interceptor_pthread_create ../../.././libsanitizer/asan/asan_interceptors.cc:183 > #1 0x7fb802084712 in uv_thread_create 3rdparty/libuv/src/unix/thread.c:66 > #2 0x7fb801dbdc13 in MVM_thread_run src/core/threads.c:129 > #3 0x7fb801d63435 in MVM_interp_run src/core/interp.c:3964 > #4 0x7fb802018c7c in MVM_vm_run_file src/moar.c:304 > #5 0x401a4f in main src/main.c:191 > #6 0x7fb801559d1c in __libc_start_main (/lib64/libc.so.6+0x1ed1c) > > SUMMARY: AddressSanitizer: double-free ../../.././libsanitizer/asan/asan_malloc_linux.cc:93 __interceptor_realloc > ==25229==ABORTING > > Nicholas Clark
RT-Send-CC: perl6-compiler [...] perl.org
On Mon Aug 08 04:09:13 2016, elizabeth wrote: Show quoted text
> As far as I understand Jonathan’s position on this, is that you > shouldn’t do that.
Well, you shouldn't do it without concurrency control if you want correct results. But SEGV isn't an OK failure mode. So it wants addressing up to that point (and I know how to do it, just didn't get to it yet). Show quoted text
> If you want to push to an array from multiple > threads, you probably should use a Channel, or use Supplies with an > .act block.
Or re-think your problem in a less imperative way. :-) Show quoted text
> In any case, > having any array automatically work correctly when being pushed to > from multiple threads, is a ticket to deadlock hell (if I remember > Jonathan’s wording on this subject correctly).
Well, I had many words, but the other notable issue is that it gives a false sense of security (even if array operations were to be individually safe, auto-viv would still a race, as would `while @foo { @foo.pop }`) and just leads people towards high-contention designs when a different framing of the problem would give a lower-contention design. /jnthn


This service is sponsored and maintained by Best Practical Solutions and runs on Perl.org infrastructure.

For issues related to this RT instance (aka "perlbug"), please contact perlbug-admin at perl.org