`pthread_detach(0)` 段错误而不是返回 ESRCH

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

我遇到了

pthread_detach
的一些意外行为。考虑以下代码:

#include <pthread.h>

int main() {
    pthread_detach(0);
}

这显然是一个错误(0 不是有效的

pthread_t
)。当我运行此代码时,进程因段错误而崩溃。

问题是,根据手册页,它应该处理这个错误并简单地返回ESRCH(因为这应该只是“没有找到ID为0的线程”的情况,对吧?)

手册页提到的唯一未定义的行为是尝试分离已经分离的线程,但事实并非如此。

我使用的是 glibc 版本 2.39-4.2;这可能是一个错误吗?

更新:我在这里找到了负责此操作的代码:https://elixir.bootlin.com/glibc/glibc-2.39/source/nptl/pthread_detach.c#L29

因此,手册页中的“线程ID”似乎指的是线程结构的某些属性(tid,请参阅here)(由

pthread_t
类型指向。这解释了段错误,但我仍然不相信这是预期的行为。

更新2:我刚刚遇到这个非常相关的问题,这似乎几乎回答了这个问题。

pthreads glibc
1个回答
0
投票

当您用

glibc
标记您的问题时,答案就在 GLIBc 源代码中。源文件是:nptl/pthread_detach.c

int
pthread_detach (pthread_t th)
{
  struct pthread *pd = (struct pthread *) th;

  /* Make sure the descriptor is valid.  */
  if (INVALID_NOT_TERMINATED_TD_P (pd))
    /* Not a valid thread handle.  */
    return ESRCH;

  int result = 0;

  /* Mark the thread as detached.  */
  if (atomic_compare_and_exchange_bool_acq (&pd->joinid, pd, NULL))
    {
      /* There are two possibilities here.  First, the thread might
     already be detached.  In this case we return EINVAL.
     Otherwise there might already be a waiter.  The standard does
     not mention what happens in this case.  */
      if (IS_DETACHED (pd))
    result = EINVAL;
    }
  else
    /* Check whether the thread terminated meanwhile.  In this case we
       will just free the TCB.  */
    if ((pd->cancelhandling & EXITING_BITMASK) != 0)
      /* Note that the code in __free_tcb makes sure each thread
     control block is freed only once.  */
      __free_tcb (pd);

  return result;
}

使用

INVALID_NOT_TERMINATED_TD_P (pd)
检查传递给 API 的参数。如果检查失败,则返回 ESRCH,但后者在 nptl/pthreadP.h 中定义为:

/* Simplified test.  This will not catch all invalid descriptors but
   is better than nothing.  And if the test triggers the thread
   descriptor is guaranteed to be invalid.  */
# define INVALID_TD_P(pd) __builtin_expect ((pd)->tid <= 0, 0)
# define INVALID_NOT_TERMINATED_TD_P(pd) __builtin_expect ((pd)->tid < 0, 0)

上面的宏不会检查参数是否有效(至少不等于0)以使用

(pd)->tid
取消引用它。这就是你崩溃的原因。

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