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

问题描述 投票:12回答:1

我有一个简单的程序:

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

valgrind semaphore
1个回答
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的所有字段都已经初始化了...我们在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字段,其中包含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抱怨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感到困惑。

© www.soinside.com 2019 - 2024. All rights reserved.