sem_open - valgrind抱怨未初始化的字节

时间:2016-02-23 12:51:15

标签: valgrind semaphore

我有一个简单的程序:

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错误与更大的项目中看到的相同,但是它会导致崩溃,我的小例子并没有。

1 个答案:

答案 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字段,其中同时包含valuenwaiters,否则它们是单独的字段。

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感到困惑。