Bug #10443 » 0001-thread.c-reinitialize-keeping-mutexes-on-fork.patch
test/ruby/test_thread.rb | ||
---|---|---|
assert_not_predicate(status, :signaled?, FailDesc[status, bug9751, output])
|
||
assert_predicate(status, :success?, bug9751)
|
||
end if Process.respond_to?(:fork)
|
||
def test_fork_while_lock_held
|
||
bug10443 = '[ruby-core:65950] [Bug #10443]'
|
||
assert_separately([], <<-EOS)
|
||
require 'tempfile'
|
||
require 'thread'
|
||
tmp = Tempfile.new('bug10443')
|
||
mutex = Mutex.new
|
||
mutex.lock
|
||
th = Thread.new do
|
||
mutex.synchronize { sleep }
|
||
end
|
||
Thread.pass until th.stop?
|
||
orig = $stderr.dup
|
||
$stderr.reopen(tmp.path, "a")
|
||
$VERBOSE = true
|
||
pid = Process.fork { exit!(mutex.locked?) }
|
||
$VERBOSE = false
|
||
$stderr.reopen(orig)
|
||
orig.close
|
||
th.kill
|
||
pid, status = Process.waitpid2(pid)
|
||
assert_equal(true, status.success?, status.inspect)
|
||
tmp.rewind
|
||
assert_match(/\\b1 Mutex resource\\(s\\) leaked on fork$/, tmp.read)
|
||
EOS
|
||
end if Process.respond_to?(:fork)
|
||
end
|
thread.c | ||
---|---|---|
void
|
||
rb_thread_atfork(void)
|
||
{
|
||
rb_thread_t *th = GET_THREAD();
|
||
size_t n = 0;
|
||
rb_mutex_t *mutex;
|
||
rb_thread_atfork_internal(terminate_atfork_i);
|
||
GET_THREAD()->join_list = NULL;
|
||
th->join_list = NULL;
|
||
/* we preserve mutex state across fork, but ensure we do not deadlock */
|
||
mutex = th->keeping_mutexes;
|
||
while (mutex) {
|
||
assert(mutex->th == th);
|
||
n++;
|
||
/* we cannot safely destroy here, zero instead */
|
||
MEMZERO(&mutex->lock, rb_nativethread_lock_t, 1);
|
||
MEMZERO(&mutex->cond, rb_nativethread_cond_t, 1);
|
||
native_mutex_initialize(&mutex->lock);
|
||
native_cond_initialize(&mutex->cond, RB_CONDATTR_CLOCK_MONOTONIC);
|
||
mutex = mutex->next_mutex;
|
||
}
|
||
if (n) {
|
||
rb_warn("%"PRIuSIZE" Mutex resource(s) leaked on fork", n);
|
||
}
|
||
/* We don't want reproduce CVE-2003-0900. */
|
||
rb_reset_random_seed();
|
||
-
|
- « Previous
- 1
- 2
- 3
- Next »