Index: include/sanitizer/dfsan_interface.h
===================================================================
--- include/sanitizer/dfsan_interface.h
+++ include/sanitizer/dfsan_interface.h
@@ -85,6 +85,12 @@
 /// callback executes.  Pass in NULL to remove any callback.
 void dfsan_set_write_callback(dfsan_write_callback_t labeled_write_callback);
 
+/// Writes the labels currently used by the program to the given file
+/// descriptor. The lines of the output have the following format:
+///
+/// <label> <parent label 1> <parent label 2> <label description if any>
+void dfsan_dump_labels(int fd);
+
 #ifdef __cplusplus
 }  // extern "C"
 
Index: lib/dfsan/dfsan.h
===================================================================
--- lib/dfsan/dfsan.h
+++ lib/dfsan/dfsan.h
@@ -61,6 +61,8 @@
   // comparison might be data-dependent on the content of the strings). This
   // applies only to the custom functions defined in 'custom.c'.
   bool strict_data_dependencies;
+  // The path of the file where to dump the labels when the program terminates.
+  const char* dump_labels_at_exit;
 };
 
 extern Flags flags_data;
Index: lib/dfsan/dfsan.cc
===================================================================
--- lib/dfsan/dfsan.cc
+++ lib/dfsan/dfsan.cc
@@ -70,10 +70,21 @@
 static const uptr kUnusedAddr = kUnionTableAddr + sizeof(dfsan_union_table_t);
 static const uptr kAppAddr = 0x700000008000;
 
+static void dfsan_fini();
+
 static atomic_dfsan_label *union_table(dfsan_label l1, dfsan_label l2) {
   return &(*(dfsan_union_table_t *) kUnionTableAddr)[l1][l2];
 }
 
+// Checks we do not run out of labels.
+static void dfsan_check_label(dfsan_label label) {
+  if (label == kInitializingLabel) {
+    Report("FATAL: DataFlowSanitizer: out of labels");
+    dfsan_fini();
+    Die();
+  }
+}
+
 // Resolves the union of two unequal labels.  Nonequality is a precondition for
 // this function (the instrumentation pass inlines the equality test).
 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
@@ -106,7 +117,7 @@
     } else {
       label =
         atomic_fetch_add(&__dfsan_last_label, 1, memory_order_relaxed) + 1;
-      CHECK_NE(label, kInitializingLabel);
+      dfsan_check_label(label);
       __dfsan_label_info[label].l1 = l1;
       __dfsan_label_info[label].l2 = l2;
     }
@@ -169,7 +180,7 @@
 dfsan_label dfsan_create_label(const char *desc, void *userdata) {
   dfsan_label label =
     atomic_fetch_add(&__dfsan_last_label, 1, memory_order_relaxed) + 1;
-  CHECK_NE(label, kInitializingLabel);
+  dfsan_check_label(label);
   __dfsan_label_info[label].l1 = __dfsan_label_info[label].l2 = 0;
   __dfsan_label_info[label].desc = desc;
   __dfsan_label_info[label].userdata = userdata;
@@ -259,14 +270,33 @@
   return static_cast<uptr>(max_label_allocated);
 }
 
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
+dfsan_dump_labels(int fd) {
+  dfsan_label last_label =
+      atomic_load(&__dfsan_last_label, memory_order_relaxed);
+  for (dfsan_label l = 0; l <= last_label; ++l) {
+    char buf[64];
+    internal_snprintf(buf, sizeof(buf), "%u %u %u ", l,
+                      __dfsan_label_info[l].l1, __dfsan_label_info[l].l2);
+    internal_write(fd, buf, internal_strlen(buf));
+    if (__dfsan_label_info[l].l1 == 0 && __dfsan_label_info[l].desc) {
+      internal_write(fd, __dfsan_label_info[l].desc,
+                     internal_strlen(__dfsan_label_info[l].desc));
+    }
+    internal_write(fd, "\n", 1);
+  }
+}
+
 static void InitializeFlags(Flags &f, const char *env) {
   f.warn_unimplemented = true;
   f.warn_nonzero_labels = false;
   f.strict_data_dependencies = true;
+  f.dump_labels_at_exit = "";
 
   ParseFlag(env, &f.warn_unimplemented, "warn_unimplemented", "");
   ParseFlag(env, &f.warn_nonzero_labels, "warn_nonzero_labels", "");
   ParseFlag(env, &f.strict_data_dependencies, "strict_data_dependencies", "");
+  ParseFlag(env, &f.dump_labels_at_exit, "dump_labels_at_exit", "");
 }
 
 #ifdef DFSAN_NOLIBC
@@ -290,7 +320,25 @@
   InitializeInterceptors();
 }
 
+static void dfsan_fini() {
+  if (internal_strcmp(flags().dump_labels_at_exit, "") != 0) {
+    fd_t fd = OpenFile(flags().dump_labels_at_exit, true /* write */);
+    if (fd == kInvalidFd) {
+      Report("WARNING: DataFlowSanitizer: unable to open output file %s\n",
+             flags().dump_labels_at_exit);
+      return;
+    }
+
+    Report("INFO: DataFlowSanitizer: dumping labels to %s\n",
+           flags().dump_labels_at_exit);
+    dfsan_dump_labels(fd);
+    internal_close(fd);
+  }
+}
+
 #if !defined(DFSAN_NOLIBC) && SANITIZER_CAN_USE_PREINIT_ARRAY
 __attribute__((section(".preinit_array"), used))
 static void (*dfsan_init_ptr)(int, char **, char **) = dfsan_init;
+__attribute__((section(".fini_array"), used))
+static void (*dfsan_fini_ptr)() = dfsan_fini;
 #endif