public inbox for glibc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug nptl/7094] New: Bug in creating/deleting posix per process timers with SIGEV_THREAD notification method
@ 2008-12-11  8:42 pavel dot smolenskiy at gmail dot com
  2009-01-23  2:29 ` [Bug nptl/7094] " jsm28 at gcc dot gnu dot org
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: pavel dot smolenskiy at gmail dot com @ 2008-12-11  8:42 UTC (permalink / raw)
  To: glibc-bugs

Issue is following.
1. Create x timers, where x>1, calling timer_create, with appropriate arguments,
and SIGEV_THREAD as notification method on expire.
2. Delete last created timer with timer_delete before it's expire time.
3. Wait for another timer to expire. On attempt to call notification function
glibc hang with SIGSEGV in timer_helper_thread().

Tested on glibc 2.4, 2.7, 2.8, 2.9 and latest cvs head with ubuntu 8.10 on amd64.

Here is test code
[code]
/* file timer_t.c */

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/time.h>
#include <time.h>
#include <errno.h>
#include <pthread.h>
#include <string.h>

void timer_expire_func(union sigval arg)
{
        void *obj = arg.sival_ptr;
        printf("%s(): called: %p\n", __FUNCTION__, obj);

}

pthread_mutex_t a = PTHREAD_MUTEX_INITIALIZER;
int q = 0;

void *thr_func(void *arg)
{
        int qf = 0;
        while(1) {
                pthread_mutex_lock(&a);
                qf = q;
                pthread_mutex_unlock(&a);
                if (qf)
                        break;
                sleep(2);
        }
        return NULL;
}

timer_t t1, t2;

int main(void)
{
        struct sigevent sigev;
        struct timeval expire;
        struct itimerval exp;

        sigev.sigev_notify = SIGEV_THREAD;
        sigev.sigev_notify_function = timer_expire_func;
        sigev.sigev_notify_attributes = 0;
        sigev.sigev_value.sival_ptr = (void *) &t1;

        expire.tv_sec = 10;
        expire.tv_usec = 0;
        if (timer_create(CLOCK_REALTIME, &sigev, &t1) ) {
                perror("timer_create");
                exit(-1);
        }
        exp.it_value.tv_sec = expire.tv_sec;
        exp.it_value.tv_usec = expire.tv_usec;
        exp.it_interval.tv_sec = 0;
        exp.it_interval.tv_usec = 0;

        printf("add timer: %p, exp(s,u) = (%lu, %lu)\n", t1,
                           expire.tv_sec, expire.tv_usec);
        timer_settime(t1, 0, (const struct itimerspec*)&exp, NULL);

        memset(&sigev, 0, sizeof(sigev));

        sigev.sigev_notify = SIGEV_THREAD;
        sigev.sigev_notify_function = timer_expire_func;
        sigev.sigev_notify_attributes = 0;
        sigev.sigev_value.sival_ptr = (void *) &t2;

        expire.tv_sec = 10;
        expire.tv_usec = 0;
        if (timer_create(CLOCK_REALTIME, &sigev, &t2) ) {
                perror("timer_create");
                exit(-1);
        }
        exp.it_value.tv_sec = expire.tv_sec;
        exp.it_value.tv_usec = expire.tv_usec;
        exp.it_interval.tv_sec = 0;
        exp.it_interval.tv_usec = 0;

        printf("add timer: %p, exp(s,u) = (%lu, %lu)\n", t2,
                           expire.tv_sec, expire.tv_usec);
        timer_settime(t2, 0, (const struct itimerspec*)&exp, NULL);

        pthread_t ptid;

        pthread_create(&ptid, NULL, thr_func, NULL);
        timer_delete(t2);
        int rr;
        pthread_join(ptid, (void**)&rr);
        exit(0);

[/code]
# gcc -Wall -g -o timer_t timer_t.c -lrt
# gdb ./timer_t
(gdb) r
Starting program: /tmp/timer_t 
[Thread debugging using libthread_db enabled]
[New Thread 0x7fd8ae7e26e0 (LWP 25091)]
[New Thread 0x41006950 (LWP 25092)]
add timer: 0xd4c130, exp(s,u) = (10, 0)
add timer: 0xd4c190, exp(s,u) = (10, 0)
[New Thread 0x42260950 (LWP 25093)]

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x41006950 (LWP 25092)]
timer_helper_thread (arg=<value optimized out>) at
../nptl/sysdeps/unix/sysv/linux/timer_routines.c:114
114			  runp = runp->next;
(gdb) p runp
$1 = (struct timer *) 0x60
(gdb) 

======
So I look up into the code and found out, that SIGEV_THREAD timers, on creation,
stored in one-way linked list, last created timer is in the head.
Then, when delete timer, glibc found that timer in linked list and delete it
from there.

nptl/sysdeps/unix/sysv/linux/timer_delete.c:42
timer_delete (timerid)
     timer_t timerid;
{
# undef timer_delete
# ifndef __ASSUME_POSIX_TIMERS
  if (__no_posix_timers >= 0)
# endif
    {
      struct timer *kt = (struct timer *) timerid;

      /* Delete the kernel timer object.  */
      int res = INLINE_SYSCALL (timer_delete, 1, kt->ktimerid);

      if (res == 0)
	{
	  if (kt->sigev_notify == SIGEV_THREAD)
	    {
	      /* Remove the timer from the list.  */
               skip
               skip
               skip
	    }

# ifndef __ASSUME_POSIX_TIMERS
	  /* We know the syscall support is available.  */
	  __no_posix_timers = 1;
# endif

	  /* Free the memory.  */
	  (void) free (kt);

	  return 0;
	}

But when look into
nptl/sysdeps/unix/sysv/linux/timer_create.c:52
timer_create (clock_id, evp, timerid)
     clockid_t clock_id;
     struct sigevent *evp;
     timer_t *timerid;
{
 /* skip non SIGEV_THREAD code */
line 162
	      struct timer *newp;
	      newp = (struct timer *) malloc (sizeof (struct timer));
	      if (newp == NULL)
		return -1;

	      /* Copy the thread parameters the user provided.  */
	      newp->sival = evp->sigev_value;
	      newp->thrfunc = evp->sigev_notify_function;
skipped
line 207
	      if (! INTERNAL_SYSCALL_ERROR_P (res, err))
		{
		  /* Add to the queue of active timers with thread
		     delivery.  */
		  pthread_mutex_lock (&__active_timer_sigev_thread_lock);
		  newp->next = __active_timer_sigev_thread;
		  __active_timer_sigev_thread = newp;
		  pthread_mutex_unlock (&__active_timer_sigev_thread_lock);

		  *timerid = (timer_t) newp;
		  return 0;
		}
}

Nobody set newp->sigev_notify = SIGEV_THREAD.

So, when call timer_delete(), kt->sigev_notify value not specified, thus lead to
simple free kt pointer, w/o deleting it from linked list prior.
So, when deleting last created timer, linked list simply become lost, cause head
was free'd, and next expired timer will hang glibc.

-- 
           Summary: Bug in creating/deleting posix per process timers with
                    SIGEV_THREAD notification method
           Product: glibc
           Version: unspecified
            Status: NEW
          Severity: normal
          Priority: P2
         Component: nptl
        AssignedTo: drepper at redhat dot com
        ReportedBy: pavel dot smolenskiy at gmail dot com
                CC: glibc-bugs at sources dot redhat dot com
 GCC build triplet: all
  GCC host triplet: All
GCC target triplet: all


http://sourceware.org/bugzilla/show_bug.cgi?id=7094

------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Bug nptl/7094] Bug in creating/deleting posix per process timers with SIGEV_THREAD notification method
  2008-12-11  8:42 [Bug nptl/7094] New: Bug in creating/deleting posix per process timers with SIGEV_THREAD notification method pavel dot smolenskiy at gmail dot com
@ 2009-01-23  2:29 ` jsm28 at gcc dot gnu dot org
  2009-01-23 15:19 ` bbuesker at qualcomm dot com
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: jsm28 at gcc dot gnu dot org @ 2009-01-23  2:29 UTC (permalink / raw)
  To: glibc-bugs


------- Additional Comments From jsm28 at gcc dot gnu dot org  2009-01-23 02:29 -------
Created an attachment (id=3681)
 --> (http://sourceware.org/bugzilla/attachment.cgi?id=3681&action=view)
Patch to fix the bug

I agree with the analysis in this bug report (at least for current glibc -
any version after the fix for bug 5220 went into CVS - not necessarily for
all the versions mentioned in the report).  I attach the obvious patch to
fix it implied by the analysis in the bug report.


-- 


http://sourceware.org/bugzilla/show_bug.cgi?id=7094

------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Bug nptl/7094] Bug in creating/deleting posix per process timers with SIGEV_THREAD notification method
  2008-12-11  8:42 [Bug nptl/7094] New: Bug in creating/deleting posix per process timers with SIGEV_THREAD notification method pavel dot smolenskiy at gmail dot com
  2009-01-23  2:29 ` [Bug nptl/7094] " jsm28 at gcc dot gnu dot org
@ 2009-01-23 15:19 ` bbuesker at qualcomm dot com
  2009-09-03  3:00 ` drepper at redhat dot com
  2009-09-03  5:18 ` pavel dot smolenskiy at gmail dot com
  3 siblings, 0 replies; 5+ messages in thread
From: bbuesker at qualcomm dot com @ 2009-01-23 15:19 UTC (permalink / raw)
  To: glibc-bugs


------- Additional Comments From bbuesker at qualcomm dot com  2009-01-23 15:19 -------
I concur with the patch. An easy way to verify the fix is by running the app
under valgrind. Here is the output before the patch:

==4907== Memcheck, a memory error detector.
==4907== Copyright (C) 2002-2008, and GNU GPL'd, by Julian Seward et al.
==4907== Using LibVEX rev 1878, a library for dynamic binary translation.
==4907== Copyright (C) 2004-2008, and GNU GPL'd, by OpenWorks LLP.
==4907== Using valgrind-3.4.0, a dynamic binary instrumentation framework.
==4907== Copyright (C) 2000-2008, and GNU GPL'd, by Julian Seward et al.
==4907== For more details, rerun with: -v
==4907==
add timer: 0x402c0e0, exp(s,u) = (10, 0)
add timer: 0x402c148, exp(s,u) = (10, 0)
==4907== Conditional jump or move depends on uninitialised value(s)
==4907==    at 0x94CC94: timer_delete (in /lib/librt-2.9.so)
==4907==    by 0x804891C: main (in /var/tmp/a.out)
==4907==
==4907== Thread 2:
==4907== Invalid read of size 4
==4907==    at 0x94DE20: timer_helper_thread (in /lib/librt-2.9.so)
==4907==    by 0x81951E: start_thread (in /lib/libpthread-2.9.so)
==4907==    by 0x74F04D: clone (in /lib/libc-2.9.so)
==4907==  Address 0x402c17c is 52 bytes inside a block of size 56 free'd
==4907==    at 0x4005B6A: free (in
/opt/share/buildtools-f10-i386/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==4907==    by 0x94CC9D: timer_delete (in /lib/librt-2.9.so)
==4907==    by 0x804891C: main (in /var/tmp/a.out)
timer_expire_func(): called: 0x8049c3c
^C==4907==
==4907== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 15 from 1)
==4907== malloc/free: in use at exit: 328 bytes in 3 blocks.
==4907== malloc/free: 6 allocs, 3 frees, 528 bytes allocated.
==4907== For counts of detected errors, rerun with: -v
==4907== Use --track-origins=yes to see where uninitialised values come from
==4907== searching for pointers to 3 not-freed blocks.
==4907== checked 10,568,324 bytes.
==4907==
==4907== LEAK SUMMARY:
==4907==    definitely lost: 0 bytes in 0 blocks.
==4907==      possibly lost: 272 bytes in 2 blocks.
==4907==    still reachable: 56 bytes in 1 blocks.
==4907==         suppressed: 0 bytes in 0 blocks.
==4907== Rerun with --leak-check=full to see details of leaked memory.

And here is the output after the patch:

==25782== Memcheck, a memory error detector.
==25782== Copyright (C) 2002-2008, and GNU GPL'd, by Julian Seward et al.
==25782== Using LibVEX rev 1878, a library for dynamic binary translation.
==25782== Copyright (C) 2004-2008, and GNU GPL'd, by OpenWorks LLP.
==25782== Using valgrind-3.4.0, a dynamic binary instrumentation framework.
==25782== Copyright (C) 2000-2008, and GNU GPL'd, by Julian Seward et al.
==25782== For more details, rerun with: -v
==25782==
add timer: 0x41e50e0, exp(s,u) = (10, 0)
add timer: 0x41e5148, exp(s,u) = (10, 0)
timer_expire_func(): called: 0x8049c3c
^C==25782==
==25782== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 18 from 1)
==25782== malloc/free: in use at exit: 328 bytes in 3 blocks.
==25782== malloc/free: 6 allocs, 3 frees, 528 bytes allocated.
==25782== For counts of detected errors, rerun with: -v
==25782== searching for pointers to 3 not-freed blocks.
==25782== checked 10,567,240 bytes.
==25782==
==25782== LEAK SUMMARY:
==25782==    definitely lost: 0 bytes in 0 blocks.
==25782==      possibly lost: 272 bytes in 2 blocks.
==25782==    still reachable: 56 bytes in 1 blocks.
==25782==         suppressed: 0 bytes in 0 blocks.
==25782== Rerun with --leak-check=full to see details of leaked memory.

-- 


http://sourceware.org/bugzilla/show_bug.cgi?id=7094

------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Bug nptl/7094] Bug in creating/deleting posix per process timers with SIGEV_THREAD notification method
  2008-12-11  8:42 [Bug nptl/7094] New: Bug in creating/deleting posix per process timers with SIGEV_THREAD notification method pavel dot smolenskiy at gmail dot com
  2009-01-23  2:29 ` [Bug nptl/7094] " jsm28 at gcc dot gnu dot org
  2009-01-23 15:19 ` bbuesker at qualcomm dot com
@ 2009-09-03  3:00 ` drepper at redhat dot com
  2009-09-03  5:18 ` pavel dot smolenskiy at gmail dot com
  3 siblings, 0 replies; 5+ messages in thread
From: drepper at redhat dot com @ 2009-09-03  3:00 UTC (permalink / raw)
  To: glibc-bugs


------- Additional Comments From drepper at redhat dot com  2009-09-03 03:00 -------
Fixed in current git.

-- 
           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|                            |FIXED


http://sourceware.org/bugzilla/show_bug.cgi?id=7094

------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Bug nptl/7094] Bug in creating/deleting posix per process timers with SIGEV_THREAD notification method
  2008-12-11  8:42 [Bug nptl/7094] New: Bug in creating/deleting posix per process timers with SIGEV_THREAD notification method pavel dot smolenskiy at gmail dot com
                   ` (2 preceding siblings ...)
  2009-09-03  3:00 ` drepper at redhat dot com
@ 2009-09-03  5:18 ` pavel dot smolenskiy at gmail dot com
  3 siblings, 0 replies; 5+ messages in thread
From: pavel dot smolenskiy at gmail dot com @ 2009-09-03  5:18 UTC (permalink / raw)
  To: glibc-bugs


------- Additional Comments From pavel dot smolenskiy at gmail dot com  2009-09-03 05:18 -------
Verified.

-- 
           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|RESOLVED                    |VERIFIED


http://sourceware.org/bugzilla/show_bug.cgi?id=7094

------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2009-09-03  5:18 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-12-11  8:42 [Bug nptl/7094] New: Bug in creating/deleting posix per process timers with SIGEV_THREAD notification method pavel dot smolenskiy at gmail dot com
2009-01-23  2:29 ` [Bug nptl/7094] " jsm28 at gcc dot gnu dot org
2009-01-23 15:19 ` bbuesker at qualcomm dot com
2009-09-03  3:00 ` drepper at redhat dot com
2009-09-03  5:18 ` pavel dot smolenskiy at gmail dot com

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).