apr_pool_check_integrity will assert at the ownership test for apr_thread_exit apr_thread_exit destroys a pool allocated on another thread. This pool is created in apr_thread_create and is the pool in which the thread resources are allocated (the pool belongs to the parent thread). So the thread trying to do destroy in apr_thread_exit does not have ownership of the pool. apr_thread_exit must be called from the thread who wants to exit since it calls pthread_exit. A solution to fix this would be for apr_thread_exit() to not call apr_pool_destroy() since it does not own the pool and leave this to the thread parent. This will comply with apr_pool_check_integrity requirements
Can you reproduce this in test/ where we do have various tests of creating and freeing threads? Or is this strictly in your application?
First I found about this in my application. Then I noticed the same behavior with your threadtest from apr/test/. More than that there is no doubt about this happening just by looking at the source code for: apr_thread_create, apr_thread_exit and apr_pool_check_integrity In general this are reproducing steps: 1. Compile apr with --enable-debug --enable-pool-debug=all 2. Run any test or apr feature that involve threads It will surely crash because of asserting from apr_pool_check_integrity.
Thanks, absolutely noting as something the project must address. Great research!
As all implementations of apr_thread_create uses a dummy_worker it would be possible to re-assign the pool's owner to the new thread before passing control to the user function. I'm not sure if this would really be correct though. Both this and the proposed solution makes our program run without asserts. Note also that the OS2 implementation doesn't seem to destroy the pool on apr_thread_exit.
Any progress with this? The use of threads is currently unsafe because of this race condition. ==32143== Possible data race during read of size 4 at 0x6896040 by thread #1 ==32143== Locks held: 2, at addresses 0x40250B8 0x4027228 ==32143== at 0x544D0AE: allocator_alloc (in /usr/lib/libapr-1.so.0.4.5) ==32143== by 0x544DDA4: apr_pool_create_ex (in /usr/lib/libapr-1.so.0.4.5) ==32143== by 0x545E222: apr_thread_create (in /usr/lib/libapr-1.so.0.4.5) ==32143== ==32143== This conflicts with a previous write of size 4 by thread #2 ==32143== Locks held: 1, at address 0x40210A8 ==32143== at 0x544D4FE: allocator_free (in /usr/lib/libapr-1.so.0.4.5) ==32143== by 0x544DD05: apr_pool_destroy (in /usr/lib/libapr-1.so.0.4.5) ==32143== by 0x545E2CD: apr_thread_exit (in /usr/lib/libapr-1.so.0.4.5) ==32143== by 0x406CEF: tester_thread (threadtest.c:63) ==32143== by 0x42D7E7: _thread_helper (core.c:77) ==32143== by 0x545E116: dummy_worker (in /usr/lib/libapr-1.so.0.4.5)
This should now work in trunk. Commits: r1460182 r1460183 r1460184 r1460185 r1460186