Index: lib/msan/msan_linux.cc
===================================================================
--- lib/msan/msan_linux.cc
+++ lib/msan/msan_linux.cc
@@ -34,6 +34,13 @@
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_procmaps.h"
 
+#if SANITIZER_NETBSD
+#include <sys/cdefs.h>
+extern "C" {
+int __cxa_thread_atexit(void (*)(void *), void *, void *) __weak;
+}
+#endif
+
 namespace __msan {
 
 void ReportMapRange(const char *descr, uptr beg, uptr size) {
@@ -175,19 +182,59 @@
 
 // ---------------------- TSD ---------------- {{{1
 
-static pthread_key_t tsd_key;
+static THREADLOCAL MsanThread *msan_current_thread;
+
+MsanThread *GetCurrentThread() { return msan_current_thread; }
+
+#if SANITIZER_NETBSD
+// Thread Static Data cannot be used in early init on NetBSD
+// Reuse the Asan TSD API for compatibility with existing code
+// with an alternative implementation.
+
 static bool tsd_key_inited = false;
+static void (*tsd_destructor)(void *tsd) = nullptr;
+
+void tsd_at_exit(void *tsd) {
+  CHECK_EQ(tsd, (void *)msan_current_thread);
+  CHECK(tsd);
+  (*tsd_destructor)(tsd);
+}
 
 void MsanTSDInit(void (*destructor)(void *tsd)) {
   CHECK(!tsd_key_inited);
   tsd_key_inited = true;
-  CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
+  tsd_destructor = destructor;
+}
+
+void SetCurrentThread(MsanThread *t) {
+  CHECK(tsd_key_inited);
+  // Make sure we do not reset the current MsanThread.
+  CHECK_EQ(0, msan_current_thread);
+  msan_current_thread = t;
+  // Make sure that MsanTSDDtor gets called at the end.
+  CHECK(tsd_key_inited);
+  if (::__cxa_thread_atexit(tsd_at_exit, t, nullptr)) {
+    Printf("MemorySanitizer: failed to setup thread atexit callback");
+    Die();
+  }
 }
 
-static THREADLOCAL MsanThread* msan_current_thread;
+void MsanTSDDtor(void *tsd) {
+  CHECK(tsd_key_inited);
+  CHECK_EQ(tsd, (void *)msan_current_thread);
+  msan_current_thread = nullptr;
+  // Make sure that signal handler can not see a stale current thread pointer.
+  atomic_signal_fence(memory_order_seq_cst);
+  MsanThread::TSDDtor(tsd);
+}
+#else
+static pthread_key_t tsd_key;
+static bool tsd_key_inited = false;
 
-MsanThread *GetCurrentThread() {
-  return msan_current_thread;
+void MsanTSDInit(void (*destructor)(void *tsd)) {
+  CHECK(!tsd_key_inited);
+  tsd_key_inited = true;
+  CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
 }
 
 void SetCurrentThread(MsanThread *t) {
@@ -211,6 +258,7 @@
   atomic_signal_fence(memory_order_seq_cst);
   MsanThread::TSDDtor(tsd);
 }
+#endif
 
 } // namespace __msan