Project

General

Profile

Bug #10443 » 0001-thread.c-reinitialize-keeping-mutexes-on-fork.patch

normalperson (Eric Wong), 10/28/2014 09:52 PM

View differences:

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();
-
(3-3/3)