From cejkar@dcse.fee.vutbr.cz  Wed Apr 19 10:32:50 2000
Return-Path: <cejkar@dcse.fee.vutbr.cz>
Received: from boco.fee.vutbr.cz (boco.fee.vutbr.cz [147.229.9.11])
	by hub.freebsd.org (Postfix) with ESMTP id 9CD1037B57E
	for <FreeBSD-gnats-submit@freebsd.org>; Wed, 19 Apr 2000 10:32:48 -0700 (PDT)
	(envelope-from cejkar@dcse.fee.vutbr.cz)
Received: from kazi.dcse.fee.vutbr.cz (kazi.dcse.fee.vutbr.cz [147.229.8.12])
	by boco.fee.vutbr.cz (8.10.1/8.10.1) with ESMTP id e3JHWkC71084
	for <FreeBSD-gnats-submit@freebsd.org>; Wed, 19 Apr 2000 19:32:46 +0200 (CEST)
Received: (from cejkar@localhost)
	by kazi.dcse.fee.vutbr.cz (8.10.1/8.10.1) id e3JHWko12798;
	Wed, 19 Apr 2000 19:32:46 +0200 (CEST)
Message-Id: <200004191732.e3JHWko12798@kazi.dcse.fee.vutbr.cz>
Date: Wed, 19 Apr 2000 19:32:46 +0200 (CEST)
From: cejkar@dcse.fee.vutbr.cz
Reply-To: cejkar@dcse.fee.vutbr.cz
To: FreeBSD-gnats-submit@freebsd.org
Subject: Bug-fixes to pthread_cond_*() (uthread_cond.c)
X-Send-Pr-Version: 3.2

>Number:         18099
>Category:       bin
>Synopsis:       Bug-fixes to pthread_cond_*() (uthread_cond.c)
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    jasone
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Apr 19 10:40:00 PDT 2000
>Closed-Date:    Mon Jul 17 16:14:13 PDT 2000
>Last-Modified:  Mon Jul 17 16:15:03 PDT 2000
>Originator:     Rudolf Cejka
>Release:        FreeBSD 5.0-CURRENT i386
>Organization:
Brno University of Technology, FEE&CS, Czech Republic
>Environment:

5.0-CURRENT and possibly all other branches.

>Description:

Here is small testing program (-pthread):

--
#define _THREAD_SAFE
#include <err.h>
#include <pthread.h>
#include <stdio.h>

pthread_t	tid;

pthread_cond_t	cond = PTHREAD_COND_INITIALIZER;

/* ARGSUSED */
void *test(void *dummy)
{

	if (pthread_cond_broadcast(&cond) != 0)
		warnx("pthread_cond_broadcast()");
	if (pthread_cond_timedwait(&cond, NULL, NULL) != 0)
		warnx("pthread_cond_timedwait()");
	return NULL;
}

int main(void)
{

	if (pthread_create(&tid, NULL, test, NULL) != 0)
		errx(1, "pthread_create()");
	if (pthread_join(tid, NULL) != 0)
		errx(1, "pthread_join()");
	return 0;
}
--

According to standards, pthread_cond_broadcast() should do nothing
without any error. And I think pthread_cond_timedwait() should not
produce a coredump. But if you run it, you get:

--
tst: pthread_cond_broadcast()
Segmentation fault (core dumped)
--

If you apply following patch, you get only:

--
tst: pthread_cond_timedwait()
--

a) pthread_cond_broadcast() will not produce any error: the problem
   occurs only when condition is initialized statically and have not
   been used (= allocated) before - maybe this is artifical example, but
   I had a problem with this in a real situation (on Solaris it works
   fine but on FreeBSD before patch it doesn't)

   (second and third chunk of patch for pthread_cond_signal() and
   pthread_cond_broadcast() functions)

b) pthread_cond_timedwait() will produce error only instead of coredump;
   if you look into sources, it really looks as a copy & paste & insert bug

   (first chunk of patch)

>How-To-Repeat:
>Fix:

--- src/lib/libc_r/uthread/uthread_cond.c.orig	Wed Apr 19 18:52:04 2000
+++ src/lib/libc_r/uthread/uthread_cond.c	Wed Apr 19 18:52:04 2000
@@ -308,19 +308,14 @@
 	
 	if (cond == NULL || abstime == NULL)
 		rval = EINVAL;
-
-	if (abstime->tv_sec < 0 || 
-		abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) {
-		errno = EINVAL;
-		_thread_leave_cancellation_point();
-		return (-1);
-	}
-
+	else if (abstime->tv_sec < 0 || 
+		abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+		rval = EINVAL;
 	/*
 	 * If the condition variable is statically initialized,
 	 * perform the dynamic initialization:
 	 */
-	if (*cond != NULL ||
+	else if (*cond != NULL ||
 	    (rval = pthread_cond_init(cond,NULL)) == 0) {
 
 		_thread_enter_cancellation_point();
@@ -473,9 +468,14 @@
 	int             rval = 0;
 	pthread_t       pthread;
 
-	if (cond == NULL || *cond == NULL)
+	if (cond == NULL)
 		rval = EINVAL;
-	else {
+	/*
+	 * If the condition variable is statically initialized,
+	 * perform the dynamic initialization:
+	 */
+	else if (*cond != NULL ||
+	    (rval = pthread_cond_init(cond, NULL)) == 0) {
 		/*
 		 * Defer signals to protect the scheduling queues
 		 * from access by the signal handler:
@@ -525,9 +525,14 @@
 	int             rval = 0;
 	pthread_t       pthread;
 
-	if (cond == NULL || *cond == NULL)
+	if (cond == NULL)
 		rval = EINVAL;
-	else {
+	/*
+	 * If the condition variable is statically initialized,
+	 * perform the dynamic initialization:
+	 */
+	else if (*cond != NULL ||
+	    (rval = pthread_cond_init(cond,NULL)) == 0) {
 		/*
 		 * Defer signals to protect the scheduling queues
 		 * from access by the signal handler:


>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->jasone 
Responsible-Changed-By: jasone 
Responsible-Changed-When: Wed Jun 7 12:45:40 PDT 2000 
Responsible-Changed-Why:  
Over to maintainer. 
State-Changed-From-To: open->closed 
State-Changed-By: jasone 
State-Changed-When: Mon Jul 17 16:14:13 PDT 2000 
State-Changed-Why:  
Patch applied (with minor modifications).  Thanks! 
>Unformatted:
