Bug#906917: sem_timedwait could always block and returns ETIMEOUT but decrements the value on i686 architecture
Hi,
On 2018-08-22 13:02, Андрей Доценко wrote:
> Package: libc6
> Version: 2.24-11+deb9-u3
>
> Using sem_timedwait on i686 gives random results. In out proprietary
> software semaphore used by two processes and located in shared memory
> mapped with mmap. All works under amd64 architecture and under another some
> distibutions. But under Debian Stretch amd64 sem_timedwait always blocks
> for timeout and returns ETIMEOUT error. Meanwhile it acquires the lock
> decreasing semaphore value.
>
> I've tried to make test for this bug. Test reproduces bug only with ASAN
> enabled. Without ASAN enabled it always passes. I've attached test but
> without ASAN support to show that I don't miss anything. I can modify test
> to enable ASAN support but if somebody ask.
Thanks, I have been able to reproduce the problem here, even with glibc
2.29. I have attached a version which doesn't need cmake nor check.
On your side, have you been able to reproduce the problem *without*
ASAN, even on a bigger codebase? I wonder if it is actually a side
effect of ASAN.
> I've discovered that symbols used by i686 are different from those from
> amd64. On amd64 symbols are:
> ~$ nm "${PROJ_PATH}/Docker/debian/9/amd64/test-bugs/test-bugs" | grep sem_
> U sem_destroy@@GLIBC_2.2.5
> U sem_getvalue@@GLIBC_2.2.5
> U sem_init@@GLIBC_2.2.5
> U sem_post@@GLIBC_2.2.5
> U sem_timedwait@@GLIBC_2.2.5
> 00000000004019b0 t test_process_sem_timedwait
> 00000000004011c0 t test_process_sem_timedwait_nolock
>
> But under i686 symbols are different:
> ~$ nm "${PROJ_PATH}/Docker/debian/9/i386/test-bugs/test-bugs" | grep sem_
> U sem_destroy@@GLIBC_2.1
> U sem_getvalue@@GLIBC_2.1
> U sem_init@@GLIBC_2.1
> U sem_post@@GLIBC_2.1
> U sem_timedwait@@GLIBC_2.2
> 08049f50 t test_process_sem_timedwait
> 08048ee0 t test_process_sem_timedwait_nolock
>
> As you can see symbols are different for i686. Version of sem_init,
> sem_wait, sem_post, sem_destroy and sem_getvalue is GLIBC_2.1, but version
> of sem_timedwait is GLIBC_2.2.
This is perfectly normal. glibc 2.2.5 is the first glibc version that
supported the amd64 architecture.
> Replacing sem_timedwait with sem_wait makes all work on i686 architecture.
> So sem_wait is ok, but sem_timedwait is not.
I confirm that.
Regards,
Aurelien
--
Aurelien Jarno GPG: 4096R/1DDD8C9B
aurelien@aurel32.net http://www.aurel32.net
/* Build with: gcc -o bug906917 bug906917.c -pthread -fsanitize=address */
#include <assert.h>
#include <errno.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
int main()
{
sem_t *sem =
mmap(NULL, sizeof(*sem), PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
int r;
r = sem_init(sem, 1, 0);
if (r == -1) {
perror("sem_init");
}
assert(r == 0);
pid_t pid = fork();
if (pid == 0) {
r = sem_post(sem);
if (r == -1) {
exit(1);
}
exit(0);
}
assert(pid > 0);
int exit_status;
pid_t child_pid;
do {
child_pid = waitpid(pid, &exit_status, 0);
}
while ((child_pid == -1) && (errno == EINTR));
if (child_pid == -1) {
perror("waitpid");
}
assert(child_pid == pid);
assert(WIFEXITED(exit_status));
assert(WEXITSTATUS(exit_status) == 0);
struct timespec abstime;
r = clock_gettime(CLOCK_REALTIME, &abstime);
assert(r == 0);
abstime.tv_sec += 5;
int value = -1;
sem_getvalue(sem, &value);
assert(value == 1);
do {
r = sem_timedwait(sem, &abstime);
}
while ((r == -1) && (errno == EINTR));
if (r == -1) {
perror("sem_timedwait");
}
assert(r == 0);
value = -1;
sem_getvalue(sem, &value);
assert(value == 0);
sem_destroy(sem);
return 0;
}
Reply to: