summaryrefslogtreecommitdiff
path: root/lib/libc/gen
diff options
context:
space:
mode:
authorKurt Miller <kurt@cvs.openbsd.org>2007-10-02 16:14:59 +0000
committerKurt Miller <kurt@cvs.openbsd.org>2007-10-02 16:14:59 +0000
commit5315b4d47c1241a88cb637090dcbe3cc894a8546 (patch)
tree25d8d0bb7a8c2417ef4953a870c433405c4fa2ff /lib/libc/gen
parent462048e05d19465c0e687072db3ec412b429bb76 (diff)
fix a libpthread PANIC in seekdir(3) caused by a recursive mutex lock.
remove the recursive lock in __seekdir() and ensure all callers properly lock dd_lock prior to calling. reported and tested by bernd@ okay marc@ tedu@
Diffstat (limited to 'lib/libc/gen')
-rw-r--r--lib/libc/gen/rewinddir.c10
-rw-r--r--lib/libc/gen/telldir.c25
2 files changed, 24 insertions, 11 deletions
diff --git a/lib/libc/gen/rewinddir.c b/lib/libc/gen/rewinddir.c
index 8d37fa8e6e1..388d6404d27 100644
--- a/lib/libc/gen/rewinddir.c
+++ b/lib/libc/gen/rewinddir.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rewinddir.c,v 1.7 2005/08/08 08:05:34 espie Exp $ */
+/* $OpenBSD: rewinddir.c,v 1.8 2007/10/02 16:14:58 kurt Exp $ */
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
@@ -31,12 +31,16 @@
#include <sys/types.h>
#include <dirent.h>
+#include "thread_private.h"
+
void __seekdir(DIR *, long);
+long __telldir_unlocked(DIR *);
void
rewinddir(DIR *dirp)
{
-
+ _MUTEX_LOCK(&dirp->dd_lock);
__seekdir(dirp, dirp->dd_rewind);
- dirp->dd_rewind = telldir(dirp);
+ dirp->dd_rewind = _telldir_unlocked(dirp);
+ _MUTEX_UNLOCK(&dirp->dd_lock);
}
diff --git a/lib/libc/gen/telldir.c b/lib/libc/gen/telldir.c
index 1314397ce93..cc9761c92f8 100644
--- a/lib/libc/gen/telldir.c
+++ b/lib/libc/gen/telldir.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: telldir.c,v 1.10 2007/06/05 18:11:48 kurt Exp $ */
+/* $OpenBSD: telldir.c,v 1.11 2007/10/02 16:14:58 kurt Exp $ */
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
@@ -37,16 +37,17 @@
#include "thread_private.h"
#include "telldir.h"
+struct dirent *_readdir_unlocked(DIR *);
+
/*
* return a pointer into a directory
*/
long
-telldir(DIR *dirp)
+_telldir_unlocked(DIR *dirp)
{
long i;
struct ddloc *lp;
- _MUTEX_LOCK(&dirp->dd_lock);
i = dirp->dd_td->td_last;
lp = &dirp->dd_td->td_locs[i];
@@ -55,7 +56,6 @@ telldir(DIR *dirp)
if (lp->loc_seek == dirp->dd_seek &&
lp->loc_loc == dirp->dd_loc) {
dirp->dd_td->td_last = i;
- _MUTEX_UNLOCK(&dirp->dd_lock);
return (i);
}
}
@@ -64,10 +64,8 @@ telldir(DIR *dirp)
size_t newsz = dirp->dd_td->td_sz * 2 + 1;
struct ddloc *p;
p = realloc(dirp->dd_td->td_locs, newsz * sizeof(*p));
- if (p == NULL) {
- _MUTEX_UNLOCK(&dirp->dd_lock);
+ if (p == NULL)
return (-1);
- }
dirp->dd_td->td_sz = newsz;
dirp->dd_td->td_locs = p;
lp = &dirp->dd_td->td_locs[i];
@@ -76,7 +74,18 @@ telldir(DIR *dirp)
lp->loc_seek = dirp->dd_seek;
lp->loc_loc = dirp->dd_loc;
dirp->dd_td->td_last = i;
+ return (i);
+}
+
+long
+telldir(DIR *dirp)
+{
+ long i;
+
+ _MUTEX_LOCK(&dirp->dd_lock);
+ i = _telldir_unlocked(dirp);
_MUTEX_UNLOCK(&dirp->dd_lock);
+
return (i);
}
@@ -100,7 +109,7 @@ __seekdir(DIR *dirp, long loc)
dirp->dd_seek = lp->loc_seek;
dirp->dd_loc = 0;
while (dirp->dd_loc < lp->loc_loc) {
- dp = readdir(dirp);
+ dp = _readdir_unlocked(dirp);
if (dp == NULL)
break;
}