我有一个简单的程序:
int main(void)
{
const char sname[]="xxx";
sem_t *pSemaphor;
if ((pSemaphor = sem_open(sname, O_CREAT, 0644, 0)) == SEM_FAILED) {
perror("semaphore initilization");
exit(1);
}
sem_unlink(sname);
sem_close(pSemaphor);
}
当我在valgrind下运行它时,我收到以下错误:
==12702== Syscall param write(buf) points to uninitialised byte(s)
==12702== at 0x4E457A0: __write_nocancel (syscall-template.S:81)
==12702== by 0x4E446FC: sem_open (sem_open.c:245)
==12702== by 0x4007D0: main (test.cpp:15)
==12702== Address 0xfff00023c is on thread 1's stack
==12702== in frame #1, created by sem_open (sem_open.c:139)
代码是从一个成功运行多年的大型项目中提取的,但现在却导致了分段错误。
我的示例中的valgrind错误与更大的项目中看到的相同,但它会导致崩溃,我的小例子没有。
我在Debian上用glibc 2.27-5看到了这个。在我的情况下,我只在一个长期运行的程序开始时打开信号量,到目前为止似乎无害 - 只是烦人。
查看sem_open.c的代码,该代码位于:https://code.woboq.org/userspace/glibc/nptl/sem_open.c.html
似乎valgrind抱怨这条线(我现在看来是270):
if (TEMP_FAILURE_RETRY (__libc_write (fd, &sem.initsem, sizeof (sem_t)))
== sizeof (sem_t)
然而,sem.initsem
之前以相当巴洛克式的方式正确初始化,首先通过明确设置sem.newsem
(联合的一部分)中的字段,然后一旦通过调用memset(L226-228)完成:
/* Initialize the remaining bytes as well. */
memset ((char *) &sem.initsem + sizeof (struct new_sem), '\0',
sizeof (sem_t) - sizeof (struct new_sem));
我认为这个特殊的恶作剧都是最优的,但是我们需要确保new_sem的所有字段都已经初始化了...我们在https://code.woboq.org/userspace/glibc/sysdeps/nptl/internaltypes.h.html中找到了这个定义,这是一个很棒的创作:
struct new_sem
{
#if __HAVE_64B_ATOMICS
/* The data field holds both value (in the least-significant 32 bytes) and
nwaiters. */
# if __BYTE_ORDER == __LITTLE_ENDIAN
# define SEM_VALUE_OFFSET 0
# elif __BYTE_ORDER == __BIG_ENDIAN
# define SEM_VALUE_OFFSET 1
# else
# error Unsupported byte order.
# endif
# define SEM_NWAITERS_SHIFT 32
# define SEM_VALUE_MASK (~(unsigned int)0)
uint64_t data;
int private;
int pad;
#else
# define SEM_VALUE_SHIFT 1
# define SEM_NWAITERS_MASK ((unsigned int)1)
unsigned int value;
int private;
int pad;
unsigned int nwaiters;
#endif
};
因此,如果我们__HAVE_64B_ATOMICS
然后结构有一个data
字段,其中包含value
和nwaiters
,否则这些是单独的字段。
在sem.newsem
的初始化中,我们可以看到这些是正确初始化的,如下所示:
#if __HAVE_64B_ATOMICS
sem.newsem.data = value;
#else
sem.newsem.value = value << SEM_VALUE_SHIFT;
sem.newsem.nwaiters = 0;
#endif
/* pad is used as a mutex on pre-v9 sparc and ignored otherwise. */
sem.newsem.pad = 0;
/* This always is a shared semaphore. */
sem.newsem.private = FUTEX_SHARED;
我在64位系统上做所有这些,所以我认为valgrind抱怨64位sem.newsem.data
的初始化与32位value
,因为从:
value = va_arg (ap, unsigned int);
我们可以看到value
被简单地定义为unsigned int
,即使在64位系统上通常仍然是32位(参见What should be the sizeof(int) on a 64-bit machine?),但这应该只是在分配时隐式转换为64位。
所以我认为这不是一个错误 - 只是valgrind感到困惑。