Project

General

Profile

Actions

Bug #12290

closed

Possible segfault with Thread#name=

Added by herwinw (Herwin Quarantainenet) almost 8 years ago. Updated almost 8 years ago.

Status:
Closed
Assignee:
-
Target version:
-
ruby -v:
ruby 2.3.0p0 (2015-12-25 revision 53290)
[ruby-core:74963]

Description

Ruby 2.3 added a Thread#name=, which may segfault when used incorrectly. This little program:

class SubClassedThread < Thread
  def initialize()
    self.name = 'foo'
    super do
      yield
    end
  end
end

SubClassedThread.new {}

Causes a segfault with both Ruby 2.3 (ruby 2.3.0p0 (2015-12-25 revision 53290)) and ruby-2.4.0-dev (ruby 2.4.0dev (2016-04-15 trunk 54594)). Moving the line that assignes the name in the block passed to super resolves the issue. Even thought there is a workaround, it shouldn't be possible to trigger a segfault from a script imho.

The relevant lines of the backtrace

/lib/i386-linux-gnu/i686/cmov/libpthread.so.0(pthread_setname_np+0x50) [0xf739ded0]
ruby(rb_thread_setname+0x95) [0xf755dc85] thread.c:2797

The system is a default Debian Jessie (32bit), with libc version 2.19-18+deb8u4.


Files

issue12290_segthread_thread_name.diff (486 Bytes) issue12290_segthread_thread_name.diff herwinw (Herwin Quarantainenet), 04/15/2016 11:43 AM
issue12290_segthread_thread_name.diff (393 Bytes) issue12290_segthread_thread_name.diff herwinw (Herwin Quarantainenet), 04/15/2016 11:50 AM

Updated by herwinw (Herwin Quarantainenet) almost 8 years ago

And of course the backtrace can be improved when installing the debugging symbols for libc

/lib/i386-linux-gnu/i686/cmov/libpthread.so.0(pthread_setname_np+0x50) [0xf73e0ed0] ../nptl/sysdeps/unix/sysv/linux/pthread_setname.c:49

The exact source can be downloaded from https://packages.debian.org/jessie/libc6 (keep in mind that the original source and the packages have to be downloaded separately, and be combined.

Updated by herwinw (Herwin Quarantainenet) almost 8 years ago

And since it's pretty easy to get the relevant source on a running debian system:

int 
pthread_setname_np (th, name)
     pthread_t th;
     const char *name;
{
  const struct pthread *pd = (const struct pthread *) th;
...
#define FMT "/proc/self/task/%u/comm" 
  char fname[sizeof (FMT) + 8];
  sprintf (fname, FMT, (unsigned int) pd->tid);

Line 49 is the last line, and this is indeed the first part where a member of td is queried.

Updated by herwinw (Herwin Quarantainenet) almost 8 years ago

And this is the simplest solution I could think of. It throws an exception, which is a better way to react than a segfault. Making it actually work would of course be even better.

Updated by herwinw (Herwin Quarantainenet) almost 8 years ago

That patch still segfaulted when using self.name = nil. Version 2 attached.

Actions #5

Updated by nobu (Nobuyoshi Nakada) almost 8 years ago

  • Status changed from Open to Closed

Applied in changeset r54598.


thread.c: must be initialized to set name

  • thread.c (get_initialized_threadptr): extract ensuring that the
    thread is initialized.
  • thread.c (rb_thread_setname): thread must be initialized to set
    the name. [ruby-core:74963] [Bug #12290]

Updated by nobu (Nobuyoshi Nakada) almost 8 years ago

  • Description updated (diff)
  • Backport changed from 2.1: UNKNOWN, 2.2: UNKNOWN, 2.3: UNKNOWN to 2.1: DONTNEED, 2.2: DONTNEED, 2.3: REQUIRED

Updated by nagachika (Tomoyuki Chikanaga) almost 8 years ago

  • Backport changed from 2.1: DONTNEED, 2.2: DONTNEED, 2.3: REQUIRED to 2.1: DONTNEED, 2.2: DONTNEED, 2.3: DONE

ruby_2_3 r54607 merged revision(s) 54598,54600.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0