brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.6 KiB · e584bd8 Raw
242 lines · cpp
1//===-- string_utils.cpp ----------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "string_utils.h"10#include "common.h"11 12#include <stdarg.h>13#include <string.h>14 15namespace scudo {16 17// Appends number in a given Base to buffer. If its length is less than18// |MinNumberLength|, it is padded with leading zeroes or spaces, depending19// on the value of |PadWithZero|.20void ScopedString::appendNumber(u64 AbsoluteValue, u8 Base, u8 MinNumberLength,21                                bool PadWithZero, bool Negative, bool Upper) {22  constexpr uptr MaxLen = 30;23  RAW_CHECK(Base == 10 || Base == 16);24  RAW_CHECK(Base == 10 || !Negative);25  RAW_CHECK(AbsoluteValue || !Negative);26  RAW_CHECK(MinNumberLength < MaxLen);27  if (Negative && MinNumberLength)28    --MinNumberLength;29  if (Negative && PadWithZero) {30    String.push_back('-');31  }32  uptr NumBuffer[MaxLen];33  int Pos = 0;34  do {35    RAW_CHECK_MSG(static_cast<uptr>(Pos) < MaxLen,36                  "appendNumber buffer overflow");37    NumBuffer[Pos++] = static_cast<uptr>(AbsoluteValue % Base);38    AbsoluteValue /= Base;39  } while (AbsoluteValue > 0);40  if (Pos < MinNumberLength) {41    memset(&NumBuffer[Pos], 0,42           sizeof(NumBuffer[0]) * static_cast<uptr>(MinNumberLength - Pos));43    Pos = MinNumberLength;44  }45  RAW_CHECK(Pos > 0);46  Pos--;47  for (; Pos >= 0 && NumBuffer[Pos] == 0; Pos--) {48    char c = (PadWithZero || Pos == 0) ? '0' : ' ';49    String.push_back(c);50  }51  if (Negative && !PadWithZero)52    String.push_back('-');53  for (; Pos >= 0; Pos--) {54    char Digit = static_cast<char>(NumBuffer[Pos]);55    Digit = static_cast<char>((Digit < 10) ? '0' + Digit56                                           : (Upper ? 'A' : 'a') + Digit - 10);57    String.push_back(Digit);58  }59}60 61void ScopedString::appendUnsigned(u64 Num, u8 Base, u8 MinNumberLength,62                                  bool PadWithZero, bool Upper) {63  appendNumber(Num, Base, MinNumberLength, PadWithZero, /*Negative=*/false,64               Upper);65}66 67void ScopedString::appendSignedDecimal(s64 Num, u8 MinNumberLength,68                                       bool PadWithZero) {69  const bool Negative = (Num < 0);70  const u64 UnsignedNum = (Num == INT64_MIN)71                              ? static_cast<u64>(INT64_MAX) + 172                              : static_cast<u64>(Negative ? -Num : Num);73  appendNumber(UnsignedNum, 10, MinNumberLength, PadWithZero, Negative,74               /*Upper=*/false);75}76 77// Use the fact that explicitly requesting 0 Width (%0s) results in UB and78// interpret Width == 0 as "no Width requested":79// Width == 0 - no Width requested80// Width  < 0 - left-justify S within and pad it to -Width chars, if necessary81// Width  > 0 - right-justify S, not implemented yet82void ScopedString::appendString(int Width, int MaxChars, const char *S) {83  if (!S)84    S = "<null>";85  int NumChars = 0;86  for (; *S; S++) {87    if (MaxChars >= 0 && NumChars >= MaxChars)88      break;89    String.push_back(*S);90    NumChars++;91  }92  if (Width < 0) {93    // Only left justification supported.94    Width = -Width - NumChars;95    while (Width-- > 0)96      String.push_back(' ');97  }98}99 100void ScopedString::appendPointer(u64 ptr_value) {101  appendString(0, -1, "0x");102  appendUnsigned(ptr_value, 16, SCUDO_POINTER_FORMAT_LENGTH,103                 /*PadWithZero=*/true,104                 /*Upper=*/false);105}106 107void ScopedString::vappend(const char *Format, va_list &Args) {108  // Since the string contains the '\0' terminator, put our size before it109  // so that push_back calls work correctly.110  DCHECK(String.size() > 0);111  String.resize(String.size() - 1);112 113  static const char *PrintfFormatsHelp =114      "Supported formats: %([0-9]*)?(z|ll)?{d,u,x,X}; %p; "115      "%[-]([0-9]*)?(\\.\\*)?s; %c\n";116  RAW_CHECK(Format);117  const char *Cur = Format;118  for (; *Cur; Cur++) {119    if (*Cur != '%') {120      String.push_back(*Cur);121      continue;122    }123    Cur++;124    const bool LeftJustified = *Cur == '-';125    if (LeftJustified)126      Cur++;127    bool HaveWidth = (*Cur >= '0' && *Cur <= '9');128    const bool PadWithZero = (*Cur == '0');129    u8 Width = 0;130    if (HaveWidth) {131      while (*Cur >= '0' && *Cur <= '9')132        Width = static_cast<u8>(Width * 10 + *Cur++ - '0');133    }134    const bool HavePrecision = (Cur[0] == '.' && Cur[1] == '*');135    int Precision = -1;136    if (HavePrecision) {137      Cur += 2;138      Precision = va_arg(Args, int);139    }140    const bool HaveZ = (*Cur == 'z');141    Cur += HaveZ;142    const bool HaveLL = !HaveZ && (Cur[0] == 'l' && Cur[1] == 'l');143    Cur += HaveLL * 2;144    s64 DVal;145    u64 UVal;146    const bool HaveLength = HaveZ || HaveLL;147    const bool HaveFlags = HaveWidth || HaveLength;148    // At the moment only %s supports precision and left-justification.149    CHECK(!((Precision >= 0 || LeftJustified) && *Cur != 's'));150    switch (*Cur) {151    case 'd': {152      DVal = HaveLL  ? va_arg(Args, s64)153             : HaveZ ? va_arg(Args, sptr)154                     : va_arg(Args, int);155      appendSignedDecimal(DVal, Width, PadWithZero);156      break;157    }158    case 'u':159    case 'x':160    case 'X': {161      UVal = HaveLL  ? va_arg(Args, u64)162             : HaveZ ? va_arg(Args, uptr)163                     : va_arg(Args, unsigned);164      const bool Upper = (*Cur == 'X');165      appendUnsigned(UVal, (*Cur == 'u') ? 10 : 16, Width, PadWithZero, Upper);166      break;167    }168    case 'p': {169      RAW_CHECK_MSG(!HaveFlags, PrintfFormatsHelp);170      appendPointer(va_arg(Args, uptr));171      break;172    }173    case 's': {174      RAW_CHECK_MSG(!HaveLength, PrintfFormatsHelp);175      // Only left-justified Width is supported.176      CHECK(!HaveWidth || LeftJustified);177      appendString(LeftJustified ? -Width : Width, Precision,178                   va_arg(Args, char *));179      break;180    }181    case 'c': {182      RAW_CHECK_MSG(!HaveFlags, PrintfFormatsHelp);183      String.push_back(static_cast<char>(va_arg(Args, int)));184      break;185    }186    // In Scudo, `s64`/`u64` are supposed to use `lld` and `llu` respectively.187    // However, `-Wformat` doesn't know we have a different parser for those188    // placeholders and it keeps complaining the type mismatch on 64-bit189    // platform which uses `ld`/`lu` for `s64`/`u64`. Therefore, in order to190    // silence the warning, we turn to use `PRId64`/`PRIu64` for printing191    // `s64`/`u64` and handle the `ld`/`lu` here.192    case 'l': {193      ++Cur;194      RAW_CHECK(*Cur == 'd' || *Cur == 'u');195 196      if (*Cur == 'd') {197        DVal = va_arg(Args, s64);198        appendSignedDecimal(DVal, Width, PadWithZero);199      } else {200        UVal = va_arg(Args, u64);201        appendUnsigned(UVal, 10, Width, PadWithZero, false);202      }203 204      break;205    }206    case '%': {207      RAW_CHECK_MSG(!HaveFlags, PrintfFormatsHelp);208      String.push_back('%');209      break;210    }211    default: {212      RAW_CHECK_MSG(false, PrintfFormatsHelp);213    }214    }215  }216  String.push_back('\0');217  if (String.back() != '\0') {218    // String truncated, make sure the string is terminated properly.219    // This can happen if there is no more memory when trying to resize220    // the string.221    String.back() = '\0';222  }223}224 225void ScopedString::append(const char *Format, ...) {226  va_list Args;227  va_start(Args, Format);228  vappend(Format, Args);229  va_end(Args);230}231 232void Printf(const char *Format, ...) {233  va_list Args;234  va_start(Args, Format);235  ScopedString Msg;236  Msg.vappend(Format, Args);237  outputRaw(Msg.data());238  va_end(Args);239}240 241} // namespace scudo242