reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
//===-- scudo_flags.cpp -----------------------------------------*- 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
//
//===----------------------------------------------------------------------===//
///
/// Hardened Allocator flag parsing logic.
///
//===----------------------------------------------------------------------===//

#include "scudo_flags.h"
#include "scudo_interface_internal.h"
#include "scudo_utils.h"

#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_flag_parser.h"

namespace __scudo {

static Flags ScudoFlags;  // Use via getFlags().

void Flags::setDefaults() {
#define SCUDO_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
#include "scudo_flags.inc"
#undef SCUDO_FLAG
}

static void RegisterScudoFlags(FlagParser *parser, Flags *f) {
#define SCUDO_FLAG(Type, Name, DefaultValue, Description) \
  RegisterFlag(parser, #Name, Description, &f->Name);
#include "scudo_flags.inc"
#undef SCUDO_FLAG
}

static const char *getCompileDefinitionScudoDefaultOptions() {
#ifdef SCUDO_DEFAULT_OPTIONS
  return SANITIZER_STRINGIFY(SCUDO_DEFAULT_OPTIONS);
#else
  return "";
#endif
}

static const char *getScudoDefaultOptions() {
  return (&__scudo_default_options) ? __scudo_default_options() : "";
}

void initFlags() {
  SetCommonFlagsDefaults();
  {
    CommonFlags cf;
    cf.CopyFrom(*common_flags());
    cf.exitcode = 1;
    OverrideCommonFlags(cf);
  }
  Flags *f = getFlags();
  f->setDefaults();

  FlagParser ScudoParser;
  RegisterScudoFlags(&ScudoParser, f);
  RegisterCommonFlags(&ScudoParser);

  // Override from compile definition.
  ScudoParser.ParseString(getCompileDefinitionScudoDefaultOptions());

  // Override from user-specified string.
  ScudoParser.ParseString(getScudoDefaultOptions());

  // Override from environment.
  ScudoParser.ParseStringFromEnv("SCUDO_OPTIONS");

  InitializeCommonFlags();

  // Sanity checks and default settings for the Quarantine parameters.

  if (f->QuarantineSizeMb >= 0) {
    // Backward compatible logic if QuarantineSizeMb is set.
    if (f->QuarantineSizeKb >= 0) {
      dieWithMessage("ERROR: please use either QuarantineSizeMb (deprecated) "
          "or QuarantineSizeKb, but not both\n");
    }
    if (f->QuarantineChunksUpToSize >= 0) {
      dieWithMessage("ERROR: QuarantineChunksUpToSize cannot be used in "
          " conjunction with the deprecated QuarantineSizeMb option\n");
    }
    // If everything is in order, update QuarantineSizeKb accordingly.
    f->QuarantineSizeKb = f->QuarantineSizeMb * 1024;
  } else {
    // Otherwise proceed with the new options.
    if (f->QuarantineSizeKb < 0) {
      const int DefaultQuarantineSizeKb = FIRST_32_SECOND_64(64, 256);
      f->QuarantineSizeKb = DefaultQuarantineSizeKb;
    }
    if (f->QuarantineChunksUpToSize < 0) {
      const int DefaultQuarantineChunksUpToSize = FIRST_32_SECOND_64(512, 2048);
      f->QuarantineChunksUpToSize = DefaultQuarantineChunksUpToSize;
    }
  }

  // We enforce an upper limit for the chunk quarantine threshold of 4Mb.
  if (f->QuarantineChunksUpToSize > (4 * 1024 * 1024)) {
    dieWithMessage("ERROR: the chunk quarantine threshold is too large\n");
  }

  // We enforce an upper limit for the quarantine size of 32Mb.
  if (f->QuarantineSizeKb > (32 * 1024)) {
    dieWithMessage("ERROR: the quarantine size is too large\n");
  }

  if (f->ThreadLocalQuarantineSizeKb < 0) {
    const int DefaultThreadLocalQuarantineSizeKb = FIRST_32_SECOND_64(16, 64);
    f->ThreadLocalQuarantineSizeKb = DefaultThreadLocalQuarantineSizeKb;
  }
  // And an upper limit of 8Mb for the thread quarantine cache.
  if (f->ThreadLocalQuarantineSizeKb > (8 * 1024)) {
    dieWithMessage("ERROR: the per thread quarantine cache size is too "
        "large\n");
  }
  if (f->ThreadLocalQuarantineSizeKb == 0 && f->QuarantineSizeKb > 0) {
    dieWithMessage("ERROR: ThreadLocalQuarantineSizeKb can be set to 0 only "
        "when QuarantineSizeKb is set to 0\n");
  }
}

Flags *getFlags() {
  return &ScudoFlags;
}

}  // namespace __scudo

#if !SANITIZER_SUPPORTS_WEAK_HOOKS
SANITIZER_INTERFACE_WEAK_DEF(const char*, __scudo_default_options, void) {
  return "";
}
#endif