[compiler-rt] r356457 - [scudo][standalone] Add string utility functions

Kostya Kortchinsky via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 19 07:47:05 PDT 2019


Author: cryptoad
Date: Tue Mar 19 07:47:05 2019
New Revision: 356457

URL: http://llvm.org/viewvc/llvm-project?rev=356457&view=rev
Log:
[scudo][standalone] Add string utility functions

Summary:
Add some string utility functions, notably to format strings, get
lengths, convert a string to a number. Those functions will be
used in reports and flags (coming up next). They were mostly borrowed
from sanitizer_common.

Make use of the string length function in a couple places in the
platform code that was checked in with inlined version of it.

Add some tests.

Reviewers: morehouse, eugenis, vitalybuka, hctim

Reviewed By: morehouse, vitalybuka

Subscribers: mgorny, delcypher, jdoerfert, #sanitizers, llvm-commits

Tags: #llvm, #sanitizers

Differential Revision: https://reviews.llvm.org/D59262

Added:
    compiler-rt/trunk/lib/scudo/standalone/string_utils.cc
    compiler-rt/trunk/lib/scudo/standalone/string_utils.h
    compiler-rt/trunk/lib/scudo/standalone/tests/strings_test.cc
Modified:
    compiler-rt/trunk/lib/scudo/standalone/CMakeLists.txt
    compiler-rt/trunk/lib/scudo/standalone/fuchsia.cc
    compiler-rt/trunk/lib/scudo/standalone/linux.cc
    compiler-rt/trunk/lib/scudo/standalone/tests/CMakeLists.txt

Modified: compiler-rt/trunk/lib/scudo/standalone/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/standalone/CMakeLists.txt?rev=356457&r1=356456&r2=356457&view=diff
==============================================================================
--- compiler-rt/trunk/lib/scudo/standalone/CMakeLists.txt (original)
+++ compiler-rt/trunk/lib/scudo/standalone/CMakeLists.txt Tue Mar 19 07:47:05 2019
@@ -38,7 +38,8 @@ set(SCUDO_SOURCES
   crc32_hw.cc
   common.cc
   fuchsia.cc
-  linux.cc)
+  linux.cc
+  string_utils.cc)
 
 # Enable the SSE 4.2 instruction set for crc32_hw.cc, if available.
 if (COMPILER_RT_HAS_MSSE4_2_FLAG)
@@ -61,6 +62,7 @@ set(SCUDO_HEADERS
   mutex.h
   platform.h
   stats.h
+  string_utils.h
   vector.h)
 
 if(COMPILER_RT_HAS_SCUDO_STANDALONE)

Modified: compiler-rt/trunk/lib/scudo/standalone/fuchsia.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/standalone/fuchsia.cc?rev=356457&r1=356456&r2=356457&view=diff
==============================================================================
--- compiler-rt/trunk/lib/scudo/standalone/fuchsia.cc (original)
+++ compiler-rt/trunk/lib/scudo/standalone/fuchsia.cc Tue Mar 19 07:47:05 2019
@@ -12,6 +12,7 @@
 
 #include "common.h"
 #include "mutex.h"
+#include "string_utils.h"
 
 #include <limits.h> // for PAGE_SIZE
 #include <stdlib.h> // for abort()
@@ -110,10 +111,7 @@ void *map(void *Addr, uptr Size, const c
         dieOnMapUnmapError(Status == ZX_ERR_NO_MEMORY);
       return nullptr;
     }
-    uptr N = 0;
-    while (Name[N])
-      N++;
-    _zx_object_set_property(Vmo, ZX_PROP_NAME, Name, N);
+    _zx_object_set_property(Vmo, ZX_PROP_NAME, Name, strlen(Name));
   }
 
   uintptr_t P;
@@ -203,10 +201,7 @@ bool getRandom(void *Buffer, uptr Length
 }
 
 void outputRaw(const char *Buffer) {
-  uptr N = 0;
-  while (Buffer[N])
-    N++;
-  __sanitizer_log_write(Buffer, N);
+  __sanitizer_log_write(Buffer, strlen(Buffer));
 }
 
 void setAbortMessage(const char *Message) {}

Modified: compiler-rt/trunk/lib/scudo/standalone/linux.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/standalone/linux.cc?rev=356457&r1=356456&r2=356457&view=diff
==============================================================================
--- compiler-rt/trunk/lib/scudo/standalone/linux.cc (original)
+++ compiler-rt/trunk/lib/scudo/standalone/linux.cc Tue Mar 19 07:47:05 2019
@@ -13,6 +13,7 @@
 #include "common.h"
 #include "linux.h"
 #include "mutex.h"
+#include "string_utils.h"
 
 #include <errno.h>
 #include <fcntl.h>
@@ -133,10 +134,7 @@ bool getRandom(void *Buffer, uptr Length
 void outputRaw(const char *Buffer) {
   static StaticSpinMutex Mutex;
   SpinMutexLock L(&Mutex);
-  uptr N = 0;
-  while (Buffer[N])
-    N++;
-  write(2, Buffer, N);
+  write(2, Buffer, strlen(Buffer));
 }
 
 extern "C" WEAK void android_set_abort_message(const char *);

Added: compiler-rt/trunk/lib/scudo/standalone/string_utils.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/standalone/string_utils.cc?rev=356457&view=auto
==============================================================================
--- compiler-rt/trunk/lib/scudo/standalone/string_utils.cc (added)
+++ compiler-rt/trunk/lib/scudo/standalone/string_utils.cc Tue Mar 19 07:47:05 2019
@@ -0,0 +1,236 @@
+//===-- string_utils.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
+//
+//===----------------------------------------------------------------------===//
+
+#include "string_utils.h"
+#include "common.h"
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <string.h>
+
+namespace scudo {
+
+static int appendChar(char **Buffer, const char *BufferEnd, char C) {
+  if (*Buffer < BufferEnd) {
+    **Buffer = C;
+    (*Buffer)++;
+  }
+  return 1;
+}
+
+// Appends number in a given Base to buffer. If its length is less than
+// |MinNumberLength|, it is padded with leading zeroes or spaces, depending
+// on the value of |PadWithZero|.
+static int appendNumber(char **Buffer, const char *BufferEnd, u64 AbsoluteValue,
+                        u8 Base, u8 MinNumberLength, bool PadWithZero,
+                        bool Negative, bool Upper) {
+  constexpr uptr MaxLen = 30;
+  RAW_CHECK(Base == 10 || Base == 16);
+  RAW_CHECK(Base == 10 || !Negative);
+  RAW_CHECK(AbsoluteValue || !Negative);
+  RAW_CHECK(MinNumberLength < MaxLen);
+  int Res = 0;
+  if (Negative && MinNumberLength)
+    --MinNumberLength;
+  if (Negative && PadWithZero)
+    Res += appendChar(Buffer, BufferEnd, '-');
+  uptr NumBuffer[MaxLen];
+  int Pos = 0;
+  do {
+    RAW_CHECK_MSG(static_cast<uptr>(Pos) < MaxLen,
+                  "appendNumber buffer overflow");
+    NumBuffer[Pos++] = AbsoluteValue % Base;
+    AbsoluteValue /= Base;
+  } while (AbsoluteValue > 0);
+  if (Pos < MinNumberLength) {
+    memset(&NumBuffer[Pos], 0,
+           sizeof(NumBuffer[0]) * static_cast<uptr>(MinNumberLength - Pos));
+    Pos = MinNumberLength;
+  }
+  RAW_CHECK(Pos > 0);
+  Pos--;
+  for (; Pos >= 0 && NumBuffer[Pos] == 0; Pos--) {
+    char c = (PadWithZero || Pos == 0) ? '0' : ' ';
+    Res += appendChar(Buffer, BufferEnd, c);
+  }
+  if (Negative && !PadWithZero)
+    Res += appendChar(Buffer, BufferEnd, '-');
+  for (; Pos >= 0; Pos--) {
+    char Digit = static_cast<char>(NumBuffer[Pos]);
+    Digit = static_cast<char>((Digit < 10) ? '0' + Digit
+                                           : (Upper ? 'A' : 'a') + Digit - 10);
+    Res += appendChar(Buffer, BufferEnd, Digit);
+  }
+  return Res;
+}
+
+static int appendUnsigned(char **Buffer, const char *BufferEnd, u64 Num,
+                          u8 Base, u8 MinNumberLength, bool PadWithZero,
+                          bool Upper) {
+  return appendNumber(Buffer, BufferEnd, Num, Base, MinNumberLength,
+                      PadWithZero, /*Negative=*/false, Upper);
+}
+
+static int appendSignedDecimal(char **Buffer, const char *BufferEnd, s64 Num,
+                               u8 MinNumberLength, bool PadWithZero) {
+  const bool Negative = (Num < 0);
+  return appendNumber(Buffer, BufferEnd,
+                      static_cast<u64>(Negative ? -Num : Num), 10,
+                      MinNumberLength, PadWithZero, Negative,
+                      /*Upper=*/false);
+}
+
+// Use the fact that explicitly requesting 0 Width (%0s) results in UB and
+// interpret Width == 0 as "no Width requested":
+// Width == 0 - no Width requested
+// Width  < 0 - left-justify S within and pad it to -Width chars, if necessary
+// Width  > 0 - right-justify S, not implemented yet
+static int appendString(char **Buffer, const char *BufferEnd, int Width,
+                        int MaxChars, const char *S) {
+  if (!S)
+    S = "<null>";
+  int Res = 0;
+  for (; *S; S++) {
+    if (MaxChars >= 0 && Res >= MaxChars)
+      break;
+    Res += appendChar(Buffer, BufferEnd, *S);
+  }
+  // Only the left justified strings are supported.
+  while (Width < -Res)
+    Res += appendChar(Buffer, BufferEnd, ' ');
+  return Res;
+}
+
+static int appendPointer(char **Buffer, const char *BufferEnd, u64 ptr_value) {
+  int Res = 0;
+  Res += appendString(Buffer, BufferEnd, 0, -1, "0x");
+  Res += appendUnsigned(Buffer, BufferEnd, ptr_value, 16,
+                        SCUDO_POINTER_FORMAT_LENGTH, /*PadWithZero=*/true,
+                        /*Upper=*/false);
+  return Res;
+}
+
+int formatString(char *Buffer, uptr BufferLength, const char *Format,
+                 va_list Args) {
+  UNUSED static const char *PrintfFormatsHelp =
+      "Supported formatString formats: %([0-9]*)?(z|ll)?{d,u,x,X}; %p; "
+      "%[-]([0-9]*)?(\\.\\*)?s; %c\n";
+  RAW_CHECK(Format);
+  RAW_CHECK(BufferLength > 0);
+  const char *BufferEnd = &Buffer[BufferLength - 1];
+  const char *Cur = Format;
+  int Res = 0;
+  for (; *Cur; Cur++) {
+    if (*Cur != '%') {
+      Res += appendChar(&Buffer, BufferEnd, *Cur);
+      continue;
+    }
+    Cur++;
+    const bool LeftJustified = *Cur == '-';
+    if (LeftJustified)
+      Cur++;
+    bool HaveWidth = (*Cur >= '0' && *Cur <= '9');
+    const bool PadWithZero = (*Cur == '0');
+    u8 Width = 0;
+    if (HaveWidth) {
+      while (*Cur >= '0' && *Cur <= '9')
+        Width = static_cast<u8>(Width * 10 + *Cur++ - '0');
+    }
+    const bool HavePrecision = (Cur[0] == '.' && Cur[1] == '*');
+    int Precision = -1;
+    if (HavePrecision) {
+      Cur += 2;
+      Precision = va_arg(Args, int);
+    }
+    const bool HaveZ = (*Cur == 'z');
+    Cur += HaveZ;
+    const bool HaveLL = !HaveZ && (Cur[0] == 'l' && Cur[1] == 'l');
+    Cur += HaveLL * 2;
+    s64 DVal;
+    u64 UVal;
+    const bool HaveLength = HaveZ || HaveLL;
+    const bool HaveFlags = HaveWidth || HaveLength;
+    // At the moment only %s supports precision and left-justification.
+    CHECK(!((Precision >= 0 || LeftJustified) && *Cur != 's'));
+    switch (*Cur) {
+    case 'd': {
+      DVal = HaveLL ? va_arg(Args, s64)
+                    : HaveZ ? va_arg(Args, sptr) : va_arg(Args, int);
+      Res += appendSignedDecimal(&Buffer, BufferEnd, DVal, Width, PadWithZero);
+      break;
+    }
+    case 'u':
+    case 'x':
+    case 'X': {
+      UVal = HaveLL ? va_arg(Args, u64)
+                    : HaveZ ? va_arg(Args, uptr) : va_arg(Args, unsigned);
+      const bool Upper = (*Cur == 'X');
+      Res += appendUnsigned(&Buffer, BufferEnd, UVal, (*Cur == 'u') ? 10 : 16,
+                            Width, PadWithZero, Upper);
+      break;
+    }
+    case 'p': {
+      RAW_CHECK_MSG(!HaveFlags, PrintfFormatsHelp);
+      Res += appendPointer(&Buffer, BufferEnd, va_arg(Args, uptr));
+      break;
+    }
+    case 's': {
+      RAW_CHECK_MSG(!HaveLength, PrintfFormatsHelp);
+      // Only left-justified Width is supported.
+      CHECK(!HaveWidth || LeftJustified);
+      Res += appendString(&Buffer, BufferEnd, LeftJustified ? -Width : Width,
+                          Precision, va_arg(Args, char *));
+      break;
+    }
+    case 'c': {
+      RAW_CHECK_MSG(!HaveFlags, PrintfFormatsHelp);
+      Res +=
+          appendChar(&Buffer, BufferEnd, static_cast<char>(va_arg(Args, int)));
+      break;
+    }
+    case '%': {
+      RAW_CHECK_MSG(!HaveFlags, PrintfFormatsHelp);
+      Res += appendChar(&Buffer, BufferEnd, '%');
+      break;
+    }
+    default: {
+      RAW_CHECK_MSG(false, PrintfFormatsHelp);
+    }
+    }
+  }
+  RAW_CHECK(Buffer <= BufferEnd);
+  appendChar(&Buffer, BufferEnd + 1, '\0');
+  return Res;
+}
+
+void ScopedString::append(const char *Format, va_list Args) {
+  CHECK_LT(Length, String.size());
+  formatString(String.data() + Length, String.size() - Length, Format, Args);
+  Length += strlen(String.data() + Length);
+  CHECK_LT(Length, String.size());
+}
+
+FORMAT(2, 3)
+void ScopedString::append(const char *Format, ...) {
+  va_list Args;
+  va_start(Args, Format);
+  append(Format, Args);
+  va_end(Args);
+}
+
+FORMAT(1, 2)
+void Printf(const char *Format, ...) {
+  va_list Args;
+  va_start(Args, Format);
+  ScopedString Msg(512);
+  Msg.append(Format, Args);
+  outputRaw(Msg.data());
+  va_end(Args);
+}
+
+} // namespace scudo

Added: compiler-rt/trunk/lib/scudo/standalone/string_utils.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/standalone/string_utils.h?rev=356457&view=auto
==============================================================================
--- compiler-rt/trunk/lib/scudo/standalone/string_utils.h (added)
+++ compiler-rt/trunk/lib/scudo/standalone/string_utils.h Tue Mar 19 07:47:05 2019
@@ -0,0 +1,42 @@
+//===-- string_utils.h ------------------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SCUDO_STRING_UTILS_H_
+#define SCUDO_STRING_UTILS_H_
+
+#include "internal_defs.h"
+#include "vector.h"
+
+#include <stdarg.h>
+
+namespace scudo {
+
+class ScopedString {
+public:
+  explicit ScopedString(uptr MaxLength) : String(MaxLength), Length(0) {
+    String[0] = '\0';
+  }
+  uptr length() { return Length; }
+  const char *data() { return String.data(); }
+  void clear() {
+    String[0] = '\0';
+    Length = 0;
+  }
+  void append(const char *Format, va_list Args);
+  void append(const char *Format, ...);
+
+private:
+  Vector<char> String;
+  uptr Length;
+};
+
+void Printf(const char *Format, ...);
+
+} // namespace scudo
+
+#endif // SCUDO_STRING_UTILS_H_

Modified: compiler-rt/trunk/lib/scudo/standalone/tests/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/standalone/tests/CMakeLists.txt?rev=356457&r1=356456&r2=356457&view=diff
==============================================================================
--- compiler-rt/trunk/lib/scudo/standalone/tests/CMakeLists.txt (original)
+++ compiler-rt/trunk/lib/scudo/standalone/tests/CMakeLists.txt Tue Mar 19 07:47:05 2019
@@ -56,6 +56,7 @@ set(SCUDO_UNIT_TEST_SOURCES
   map_test.cc
   mutex_test.cc
   stats_test.cc
+  strings_test.cc
   vector_test.cc
   scudo_unit_test_main.cc)
 

Added: compiler-rt/trunk/lib/scudo/standalone/tests/strings_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/standalone/tests/strings_test.cc?rev=356457&view=auto
==============================================================================
--- compiler-rt/trunk/lib/scudo/standalone/tests/strings_test.cc (added)
+++ compiler-rt/trunk/lib/scudo/standalone/tests/strings_test.cc Tue Mar 19 07:47:05 2019
@@ -0,0 +1,98 @@
+//===-- strings_test.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
+//
+//===----------------------------------------------------------------------===//
+
+#include "scudo/standalone/string_utils.h"
+#include "gtest/gtest.h"
+
+#include <limits.h>
+
+TEST(ScudoStringsTest, Basic) {
+  scudo::ScopedString Str(128);
+  Str.append("a%db%zdc%ue%zuf%xh%zxq%pe%sr", static_cast<int>(-1),
+             static_cast<scudo::uptr>(-2), static_cast<unsigned>(-4),
+             static_cast<scudo::uptr>(5), static_cast<unsigned>(10),
+             static_cast<scudo::uptr>(11), reinterpret_cast<void *>(0x123),
+             "_string_");
+  EXPECT_EQ(Str.length(), strlen(Str.data()));
+
+  std::string expectedString = "a-1b-2c4294967292e5fahbq0x";
+  expectedString += std::string(SCUDO_POINTER_FORMAT_LENGTH - 3, '0');
+  expectedString += "123e_string_r";
+  EXPECT_EQ(Str.length(), strlen(Str.data()));
+  EXPECT_STREQ(expectedString.c_str(), Str.data());
+}
+
+TEST(ScudoStringsTest, Precision) {
+  scudo::ScopedString Str(128);
+  Str.append("%.*s", 3, "12345");
+  EXPECT_EQ(Str.length(), strlen(Str.data()));
+  EXPECT_STREQ("123", Str.data());
+  Str.clear();
+  Str.append("%.*s", 6, "12345");
+  EXPECT_EQ(Str.length(), strlen(Str.data()));
+  EXPECT_STREQ("12345", Str.data());
+  Str.clear();
+  Str.append("%-6s", "12345");
+  EXPECT_EQ(Str.length(), strlen(Str.data()));
+  EXPECT_STREQ("12345 ", Str.data());
+}
+
+static void fillString(scudo::ScopedString &Str, scudo::uptr Size) {
+  for (scudo::uptr I = 0; I < Size; I++)
+    Str.append("A");
+}
+
+TEST(ScudoStringTest, PotentialOverflows) {
+  // Use a ScopedString that spans a page, and attempt to write past the end
+  // of it with variations of append. The expectation is for nothing to crash.
+  const scudo::uptr PageSize = scudo::getPageSizeCached();
+  scudo::ScopedString Str(PageSize);
+  Str.clear();
+  fillString(Str, 2 * PageSize);
+  Str.clear();
+  fillString(Str, PageSize - 64);
+  Str.append("%-128s", "12345");
+  Str.clear();
+  fillString(Str, PageSize - 16);
+  Str.append("%024x", 12345);
+  Str.clear();
+  fillString(Str, PageSize - 16);
+  Str.append("EEEEEEEEEEEEEEEEEEEEEEEE");
+}
+
+template <typename T>
+static void testAgainstLibc(const char *Format, T Arg1, T Arg2) {
+  scudo::ScopedString Str(128);
+  Str.append(Format, Arg1, Arg2);
+  char Buffer[128];
+  snprintf(Buffer, sizeof(Buffer), Format, Arg1, Arg2);
+  EXPECT_EQ(Str.length(), strlen(Str.data()));
+  EXPECT_STREQ(Buffer, Str.data());
+}
+
+TEST(ScudoStringsTest, MinMax) {
+  testAgainstLibc<int>("%d-%d", INT_MIN, INT_MAX);
+  testAgainstLibc<unsigned>("%u-%u", 0, UINT_MAX);
+  testAgainstLibc<unsigned>("%x-%x", 0, UINT_MAX);
+  testAgainstLibc<long>("%zd-%zd", LONG_MIN, LONG_MAX);
+  testAgainstLibc<unsigned long>("%zu-%zu", 0, ULONG_MAX);
+  testAgainstLibc<unsigned long>("%zx-%zx", 0, ULONG_MAX);
+}
+
+TEST(ScudoStringsTest, Padding) {
+  testAgainstLibc<int>("%3d - %3d", 1, 0);
+  testAgainstLibc<int>("%3d - %3d", -1, 123);
+  testAgainstLibc<int>("%3d - %3d", -1, -123);
+  testAgainstLibc<int>("%3d - %3d", 12, 1234);
+  testAgainstLibc<int>("%3d - %3d", -12, -1234);
+  testAgainstLibc<int>("%03d - %03d", 1, 0);
+  testAgainstLibc<int>("%03d - %03d", -1, 123);
+  testAgainstLibc<int>("%03d - %03d", -1, -123);
+  testAgainstLibc<int>("%03d - %03d", 12, 1234);
+  testAgainstLibc<int>("%03d - %03d", -12, -1234);
+}




More information about the llvm-commits mailing list