pthread_threadid_np() reports an incorrect thread ID after fork() on Mojave b9

Originator:mark
Number:rdar://43843552 Date Originated:2018-08-29
Status:Open Resolved:
Product:macOS + SDK Product Version:10.14db9 18A377a
Classification:Serious Bug Reproducible:Always
 
Area:
Something not on this list

Summary: The thread ID reported by pthread_threadid_np() is not correct after calling fork(). In the forked process, the thread receives a new thread ID from the kernel, but the ID reported by pthread_threadid_np() continues to reflect the original pre-forked thread’s ID.

This is a regression somewhere in the Mojave beta series. I experience it on 10.14db9 18A377a.

Steps to Reproduce: Run the attached test program, which compares the results of pthread_threadid_np(pthread_self()) with the thread_selfid() system call.

mark@garbage zsh% clang thread_id_test.c -o thread_id_test
mark@garbage zsh% ./thread_id_test 

Expected Results:
The exact numbers are irrelevant, but three lines should be printed, and all should report “ok”.

mark@garbage zsh% ./thread_id_test 
prefork: pthread_thread_id 0x48bfe == thread_id 0x48bfe (ok)
parent: pthread_thread_id 0x48bfe == thread_id 0x48bfe (ok)
child: pthread_thread_id 0x48bff == thread_id 0x48bff (ok)
mark@garbage zsh% sw_vers
ProductName:	Mac OS X
ProductVersion:	10.13.6
BuildVersion:	17G65

Actual Results:
On 10.14, the “child” line prints BAD. On the child side of a fork(), pthread_threadid_np(pthread_self()) is incorrect.

litterbox@ten-fourteen zsh% sw_vers; ./thread_id_test
prefork: pthread_thread_id 0x3072 == thread_id 0x3072 (ok)
parent: pthread_thread_id 0x3072 == thread_id 0x3072 (ok)
child: pthread_thread_id 0x3072 != thread_id 0x3073 (BAD)
litterbox@ten-fourteen zsh% sw_vers
ProductName:	Mac OS X
ProductVersion:	10.14
BuildVersion:	18A377a

Version/Build:
10.14db9 18A377a, xnu-4903.201.2~4/RELEASE_X86_64, libpthread-330.201.1

This bug is a regression. It is not present in 10.13.6 17G65. It was not present in at least some earlier 10.14 developer betas, although I’m not certain which beta introduced the bug.

--

thread_id_test.c

// clang thread_id_test.c -o thread_id_test

#include <err.h>
#include <errno.h>
#include <limits.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <unistd.h>

void Test(const char* tag) {
  uint64_t pthread_thread_id;
  errno = pthread_threadid_np(pthread_self(), &pthread_thread_id);
  if (errno != 0) {
    err(EXIT_FAILURE, "%s: pthread_threadid_np()", tag);
  }

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
  int thread_id = syscall(SYS_thread_selfid);
#pragma clang diagnostic pop
  if (thread_id == -1) {
    err(EXIT_FAILURE, "%s: thread_selfid()", tag);
  }

  if (pthread_thread_id > INT_MAX) {
    printf("%s: pthread_thread_id 0x%llx is too large, thread_id is 0x%x\n",
           tag,
           pthread_thread_id,
           thread_id);
  }

  _Bool ok = pthread_thread_id == thread_id;
  printf("%s: pthread_thread_id 0x%llx %s thread_id 0x%x (%s)\n",
         tag,
         pthread_thread_id,
         ok ? "==" : "!=",
         thread_id,
         ok ? "ok" : "BAD");
}

int main(int argc, char* argv[]) {
  Test("prefork");

  pid_t pid = fork();
  if (pid < 0) {
    err(EXIT_FAILURE, "fork()");
  }

  if (pid == 0) {
    Test("child");
  } else {
    Test("parent");
  }

  return EXIT_SUCCESS;
}

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!