Index: compiler-rt/lib/sanitizer_common/CMakeLists.txt
===================================================================
--- compiler-rt/lib/sanitizer_common/CMakeLists.txt
+++ compiler-rt/lib/sanitizer_common/CMakeLists.txt
@@ -32,6 +32,7 @@
   sanitizer_procmaps_linux.cpp
   sanitizer_procmaps_mac.cpp
   sanitizer_procmaps_solaris.cpp
+  sanitizer_report_decorator.cpp
   sanitizer_rtems.cpp
   sanitizer_solaris.cpp
   sanitizer_stoptheworld_mac.cpp
Index: compiler-rt/lib/sanitizer_common/sanitizer_common.cpp
===================================================================
--- compiler-rt/lib/sanitizer_common/sanitizer_common.cpp
+++ compiler-rt/lib/sanitizer_common/sanitizer_common.cpp
@@ -15,6 +15,7 @@
 #include "sanitizer_allocator_internal.h"
 #include "sanitizer_atomic.h"
 #include "sanitizer_flags.h"
+#include "sanitizer_file.h"
 #include "sanitizer_libc.h"
 #include "sanitizer_placement_new.h"
 
@@ -93,6 +94,30 @@
   __sanitizer_report_error_summary(buff.data());
 }
 
+#if !SANITIZER_FUCHSIA
+
+static INLINE bool ReportSupportsColors() {
+  return report_file.SupportsColors();
+}
+
+#else  // SANITIZER_FUCHSIA
+
+// Fuchsia's logs always go through post-processing that handles colorization.
+static INLINE bool ReportSupportsColors() { return true; }
+
+#endif  // !SANITIZER_FUCHSIA
+
+bool ColorizeReports() {
+  // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color
+  // printing on Windows.
+  if (SANITIZER_WINDOWS)
+    return false;
+
+  const char *flag = common_flags()->color;
+  return internal_strcmp(flag, "always") == 0 ||
+         (internal_strcmp(flag, "auto") == 0 && ReportSupportsColors());
+}
+
 // Removes the ANSI escape sequences from the input string (in-place).
 void RemoveANSIEscapeSequencesFromString(char *str) {
   if (!str)
Index: compiler-rt/lib/sanitizer_common/sanitizer_printf.cpp
===================================================================
--- compiler-rt/lib/sanitizer_common/sanitizer_printf.cpp
+++ compiler-rt/lib/sanitizer_common/sanitizer_printf.cpp
@@ -16,6 +16,7 @@
 #include "sanitizer_common.h"
 #include "sanitizer_flags.h"
 #include "sanitizer_libc.h"
+#include "sanitizer_report_decorator.h"
 
 #include <stdio.h>
 #include <stdarg.h>
@@ -290,6 +291,7 @@
     break;
 #   undef CHECK_NEEDED_LENGTH
   }
+  SanitizerCommonDecorator().Compact(buffer);
   RawWrite(buffer);
 
   // Remove color sequences from the message.
Index: compiler-rt/lib/sanitizer_common/sanitizer_report_decorator.h
===================================================================
--- compiler-rt/lib/sanitizer_common/sanitizer_report_decorator.h
+++ compiler-rt/lib/sanitizer_common/sanitizer_report_decorator.h
@@ -24,23 +24,45 @@
   // stdout, which is not the case on Windows (see SetConsoleTextAttribute()).
  public:
   SanitizerCommonDecorator() : ansi_(ColorizeReports()) {}
-  const char *Bold() const { return ansi_ ? "\033[1m" : ""; }
-  const char *Default() const { return ansi_ ? "\033[1m\033[0m"  : ""; }
+  const char *Bold() const { return ToStr(kBold); }
+  const char *Default() const { return ToStr(kDefault); }
   const char *Warning() const { return Red(); }
   const char *Error() const { return Red(); }
   const char *MemoryByte() const { return Magenta(); }
 
+  // Coalesce sequences of special strings that would overwrite each other.
+  // The string is modified in place.
+  void Compact(char* str) const;
+
  protected:
-  const char *Black()   const { return ansi_ ? "\033[1m\033[30m" : ""; }
-  const char *Red()     const { return ansi_ ? "\033[1m\033[31m" : ""; }
-  const char *Green()   const { return ansi_ ? "\033[1m\033[32m" : ""; }
-  const char *Yellow()  const { return ansi_ ? "\033[1m\033[33m" : ""; }
-  const char *Blue()    const { return ansi_ ? "\033[1m\033[34m" : ""; }
-  const char *Magenta() const { return ansi_ ? "\033[1m\033[35m" : ""; }
-  const char *Cyan()    const { return ansi_ ? "\033[1m\033[36m" : ""; }
-  const char *White()   const { return ansi_ ? "\033[1m\033[37m" : ""; }
+  const char *Black() const { return ToStr(kBlack); }
+  const char *Red() const { return ToStr(kRed); }
+  const char *Green() const { return ToStr(kGreen); }
+  const char *Yellow() const { return ToStr(kYellow); }
+  const char *Blue() const { return ToStr(kBlue); }
+  const char *Magenta() const { return ToStr(kMagenta); }
+  const char *Cyan() const { return ToStr(kCyan); }
+  const char *White() const { return ToStr(kWhite); }
+
  private:
-  bool ansi_;
+  // The currently supported ANSI tags.
+  enum DecorationKind {
+    kUnknown = -1,
+    kDefault = 0,
+    kBold = 1,
+    kBlack = 30,
+    kRed = 31,
+    kGreen = 32,
+    kYellow = 33,
+    kBlue = 34,
+    kMagenta = 35,
+    kCyan = 36,
+    kWhite = 37,
+  };
+
+  const char* ToStr(DecorationKind kind) const;
+
+  const bool ansi_;
 };
 
 }  // namespace __sanitizer
Index: compiler-rt/lib/sanitizer_common/sanitizer_report_decorator.cpp
===================================================================
--- /dev/null
+++ compiler-rt/lib/sanitizer_common/sanitizer_report_decorator.cpp
@@ -0,0 +1,107 @@
+//===-- sanitizer_report_decorator.cc ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer.
+//
+// Methods to manipulate supported ANSI tags.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_report_decorator.h"
+
+#include "sanitizer_libc.h"
+
+namespace __sanitizer {
+
+const char* SanitizerCommonDecorator::ToStr(DecorationKind kind) const {
+  if (!ansi_)
+    return "";
+  switch (kind) {
+    case kDefault:
+      return "\033[0m";
+    case kBold:
+      return "\033[1m";
+    case kBlack:
+      return "\033[1m\033[30m";
+    case kRed:
+      return "\033[1m\033[31m";
+    case kGreen:
+      return "\033[1m\033[32m";
+    case kYellow:
+      return "\033[1m\033[33m";
+    case kBlue:
+      return "\033[1m\033[34m";
+    case kMagenta:
+      return "\033[1m\033[35m";
+    case kCyan:
+      return "\033[1m\033[36m";
+    case kWhite:
+      return "\033[1m\033[37m";
+    default:
+      return "";
+  }
+}
+
+void SanitizerCommonDecorator::Compact(char* str) const {
+  if (!str)
+    return;
+  const char *in = str;
+  char* out = str;
+
+  // We need to keep track of whatever decoration tag we last printed with, as
+  // well as whatever one is currently-active and where the string to print it
+  // is located in the buffer.
+  DecorationKind prev = kUnknown, next = kUnknown;
+  do {
+    // Consume recognized tags in a loop. Tags are not immediately-printed,
+    // and each successive one replaces the previous, so that only-the last
+    // in a sequence is active.
+    while (true) {
+      s64 code = kUnknown;
+      const char* endptr = in;
+      if (internal_strncmp(in, "\033[", 2) == 0)
+        code = internal_simple_strtoll(in + 2, &endptr, 10);
+      if (endptr <= in + 2 || *endptr != 'm')
+        code = kUnknown;
+      switch (code) {
+        case kDefault:
+        case kBold:
+          break;
+        case kBlack:
+        case kRed:
+        case kGreen:
+        case kYellow:
+        case kBlue:
+        case kMagenta:
+        case kCyan:
+        case kWhite:
+          if (next != kBold)
+            code = kUnknown;
+          break;
+        default:
+          code = kUnknown;
+      }
+      if (code == kUnknown)
+        break;
+      in = endptr + 1;
+      next = static_cast<DecorationKind>(code);
+    }
+
+    // If the current character is printable or the end of the string, and the
+    // active tag has changed, print the tag.
+    if (((0x20 < *in && *in < 0x7f) || *in == '\0') && prev != next) {
+      auto tag = ToStr(next);
+      auto tag_len = internal_strlen(tag);  // Not null-terminated!
+      internal_strncpy(out, tag, tag_len);
+      prev = next;
+      out += tag_len;
+    }
+  } while((*out++ = *in++) != '\0');
+}
+
+}  // namespace __sanitizer
Index: compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp
===================================================================
--- compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp
+++ compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp
@@ -39,36 +39,6 @@
 }
 #endif
 
-#if !SANITIZER_FUCHSIA
-
-bool ReportFile::SupportsColors() {
-  SpinMutexLock l(mu);
-  ReopenIfNecessary();
-  return SupportsColoredOutput(fd);
-}
-
-static INLINE bool ReportSupportsColors() {
-  return report_file.SupportsColors();
-}
-
-#else  // SANITIZER_FUCHSIA
-
-// Fuchsia's logs always go through post-processing that handles colorization.
-static INLINE bool ReportSupportsColors() { return true; }
-
-#endif  // !SANITIZER_FUCHSIA
-
-bool ColorizeReports() {
-  // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color
-  // printing on Windows.
-  if (SANITIZER_WINDOWS)
-    return false;
-
-  const char *flag = common_flags()->color;
-  return internal_strcmp(flag, "always") == 0 ||
-         (internal_strcmp(flag, "auto") == 0 && ReportSupportsColors());
-}
-
 void ReportErrorSummary(const char *error_type, const StackTrace *stack,
                         const char *alt_tool_name) {
 #if !SANITIZER_GO
Index: compiler-rt/lib/sanitizer_common/tests/sanitizer_printf_test.cpp
===================================================================
--- compiler-rt/lib/sanitizer_common/tests/sanitizer_printf_test.cpp
+++ compiler-rt/lib/sanitizer_common/tests/sanitizer_printf_test.cpp
@@ -157,4 +157,165 @@
   EXPECT_STREQ("12345  ", buf);
 }
 
+// Value parameterized test for compacting ANSI color sequences.
+struct CompactParam {
+  const char *Input;
+  const char *WithoutColor;
+  const char *WithColor;
+};
+
+class CompactTest : public testing::TestWithParam<CompactParam> {};
+
+// Derived decorator that allows setting color support manualy.
+class TestDecorator : public SanitizerCommonDecorator {
+  TestDecorator(bool ansi) { ansi_ = ansi; }
+};
+
+TEST_P(CompactTest, WithoutColor) {
+  auto Param = GetParam();
+  char *Actual = strdup(Param.Input);
+  ASSERT_NOT_NULL(Actual);
+  TestDecorator(false).Compact(Actual);
+  EXPECT_STREQ(Actual, Param.WithoutColor);
+  free(Actual);
+};
+
+TEST_P(CompactTest, WithColor) {
+  auto Param = GetParam();
+  char *Actual = strdup(Param.Input);
+  ASSERT_NOT_NULL(Actual);
+  TestDecorator(true).Compact(Actual);
+  EXPECT_STREQ(Actual, Param.WithColor);
+  free(Actual);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    WithSpaces, CompactTest,
+    testing::Values(
+        {
+            " x\033[1m\033[31m\033[1m\033[31m\033[1m\033[34my",
+            " xy",
+            " x\033[1m\033[34my",
+        },
+        {
+            "\033[1m\033[31m x\033[1m\033[31m\033[1m\033[31m\033[1m\033[34my",
+            " xy",
+            " \033[1m\033[31mx\033[1m\033[34my",
+        },
+        {
+            "\033[1m\033[34mx \033[1m\033[31m\033[1m\033[31m\033[1m\033[34my",
+            "x y",
+            "\033[1m\033[34mx y",
+        },
+        {
+            "\033[1m\033[31mx\033[1m\033[31m "
+            "\033[1m\033[31m\033[1m\033[34my\033[1m\033[31m",
+            "x y",
+            "\033[1m\033[31mx \033[1m\033[34my\033[1m\033[31m",
+        },
+        {
+            "\033[1m\033[34mx\033[1m\033[31m\033[1m\033[31m "
+            "\033[1m\033[34my\033[1m\033[31m",
+            "x y",
+            "\033[1m\033[34mx y\033[1m\033[31m",
+        },
+        {
+            "\033[1m\033[31mx\033[1m\033[31m\033[1m\033[31m\033[1m\033[34m "
+            "y\033[1m\033[34m",
+            "x y",
+            "\033[1m\033[31mx \033[1m\033[34my",
+        },
+        {
+            "\033[1m\033[34mx\033[1m\033[31m\033[1m\033[31m\033[1m\033[34my "
+            "\033[1m\033[34m",
+            "xy ",
+            "\033[1m\033[34mxy ",
+        },
+        {
+            "x\033[1m\033[31m\033[1m\033[34m\033[1m\033[31my ",
+            "xy ",
+            "x\033[1m\033[31my ",
+        }));
+
+INSTANTIATE_TEST_SUITE_P(
+    WithNewlines, CompactTest,
+    testing::Values(
+        {
+            "\n\033[1m\033[31mx\033[1m\033[31m\033[1m\033[34m\033[1m\033[31my",
+            "\nxy",
+            "\n\033[1m\033[31mxy",
+        },
+        {
+            "\033[1m\033[34m\nx\033[1m\033[31m\033[1m\033[34m\033[1m\033[31my",
+            "\nxy",
+            "\n\033[1m\033[34mx\033[1m\033[31my",
+        },
+        {
+            "\033[1m\033[31mx\n\033[1m\033[31m\033[1m\033[34m\033[1m\033["
+            "31my\033[1m\033[31m",
+            "x\ny",
+            "\033[1m\033[31mx\ny",
+        },
+        {
+            "\033[1m\033[34mx\033[1m\033[31m\n\033[1m\033[34m\033[1m\033["
+            "31my\033[1m\033[31m",
+            "x\ny",
+            "\033[1m\033[34mx\n\033[1m\033[31my",
+        },
+        {
+            "\033[1m\033[31mx\033[1m\033[31m\033[1m\033[34m\n\033[1m\033["
+            "31my\033[1m\033[34m",
+            "x\ny",
+            "\033[1m\033[31mx\ny\033[1m\033[34m",
+        },
+        {
+            "\033[1m\033[34mx\033[1m\033[31m\033[1m\033[34m\033[1m\033["
+            "31m\ny\033[1m\033[34m",
+            "x\ny",
+            "\033[1m\033[34mx\n\033[1m\033[31my\033[1m\033[34m",
+        },
+        {
+            "x\033[1m\033[34m\033[1m\033[31m\033[1m\033[31my\n",
+            "xy\n",
+            "x\033[1m\033[31my\n",
+        },
+        {
+            "\033[1m\033[31mx\033[1m\033[34m\033[1m\033[31m\033[1m\033[31my\n",
+            "xy\n",
+            "\033[1m\033[31mxy\n",
+        }));
+
+INSTANTIATE_TEST_SUITE_P(
+    WithTabs, CompactTest,
+    testing::Values(
+        {
+            "\t\033[1m\033[34mx\033[1m\033[34m\033[1m\033[31m\033[1m\033[31my",
+            "\txy",
+            "\t\033[1m\033[34mx\033[1m\033[31my",
+        },
+        {
+            "\033[1m\033[31m\tx\033[1m\033[34m\033[1m\033[31m\033[1m\033["
+            "31my\033[1m\033[31m",
+            "\txy",
+            "\t\033[1m\033[31mxy",
+        },
+        {
+            "\033[1m\033[34mx\t\033[1m\033[34m\033[1m\033[31m\033[1m\033["
+            "31my\033[1m\033[31m",
+            "x\ty",
+            "\033[1m\033[34mx\t\033[1m\033[31my",
+        },
+        {
+            "\033[1m\033[31mx\033[1m\033[34m\t\033[1m\033[31m\033[1m\033["
+            "31my\033[1m\033[34m",
+            "x\ty",
+            "\033[1m\033[31mx\ty\033[1m\033[34m",
+        },
+        {
+            "\033[1m\033[34mx\033[1m\033[34m\033[1m\033[31m\t\033[1m\033["
+            "31my\033[1m\033[34m",
+            "x\ty",
+            "\033[1m\033[34mx\t\033[1m\033[31my\033[1m\033[34m",
+        }));
+
 }  // namespace __sanitizer