Make macOS semaphore names more unique, improve assertion

On macOS, semaphore names are global and processes can open semaphores of other processes by using their name. It was possible that multiple client/server processes randomly tried to create semaphores with the same memory address, which would cause them to have the same name. In that case, `sem_open` would fail because `O_EXCL` prevents creating semaphores if the name is already used.

This is made more unlikely by also including the PID in the semaphore name. Additionally, the semaphore name is prefixed with `/` to more closely follow the construction rules for semaphore names. In particular, the behavior is implementation-defined if the name is not prefixed with a slash.

See https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_open.html

Closes #8773.

More details are added to the assertion error message in case this does not end up fixing the issue.
This commit is contained in:
Robert Müller 2024-08-20 19:53:08 +02:00
parent 580b2690a0
commit 839c511af4

View file

@ -867,10 +867,15 @@ void sphore_destroy(SEMAPHORE *sem)
#elif defined(CONF_PLATFORM_MACOS) #elif defined(CONF_PLATFORM_MACOS)
void sphore_init(SEMAPHORE *sem) void sphore_init(SEMAPHORE *sem)
{ {
char aBuf[32]; char aBuf[64];
str_format(aBuf, sizeof(aBuf), "%p", (void *)sem); str_format(aBuf, sizeof(aBuf), "/%d.%p", pid(), (void *)sem);
*sem = sem_open(aBuf, O_CREAT | O_EXCL, S_IRWXU | S_IRWXG, 0); *sem = sem_open(aBuf, O_CREAT | O_EXCL, S_IRWXU | S_IRWXG, 0);
dbg_assert(*sem != SEM_FAILED, "sem_open failure"); if(*sem == SEM_FAILED)
{
char aError[128];
str_format(aError, sizeof(aError), "sem_open failure, errno=%d, name='%s'", errno, aBuf);
dbg_assert(false, aError);
}
} }
void sphore_wait(SEMAPHORE *sem) void sphore_wait(SEMAPHORE *sem)
{ {
@ -888,8 +893,8 @@ void sphore_signal(SEMAPHORE *sem)
void sphore_destroy(SEMAPHORE *sem) void sphore_destroy(SEMAPHORE *sem)
{ {
dbg_assert(sem_close(*sem) == 0, "sem_close failure"); dbg_assert(sem_close(*sem) == 0, "sem_close failure");
char aBuf[32]; char aBuf[64];
str_format(aBuf, sizeof(aBuf), "%p", (void *)sem); str_format(aBuf, sizeof(aBuf), "/%d.%p", pid(), (void *)sem);
dbg_assert(sem_unlink(aBuf) == 0, "sem_unlink failure"); dbg_assert(sem_unlink(aBuf) == 0, "sem_unlink failure");
} }
#elif defined(CONF_FAMILY_UNIX) #elif defined(CONF_FAMILY_UNIX)