I wrote:
> This is from current macOS, but equivalent text appears on Linux and
> in the POSIX spec. So it's just luck that nobody has reported the
> same problem elsewhere --- unless maybe there is some macOS-specific
> behavior making it more likely that different installs would try the
> same key.
Hmm, no, there is a platform dependency here. I made the attached
test program to see what happens when there's a key collision,
and on Linux I get
semget(SEMAS_PER_SET) failed: File exists
semget(SEMAS_PER_SET + 1) failed: File exists
but macOS and NetBSD give
semget(SEMAS_PER_SET) failed: File exists
semget(SEMAS_PER_SET + 1) failed: Invalid argument
I didn't try other BSDen; this might be a NetBSD-ism that Apple
inherited, or maybe it's common among the BSDen. I don't see any
text in POSIX specifying which errno is to be returned in this case,
so we can't really argue that the behavior is wrong.
regards, tom lane
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/stat.h>
typedef key_t IpcSemaphoreKey; /* semaphore key passed to semget(2) */
#ifndef HAVE_UNION_SEMUN
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
};
#endif
#define SEMAS_PER_SET 16
#define IPCProtection (0600) /* access/modify by user only */
int main(int argc, char **argv)
{
IpcSemaphoreKey semKey = 42;
int semId;
int semId2;
union semun semun;
/*
* Find a free semaphore key, and create a set with SEMAS_PER_SET semas.
*/
for(;;)
{
semId = semget(semKey, SEMAS_PER_SET,
IPC_CREAT | IPC_EXCL | IPCProtection);
if (semId >= 0)
break;
semKey++;
}
/*
* Check behavior if we try to make another set with same # of semas.
*/
semId2 = semget(semKey, SEMAS_PER_SET,
IPC_CREAT | IPC_EXCL | IPCProtection);
if (semId2 < 0)
fprintf(stderr, "semget(SEMAS_PER_SET) failed: %s\n",
strerror(errno));
else
fprintf(stderr, "semget(SEMAS_PER_SET) unexpectedly succeeded\n");
/*
* Check behavior if we try to make another set with more semas.
*/
semId2 = semget(semKey, SEMAS_PER_SET + 1,
IPC_CREAT | IPC_EXCL | IPCProtection);
if (semId2 < 0)
fprintf(stderr, "semget(SEMAS_PER_SET + 1) failed: %s\n",
strerror(errno));
else
fprintf(stderr, "semget(SEMAS_PER_SET + 1) unexpectedly succeeded\n");
/*
* Clean up
*/
semun.val = 0; /* unused, but keep compiler quiet */
if (semctl(semId, 0, IPC_RMID, semun) < 0)
fprintf(stderr, "semctl(%d, 0, IPC_RMID, ...) failed: %s\n",
semId, strerror(errno));
return 0;
}