about summary refs log tree commit diff
path: root/src/thread
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2012-09-30 19:44:45 -0400
committerRich Felker <dalias@aerifal.cx>2012-09-30 19:44:45 -0400
commite44849f5cf331e655705b18d6c81c616e29d50d0 (patch)
tree011adb2a2c4406bc94564e7c99c43569e87e4191 /src/thread
parentbf258341b71711461ce19891674d43c135827d0e (diff)
downloadmusl-e44849f5cf331e655705b18d6c81c616e29d50d0.tar.gz
musl-e44849f5cf331e655705b18d6c81c616e29d50d0.tar.xz
musl-e44849f5cf331e655705b18d6c81c616e29d50d0.zip
protect sem_open against cancellation
also fix one minor bug: failure to free the early-reserved slot when
the semaphore later found to already be mapped.
Diffstat (limited to 'src/thread')
-rw-r--r--src/thread/sem_open.c32
1 files changed, 19 insertions, 13 deletions
diff --git a/src/thread/sem_open.c b/src/thread/sem_open.c
index 08f98c25..ed2353c8 100644
--- a/src/thread/sem_open.c
+++ b/src/thread/sem_open.c
@@ -29,7 +29,7 @@ sem_t *sem_open(const char *name, int flags, ...)
 	va_list ap;
 	mode_t mode;
 	unsigned value;
-	int fd, i, e, slot, first=1, cnt;
+	int fd, i, e, slot, first=1, cnt, cs;
 	sem_t newsem;
 	void *map;
 	char tmp[64];
@@ -74,6 +74,8 @@ sem_t *sem_open(const char *name, int flags, ...)
 		return SEM_FAILED;
 	}
 
+	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
+
 	for (;;) {
 		/* If exclusive mode is not requested, try opening an
 		 * existing file first and fall back to creation. */
@@ -83,16 +85,16 @@ sem_t *sem_open(const char *name, int flags, ...)
 				if ((map = mmap(0, sizeof(sem_t), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED ||
 				    fstat(fd, &st) < 0) {
 					close(fd);
-					return SEM_FAILED;
+					goto fail;
 				}
 				close(fd);
 				break;
 			}
 			if (errno != ENOENT)
-				return SEM_FAILED;
+				goto fail;
 		}
 		if (!(flags & O_CREAT))
-			return SEM_FAILED;
+			goto fail;
 		if (first) {
 			first = 0;
 			va_start(ap, flags);
@@ -101,7 +103,7 @@ sem_t *sem_open(const char *name, int flags, ...)
 			va_end(ap);
 			if (value > SEM_VALUE_MAX) {
 				errno = EINVAL;
-				return SEM_FAILED;
+				goto fail;
 			}
 			sem_init(&newsem, 1, value);
 		}
@@ -112,13 +114,13 @@ sem_t *sem_open(const char *name, int flags, ...)
 		fd = open(tmp, O_CREAT|O_EXCL|FLAGS, mode);
 		if (fd < 0) {
 			if (errno == EEXIST) continue;
-			return SEM_FAILED;
+			goto fail;
 		}
 		if (write(fd, &newsem, sizeof newsem) != sizeof newsem || fstat(fd, &st) < 0 ||
 		    (map = mmap(0, sizeof(sem_t), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
 			close(fd);
 			unlink(tmp);
-			return SEM_FAILED;
+			goto fail;
 		}
 		close(fd);
 		if (link(tmp, name) == 0) break;
@@ -128,7 +130,7 @@ sem_t *sem_open(const char *name, int flags, ...)
 		 * otherwise, next iteration will try to open the
 		 * existing file. */
 		if (e != EEXIST || flags == (O_CREAT|O_EXCL))
-			return SEM_FAILED;
+			goto fail;
 	}
 
 	/* See if the newly mapped semaphore is already mapped. If
@@ -138,16 +140,20 @@ sem_t *sem_open(const char *name, int flags, ...)
 	for (i=0; i<SEM_NSEMS_MAX && semtab[i].ino != st.st_ino; i++);
 	if (i<SEM_NSEMS_MAX) {
 		munmap(map, sizeof(sem_t));
-		semtab[i].refcnt++;
-		UNLOCK(lock);
-		return semtab[i].sem;
+		semtab[slot].sem = 0;
+		slot = i;
+		map = semtab[i].sem;
 	}
-	semtab[slot].refcnt = 1;
+	semtab[slot].refcnt++;
 	semtab[slot].sem = map;
 	semtab[slot].ino = st.st_ino;
 	UNLOCK(lock);
-
+	pthread_setcancelstate(cs, 0);
 	return map;
+
+fail:
+	pthread_setcancelstate(cs, 0);
+	return SEM_FAILED;
 }
 
 int sem_close(sem_t *sem)