[compiler-rt] r358011 - [scudo][standalone] Add flags & related parsers

Kostya Kortchinsky via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 9 07:57:25 PDT 2019


Author: cryptoad
Date: Tue Apr  9 07:57:25 2019
New Revision: 358011

URL: http://llvm.org/viewvc/llvm-project?rev=358011&view=rev
Log:
[scudo][standalone] Add flags & related parsers

Summary:
As with other Sanitizers, and the current version of Scudo, we can
provide flags in differents way: at compile time, through a weak
function, through an environment variable.

This change adds support for the configuration flags, and the string
parsers. Those are fairly similar to the sanitizer_common way of doing
things.

Reviewers: morehouse, hctim, vitalybuka

Reviewed By: morehouse, vitalybuka

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

Tags: #llvm, #sanitizers

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

Added:
    compiler-rt/trunk/lib/scudo/standalone/flags.cc
    compiler-rt/trunk/lib/scudo/standalone/flags.h
    compiler-rt/trunk/lib/scudo/standalone/flags.inc
    compiler-rt/trunk/lib/scudo/standalone/flags_parser.cc
    compiler-rt/trunk/lib/scudo/standalone/flags_parser.h
    compiler-rt/trunk/lib/scudo/standalone/interface.h
    compiler-rt/trunk/lib/scudo/standalone/tests/flags_test.cc
Modified:
    compiler-rt/trunk/lib/scudo/standalone/CMakeLists.txt
    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=358011&r1=358010&r2=358011&view=diff
==============================================================================
--- compiler-rt/trunk/lib/scudo/standalone/CMakeLists.txt (original)
+++ compiler-rt/trunk/lib/scudo/standalone/CMakeLists.txt Tue Apr  9 07:57:25 2019
@@ -37,6 +37,8 @@ set(SCUDO_SOURCES
   checksum.cc
   crc32_hw.cc
   common.cc
+  flags.cc
+  flags_parser.cc
   fuchsia.cc
   linux.cc
   report.cc
@@ -57,6 +59,9 @@ set(SCUDO_HEADERS
   atomic_helpers.h
   bytemap.h
   checksum.h
+  flags.h
+  flags_parser.h
+  interface.h
   internal_defs.h
   linux.h
   list.h

Added: compiler-rt/trunk/lib/scudo/standalone/flags.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/standalone/flags.cc?rev=358011&view=auto
==============================================================================
--- compiler-rt/trunk/lib/scudo/standalone/flags.cc (added)
+++ compiler-rt/trunk/lib/scudo/standalone/flags.cc Tue Apr  9 07:57:25 2019
@@ -0,0 +1,57 @@
+//===-- flags.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 "flags.h"
+#include "common.h"
+#include "flags_parser.h"
+#include "interface.h"
+
+namespace scudo {
+
+Flags *getFlags() {
+  static Flags F;
+  return &F;
+}
+
+void Flags::setDefaults() {
+#define SCUDO_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
+#include "flags.inc"
+#undef SCUDO_FLAG
+}
+
+void registerFlags(FlagParser *Parser, Flags *F) {
+#define SCUDO_FLAG(Type, Name, DefaultValue, Description)                      \
+  Parser->registerFlag(#Name, Description, FlagType::FT_##Type,                \
+                       reinterpret_cast<void *>(&F->Name));
+#include "flags.inc"
+#undef SCUDO_FLAG
+}
+
+static const char *getCompileDefinitionScudoDefaultOptions() {
+#ifdef SCUDO_DEFAULT_OPTIONS
+  return STRINGIFY(SCUDO_DEFAULT_OPTIONS);
+#else
+  return "";
+#endif
+}
+
+static const char *getScudoDefaultOptions() {
+  return (&__scudo_default_options) ? __scudo_default_options() : "";
+}
+
+void initFlags() {
+  Flags *F = getFlags();
+  F->setDefaults();
+  FlagParser Parser;
+  registerFlags(&Parser, F);
+  Parser.parseString(getCompileDefinitionScudoDefaultOptions());
+  Parser.parseString(getScudoDefaultOptions());
+  Parser.parseString(getEnv("SCUDO_OPTIONS"));
+}
+
+} // namespace scudo

Added: compiler-rt/trunk/lib/scudo/standalone/flags.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/standalone/flags.h?rev=358011&view=auto
==============================================================================
--- compiler-rt/trunk/lib/scudo/standalone/flags.h (added)
+++ compiler-rt/trunk/lib/scudo/standalone/flags.h Tue Apr  9 07:57:25 2019
@@ -0,0 +1,30 @@
+//===-- flags.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_FLAGS_H_
+#define SCUDO_FLAGS_H_
+
+#include "internal_defs.h"
+
+namespace scudo {
+
+struct Flags {
+#define SCUDO_FLAG(Type, Name, DefaultValue, Description) Type Name;
+#include "flags.inc"
+#undef SCUDO_FLAG
+  void setDefaults();
+};
+
+Flags *getFlags();
+void initFlags();
+class FlagParser;
+void registerFlags(FlagParser *Parser, Flags *F);
+
+} // namespace scudo
+
+#endif // SCUDO_FLAGS_H_

Added: compiler-rt/trunk/lib/scudo/standalone/flags.inc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/standalone/flags.inc?rev=358011&view=auto
==============================================================================
--- compiler-rt/trunk/lib/scudo/standalone/flags.inc (added)
+++ compiler-rt/trunk/lib/scudo/standalone/flags.inc Tue Apr  9 07:57:25 2019
@@ -0,0 +1,50 @@
+//===-- flags.inc -----------------------------------------------*- 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_FLAG
+#error "Define SCUDO_FLAG prior to including this file!"
+#endif
+
+SCUDO_FLAG(int, quarantine_size_kb, 0,
+           "Size (in kilobytes) of quarantine used to delay the actual "
+           "deallocation of chunks. Lower value may reduce memory usage but "
+           "decrease the effectiveness of the mitigation.")
+
+SCUDO_FLAG(int, thread_local_quarantine_size_kb, 0,
+           "Size (in kilobytes) of per-thread cache used to offload the global "
+           "quarantine. Lower value may reduce memory usage but might increase "
+           "the contention on the global quarantine.")
+
+SCUDO_FLAG(int, quarantine_max_chunk_size, 0,
+           "Size (in bytes) up to which chunks will be quarantined (if lower "
+           "than or equal to).")
+
+SCUDO_FLAG(bool, dealloc_type_mismatch, false,
+           "Terminate on a type mismatch in allocation-deallocation functions, "
+           "eg: malloc/delete, new/free, new/delete[], etc.")
+
+SCUDO_FLAG(bool, delete_size_mismatch, true,
+           "Terminate on a size mismatch between a sized-delete and the actual "
+           "size of a chunk (as provided to new/new[]).")
+
+SCUDO_FLAG(bool, zero_contents, false, "Zero chunk contents on allocation.")
+
+SCUDO_FLAG(int, rss_limit_mb, -1,
+           "Enforce an upper limit (in megabytes) to the process RSS. The "
+           "allocator will terminate or return NULL when allocations are "
+           "attempted past that limit (depending on may_return_null). Negative "
+           "values disable the feature.")
+
+SCUDO_FLAG(bool, may_return_null, true,
+           "Indicate whether the allocator should terminate instead of "
+           "returning NULL in otherwise non-fatal error scenarios, eg: OOM, "
+           "invalid allocation alignments, etc.")
+
+SCUDO_FLAG(int, release_to_os_interval_ms, 5000,
+           "Interval (in milliseconds) at which to attempt release of unused "
+           "memory to the OS. Negative values disable the feature.")

Added: compiler-rt/trunk/lib/scudo/standalone/flags_parser.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/standalone/flags_parser.cc?rev=358011&view=auto
==============================================================================
--- compiler-rt/trunk/lib/scudo/standalone/flags_parser.cc (added)
+++ compiler-rt/trunk/lib/scudo/standalone/flags_parser.cc Tue Apr  9 07:57:25 2019
@@ -0,0 +1,163 @@
+//===-- flags_parser.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 "flags_parser.h"
+#include "common.h"
+#include "report.h"
+
+#include <string.h>
+
+namespace scudo {
+
+class UnknownFlagsRegistry {
+  static const u32 MaxUnknownFlags = 16;
+  const char *UnknownFlagsNames[MaxUnknownFlags];
+  u32 NumberOfUnknownFlags;
+
+public:
+  void add(const char *Name) {
+    CHECK_LT(NumberOfUnknownFlags, MaxUnknownFlags);
+    UnknownFlagsNames[NumberOfUnknownFlags++] = Name;
+  }
+
+  void report() {
+    if (!NumberOfUnknownFlags)
+      return;
+    Printf("Scudo WARNING: found %d unrecognized flag(s):\n",
+           NumberOfUnknownFlags);
+    for (u32 I = 0; I < NumberOfUnknownFlags; ++I)
+      Printf("    %s\n", UnknownFlagsNames[I]);
+    NumberOfUnknownFlags = 0;
+  }
+};
+static UnknownFlagsRegistry UnknownFlags;
+
+void reportUnrecognizedFlags() { UnknownFlags.report(); }
+
+void FlagParser::printFlagDescriptions() {
+  Printf("Available flags for Scudo:\n");
+  for (u32 I = 0; I < NumberOfFlags; ++I)
+    Printf("\t%s\n\t\t- %s\n", Flags[I].Name, Flags[I].Desc);
+}
+
+static bool isSeparator(char C) {
+  return C == ' ' || C == ',' || C == ':' || C == '\n' || C == '\t' ||
+         C == '\r';
+}
+
+static bool isSeparatorOrNull(char C) { return !C || isSeparator(C); }
+
+void FlagParser::skipWhitespace() {
+  while (isSeparator(Buffer[Pos]))
+    ++Pos;
+}
+
+void FlagParser::parseFlag() {
+  const uptr NameStart = Pos;
+  while (Buffer[Pos] != '=' && !isSeparatorOrNull(Buffer[Pos]))
+    ++Pos;
+  if (Buffer[Pos] != '=')
+    reportError("expected '='");
+  const char *Name = Buffer + NameStart;
+  const uptr ValueStart = ++Pos;
+  const char *Value;
+  if (Buffer[Pos] == '\'' || Buffer[Pos] == '"') {
+    const char Quote = Buffer[Pos++];
+    while (Buffer[Pos] != 0 && Buffer[Pos] != Quote)
+      ++Pos;
+    if (Buffer[Pos] == 0)
+      reportError("unterminated string");
+    Value = Buffer + ValueStart + 1;
+    ++Pos; // consume the closing quote
+  } else {
+    while (!isSeparatorOrNull(Buffer[Pos]))
+      ++Pos;
+    Value = Buffer + ValueStart;
+  }
+  if (!runHandler(Name, Value))
+    reportError("flag parsing failed.");
+}
+
+void FlagParser::parseFlags() {
+  while (true) {
+    skipWhitespace();
+    if (Buffer[Pos] == 0)
+      break;
+    parseFlag();
+  }
+}
+
+void FlagParser::parseString(const char *S) {
+  if (!S)
+    return;
+  // Backup current parser state to allow nested parseString() calls.
+  const char *OldBuffer = Buffer;
+  const uptr OldPos = Pos;
+  Buffer = S;
+  Pos = 0;
+
+  parseFlags();
+
+  Buffer = OldBuffer;
+  Pos = OldPos;
+}
+
+INLINE bool parseBool(const char *Value, bool *b) {
+  if (strncmp(Value, "0", 1) == 0 || strncmp(Value, "no", 2) == 0 ||
+      strncmp(Value, "false", 5) == 0) {
+    *b = false;
+    return true;
+  }
+  if (strncmp(Value, "1", 1) == 0 || strncmp(Value, "yes", 3) == 0 ||
+      strncmp(Value, "true", 4) == 0) {
+    *b = true;
+    return true;
+  }
+  return false;
+}
+
+bool FlagParser::runHandler(const char *Name, const char *Value) {
+  for (u32 I = 0; I < NumberOfFlags; ++I) {
+    const uptr Len = strlen(Flags[I].Name);
+    if (strncmp(Name, Flags[I].Name, Len) != 0 || Name[Len] != '=')
+      continue;
+    bool Ok = false;
+    switch (Flags[I].Type) {
+    case FlagType::FT_bool:
+      Ok = parseBool(Value, reinterpret_cast<bool *>(Flags[I].Var));
+      if (!Ok)
+        reportInvalidFlag("bool", Value);
+      break;
+    case FlagType::FT_int:
+      char *ValueEnd;
+      *reinterpret_cast<int *>(Flags[I].Var) =
+          static_cast<int>(strtol(Value, &ValueEnd, 10));
+      Ok =
+          *ValueEnd == '"' || *ValueEnd == '\'' || isSeparatorOrNull(*ValueEnd);
+      if (!Ok)
+        reportInvalidFlag("int", Value);
+      break;
+    }
+    return Ok;
+  }
+  // Unrecognized flag. This is not a fatal error, we may print a warning later.
+  UnknownFlags.add(Name);
+  return true;
+}
+
+void FlagParser::registerFlag(const char *Name, const char *Desc, FlagType Type,
+                              void *Var) {
+  CHECK_LT(NumberOfFlags, MaxFlags);
+  Flags[NumberOfFlags].Name = Name;
+  Flags[NumberOfFlags].Desc = Desc;
+  Flags[NumberOfFlags].Type = Type;
+  Flags[NumberOfFlags].Var = Var;
+  ++NumberOfFlags;
+}
+
+} // namespace scudo

Added: compiler-rt/trunk/lib/scudo/standalone/flags_parser.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/standalone/flags_parser.h?rev=358011&view=auto
==============================================================================
--- compiler-rt/trunk/lib/scudo/standalone/flags_parser.h (added)
+++ compiler-rt/trunk/lib/scudo/standalone/flags_parser.h Tue Apr  9 07:57:25 2019
@@ -0,0 +1,56 @@
+//===-- flags_parser.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_FLAGS_PARSER_H_
+#define SCUDO_FLAGS_PARSER_H_
+
+#include "report.h"
+#include "string_utils.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+
+namespace scudo {
+
+enum class FlagType : u8 {
+  FT_bool,
+  FT_int,
+};
+
+class FlagParser {
+public:
+  void registerFlag(const char *Name, const char *Desc, FlagType Type,
+                    void *Var);
+  void parseString(const char *S);
+  void printFlagDescriptions();
+
+private:
+  static const u32 MaxFlags = 12;
+  struct Flag {
+    const char *Name;
+    const char *Desc;
+    FlagType Type;
+    void *Var;
+  } Flags[MaxFlags];
+
+  u32 NumberOfFlags = 0;
+  const char *Buffer = nullptr;
+  uptr Pos = 0;
+
+  void reportFatalError(const char *Error);
+  void skipWhitespace();
+  void parseFlags();
+  void parseFlag();
+  bool runHandler(const char *Name, const char *Value);
+};
+
+void reportUnrecognizedFlags();
+
+} // namespace scudo
+
+#endif // SCUDO_FLAGS_PARSER_H_

Added: compiler-rt/trunk/lib/scudo/standalone/interface.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/standalone/interface.h?rev=358011&view=auto
==============================================================================
--- compiler-rt/trunk/lib/scudo/standalone/interface.h (added)
+++ compiler-rt/trunk/lib/scudo/standalone/interface.h Tue Apr  9 07:57:25 2019
@@ -0,0 +1,29 @@
+//===-- interface.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_INTERFACE_H_
+#define SCUDO_INTERFACE_H_
+
+#include "internal_defs.h"
+
+extern "C" {
+
+WEAK INTERFACE const char *__scudo_default_options();
+
+// Post-allocation & pre-deallocation hooks.
+// They must be thread-safe and not use heap related functions.
+WEAK INTERFACE void __scudo_allocate_hook(void *ptr, size_t size);
+WEAK INTERFACE void __scudo_deallocate_hook(void *ptr);
+
+WEAK INTERFACE void __scudo_print_stats(void);
+
+typedef void (*iterate_callback)(uintptr_t base, size_t size, void *arg);
+
+} // extern "C"
+
+#endif // SCUDO_INTERFACE_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=358011&r1=358010&r2=358011&view=diff
==============================================================================
--- compiler-rt/trunk/lib/scudo/standalone/tests/CMakeLists.txt (original)
+++ compiler-rt/trunk/lib/scudo/standalone/tests/CMakeLists.txt Tue Apr  9 07:57:25 2019
@@ -52,6 +52,7 @@ set(SCUDO_UNIT_TEST_SOURCES
   atomic_test.cc
   bytemap_test.cc
   checksum_test.cc
+  flags_test.cc
   list_test.cc
   map_test.cc
   mutex_test.cc

Added: compiler-rt/trunk/lib/scudo/standalone/tests/flags_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/standalone/tests/flags_test.cc?rev=358011&view=auto
==============================================================================
--- compiler-rt/trunk/lib/scudo/standalone/tests/flags_test.cc (added)
+++ compiler-rt/trunk/lib/scudo/standalone/tests/flags_test.cc Tue Apr  9 07:57:25 2019
@@ -0,0 +1,119 @@
+//===-- flags_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 "flags.h"
+#include "flags_parser.h"
+
+#include "gtest/gtest.h"
+
+#include <string.h>
+
+static const char FlagName[] = "flag_name";
+static const char FlagDesc[] = "flag description";
+
+template <typename T>
+static void testFlag(scudo::FlagType Type, T StartValue, const char *Env,
+                     T FinalValue) {
+  scudo::FlagParser Parser;
+  T Flag = StartValue;
+  Parser.registerFlag(FlagName, FlagDesc, Type, &Flag);
+  Parser.parseString(Env);
+  EXPECT_EQ(FinalValue, Flag);
+  // Reporting unrecognized flags is needed to reset them.
+  scudo::reportUnrecognizedFlags();
+}
+
+TEST(ScudoFlagsTest, BooleanFlags) {
+  testFlag(scudo::FlagType::FT_bool, false, "flag_name=1", true);
+  testFlag(scudo::FlagType::FT_bool, false, "flag_name=yes", true);
+  testFlag(scudo::FlagType::FT_bool, false, "flag_name='yes'", true);
+  testFlag(scudo::FlagType::FT_bool, false, "flag_name=true", true);
+  testFlag(scudo::FlagType::FT_bool, true, "flag_name=0", false);
+  testFlag(scudo::FlagType::FT_bool, true, "flag_name=\"0\"", false);
+  testFlag(scudo::FlagType::FT_bool, true, "flag_name=no", false);
+  testFlag(scudo::FlagType::FT_bool, true, "flag_name=false", false);
+  testFlag(scudo::FlagType::FT_bool, true, "flag_name='false'", false);
+}
+
+TEST(ScudoFlagsDeathTest, BooleanFlags) {
+  EXPECT_DEATH(testFlag(scudo::FlagType::FT_bool, false, "flag_name", true),
+               "expected '='");
+  EXPECT_DEATH(testFlag(scudo::FlagType::FT_bool, false, "flag_name=", true),
+               "invalid value for bool option: ''");
+  EXPECT_DEATH(testFlag(scudo::FlagType::FT_bool, false, "flag_name=2", true),
+               "invalid value for bool option: '2'");
+  EXPECT_DEATH(testFlag(scudo::FlagType::FT_bool, false, "flag_name=-1", true),
+               "invalid value for bool option: '-1'");
+  EXPECT_DEATH(testFlag(scudo::FlagType::FT_bool, false, "flag_name=on", true),
+               "invalid value for bool option: 'on'");
+}
+
+TEST(ScudoFlagsTest, IntFlags) {
+  testFlag(scudo::FlagType::FT_int, -11, nullptr, -11);
+  testFlag(scudo::FlagType::FT_int, -11, "flag_name=0", 0);
+  testFlag(scudo::FlagType::FT_int, -11, "flag_name='0'", 0);
+  testFlag(scudo::FlagType::FT_int, -11, "flag_name=42", 42);
+  testFlag(scudo::FlagType::FT_int, -11, "flag_name=-42", -42);
+  testFlag(scudo::FlagType::FT_int, -11, "flag_name=\"-42\"", -42);
+
+  // Unrecognized flags are ignored.
+  testFlag(scudo::FlagType::FT_int, -11, "--flag_name=42", -11);
+  testFlag(scudo::FlagType::FT_int, -11, "zzzzzzz=42", -11);
+}
+
+TEST(ScudoFlagsDeathTest, IntFlags) {
+  EXPECT_DEATH(testFlag(scudo::FlagType::FT_int, -11, "flag_name", 0),
+               "expected '='");
+  EXPECT_DEATH(testFlag(scudo::FlagType::FT_int, -11, "flag_name=42U", 0),
+               "invalid value for int option");
+}
+
+static void testTwoFlags(const char *Env, bool ExpectedFlag1,
+                         const int ExpectedFlag2, const char *Name1 = "flag1",
+                         const char *Name2 = "flag2") {
+  scudo::FlagParser Parser;
+  bool Flag1 = !ExpectedFlag1;
+  int Flag2;
+  Parser.registerFlag(Name1, FlagDesc, scudo::FlagType::FT_bool, &Flag1);
+  Parser.registerFlag(Name2, FlagDesc, scudo::FlagType::FT_int, &Flag2);
+  Parser.parseString(Env);
+  EXPECT_EQ(ExpectedFlag1, Flag1);
+  EXPECT_EQ(Flag2, ExpectedFlag2);
+  // Reporting unrecognized flags is needed to reset them.
+  scudo::reportUnrecognizedFlags();
+}
+
+TEST(ScudoFlagsTest, MultipleFlags) {
+  testTwoFlags("flag1=1 flag2=42", true, 42);
+  testTwoFlags("flag2=-1 flag1=0", false, -1);
+  testTwoFlags("flag1=false:flag2=1337", false, 1337);
+  testTwoFlags("flag2=42:flag1=yes", true, 42);
+  testTwoFlags("flag2=42\nflag1=yes", true, 42);
+  testTwoFlags("flag2=42\r\nflag1=yes", true, 42);
+  testTwoFlags("flag2=42\tflag1=yes", true, 42);
+}
+
+TEST(ScudoFlagsTest, CommonSuffixFlags) {
+  testTwoFlags("flag=1 other_flag=42", true, 42, "flag", "other_flag");
+  testTwoFlags("other_flag=42 flag=1", true, 42, "flag", "other_flag");
+}
+
+TEST(ScudoFlagsTest, AllocatorFlags) {
+  scudo::FlagParser Parser;
+  scudo::Flags Flags;
+  scudo::registerFlags(&Parser, &Flags);
+  Flags.setDefaults();
+  Flags.dealloc_type_mismatch = false;
+  Flags.delete_size_mismatch = false;
+  Flags.quarantine_max_chunk_size = 1024;
+  Parser.parseString("dealloc_type_mismatch=true:delete_size_mismatch=true:"
+                     "quarantine_max_chunk_size=2048");
+  EXPECT_TRUE(Flags.dealloc_type_mismatch);
+  EXPECT_TRUE(Flags.delete_size_mismatch);
+  EXPECT_EQ(2048, Flags.quarantine_max_chunk_size);
+}




More information about the llvm-commits mailing list