diff options
author | Kurt Miller <kurt@cvs.openbsd.org> | 2007-10-02 16:14:59 +0000 |
---|---|---|
committer | Kurt Miller <kurt@cvs.openbsd.org> | 2007-10-02 16:14:59 +0000 |
commit | 5315b4d47c1241a88cb637090dcbe3cc894a8546 (patch) | |
tree | 25d8d0bb7a8c2417ef4953a870c433405c4fa2ff /lib/libc/gen | |
parent | 462048e05d19465c0e687072db3ec412b429bb76 (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.c | 10 | ||||
-rw-r--r-- | lib/libc/gen/telldir.c | 25 |
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; } |