我有一个简单的程序:
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错误与更大的项目中看到的相同,但是它会导致崩溃,我的小例子并没有。
答案 0 :(得分:0)
我在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的所有字段实际上都已被初始化。我们在{{3}中找到了定义},这就是这个奇妙的创作:
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抱怨使用32位sem.newsem.data
来初始化64位value
,原因是:
value = va_arg (ap, unsigned int);
我们可以看到value
被简单地定义为unsigned int
,即使在64位系统上,它通常仍为32位(请参见https://code.woboq.org/userspace/glibc/sysdeps/nptl/internaltypes.h.html),但这应该只是分配时隐式转换为64位。
所以我认为这不是错误-只是valgrind感到困惑。